我需要解决大量形如“Ax=B”的线性矩阵方程,其中A是一个稀疏矩阵,主对角线上有值,而B是一个向量。
我的第一种方法是使用numpy中的密集数组和numpy.linalg.solve函数。使用(N,n,n)维数组(其中N是线性矩阵方程的数量,n是矩阵的维度)通过for循环迭代所有方程,虽然可以正常运行,但速度相对较慢。后来我发现其实还可以直接将(N,n,n)维数组传递给numpy.linalg.solve函数,这在我读的文档中并没有提到。这样就大大提高了计算速度(详见下文)。
然而,由于我有稀疏矩阵,因此我也查看了scipy.sparse.linalg.spsolve函数,它与相应的numpy函数类似。使用for循环迭代所有方程比numpy解决方案快得多,但似乎不可能直接将(N,n,n)维数组传递给scipy的spsolve函数。
以下是我迄今为止尝试过的方法:
首先,我使用随机数计算了一些虚构的A矩阵和B向量供测试使用,分别是稀疏和密集形式:
import numpy as np
from scipy import sparse
from scipy.sparse.linalg import spsolve
number_of_systems = 100 #corresponds to N in the text
number_of_data_points = 1000 #corresponds to n in the text
#calculation of sample matrices (dense and sparse)
A_sparse = np.empty(number_of_systems,dtype=object)
A_dense = np.empty((number_of_systems,number_of_data_points,number_of_data_points))
for ii in np.arange(number_of_systems):
A_sparse[ii] = sparse.spdiags(np.random.random(number_of_data_points),0,number_of_data_points,number_of_data_points)
A_dense[ii] = A_sparse[ii].todense()
#calculation of sample vectors
B = np.random.random((number_of_systems,number_of_data_points))
1) 第一种方法:使用numpy.linalg.solve和for循环:
def solve_dense_3D(A,B):
results = np.empty((A.shape[0],A.shape[1]))
for ii in np.arange(A.shape[0]):
results[ii] = np.linalg.solve(A[ii],B[ii])
return results
result_dense_for = solve_dense_3D(A_dense,B)
时间控制:
timeit(solve_dense_3D(A_dense,B))
1.25 s ± 27.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
第二种方法:直接将(N,n,n)维矩阵传递给numpy.linalg.solve:
result_dense = np.linalg.solve(A_dense,B)
时间掌握:
timeit(np.linalg.solve(A_dense,B))
769 ms ± 9.68 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
第三种方法:使用带有for循环的scipy.sparse.linalg.spsolve:
def solve_sparse_3D(A,B):
results = np.empty((A.shape[0],A[0].shape[0]))
for ii in np.arange(A.shape[0]):
results[ii] = spsolve(A[ii],B[ii])
return results
result_sparse_for = solve_sparse_3D(A_sparse,B)
时间控制:
timeit(solve_sparse_3D(A_sparse,B))
30.9 ms ± 132 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
很明显,从方法1和2中省略for循环是有优势的。截至目前,最快的选择显然是使用稀疏矩阵的方法3。
由于本例中方程的数量对我来说仍然较低,并且我经常需要执行此类操作,如果能使用scipy的稀疏矩阵解决问题而不需要for循环,我会非常高兴。有人知道如何实现吗?或者也许还有其他不同的解决问题的方法?欢迎提出建议。
spsolve
可以识别这种结构并执行相应的操作。 - Lutz Lehmann