【问题标题】:scipy slow sparse matrix solverscipy慢稀疏矩阵求解器
【发布时间】:2016-11-21 12:24:48
【问题描述】:

我似乎无法从 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的条件数似乎并没有那么大,但是我对这种事情没有太多经验。

【问题讨论】:

  • 收敛还取决于您选择的初始猜测。如果您碰巧选择了正确的答案作为起点,您将在一次迭代中收敛;做出一个糟糕的选择,你可能需要更多的迭代。这不仅仅是关于矩阵及其条件。
  • (1000, 1000) 矩阵非常小。尝试更大更稀疏的东西。
  • 在我的第二个示例中将 x0=x 添加到 bicg 调用并不能解决问题。将大小减小到 10 时,我使用 bicg 得到一个有效结果,而无需开始猜测。添加 x0=x 给我一个错误的解决方案。我做错了什么?

标签: scipy sparse-matrix


【解决方案1】:

您使用

创建 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

【讨论】:

  • 我正在观察其他一些事情。我目前正在运行 LU 求解,它使用了我的八个处理器中的四个。我根本没想到它会做 MP,但现在我想知道为什么它没有使用 100%。是默认情况下只使用了一半的 procs(即,这是我可以影响的东西)还是由于实施而所有八个都只使用了 50%?我找到了一个涉及该问题的链接,但似乎没有完全回答:stackoverflow.com/questions/28751093/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-01
  • 2021-03-05
  • 2017-03-26
  • 2017-03-31
  • 2023-04-10
  • 2015-02-07
  • 2017-07-21
相关资源
最近更新 更多