设置
所有东西都在Ubuntu 14.04上运行。
Python版本为3.4.0。
NumPy版本为1.8.1,编译时使用了OpenBLAS。
Octave版本为3.8.1,编译时使用了OpenBLAS。
示例代码
Python示例代码。
import numpy as np
from scipy import linalg as la
def build_laplacian(n):
lap=np.zeros([n,n])
for j in range(n-1):
lap[j+1][j]=1
lap[j][j+1]=1
lap[n-1][n-2]=1
lap[n-2][n-1]=1
return lap
def evolve(s, lap):
wave=la.expm(-1j*s*lap).dot([1]+[0]*(lap.shape[0]-1))
for i in range(len(wave)):
wave[i]=np.linalg.norm(wave[i])**2
return wave
我们现在运行以下内容。
np.min(evolve(2, build_laplacian(500)))
这将会得到大约为e-34
的值。
我们可以在Octave/MATLAB中生成类似的代码:
function lap=build_laplacian(n)
lap=zeros(n,n);
for i=1:(n-1)
lap(i+1,i)=1;
lap(i,i+1)=1;
end
lap(n,n-1)=1;
lap(n-1,n)=1;
end
function result=evolve(s, lap)
d=zeros(length(lap(:,1)),1); d(1)=1;
result=expm(-1i*s*lap)*d;
for i=1:length(result)
result(i)=norm(result(i))^2;
end
end
我们接下来运行
min(evolve(2, build_laplacian(500)))
并且获得0
。实际上,evolve(2, build_laplacian(500)))(60)
的结果大约是e-100
或更少(如预期所示)。
问题
有没有人知道什么会导致NumPy和Octave之间存在如此大的差异(再次说明,我没有使用MATLAB测试过代码,但我希望看到类似的结果)。
当然,也可以通过首先将矩阵对角化来计算矩阵指数。我已经这样做了,并得到了类似或更糟糕的结果(使用NumPy)。
编辑
我的scipy
版本是0.14.0
。我知道Octave / MATLAB使用Pade逼近方案,并熟悉此算法。我不确定scipy
做了什么,但我们可以尝试以下操作。
使用
numpy
的eig
或eigh
(在我们的情况下,后者很好用,因为矩阵是Hermitian)对矩阵进行对角化。结果我们得到两个矩阵:一个对角线矩阵D
,和矩阵U
,其中D
由原始矩阵的特征值组成,而U
由相应的特征向量组成为列;因此原始矩阵由U.T.dot(D).dot(U)
给出。对
D
进行指数化(现在易于做到,因为D
是对角线)。现在,如果
M
是原始矩阵,d
是原始向量d=[1]+[0]*n
,我们得到scipy.linalg.expm(-1j*s*M).dot(d)=U.T.dot(numpy.exp(-1j*s*D).dot(U.dot(d))
。
不幸的是,这产生了与以前相同的结果。因此,这可能与numpy.linalg.eig
和numpy.linalg.eigh
的工作方式有关,或者与numpy
内部执行算术的方式有关。
所以问题是:我们如何增加numpy
的精度?实际上,如上所述,Octave似乎在这种情况下做得更好。
scipy
中的expm
方法。你使用的是哪个版本的scipy
? - Warren Weckesserexpm
是一个棘手的函数。http://www.mathworks.com/help/matlab/ref/expm.html引用了Moler关于“19个可疑方法”的文章。Pade逼近法强烈依赖于预处理策略。Octave文档中的`expm`也讨论了这个逼近问题。 - hpauljscipy/numpy
则相差几个数量级。我们可以使用numpy
的eig
或eigh
先对矩阵进行对角化,然后取对角矩阵的指数。这会产生相同的结果。我不知道scipy
使用哪种算法,但似乎这要么与numpy
对角化矩阵的方式有关,要么与内部算术工作有关。问题是,我们如何增加numpy
的精度? - user2321808expm
在scipy中已经实现。开发版本的源代码可以在https://github.com/scipy/scipy/blob/master/scipy/linalg/matfuncs.py找到;那里的`expm`函数只是一个薄包装,真正的实现在https://github.com/scipy/scipy/blob/master/scipy/sparse/linalg/matfuncs.py中。 - Warren Weckesser