【发布时间】:2020-03-22 21:49:49
【问题描述】:
我试图在scipy.linalg.expm 中实现矩阵指数函数。我从kaityo256's github repository 获得灵感。因此,我写下了以下内容。
from scipy.linalg import expm
from scipy.linalg import eigh
from scipy.linalg import inv
from math import exp as math_exp
from numpy import array, zeros
from numpy.random import random_sample
from numpy.testing import assert_allclose
def diag2sqr(x):
'''Makes an square matrix from a diagonal one.
Takes a 1d matrix. Determines its data type.
Finds out the shape of the 1d matrix.
Makes an empty square matrix with both
dimensions equal to largest (nonzero) dimension of
the 1d matrix. It then fills the elements of the
1d matrix into diagonal slots of the empty
square one.
Parameters
----------
x : ndarray
ndarray of be coverted to a square ndarray
Returns
-------
xsqr : ndarray
ndarray with diagonals sameas those of x
all other elements are zero
dtype same as that of x
'''
x_flat = x.ravel()
xsqr = zeros((x_flat.shape[0], x_flat.shape[0]), dtype=x.dtype)
# Making the empty matrix
for i in range(x_flat.shape[0]):
xsqr[i, i] = x_flat[i]
# filling up the ith element
print('xsqr', xsqr)
return xsqr
def kaityo_expm(x, ):
'''Exponentiates an ndarray (kaityo).
Exponentiates a ndarray in the most naive way.
Parameters
----------
x : ndarray
The ndarray to be exponentiated
Returns
-------
kexpm : ndarray
x after exponentiating
'''
rx, ux = eigh(x)
# Find eigenvalues and eigenvectors
# eigenvectors composed to form a unitary
ux_inv = inv(ux)
# Inverse of the unitary
# tx = diag([array([math_exp(i) for i in rx]).ravel()])
# tx = array([math_exp(i) for i in rx])
tx = diag2sqr(array([math_exp(i) for i in rx]))
# Constructing the diagonal matrix
kexpm1 = tx@ux_inv
kexpm = ux@kexpm1
return kexpm
之后,我尝试测试上面的代码和scipy.linalg.expm。
x = random_sample((10, 10))
assert_allclose(expm(x), kaityo_expm(x))
这导致以下输出。
AssertionError:
Not equal to tolerance rtol=1e-07, atol=0
Mismatch: 100%
Max absolute difference: 7.04655733
Max relative difference: 0.59875635
x: array([[18.032424, 16.224408, 12.432163, 16.614248, 12.85653 , 13.705387,
15.096966, 10.577946, 18.399573, 17.938062],
[16.352809, 17.525898, 12.79079 , 16.295562, 13.512996, 14.407979,...
y: array([[18.649103, 13.157682, 11.264763, 16.099163, 15.2293 , 17.854499,
11.691586, 13.412066, 15.023189, 15.598455],
[13.157682, 13.612502, 9.628261, 12.659313, 13.559437, 13.382417,..
显然,两种实现方式都不同。 问题如下:
- 他们可以接受不同吗?
- 我的实现有错吗?
- 如果我的实现有误,我该如何解决?
- 如果我的实现是正确的,什么时候可以安全使用
scipy.linalg.expm?
我看到了以下问题:
【问题讨论】:
-
如果有人赶时间,这里是 Jupyter notebook 版本。 dropbox.com/s/w5pia3doed369g3/expm_compare.ipynb?dl=0
-
两件事:1)
eigh仅用于 Hermitian 或实对称矩阵,您的示例不是。 2)一元的逆是它的共轭转置,而是通过inv是浪费的并且引入了不必要的数值错误。 --- 我假设是 1) 导致您观察到的差异。 -
我试图修复 dropbox.com/s/9o9j40hf82toykg/expm_compare-eig-real.ipynb?dl=0 和 dropbox.com/s/g046aem8lrrq2jy/… 中的 1)。但似乎还是有问题。