我在python中编写了一些代码,需要经常反转大方块矩阵(100-200行/列)。
我达到了机器精度的极限,所以我们开始尝试使用mpmath
来进行任意精度矩阵求逆,但即使使用gmpy
它也很慢。
以精度30(十进制)反转大小为20,30,60的随机矩阵需要~0.19,0.60和4.61秒,而mathematica
中的相同操作需要0.0084,0.015和0.055秒。
这是在arch linux机器上使用python3
和mpmath 0.17
(不确定gmpy版本)。我不确定为什么mpmath这么慢,但是有没有任何开源库接近mathematica为此管理的速度(即便1/2也会很快)?
我不需要任意精度 - 128位可能就足够了。我也只是不明白mpmath怎么会这么慢。它必须使用非常不同的矩阵求逆算法。具体来说我正在使用M**-1
。
有没有办法让它使用更快的算法或加快速度。
答案 0 :(得分:2)
不幸的是,mpmath中的Linera代数相当慢。有许多库可以更好地解决这个问题(例如Sage)。也就是说,作为Stuart建议的后续内容,在Python中进行合理快速的高精度矩阵乘法相当容易,而无需使用定点算法安装任何库。这是一个使用mpmath矩阵进行输入和输出的版本:
def fixmul(A, B, prec):
m = A.rows; p = B.rows; n = B.cols;
A = [[A[i,j].to_fixed(prec) for j in range(p)] for i in range(m)]
B = [[B[i,j].to_fixed(prec) for j in range(n)] for i in range(p)]
C = [([0] * n) for r in range(m)]
for i in range(m):
for j in range(n):
s = 0
for k in range(p):
s += A[i][k] * B[k][j]
C[i][j] = s
return mp.matrix(C) * mpf(2)**(-2*prec)
在256位精度下,对于我来说,这两个200x200矩阵的乘法速度比mpmath快16倍。以这种方式直接编写矩阵求逆程序也不难。当然,如果矩阵条目非常大或非常小,您需要先重新缩放它们。一个更可靠的解决方案是使用gmpy中的浮点类型编写自己的矩阵函数,这应该基本上一样快。
答案 1 :(得分:1)
我假设双精度对于最终结果的精度不是问题,但是对于某些矩阵而言,它在反向的中间结果中引起问题。在这种情况下,让我们将正常numpy(双精度)逆的结果视为一个很好的近似,然后用它作为牛顿方法的几次迭代的起点来求解逆。
让 A 成为我们试图反转的矩阵, X 是我们对逆的估计。牛顿方法的迭代只包括:
X = X*(2I - AX)
对于大型矩阵,计算上述几次迭代的努力与找到逆的算法相比几乎无关紧要,并且可以极大地提高最终结果的准确性。试一试。
BTW, I 是上述等式中的单位矩阵。
编辑以添加代码以测试浮动类型的精度。
使用此代码测试浮点类型的精度。
x = float128('1.0')
wun = x
two = wun + wun
cnt = 1
while True:
x = x/two
y = wun + x
if y<=wun: break
cnt +=1
print 'The effective number of mantissa bits is', cnt
答案 2 :(得分:0)
Multiprecision toolbox for MATLAB使用128位精度(Core i7 930)提供以下时序:
20x20 - 0.007秒
30x30 - 0.019秒
60x60 - 0.117秒
200x200 - 3.2秒
请注意,现代CPU的这些数字要低得多。