
线性方程组 AX=b 在科学计算、工程、统计学等领域无处不在。然而,在许多实际应用中,解向量 X 往往需要满足额外的条件,即线性等式约束。例如,某些变量的和必须为零,或者某些变量之间存在固定的比例关系。
当 X 向量受到这些线性等式约束时,直接求解 AX=b 变得复杂。常见的误区是尝试将约束作为优化问题的惩罚项或使用通用非线性优化器(如 scipy.optimize.minimize),但这可能导致解在满足约束的同时,无法精确满足原始方程 AX=b。本文将介绍一种更直接、更高效的方法,通过构建增广系统并利用 NumPy 的 np.linalg.lstsq 函数来解决这类问题。
假设我们有一个原始的线性方程组 A X = b,其中 A 是一个 m x n 的系数矩阵,X 是一个 n x 1 的未知向量,b 是一个 m x 1 的常数向量。
同时,我们有 k 个线性等式约束,它们可以被表示为 C X = d,其中 C 是一个 k x n 的约束矩阵,d 是一个 k x 1 的常数向量。
示例: 假设 X = [x1, y1, x2, y2, x3, y3, x4, y4] 是一个 8x1 的向量。 给定以下三个约束:
我们可以将这些约束转化为矩阵 C 和向量 d 的形式。
因此,我们可以构建约束矩阵 AC (对应 C) 和约束向量 bC (对应 d):
import numpy as np
# 假设 A 和 b 已定义
A = np.array([
[-261.60, 11.26, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[ 4.07, -12.75, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[ 0.0, 0.0, -158.63, -5.65, 0.0, 0.0, 0.0, 0.0],
[ 0.0, 0.0, -2.81, -12.14, 0.0, 0.0, 0.0, 0.0],
[ 0.0, 0.0, 0.0, 0.0, -265.99, 19.29, 0.0, 0.0],
[ 0.0, 0.0, 0.0, 0.0, 12.59, -12.34, 0.0, 0.0],
[ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -166.25, -12.63],
[ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -8.40, -11.14]
])
b = np.array([
-6.95,
16.35,
-0.96,
16.35,
19.19,
-15.85,
-12.36,
-15.63]).reshape(-1, 1)
# 构建约束矩阵 AC 和约束向量 bC
AC = np.zeros([3, A.shape[1]]) # 3个约束,X有8个变量
bC = np.zeros((3, 1))
# 0.5 * (y1 + y2) = 0 => x[1] 和 x[3]
AC[0, [1, 3]] = 0.5
# 0.5 * (x3 + x4) = 0 => x[4] 和 x[6]
AC[1, [4, 6]] = 0.5
# 0.5 * (y3 + y4) = 0 => x[5] 和 x[7]
AC[2, [5, 7]] = 0.5
print("约束矩阵 AC:\n", AC)
print("约束向量 bC:\n", bC)为了同时解决原始方程组和所有线性等式约束,我们可以将它们合并成一个更大的、增广的线性系统。这个增广系统可以表示为:
$$ \begin{bmatrix} A \ C \end{bmatrix} X = \begin{bmatrix} b \ d \end{bmatrix} $$
或者简化为 A_aug X = b_aug,其中:
任何满足 A_aug X = b_aug 的向量 X 都将同时满足原始方程 A X = b 和所有线性等式约束 C X = d。
在 NumPy 中,可以使用 np.vstack 函数来实现矩阵和向量的垂直堆叠:
# 堆叠原始矩阵 A 和约束矩阵 AC
A_augmented = np.vstack([A, AC])
# 堆叠原始向量 b 和约束向量 bC
b_augmented = np.vstack([b, bC])
print("\n增广矩阵 A_augmented 的形状:", A_augmented.shape)
print("增广向量 b_augmented 的形状:", b_augmented.shape)此时,A_augmented 的形状将是 (m+k) x n,b_augmented 的形状将是 (m+k) x 1。
np.linalg.lstsq 函数是 NumPy 库中用于求解线性最小二乘问题的核心工具。它寻找一个向量 X,使得 ||A_aug X - b_aug||^2 最小。
对于我们构建的增广系统,lstsq 将直接找到一个 X,它在满足所有线性等式约束的同时,也尽可能地满足原始方程 A X = b。如果原始系统与约束本身是兼容的,它将找到一个精确解。
代码示例:
# 使用 np.linalg.lstsq 求解增广系统
x_solution, residuals, rank, singular_values = np.linalg.lstsq(A_augmented, b_augmented, rcond=None)
print("\n求解得到的 X 向量:\n", x_solution)rcond=None 参数是推荐的用法,它使用机器精度来确定奇异值的阈值,而不是默认的固定值,这有助于提高数值稳定性。
求解得到 x_solution 后,我们应该验证它是否同时满足原始方程和所有约束。
验证原始方程 A X = b:
# 检查是否满足原始方程 A X = b
b_predicted = np.matmul(A, x_solution)
print("\n原始方程左侧 (A * X_solution):\n", b_predicted)
print("原始方程右侧 (b):\n", b)
# 计算残差
original_equation_residuals = b_predicted - b
print("\n原始方程残差:\n", original_equation_residuals)
print("原始方程残差的L2范数:", np.linalg.norm(original_equation_residuals))验证线性等式约束 C X = d:
# 检查是否满足约束 C X = d
constraints_satisfied = np.matmul(AC, x_solution)
print("\n约束左侧 (AC * X_solution):\n", constraints_satisfied)
print("约束右侧 (bC):\n", bC)
# 计算约束残差
constraint_residuals = constraints_satisfied - bC
print("\n约束残差:\n", constraint_residuals)
print("约束残差的L2范数:", np.linalg.norm(constraint_residuals))通过观察残差是否接近于零,我们可以判断解的质量。对于线性等式约束,通常期望约束残差非常接近零(在浮点精度范围内)。
通过将原始线性方程组 AX=b 与线性等式约束 CX=d 合并成一个增广系统 A_aug X = b_aug,并利用 NumPy 的 np.linalg.lstsq 函数,我们可以高效且准确地求解带线性等式约束的线性系统。这种方法简洁、直接,能够同时满足原始方程和所有约束,是处理这类问题的强大工具。理解其背后的最小二乘原理和适用范围,将有助于在实际应用中做出正确的选择。
以上就是使用 NumPy 解决带线性约束的线性方程组的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号