【发布时间】:2021-10-30 09:40:17
【问题描述】:
假设我有一个大型线性方程组:
X_1*a_11 + X_2*a_21 + ... + X_n*a_n1 = b_1
.
.
.
X_1*a_1m + X_2*a_2m + ... + X_n*anm = b_m
尺寸n 和m 是固定的(不是符号)。
我可以找到并插入每个系数a_ij 的值,我想解决所有X_i。如果我可以将这些写成矩阵形式,例如,我可以使用numpy.linalg.solve。但是,我不想用系数手动构造这个矩阵。有没有一种有效的方法可以将此方程组转换为矩阵并使用numpy.linalg.solve 求解?
我知道我可以将所有 X 定义为 Sympy 符号,创建方程式列表并使用例如 Sympy 的 linear_eq_to_matrix 将符号方程式列表转换为符号矩阵。我也可以使用 Sympy 的 solve 或 linsolve 使用这个方程列表和一个未知数列表,但我认为与使用 Numpy 相比存在性能损失。
解决这个问题的最佳方法是什么?
编辑
一个非常简单的例子
from sympy import *
import numpy as np
dim = 4
# Getting coefficients
a = np.random.uniform(low = -3, high = 3, size= (dim,dim))
b = np.random.uniform(low = -3, high = 3, size= (dim,))
# Numerical array for solutions
n_X = np.empty(shape = (2,))
n_Y = np.empty(shape = (2,))
# Defining unknowns
s_X_1 = Symbol('X_1')
s_Y_1 = Symbol('Y_1')
s_X_2 = Symbol('X_2')
s_Y_2 = Symbol('Y_2')
#Defining equations
eq1 = s_X_1*a[0,0] + s_Y_1*a[1,0] + s_X_2*a[2,0] + s_Y_2*a[3,0]- b[0]
eq2 = s_X_1*a[0,1] + s_Y_1*a[1,1] + s_X_2*a[2,1] + s_Y_2*a[3,1]- b[1]
eq3 = s_X_1*a[0,2] + s_Y_1*a[1,2] + s_X_2*a[2,2] + s_Y_2*a[3,2]- b[2]
eq4 = s_X_1*a[0,3] + s_Y_1*a[1,3] + s_X_2*a[2,3] + s_Y_2*a[3,3]- b[3]
unknowns = [s_X_1, s_X_2] + [s_Y_1, s_Y_2]
eqs = [eq1, eq2, eq3, eq4]
# Transforming the system into matrix form and solving
A, b = linear_eq_to_matrix(eqs, unknowns)
result = list(linsolve((A,b), unknowns))[0]
# Filling the numerical array with the sympy result
n_X[0] = result[unknowns.index(s_X_1)]
n_X[1] = result[unknowns.index(s_X_2)]
n_Y[0] = result[unknowns.index(s_Y_1)]
n_Y[1] = result[unknowns.index(s_Y_2)]
但是,如果我已经拥有 A 和 B,我可以这样做:
A_num = np.array(A).astype(np.float64)
b_num = np.array(b).astype(np.float64)
result_num = np.linalg.solve(A_num, b_num)
衡量绩效:
%%timeit -r 100 -n 100
result_sym = list(linsolve((A,b), unknowns))[0]
1.95 ms ± 285 µs per loop (mean ± std. dev. of 100 runs, 100 loops each)
%timeit -r 100 -n 100
result_num = np.linalg.solve(A_num, b_num)
The slowest run took 9.04 times longer than the fastest. This could mean that an intermediate result is being cached.
15.5 µs ± 10.3 µs per loop (mean ± std. dev. of 100 runs, 100 loops each)
%%timeit -r 100 -n 100
A, b = linear_eq_to_matrix(eqs, unknowns)
A_num = np.array(A).astype(np.float64)
b_num = np.array(b).astype(np.float64)
441 µs ± 112 µs per loop (mean ± std. dev. of 100 runs, 100 loops each)
如您所见,sympy 解决方案比 numpy 解决方案慢几个数量级。同样,将我们的数值系统转换为矩阵形式,然后将其转换为 numpy 数组以使用numpy.linalg.solve 的操作比求解系统本身要慢得多!
【问题讨论】:
-
我不知道你有什么数据,确切地说。如果 a_ij 尚未存储在矩阵中,它们在哪里?
-
您有很多想法,但除非您在帖子中提供人们可以自行粘贴和运行的代码示例,否则人们将很难为您提供帮助。你不应该粘贴你的整个代码,而只是一个小例子(可能是 3 x 3 矩阵系统),展示你是如何被卡住的以及你尝试了什么。
-
不是对 OP 帖子的评论,而是@BatWannaBe 的 cmets。只是想说领导 OP 用温和的刺激来改善他们的问题做得很好。我现在才第一次看到这个文本,它的形式非常容易回答,主要是由于你提供的帮助。向你致敬!
-
代码示例肯定很有帮助,它为您所知道和尝试过的内容提供了很多启示。但是我关于你从哪里得到你的系数的问题还没有完全回答。您为您的 MWE 构建随机 NumPy 数组
a和b:它们已经准备好进入scipy.linalg.solve。在 SymPy 方程系统中编写a[0,0],a[0,1], ... 就像输入系数值一样“手动”;如果再添加一个变量或方程,您将不得不重写所有内容。 -
我目前的怀疑是你实际拥有的是几个你知道下标的非 0 系数值,所以每个数据点都是 (a_jk : float, j : int, k :int) .显然你不想在矩阵或线性系统中手写所有的 0。没关系,其实。您可以从最大的 i 和 j 值找出您的系统有多大,用
np.zeros构造一个 0s 矩阵,并在 for 循环中将非零系数a[j-1, k-1] = a_ij一个一个填充。绝对比手工好。
标签: python numpy sympy equation-solving linear-equation