线性方程组/矩阵方程求解(方法汇总)
文章目录
- 前言
- 1 线性方程组(矩阵方程)
- 2 QR分解
- 2.1 ColPivHouseholderQR分解
- 2.2 HouseholderQR分解
- 2.3 FullPivHouseholderQR分解
- 3 LLT分解
- 3 LDLT分解
- 4 LU分解
- 4.1 LU分解
- 4.2 PartialPivLu分解
- 4.3 FullPivLu分解
- 5 SVD分解
- 5.1 BDCSVD分解
- 5.2 JacobiSVD分解
- 6 公式法(x=A−1bx=A^{-1}bx=A−1b)
前言
Eigen 是一个基于C++模板的线性代数库,提供了很多求解矩阵方程的方式,如比如LU分解、QR分解、SVD分解等。
本文以实用性为主,重点讨论几种求解矩阵方程的方法,以及不同方法的优缺点。对于每种方法的原理不做过多介绍。
下面给出不同分解方式的对比图,主要是计算速度和精度的对比,同时不同的分解方式对系数矩阵的形式也有不同的要求。
1 线性方程组(矩阵方程)
线性方程组是各个方程关于未知量均为一次的方程组,可以采用矩阵方程的形式表示。比如已知一个线性方程组
{a1x1+b1x2+c1x3=d1a2x1+b2x2+c2x3=d2a3x1+b3x2+c3x3=d3\begin{cases} a_1x_1+b_1x_2+c_1x_3=d_1\\ a_2x_1+b_2x_2+c_2x_3=d_2\\ a_3x_1+b_3x_2+c_3x_3=d_3\\ \end{cases}⎩⎪⎨⎪⎧a1x1+b1x2+c1x3=d1a2x1+b2x2+c2x3=d2a3x1+b3x2+c3x3=d3
写成矩阵形式
Ax=bAx=bAx=b
其中,
A=[a1b1c1a2b2c2a3b3c3]A=\begin{bmatrix}a_1&b_1&c_1 \\a_2&b_2&c_2\\a_3&b_3&c_3\\\end{bmatrix}A=⎣⎡a1a2a3b1b2b3c1c2c3⎦⎤,x=[x1x2x3]x=\begin{bmatrix}x_1\\x_2\\x_3\\\end{bmatrix}x=⎣⎡x1x2x3⎦⎤,d=[d1d2d3]d=\begin{bmatrix}d_1\\d_2\\d_3\\\end{bmatrix}d=⎣⎡d1d2d3⎦⎤
以线性方程组
{x1+2x2+3x3=34x1+5x2+6x3=37x1+8x2+10x3=4\begin{cases} x_1+2x_2+3x_3=3\\ 4x_1+5x_2+6x_3=3\\ 7x_1+8x_2+10x_3=4\\ \end{cases}⎩⎪⎨⎪⎧x1+2x2+3x3=34x1+5x2+6x3=37x1+8x2+10x3=4
为例,进行求解。写成矩阵形式为
[1234567810][x1x2x3]=[334]\begin{bmatrix}1&2&3 \\4&5&6\\7&8&10\\\end{bmatrix}\begin{bmatrix}x_1\\x_2\\x_3\\\end{bmatrix}=\begin{bmatrix}3\\3\\4\\\end{bmatrix}⎣⎡1472583610⎦⎤⎣⎡x1x2x3⎦⎤=⎣⎡334⎦⎤
可以选择不同的分解方式,这取决于矩阵A的形式,也取决于求解的速度和精度。
2 QR分解
QR分解类中的solution()方法也可以用来求解矩阵方程,有三个QR分解类:
- HouseholderQR:无旋转(no pivoting),速度很快但不稳定
- ColPivHouseholderQR:列旋转(column pivoting),速度稍慢但更精确
- FullPivHouseholderQR:全旋转(full pivoting),速度慢,最稳定
2.1 ColPivHouseholderQR分解
ColPivHouseholderQR分解是一个很好的折衷方案,因为它适用于所有矩阵,同时速度非常快。
代码:
#include <iostream>
#include <Eigen/Dense>using namespace std;
using namespace Eigen;int main()
{Matrix3d A; //系数矩阵AVector3d b; //常数矩阵bVector3d x; //未知数矩阵xA << 1,2,3, 4,5,6, 7,8,10;b << 3, 3, 4;cout << "系数矩阵A:\n" << A << endl;cout << "常数矩阵b:\n" << b << endl;x = A.colPivHouseholderQr().solve(b);cout << "未知数矩阵x:\n" << x << endl;return 0;
}
输出结果:
系数矩阵A:1 2 34 5 67 8 10
常数矩阵b:
3
3
4
未知数矩阵x:
-211
2.2 HouseholderQR分解
相比于ColPivHouseholderQR分解,HouseholderQR分解计算速度更快,但精度不如ColPivHouseholderQR分解。
代码
#include <iostream>
#include <Eigen/Dense>using namespace std;
using namespace Eigen;int main()
{Matrix3d A; //系数矩阵AVector3d b; //常数矩阵bVector3d x; //未知数矩阵xA << 1,2,3, 4,5,6, 7,8,10;b << 3, 3, 4;cout << "系数矩阵A:\n" << A << endl;cout << "常数矩阵b:\n" << b << endl;x = A.householderQr().solve(b);cout << "未知数矩阵x:\n" << x << endl;return 0;
}
输出结果:
系数矩阵A:1 2 34 5 67 8 10
常数矩阵b:
3
3
4
未知数矩阵x:
-211
2.3 FullPivHouseholderQR分解
FullPivHouseholderQR分解相比于前两种QR分解,速度更慢,但精度更高。
代码:
#include <iostream>
#include <Eigen/Dense>using namespace std;
using namespace Eigen;int main()
{Matrix3d A; //系数矩阵AVector3d b; //常数矩阵bVector3d x; //未知数矩阵xA << 1,2,3, 4,5,6, 7,8,10;b << 3, 3, 4;cout << "系数矩阵A:\n" << A << endl;cout << "常数矩阵b:\n" << b << endl;x = A.fullPivHouseholderQr().solve(b);cout << "未知数矩阵x:\n" << x << endl;return 0;
}
输出结果:
系数矩阵A:1 2 34 5 67 8 10
常数矩阵b:
3
3
4
未知数矩阵x:
-211
3 LLT分解
LLT分解要求系数矩阵A是正定矩阵(Positive definite matrix),是所有分解方式中速度最快的一种。用于非正定矩阵的分解时,难以得到正确的结果。
代码:
#include <iostream>
#include <Eigen/Dense>using namespace std;
using namespace Eigen;int main()
{Matrix3d A; //系数矩阵AVector3d b; //常数矩阵bVector3d x; //未知数矩阵xA << 1,2,3, 4,5,6, 7,8,10;b << 3, 3, 4;cout << "系数矩阵A:\n" << A << endl;cout << "常数矩阵b:\n" << b << endl;x = A.llt().solve(b);cout << "未知数矩阵x:\n" << x << endl;return 0;
}
输出结果:
系数矩阵A:1 2 34 5 67 8 10
常数矩阵b:
3
3
4
未知数矩阵x:4.4556
-0.3184-0.026
3 LDLT分解
LDLT分解要求系数矩阵A是正定矩阵(positive definite matrix)或者半负定矩阵(negative semi-definite matrix)。用于其他矩阵的分解时,难以得到正确的结果。
代码:
#include <iostream>
#include <Eigen/Dense>using namespace std;
using namespace Eigen;int main()
{Matrix3d A; //系数矩阵AVector3d b; //常数矩阵bVector3d x; //未知数矩阵xA << 1,2,3, 4,5,6, 7,8,10;b << 3, 3, 4;cout << "系数矩阵A:\n" << A << endl;cout << "常数矩阵b:\n" << b << endl;x = A.ldlt().solve(b);cout << "未知数矩阵x:\n" << x << endl;return 0;
}
输出结果:
系数矩阵A:1 2 34 5 67 8 10
常数矩阵b:
3
3
4
未知数矩阵x:
-0.2068970.379310.241379
4 LU分解
4.1 LU分解
代码:
#include <iostream>
#include <Eigen/Dense>using namespace std;
using namespace Eigen;int main()
{Matrix3d A; //系数矩阵AVector3d b; //常数矩阵bVector3d x; //未知数矩阵xA << 1,2,3, 4,5,6, 7,8,10;b << 3, 3, 4;cout << "系数矩阵A:\n" << A << endl;cout << "常数矩阵b:\n" << b << endl;x = A.lu().solve(b);cout << "未知数矩阵x:\n" << x << endl;return 0;
}
输出结果:
系数矩阵A:1 2 34 5 67 8 10
常数矩阵b:
3
3
4
未知数矩阵x:
-211
4.2 PartialPivLu分解
代码:
#include <iostream>
#include <Eigen/Dense>using namespace std;
using namespace Eigen;int main()
{Matrix3d A; //系数矩阵AVector3d b; //常数矩阵bVector3d x; //未知数矩阵xA << 1,2,3, 4,5,6, 7,8,10;b << 3, 3, 4;cout << "系数矩阵A:\n" << A << endl;cout << "常数矩阵b:\n" << b << endl;x = A.partialPivLu().solve(b);cout << "未知数矩阵x:\n" << x << endl;return 0;
}
输出结果:
系数矩阵A:1 2 34 5 67 8 10
常数矩阵b:
3
3
4
未知数矩阵x:
-211
4.3 FullPivLu分解
代码:
#include <iostream>
#include <Eigen/Dense>using namespace std;
using namespace Eigen;int main()
{Matrix3d A; //系数矩阵AVector3d b; //常数矩阵bVector3d x; //未知数矩阵xA << 1,2,3, 4,5,6, 7,8,10;b << 3, 3, 4;cout << "系数矩阵A:\n" << A << endl;cout << "常数矩阵b:\n" << b << endl;x = A.fullPivLu().solve(b);cout << "未知数矩阵x:\n" << x << endl;return 0;
}
生成失败:
error C1128: 节数超过对象文件格式限制: 请使用 /bigobj 进行编译
5 SVD分解
当方程个数大于未知数个数时,需要进行最小二乘求解,有效的办法是进行奇异值分解。Eigen提供了两种实现方式,推荐使用 BDCSVD 类,它可以很好地扩展大型矩阵,而对于较小的矩阵,它会自动退回到JacobiSVD类。
注意:采用SVD分解时,要用 动态矩阵 定义系数矩阵A、常数矩阵b、未知数矩阵x
5.1 BDCSVD分解
代码:
#include <iostream>
#include <Eigen/Dense>using namespace std;
using namespace Eigen;int main()
{MatrixXd A(3,2); //系数矩阵A,3×2阶VectorXd b(3,1); //常数矩阵b,3×1阶VectorXd x(3,1); //未知数矩阵x,3×1阶A << 1, 2, 4, 5, 7, 8;b << 3, 3, 4;cout << "系数矩阵A:\n" << A << endl;cout << "常数矩阵b:\n" << b << endl;x = A.bdcSvd(ComputeThinU | ComputeThinV).solve(b);cout << "未知数矩阵x:\n" << x << endl;return 0;
}
输出结果:
系数矩阵A:
1 2
4 5
7 8
常数矩阵b:
3
3
4
未知数矩阵x:-2.5
2.66667
5.2 JacobiSVD分解
代码:
#include <iostream>
#include <Eigen/Dense>using namespace std;
using namespace Eigen;int main()
{MatrixXd A(3,2); //系数矩阵A,3×2阶VectorXd b(3,1); //常数矩阵b,3×1阶VectorXd x(3,1); //未知数矩阵x,3×1阶A << 1, 2, 4, 5, 7, 8;b << 3, 3, 4;cout << "系数矩阵A:\n" << A << endl;cout << "常数矩阵b:\n" << b << endl;x = A.jacobiSvd(ComputeThinU | ComputeThinV).solve(b);cout << "未知数矩阵x:\n" << x << endl;return 0;
}
输出结果:
系数矩阵A:
1 2
4 5
7 8
常数矩阵b:
3
3
4
未知数矩阵x:-2.5
2.66667
6 公式法(x=A−1bx=A^{-1}bx=A−1b)
虽然逆(inverse)和行列式(determinant)是基本的数学概念,但在线性代数中,它们不像在纯数学中那么流行。逆运算通常被 solve 运算所代替,行列式通常不是检查矩阵是否可逆的好方法。
但是,对于非常小的矩阵,逆矩阵和行列式是非常有用的。
虽然某些分解(如PartialPivLU和FullPivLU)提供了inverse()和determinate()方法,但也可以直接对矩阵调用inverse()和determinate()。如果矩阵是一个非常小的(最多4x4)静态矩阵,Eigen可使用公式 x=A−1bx=A^{-1}bx=A−1b,比矩阵分解的方式更有效。
代码:
#include <iostream>
#include <Eigen/Dense>using namespace std;
using namespace Eigen;int main()
{Matrix3d A; //系数矩阵AVector3d b; //常数矩阵bVector3d x; //未知数矩阵xA << 1,2,3, 4,5,6, 7,8,10;b << 3, 3, 4;cout << "系数矩阵A:\n" << A << endl;cout << "常数矩阵b:\n" << b << endl;if (A.determinant() != 0){//矩阵行列式大于0,x = A.inverse()*b;cout << "未知数矩阵x:\n" << x << endl;}else{cout << "矩阵行列式小于0,矩阵方程无解!\a\n" << endl;}return 0;
}
输出结果:
系数矩阵A:1 2 34 5 67 8 10
常数矩阵b:
3
3
4
未知数矩阵x:
-211
线性方程组/矩阵方程求解(方法汇总)相关推荐
- 重磅!一文读懂线性方程组的求解方法
目录 1.AAA为方阵 直接法 迭代法 2.AAA为非方阵且A∈Rm×n,m>nA\in R^{m\times n},m>nA∈Rm×n,m>n 2.1. r(A)=n<mr( ...
- python计算矩阵方程_python/sympy求解矩阵方程的方法
sympy版本:1.2 假设求解矩阵方程 AX=A+2X 其中 求解之前对矩阵方程化简为 (A−2E)X=A 令 B=(A−2E) 使用qtconsole输入下面程序进行求解 In [26]: fro ...
- python解一元三次方程_python/sympy求解矩阵方程的方法
sympy版本:1.2 假设求解矩阵方程 AX=A+2X 其中 求解之前对矩阵方程化简为 (A−2E)X=A 令 B=(A−2E) 使用qtconsole输入下面程序进行求解 In [26]: fro ...
- 数值计算——系数矩阵部分对角线为0时线性方程组求解方法(附程序)
求解线性方程组时,我们经常用的方法是高斯消去法,矩阵三角分解,雅克比迭代,以及迭代方法如共轭梯度等.在使用这些方法求解的过程中,通常需要,但是难免会遇到对角线有一些数为0的情况.本文求解方法大致求解思 ...
- 二维Poisson方程五点差分格式及简单求解方法Python实现
二维Poisson方程简介 给出 二维 PoissonPoissonPoisson 方程 DirichletDirichletDirichlet 边值问题: {−Δu=f(x,y)(x,y)∈Ωu=φ ...
- 特征点匹配+特征检测方法汇总
特征点匹配+特征检测方法汇总 特征提取与匹配---SURF:SIFT:ORB:FAST:Harris角点 匹配方法 匹配函数 1. OpenCV提供了两种Matching方式: • Brute-for ...
- matlab 解相位_光测力学栅线投影技术-相位求解方法
目前相位求解方法主要有傅里叶方法和相移方法两种,主要有以下区别: 傅里叶方法仅需要一张栅线图像,相移则需要至少三张(两步相移法是一种特殊情况,其相位求解方式严格来说并不是用的相移算法,这个在今后的文章 ...
- python求极限中有算术平方根如何表达_Python求算数平方根和约数的方法汇总
Python求算数平方根和约数的方法汇总 一.求算术平方根 a= x=int(raw_input('Enter a number:')) if x >= : while a*a < x: ...
- matlab解方程组方法,第二章解线性方程组的直接方法matlab用法
第二章解线性方程组的直接方法matlab用法 第二章 解线性方程组的直接方法的 MATLAB 程序24. 在这章中我们要学习线性方程组的直接法,特别是适 合用数学软件在计算机上求解的方法. 2.1 方 ...
- 非线性方程组求解方法,神经网络的非线性函数
1.rbf神经网络原理 rbf神经网络原理是用RBF作为隐单元的"基"构成隐含层空间,这样就可以将输入矢量直接映射到隐空间,而不需要通过权连接. 当RBF的中心点确定以后,这种映射 ...
最新文章
- QT Creator 版本大全及下载地址
- linux下软件编译安装 前提和方式
- 《Python语言程序设计》——2.10 增强型赋值运算符
- [转]英语飙升的好方法
- Windows 10 install Pycharm 开发环境
- L8.1 lvs+heartbeat-ldirectord实现高可用负载均衡
- C#访问MySQL数据库的方法
- 动态规划 - 买卖股票的最佳时机 IV
- 海量数据处理(二) :常见海量数据处理方法
- python 单例模式 redis_python 单例模式实现多线程共享连接池
- 自己总结的sql基本操作
- android 自定义 黑点,Android自定义密码样式 黑点转换成特殊字符
- dubbogo PMC何鑫铭:没有热爱就做不成这件事情
- Web后端开发入门(1)
- CSS简易导航列表样式
- mysql 连续打卡天数_Sql如何统计连续打卡天数
- 面试官:为何Redis使用跳表而非红黑树实现SortedSet?
- 各种DBCO偶联试剂成为点击化学反应的操控新策略
- k8s部署jenkins和Pod始终为pending状态“persistentvolume-controller no persistent volumes available.....”解决办法
- LWN: STARTTLS 的坏处!
热门文章
- 易捷行云EasyStack获OpenInfra社区卓越领导力奖
- d3.js v5 数据加载
- 修复DialogFragment Fragment already added 异常
- 鼻咽癌有什么症状表现?
- 1072 开学寄语 Python实现
- 项目(百万并发网络通信架构)10.2---recv()函数的极限测试
- ignore在mysql中什么意思_ignore是什么意思
- 正睿集训模拟赛 Day1
- java商城管理系统_带数据库_带界面化可用来毕业设计
- 【LabVIEW串口编程】 02 串口发送