【Eigen教程】密集线性问题和分解(五)

第5章 密集线性问题和分解 (本文由微软Copilot - Think Deeper辅助完成)

  • 1. 向量空间

    • 1.1. 向量空间示例

    • 1.2. 向量积

    • 1.2.1 点积

    • 1.2.2 哈达马德积(舒尔积)

    • 1.2.3 克罗内克积

  • 2. 线性方程

    • 2.1. 矩阵乘法的直觉

    • 2.2. 解集

    • 2.3. 欠定系统

    • 2.4. 超定系统

    • 2.5. 定解

    • 2.6. 齐次与非齐次

  • 3. 解线性方程

    • 3.1. 使用奇异值分解(SVD)

    • 3.2. 完全正交分解

    • 3.3. 使用QR分解

    • 3.4. 使用Cholesky分解

    • 3.5. 高斯消元法(行简化)3.5.1. 前向消元

    • 3.5.2. 前向和后向代换

    • 3.5.3. 部分选主和全选主

    • 3.5.4. 高斯消元法的数值稳定性

    • 3.5.5. 高斯消元算法示例

    • 3.5.6. 行阶梯形

    • 3.5.7. 简化行阶梯形

    • 3.5.8. 行阶梯形示例

    • 3.5.9. 阶梯枢轴列

  • 4. 矩阵分解

    • 4.1. QR分解

    • 4.1.1. 方阵QR分解

    • 4.1.2. 矩形矩阵QR分解

    • 4.2. 计算QR分解

    • 4.3. 格拉姆-施密特正交化

    • 4.4. Householder变换

    • 4.5. QL,RQ和LQ分解

    • 4.6. Cholesky分解LL*

    • 4.7. 厄米特矩阵

    • 4.8. 正定(半定)矩阵

    • 4.9. LDL分解

    • 4.10. 下三角上三角(LU)分解

    • 4.11. 下三角对角上三角(LDU)分解

    • 4.12. 特征值和特征向量

    • 4.13. 计算特征值和特征向量

    • 4.13.1 计算特征值和特征向量的示例

    • 4.14. 矩阵的特征分解

    • 4.15. 奇异值分解

    • 4.15.1 奇异值分解的应用

    • 4.15.1.1 伪逆

    • 4.15.1.2 解齐次线性方程

    • 4.15.1.3 值域,零空间和秩

    • 4.15.1.4 最近的正交矩阵

  • 5. 线性映射

  • 6. 张量

  • 7. 子空间

  • 7.1. 行空间和列空间

  • 8. 矩阵的值域

    • 8.1. 行空间示例

  • 9. 基

    • 9.1. 计算列空间基的示例

    • 9.2. 计算行空间基的示例

    • 9.3. 基向量的变化

    • 9.4. 向量的协变和逆变

    • 9.5. 创建基集合

    • 9.6. 基的变化

    • 9.7. 向量场

    • 9.8. 坐标系

    • 9.8.1. 笛卡尔、极坐标、曲线坐标、圆柱坐标和球坐标

    • 9.9. 坐标变换

    • 9.10. 仿射和曲线变换

  • 10. 矩阵的秩

    • 10.1. 计算秩的结论

  • 11. 列空间的维度

  • 12. 零空间(核)

    • 12.1. 计算零空间的示例

  • 13. 零度

  • 14. 秩-零度定理

  • 15. 矩阵的行列式

  • 16. 求矩阵的逆

  • 17. 线性代数基本定理

  • 18. 置换矩阵

  • 19. 增广矩阵

1. 向量空间

向量空间是一个由向量组成的集合,配备了两个满足特定公理的运算:向量加法标量乘法。在这个空间中,向量可以进行加法运算,也可以被标量(通常为实数或复数)所乘,以得到新的向量。

向量空间满足以下八个公理,其中 VV 是向量集合, FF 是数域(例如实数域 RR 或复数域 CC)。

270d7c61d0010cfc530eb20aff3d575c.png

1.1 向量空间的例子

为了更直观地理解向量空间,我们来看一些具体的例子。

335ed0a561383821d30a89ea834a5f47.png

08b4bebb175287a79a204fadbbe90a58.png

#include <iostream>
#include <Eigen/Dense>

intmain(){
    // 定义二维向量 v1 和 v2
    Eigen::Vector2d v1(1.0,2.0);
    Eigen::Vector2d v2(3.0,4.0);

    // 向量加法
    Eigen::Vector2d v_sum = v1 + v2;

    // 标量乘法
    double scalar =2.0;
    Eigen::Vector2d v_scaled = scalar * v1;

    // 输出结果
    std::cout <<"向量 v1: \n"<< v1 <<"\n\n";
    std::cout <<"向量 v2: \n"<< v2 <<"\n\n";
    std::cout <<"v1 + v2 = \n"<< v_sum <<"\n\n";
    std::cout <<"2 * v1 = \n"<< v_scaled <<"\n";

    return0;
}

代码详解

  • 包含头文件

    #include <iostream>       // 标准输入输出库
    #include <Eigen/Dense>    // Eigen 库,用于线性代数运算
  • 定义主函数

    int main() {
        // ...代码...
        return 0;
    }
  • 定义向量

    Eigen::Vector2d v1(1.0, 2.0);
    Eigen::Vector2d v2(3.0, 4.0);
    • Eigen::Vector2d

       表示 2 维双精度(double)向量。

  • 向量加法和标量乘法

    Eigen::Vector2d v_sum = v1 + v2;
    Eigen::Vector2d v_scaled = scalar * v1;
    • v_sum

       是向量加法的结果。

    • v_scaled

       是标量乘法的结果。

  • 输出结果

    std::cout <<"向量 v1: \n"<< v1 <<"\n\n";
    std::cout <<"向量 v2: \n"<< v2 <<"\n\n";
    std::cout <<"v1 + v2 = \n"<< v_sum <<"\n\n";
    std::cout <<"2 * v1 = \n"<< v_scaled <<"\n";

运行结果

向量 v1: 
1
2

向量 v2: 
3
4

v1 + v2 = 
4
6

2 * v1 = 
2
4

1.2 向量积

向量积是指向量之间的乘法运算,根据运算方式的不同,结果可能是标量或新向量。

1.2.1 点积

点积(内积)是两个向量对应分量相乘后再求和的运算,结果为一个标量。

公式:

6befa93f182831fb3ab52f458da832c5.png

示例代码

#include <iostream>
#include <Eigen/Dense>

intmain(){
    // 定义三个维度的向量 u 和 v
    Eigen::Vector3d u(1.0,2.0,3.0);
    Eigen::Vector3d v(4.0,5.0,6.0);

    // 计算点积
    double dot = u.dot(v);

    // 输出结果
    std::cout <<"向量 u: \n"<< u <<"\n\n";
    std::cout <<"向量 v: \n"<< v <<"\n\n";
    std::cout <<"u ⋅ v = "<< dot <<"\n";

    return0;
}

代码详解

  • u.dot(v)

     计算向量 u 和 v 的点积。

运行结果

向量 u: 
1
2
3

向量 v: 
4
5
6

u ⋅ v = 32

计算

50c5e535b9de6bc51ac50784f524daf9.png

1.2.2 哈达玛积(舒尔积)

哈达玛积(Hadamard 积)是两个同维度向量对应元素相乘,得到新的向量。

706c7dd30b3783bf3375ae18939e9cea.png

示例代码

#include <iostream>
#include <Eigen/Dense>

intmain(){
    // 定义向量 s 和 t
    Eigen::Vector2d s(1.0,2.0);
    Eigen::Vector2d t(3.0,4.0);

    // 计算哈达玛积
    Eigen::Vector2d hadamard = s.array()* t.array();

    // 输出结果
    std::cout <<"向量 s: \n"<< s <<"\n\n";
    std::cout <<"向量 t: \n"<< t <<"\n\n";
    std::cout <<"s ⊙ t = \n"<< hadamard <<"\n";

    return0;
}

代码详解

  • s.array()

     将向量视为数组,以便进行按元素的操作。

  • *

     运算符用于数组的逐元素乘法。

运行结果

向量 s: 
1
2

向量 t: 
3
4

s ⊙ t = 
3
8

1.2.3 克罗内克积

克罗内克积(Kronecker 积)是矩阵之间的张量积,结果是一个更大的矩阵。

31d5acd88551915a573247148b0ec2f6.png

示例代码

#include <iostream>
#include <Eigen/Dense>

intmain(){
    // 定义矩阵 A 和 B
    Eigen::Matrix2d A;
    Eigen::Matrix2d B;

    A <<1,2,
         3,4;

    B <<0,5,
         6,7;

    // 计算克罗内克积
    Eigen::MatrixXd kron =Eigen::kroneckerProduct(A, B).eval();

    // 输出结果
    std::cout <<"矩阵 A: \n"<< A <<"\n\n";
    std::cout <<"矩阵 B: \n"<< B <<"\n\n";
    std::cout <<"A ⊗ B = \n"<< kron <<"\n";

    return0;
}

代码详解

  • Eigen::kroneckerProduct(A, B)

     计算克罗内克积。

  • eval()

     用于强制计算结果,以确保后续输出正确。

运行结果

矩阵 A: 
1 2
3 4

矩阵 B: 
0 5
6 7

A ⊗ B = 
0 5 0 10
6 7 12 14
0 15 0 20
18 21 24 28

总结

通过以上内容,我们深入了解了向量空间的定义和公理,同时探讨了向量空间的具体例子。我们还介绍了向量乘积的不同类型,包括点积、哈达玛积和克罗内克积,并通过代码示例演示了如何计算和应用这些运算。

延伸阅读

  • 线性映射与矩阵表示

    :了解向量空间之间的线性映射及其矩阵表示。

  • 基与维度

    :学习向量空间的基的概念,以及如何确定向量空间的维度。

  • 内积空间

    :深入探讨具有内积结构的向量空间,即赋予向量空间长度和角度的概念。

向量空间是线性代数的核心概念,广泛应用于物理学、工程学、计算机科学等领域。理解向量空间及其运算,对于深入学习和应用线性代数至关重要。

2. 线性方程

6a1f71821812e3196458e0a6541a5a70.png

解析:这意味着我们将系数、未知数和常数项分别组合成矩阵和向量的形式,利用矩阵运算的简洁性,方便求解和分析。这种表示方法在工程、物理、计算机科学(例如计算机图形学、机器学习中的回归问题)等领域尤为重要。

2.1 矩阵乘法的直观理解

矩阵乘法可以被视为向量的线性组合。具体来说,矩阵与向量相乘,相当于用向量的各个分量对矩阵的列进行加权,然后将结果相加。

1ee620db4c4b9f185626fa4b117523c7.png

2.2 解集的可能性

一个线性方程组可能存在以下三种情况之一:

  1. 无数个解

    :当方程组具有自由度,未知数多于独立方程数量,且方程彼此不矛盾。

  2. 唯一解

    :当方程数量等于未知数数量,且方程组满秩(矩阵 AA 可逆)。

  3. 无解

    :当方程组存在矛盾,无法找到同时满足所有方程的解。

解集的情况取决于方程与未知数的数量以及方程之间的独立性。

2.3 欠定系统

方程数量少于未知数数量时,称为欠定系统。在这种情况下:

  • 如果方程不矛盾,通常存在无数个解(无限解)。

  • 如果方程矛盾,则无解。

2.4 超定系统

方程数量多于未知数数量时,称为超定系统。在这种情况下:

  • 方程可能矛盾,导致无解。

  • 若方程近似一致,可以通过最小二乘法找到一个近似解,使得误差平方和最小。

2.5 适定系统

方程数量等于未知数数量时,称为适定系统。在这种情况下:

  • 如果矩阵 AA 满秩(可逆),则存在唯一解。

  • 如果矩阵 AA 不满秩,则可能存在无数个解或无解。

根据具体情况,可选择不同的求解方法,平衡速度与精度。

2.6 齐次与非齐次方程组

a0da74d969048c131f924b9abddc6558.png

2.7 线性方程组的求解方法

为了具体展示线性方程组的求解过程,我们将使用 C++ 和 Eigen 库编写代码,并添加详细的注释。

示例代码:求解线性方程组

#include <iostream>
#include <Eigen/Dense>

intmain(){
    // 定义一个 3x3 的矩阵 A,系数矩阵
    Eigen::Matrix3f A;
    A <<1,2,3,   // 第一行元素:a_{11}, a_{12}, a_{13}
         4,5,6,   // 第二行元素:a_{21}, a_{22}, a_{23}
         7,8,10;// 第三行元素:a_{31}, a_{32}, a_{33}
    
    // 定义一个 3x1 的向量 b,常数项
    Eigen::Vector3f b;
    b <<6,15,25;// 常数项 b_1, b_2, b_3

    // 输出矩阵 A 和向量 b
    std::cout <<"系数矩阵 A:\n"<< A << std::endl;
    std::cout <<"常数向量 b:\n"<< b << std::endl;

    // 使用 PartialPivLU 分解求解 Ax = b
    Eigen::Vector3f x = A.partialPivLu().solve(b);

    // 输出解 x
    std::cout <<"方程组的解 x:\n"<< x << std::endl;

    return0;
}

代码详解:

  1. 包含必要的头文件:

    #include <iostream>      // 用于标准输入输出
    #include <Eigen/Dense>   // 包含 Eigen 库的密集矩阵相关功能
  2. 主函数:

    int main() {
        // ... 代码 ...
        return 0;
    }
  3. 定义系数矩阵 A:

    Eigen::Matrix3f A;
    A << 1, 2, 3,
         4, 5, 6,
         7, 8, 10;
  • Eigen::Matrix3f

     表示 3x3 的浮点矩阵。

  • 使用逗号初始化器 << 按行填充矩阵元素。

定义常数向量 b:

Eigen::Vector3f b;
b << 6, 15, 25;
  • Eigen::Vector3f

     表示 3x1 的浮点向量。

  • 填充常数项。

输出矩阵 A 和向量 b:

std::cout << "系数矩阵 A:\n" << A << std::endl;
std::cout << "常数向量 b:\n" << b << std::endl;
  • 使用 std::cout 输出矩阵和向量。

求解线性方程组:

Eigen::Vector3f x = A.partialPivLu().solve(b);
  • partialPivLu()

    :对矩阵 A 进行部分主元 LU 分解,数值稳定性较好。

  • solve(b)

    :求解方程组 Ax=b

输出解 x:

std::cout << "方程组的解 x:\n" << x << std::endl;
  • 输出求得的未知数向量 x。

运行结果:

系数矩阵 A:
1 2 3
4 5 6
7 8 10
常数向量 b:
6
15
25
方程组的解 x:
1
1
1

e731636ea210ea64a567d652f4cc0a23.png

2.8 不同求解方法的比较

在求解线性方程组时,根据系数矩阵的性质和精度要求,可以选择不同的方法:

  1. 直接求逆(不推荐)

    Eigen::Vector3f x = A.inverse() * b;
  • 缺点

    :计算矩阵逆存在数值不稳定性和较高的计算代价。

  • 建议

    :除非矩阵非常小且条件数较好,否则不推荐直接求逆。

LU 分解

Eigen::Vector3f x = A.lu().solve(b);
  • 适用场景

    :一般情况下,LU 分解速度快,适用于方阵。

QR 分解

Eigen::Vector3f x = A.householderQr().solve(b);
  • 适用场景

    :适用于非方阵或接近奇异的矩阵。

最小二乘法(适用于超定方程组)

Eigen::VectorXf x = A.colPivHouseholderQr().solve(b);
  • 适用场景

    :当方程数量多于未知数数量,需要找到误差最小的近似解。

Cholesky 分解(适用于正定矩阵)

Eigen::Vector3f x = A.ldlt().solve(b);
  • 适用场景

    :系数矩阵对称且正定,计算效率高。

2.9 线性方程组的数值稳定性

在实际计算中,系数矩阵的条件数会影响求解结果的精度:

  • 条件数大

    (矩阵接近奇异):求解结果对输入数据和舍入误差非常敏感,可能产生较大误差。

  • 条件数小

    (矩阵较好):求解结果对误差不敏感,计算结果可靠。

建议

  • 避免直接求逆
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值