web-dev-qa-db-ja.com

Pythonの行列指数

Pythonで複雑な行列をべき乗しようとしていますが、問題が発生しています。scipy.linalg.expm関数を使用していますが、試行するとかなり奇妙なエラーメッセージが表示されます。次のコード:

import numpy as np
from scipy import linalg

hamiltonian = np.mat('[1,0,0,0;0,-1,0,0;0,0,-1,0;0,0,0,1]')

# This works
t_list = np.linspace(0,1,10)
unitary = [linalg.expm(-(1j)*t*hamiltonian) for t in t_list]

# This doesn't
t_list = np.linspace(0,10,100)
unitary = [linalg.expm(-(1j)*t*hamiltonian) for t in t_list]

2番目の実験を実行したときのエラーは次のとおりです。

This works!
Traceback (most recent call last):
  File "matrix_exp.py", line 11, in <module>
    unitary_t = [linalg.expm(-1*t*(1j)*hamiltonian) for t in t_list]
  File "/usr/lib/python2.7/dist-packages/scipy/linalg/matfuncs.py",     line 105, in expm
    return scipy.sparse.linalg.expm(A)
  File "/usr/lib/python2.7/dist- packages/scipy/sparse/linalg/matfuncs.py", line 344, in expm
    X = _fragment_2_1(X, A, s)
  File "/usr/lib/python2.7/dist-  packages/scipy/sparse/linalg/matfuncs.py", line 462, in _fragment_2_1
    X[k, k] = exp_diag[k]
TypeError: only length-1 arrays can be converted to Python scalars

私が変更したのは使用していたtの範囲だけだったので、これは本当に奇妙に思えます。ハミルトニアンが対角であるからですか?一般的に、ハミルトニアンはそうではありませんが、対角線のハミルトニアンでも機能するようにしたいと思います。 expmの仕組みはよくわからないので、助けていただければ幸いです。

8
anar

それは興味深い。私が言えることの1つは、問題は_np.matrix_サブクラスに固有であるということです。たとえば、次のように正常に機能します。

_h = np.array(hamiltonian)
unitary = [linalg.expm(-(1j)*t*h) for t in t_list]
_

トレースバックをもう少し深く掘り下げると、例外は__fragment_2_1_の_scipy.sparse.linalg.matfuncs.py_で発生しています。具体的には これらの行

_n = X.shape[0]
diag_T = T.diagonal().copy()

# Replace diag(X) by exp(2^-s diag(T)).
scale = 2 ** -s
exp_diag = np.exp(scale * diag_T)
for k in range(n):
    X[k, k] = exp_diag[k]
_

エラーメッセージ

_    X[k, k] = exp_diag[k]
TypeError: only length-1 arrays can be converted to Python scalars
_

_exp_diag[k]_はスカラーである必要がありますが、代わりにベクトルを返していることを私に示唆しています(そして、スカラーである_X[k, k]_にベクトルを割り当てることはできません)。

ブレークポイントを設定し、これらの変数の形状を調べると、これが確認されます。

_ipdb> l
    751     # Replace diag(X) by exp(2^-s diag(T)).
    752     scale = 2 ** -s
    753     exp_diag = np.exp(scale * diag_T)
    754     for k in range(n):
    755         import ipdb; ipdb.set_trace()  # breakpoint e86ebbd4 //
--> 756         X[k, k] = exp_diag[k]
    757 
    758     for i in range(s-1, -1, -1):
    759         X = X.dot(X)
    760 
    761         # Replace diag(X) by exp(2^-i diag(T)).

ipdb> exp_diag.shape
(1, 4)
ipdb> exp_diag[k].shape
(1, 4)
ipdb> X[k, k].shape
()
_

根本的な問題は、_exp_diag_が1Dまたは列ベクトルのいずれかであると想定されているが、_np.matrix_オブジェクトの対角線が行ベクトルであるということです。これは、_np.matrix_は一般的に_np.ndarray_よりもサポートが不十分であるというより一般的な点を強調しているため、ほとんどの場合、後者を使用することをお勧めします。

考えられる解決策の1つは、np.ravel()を使用して_diag_T_を1D _np.ndarray_にフラット化することです。

_diag_T = np.ravel(T.diagonal().copy())
_

_np.matrix_に関連する他の問題がまだ見つかっていない可能性がありますが、これで発生している問題は修正されているようです。


プルリクエストを開きました ここ

3
ali_m