scipy慢稀疏矩阵求解器

时间:2016-07-18 19:22:50

标签: scipy sparse-matrix

我似乎无法从scipy的CG和稀疏矩阵算法中获益。

当我试图解决这个带状矩阵方程时

import time
import scipy.sparse.linalg as ssla
import scipy.sparse as ss
import numpy as np

size = 3000
x = np.ones(size)
A = ss.diags([1, -2, 1], [-1, 0, 1], shape=[size, size]).toarray()
print 'cond. nr.:{}'.format(np.linalg.cond(A))
b = np.dot(A, x)

start_time = time.clock()
sol = np.linalg.solve(A, b)
elapsed_time = time.clock() - start_time
error = np.sum(np.abs(sol - x))
print 'LU time, error:', elapsed_time, error

start_time = time.clock()
sol, info = ssla.bicg(A, b, tol=1e-12)
elapsed_time = time.clock() - start_time
error = np.sum(np.abs(sol - x))
print 'CG time, ret code, error:', elapsed_time, info, error

它大约需要LU解算器的20倍。根据我的理解,CG并不比LU贵得多,即使它必须使用所有N次迭代来达到结果。所以我预计它至少会快,但实际上要快得多,因为先前有关带状的知识。这与条件数有关吗?

在密集矩阵的情况下

import time
import scipy.sparse.linalg as ssla
import numpy as np
import matplotlib.pyplot as plt

size = 1000
x = np.ones(size)
np.random.seed(1)
A = np.random.random_integers(-size, size,
                              size=(size, size))
print 'cond. nr.:{}'.format(np.linalg.cond(A))
b = np.dot(A, x)

start_time = time.clock()
sol = np.linalg.solve(A, b)
elapsed_time = time.clock() - start_time
error = np.sum(np.abs(sol - x))
print 'LU time, error:', elapsed_time, error

start_time = time.clock()
sol, info = ssla.bicg(A, b, tol=1e-12)
elapsed_time = time.clock() - start_time
error = np.sum(np.abs(sol - x))
print 'CG time, ret code, error:', elapsed_time, info, error

我根本没有收敛。在这种情况下,A的条件数似乎不大,但是我没有这方面的经验。

1 个答案:

答案 0 :(得分:2)

您使用

创建A
A = ss.diags([1, -2, 1], [-1, 0, 1], shape=[size, size]).toarray()

.toarray()的调用将稀疏矩阵转换为常规numpy数组。因此,您将常规数组传递给稀疏求解器,这意味着稀疏求解器无法利用任何稀疏性结构。 如果将原始稀疏矩阵传递给求解器,则速度要快得多。

对于解决带状系统,快速替代方案是scipy.linalg.solve_banded。 (Hermitian系统也有scipy.linalg.solveh_banded。)

这是你的例子,但稀疏矩阵传递给稀疏求解器。还包括使用scipy.linalg.solve_banded计算的解决方案,其结果比其他两种方法更快

import time
import scipy.sparse.linalg as ssla
import scipy.sparse as ss
from scipy.linalg import solve_banded
import numpy as np

size = 3000
x = np.ones(size)
S = ss.diags([1, -2, 1], [-1, 0, 1], shape=[size, size])
A = S.toarray()
print 'cond. nr.:{}'.format(np.linalg.cond(A))
b = np.dot(A, x)

start_time = time.clock()
sol = np.linalg.solve(A, b)
elapsed_time = time.clock() - start_time
error = np.sum(np.abs(sol - x))
print 'LU time, error          :  %9.6f    %g' % (elapsed_time, error)

start_time = time.clock()
sol, info = ssla.bicg(S, b, tol=1e-12)
elapsed_time = time.clock() - start_time
error = np.sum(np.abs(sol - x))
print 'CG time, ret code, error:  %9.6f %2d %g' % (elapsed_time, info, error)

B = np.empty((3, size))
B[0, :] = 1
B[1, :] = -2
B[2, :] = 1
start_time = time.clock()
sol = solve_banded((1, 1), B, b)
elapsed_time = time.clock() - start_time
error = np.sum(np.abs(sol - x))
print 'solve_banded time, error:  %9.6f    %g' % (elapsed_time, error)

输出:

cond. nr.:3649994.05818
LU time, error          :   0.858295    4.05262e-09
CG time, ret code, error:   0.552952  0 6.7263e-11
solve_banded time, error:   0.000750    4.05262e-09