[英]numpy arbitrary precision linear algebra
我有一个numpy 2d阵列[中/大型 - 比如500x500]。 我想找到它的元素指数的特征值。 问题是某些值非常消极(-800,-1000等),并且它们的指数下溢(意味着它们非常接近零,因此numpy将它们视为零)。 无论如何在numpy中使用任意精度?
我梦想的方式:
import numpy as np
np.set_precision('arbitrary') # <--- Missing part
a = np.array([[-800.21,-600.00],[-600.00,-1000.48]])
ex = np.exp(a) ## Currently warns about underflow
eigvals, eigvecs = np.linalg.eig(ex)
我已经搜索了一个gmpy和mpmath的解决方案无济于事。 任何想法都会受到欢迎。
SymPy可以计算任意精度:
from sympy import exp, N, S
from sympy.matrices import Matrix
data = [[S("-800.21"),S("-600.00")],[S("-600.00"),S("-1000.48")]]
m = Matrix(data)
ex = m.applyfunc(exp).applyfunc(lambda x:N(x, 100))
vecs = ex.eigenvects()
print vecs[0][0] # eigen value
print vecs[1][0] # eigen value
print vecs[0][2] # eigen vect
print vecs[1][2] # eigen vect
输出:
-2.650396553004310816338679447269582701529092549943247237903254759946483528035516341807463648841185335e-261
2.650396553004310816338679447269582701529092549943247237903254759946483528035516341807466621962539464e-261
[[-0.9999999999999999999999999999999999999999999999999999999999999999999999999999999999999994391176386872]
[ 1]]
[[1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000560882361313]
[ 1]]
您可以将N(x,100)中的100更改为其他精度,但是,当我尝试1000时,本征vect的计算失败。
在64位系统上,有一个numpy.float128
。 (我相信在32位系统上也有一个float96
)虽然numpy.linalg.eig
不支持128位浮点数, scipy.linalg.eig
(有点)可以。
但是,从长远来看,这一切都不重要 。 任何特征值问题的一般求解器都是迭代的,而不是精确的,所以你不能通过保持额外的精度来获得任何东西! np.linalg.eig
适用于任何形状,但永远不会返回精确的解决方案。
如果你总是在解决2x2矩阵问题,那么编写你自己的解算器应该更加精确。 我将在最后展示一个这样的例子......
无论如何,进入无意义的精确内存容器:
import numpy as np
import scipy as sp
import scipy.linalg
a = np.array([[-800.21,-600.00],[-600.00,-1000.48]], dtype=np.float128)
ex = np.exp(a)
print ex
eigvals, eigvecs = sp.linalg.eig(ex)
# And to test...
check1 = ex.dot(eigvecs[:,0])
check2 = eigvals[0] * eigvecs[:,0]
print 'Checking accuracy..'
print check1, check2
print (check1 - check2).dot(check1 - check2), '<-- Should be zero'
但是,你会注意到你所得到的只是做np.linalg.eig(ex.astype(np.float64)
。事实上,我很确定scipy
正在做什么,而numpy
提出错误而不是而不是默默地做。我可能是错的,不过......
如果你不想使用scipy,一种解决方法是在取幂后重新定标,但在求解特征值之前,将它们转换为“正常”浮点数,求解特征值,然后将事物重新转换为float128,然后重新缩放。
例如
import numpy as np
a = np.array([[-800.21,-600.00],[-600.00,-1000.48]], dtype=np.float128)
ex = np.exp(a)
factor = 1e300
ex_rescaled = (ex * factor).astype(np.float64)
eigvals, eigvecs = np.linalg.eig(ex_rescaled)
eigvals = eigvals.astype(np.float128) / factor
# And to test...
check1 = ex.dot(eigvecs[:,0])
check2 = eigvals[0] * eigvecs[:,0]
print 'Checking accuracy..'
print check1, check2
print (check1 - check2).dot(check1 - check2), '<-- Should be zero'
最后,如果您只是求解2x2或3x3矩阵,您可以编写自己的求解器, 它将为这些矩阵形状返回精确值。
import numpy as np
def quadratic(a,b,c):
sqrt_part = np.lib.scimath.sqrt(b**2 - 4*a*c)
root1 = (-b + sqrt_part) / (2 * a)
root2 = (-b - sqrt_part) / (2 * a)
return root1, root2
def eigvals(matrix_2x2):
vals = np.zeros(2, dtype=matrix_2x2.dtype)
a,b,c,d = matrix_2x2.flatten()
vals[:] = quadratic(1.0, -(a+d), (a*d-b*c))
return vals
def eigvecs(matrix_2x2, vals):
a,b,c,d = matrix_2x2.flatten()
vecs = np.zeros_like(matrix_2x2)
if (b == 0.0) and (c == 0.0):
vecs[0,0], vecs[1,1] = 1.0, 1.0
elif c != 0.0:
vecs[0,:] = vals - d
vecs[1,:] = c
elif b != 0:
vecs[0,:] = b
vecs[1,:] = vals - a
return vecs
def eig_2x2(matrix_2x2):
vals = eigvals(matrix_2x2)
vecs = eigvecs(matrix_2x2, vals)
return vals, vecs
a = np.array([[-800.21,-600.00],[-600.00,-1000.48]], dtype=np.float128)
ex = np.exp(a)
eigvals, eigvecs = eig_2x2(ex)
# And to test...
check1 = ex.dot(eigvecs[:,0])
check2 = eigvals[0] * eigvecs[:,0]
print 'Checking accuracy..'
print check1, check2
print (check1 - check2).dot(check1 - check2), '<-- Should be zero'
这个返回一个真正精确的解决方案,但只适用于2x2矩阵。 然而,这是唯一可以从额外精度中获益的解决方案!
据我所知,numpy不支持高于double精度(float64),如果没有指定则是默认值。
尝试使用此功能: http : //code.google.com/p/mpmath/
功能列表(等)
算术:
我没有特别喜欢numpy的经验,但是添加一个带有一定数量零的小数点可能会有所帮助。 例如,使用1.0000而不是1.在我遇到这个问题的普通python脚本中,这有帮助,所以除非你的问题是由于numpy中的奇怪而与python无关,否则这应该有所帮助。
祝好运!
所以你需要350位数的精度。 你不会得到IEEE浮点数(numpy正在使用)。 你可以用bc程序得到它:
$ bc -l
bc 1.06
Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
scale=350
e(-800)
.<hundreds of zeros>00366
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.