我通常不会一直打死马,但碰巧我解决您的其他问题的非矢量化方法在事情变得大时有一些优点。因为我实际上是一次填充系数矩阵,所以很容易转化为COO稀疏矩阵格式,可以高效地转化为CSC并求解。以下是这样做的:
import scipy.sparse
def sps_solve(n) :
# Solution vector is [N[0], N[1], ..., N[n - 2], M[1], M[2], ..., M[n - 1]]
n_pos = lambda p : p
m_pos = lambda p : p + n - 2
data = []
row = []
col = []
# p = 0
# n * N[0] + (1 - n) * M[n-1] = n
row += [n_pos(0), n_pos(0)]
col += [n_pos(0), m_pos(n - 1)]
data += [n, 1 - n]
for p in xrange(1, n - 1) :
# n * M[p] + (1 + p - n) * M[n - 1] - 2 * N[p - 1] +
# (1 - p) * M[p - 1] = n
row += [m_pos(p)] * (4 if p > 1 else 3)
col += ([m_pos(p), m_pos(n - 1), n_pos(p - 1)] +
([m_pos(p - 1)] if p > 1 else []))
data += [n, 1 + p - n , -2] + ([1 - p] if p > 1 else [])
# n * N[p] + (1 + p -n) * M[n - 1] - p * N[p - 1] = n
row += [n_pos(p)] * 3
col += [n_pos(p), m_pos(n - 1), n_pos(p - 1)]
data += [n, 1 + p - n, -p]
if n > 2 :
# p = n - 1
# n * M[n - 1] - 2 * N[n - 2] + (2 - n) * M[n - 2] = n
row += [m_pos(n-1)] * 3
col += [m_pos(n - 1), n_pos(n - 2), m_pos(n - 2)]
data += [n, -2, 2 - n]
else :
# p = 1
# n * M[1] - 2 * N[0] = n
row += [m_pos(n - 1)] * 2
col += [m_pos(n - 1), n_pos(n - 2)]
data += [n, -2]
coeff_mat = scipy.sparse.coo_matrix((data, (row, col))).tocsc()
return scipy.sparse.linalg.spsolve(coeff_mat,
np.ones(2 * (n - 1)) * n)
它当然比从向量化块构建它要冗长得多,就像 TheodorosZelleke 所做的那样,但是当你对这两种方法进行计时时会发生一件有趣的事情:
首先,这(非常)好,时间在两种解决方案中都是线性缩放的,正如人们对使用稀疏方法所期望的那样。但是我在这个答案中给出的解决方案总是更快,对于更大n
的 s 更是如此。只是为了好玩,我还从另一个问题对 TheodorosZelleke 的密集方法进行了计时,它给出了这个很好的图表,显示了两种解决方案的不同缩放比例,以及多早,在某个地方n = 75
,这里的解决方案应该是你的选择:
尽管我scipy.sparse
严重怀疑使用 LIL 格式的稀疏矩阵,但我对真正弄清楚这两种稀疏方法之间的差异的原因知之甚少。通过将 TheodorosZelleke 的答案转换为 COO 格式,尽管代码非常紧凑,但可能会有一些非常微小的性能提升。但这留给OP练习!