我有一个大的坐标网格(矢量a和b),我为此生成并求解矩阵(10x10)方程。有scipy.linalg.solve
接受矢量输入的方法吗?到目前为止,我的解决方案是在坐标数组上运行 循环。
import time
import numpy as np
import scipy.linalg
N = 10
a = np.linspace(0, 1, 10**3)
b = np.linspace(0, 1, 2*10**3)
A = np.random.random((N, N)) # input matrix, not static
def f(a,b,n): # array-filling function
return a*b*n
def sol(x,y): # matrix solver
D = np.arange(0,N)
B = f(x,y,D)**2 + f(x-1, y+1, D) # source vector
X = scipy.linalg.solve(A,B)
return X # output an N-size vector
start = time.time()
answer = np.zeros(shape=(a.size, b.size)) # predefine output array
for egg in range(a.size): # an ugly double-for cycle
for ham in range(b.size):
aa = a[egg]
bb = b[ham]
answer[egg,ham] = sol(aa,bb)[0]
print time.time() - start
答案 0 :(得分:2)
为了说明我对广义ufuncs的观点,以及消除蛋和火腿循环的能力,请考虑以下代码:
import numpy as np
A = np.random.randn(4,4,10,10)
AI = np.linalg.inv(A)
#check that generalized ufuncs work as expected
I = np.einsum('xyij,xyjk->xyik', A, AI)
print np.allclose(I, np.eye(10)[np.newaxis, np.newaxis, :, :])
答案 1 :(得分:1)
@yevgeniy你是对的,有效地解决了多个独立的线性系统 A x = b ,scipy有点棘手(假设 A 数组在每次迭代时都会发生变化)。
例如,这是一个解决1000个系统形式的基准, A x = b ,其中A是10x10
矩阵,b
a {{ 1}}元素向量。令人惊讶的是,将所有这些放入一个块对角矩阵并且调用10
一次的方法对于密集和稀疏矩阵来说确实较慢。
scipy.linalg.solve
具有稀疏数组的线性系统的解决方案更快,但创建此块对角线阵列的时间实际上非常慢。对于密集阵列,在这种情况下它们只是速度较慢(并占用大量RAM)。
也许我错过了一些关于如何使用稀疏数组有效地工作的东西,但是如果你保留import numpy as np
from scipy.linalg import block_diag, solve
from scipy.sparse import block_diag as sp_block_diag
from scipy.sparse.linalg import spsolve
N = 10
M = 1000 # number of coordinates
Ai = np.random.randn(N, N) # we can compute the inverse here,
# but let's assume that Ai are different matrices in the for loop loop
bi = np.random.randn(N)
%timeit [solve(Ai, bi) for el in range(M)]
# 10 loops, best of 3: 32.1 ms per loop
Afull = sp_block_diag([Ai]*M, format='csr')
bfull = np.tile(bi, M)
%timeit Afull = sp_block_diag([Ai]*M, format='csr')
%timeit spsolve(Afull, bfull)
# 1 loops, best of 3: 303 ms per loop
# 100 loops, best of 3: 5.55 ms per loop
Afull = block_diag(*[Ai]*M)
%timeit Afull = block_diag(*[Ai]*M)
%timeit solve(Afull, bfull)
# 100 loops, best of 3: 14.1 ms per loop
# 1 loops, best of 3: 23.6 s per loop
循环,那么你可以做两件事来进行优化。
从纯python中,查看scipy.linalg.solve
的源代码:删除不必要的测试并分解循环外的所有重复操作。例如,假设您的数组不是对称的正数,我们可以做
for
导致6.5倍的加速。
如果你需要更好的性能,你必须在Cython中将它移植到for循环中并直接在C中连接from scipy.linalg import get_lapack_funcs
gesv, = get_lapack_funcs(('gesv',), (Ai, bi))
def solve_opt(A, b, gesv=gesv):
# not sure if copying A and B is necessary, but just in case (faster if arrays are not copied)
lu, piv, x, info = gesv(A.copy(), b.copy(), overwrite_a=False, overwrite_b=False)
if info == 0:
return x
if info > 0:
raise LinAlgError("singular matrix")
raise ValueError('illegal value in %d-th argument of internal gesv|posv' % -info)
%timeit [solve(Ai, bi) for el in range(M)]
%timeit [solve_opt(Ai, bi) for el in range(M)]
# 10 loops, best of 3: 30.1 ms per loop
# 100 loops, best of 3: 3.77 ms per loop
BLAS函数,如所讨论的here,或者更好地使用Cython API for BLAS / Scacky 0.16中的LAPACK。
编辑:正如@Eelco Hoogendoorn所说,如果你的 A 矩阵是固定的,那么有一种更简单,更有效的方法。