Eigen笔记(二)

C++线性代数库——Eigen

内容概要

上次我们介绍了Eigen的一些基本概况,下面我们再来探讨一些Eigen中运算符重载、重要API以及矩阵建立的一些问题。

Operator overload

Eigen中基本数据类型Matrix在其命名空间内重载了一些方便矩阵运算的运算符。

  • **+**运算符的重载

    Matrix数据类型支持 + 法运算符。加法运算符的重载可以让我们完成矩阵以及向量的加法运算。值得注意的是

    加法运算符不会在编译时检测加法运算的合法性,只会在程序运行时检测运算的合理性,如果运算不合理将会抛出异常,所以在大型程序编写中,我们应该捕获可能出现的异常。

    #include <iostream>
    #include "Eigen/Dense"
    
    using namespace std;
    using namespace Eigen;
    int main()
    {
        Matrix<float,-1,-1> A(3,3);
        Matrix<float,-1,-1> B(3,2);
        try {
            A + B;
        } catch (exception e) {
            cout << "不合法的加法运算" <<endl;
            cout << e.what();
        }
        return 0;
    }
    
  • - 运算符的重载

    + 预算符的重载

  • *****运算符的重载

    + 运算符的重载

  • / 运算符的重载

    rate divide

  • += and **-=**运算符的重载

    同**+**运算符的重载

  • << 运算符的重载

    为了方便对矩阵进行初始化,Eigen对右移位运算符进行了重载,类似流式操作,对矩阵进行初始化。但是对矩阵进行初始化时,右移位运算符必须一次性把矩阵中所有的元素都进行初始化。

    也就是说,初始化操作要一次性完成。初始化元素个数不可以不等于矩阵的大小。

    #include <iostream>
    #include "Eigen/Dense"
    
    using namespace std;
    using namespace Eigen;
    int main()
    {
        Matrix<float,-1,-1> A(3,3);
        Matrix<float,-1,-1> B(3,2);
        A << 1,2,3,
             2,3,4,
             3,4,5;
        return 0;
    }
    
    
  • ostream的重载

    为了方便打印矩阵,Eigen对编译器的标准输出流做了重载。

    #include <iostream>
    #include "Eigen/Dense"
    
    using namespace std;
    using namespace Eigen;
    int main()
    {
        Matrix<float,-1,-1> A(3,3);
        Matrix<float,-1,-1> B(3,2);
        A << 1,2,3,
             2,3,4,
             3,4,5;
    	cout << A << endl;
        return 0;
    }
    

矢量化的操作(vector operation)

在Eigen中,矢量化的操作是极为便捷的。Matrix数据类型支持矢量化的乘除运算。也就是对矩阵进行倍率的放大和缩小。

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

using namespace std;
using namespace Eigen;
int main()
{
    Matrix<float,-1,-1> A(3,3);
    Matrix<float,-1,-1> B(1,3);
    A << 1,2,3,
         2,3,4,
         3,4,5;
    B << 1,2,3;
    cout << "now A is:" << endl;
    cout << A << endl;
    cout << "A * 2 = " << endl;
    cout << A * 2 << endl;
    cout << "As well as division" << endl;
    cout << A / 2 << endl;
    return 0;
}

程序执行结果

now A is:
1 2 3
2 3 4
3 4 5
A * 2 =
 2  4  6
 4  6  8
 6  8 10
As well as division
0.5   1 1.5
  1 1.5   2
1.5   2 2.5

as well as vector to do that

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

using namespace std;
using namespace Eigen;
int main()
{
    Matrix<float,-1,-1> A(3,3);
    Matrix<float,-1,-1> B(1,3);
    A << 1,2,3,
         2,3,4,
         3,4,5;
    B << 1,2,3;
    cout << "now B is:" << endl;
    cout << B << endl;
    cout << "B * 2 = " << endl;
    cout << B * 2 << endl;
    cout << "As well as division" << endl;
    cout << B / 2 << endl;
    return 0;
}

程序执行结果

now B is:
1 2 3
B * 2 =
2 4 6
As well as division
0.5   1 1.5

Transposition(转置) ,Conjugation(共轭) and Adjoint(伴随)

下面我们来说Matrix模板类中的重要的两个成员函数。transpose()&conjugation()&adjoint()。这两个成员函数可以完成矩阵的转置,共轭矩阵的求解和伴随矩阵的问题。下面我们通过代码实例进行了解

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

using namespace std;
using namespace Eigen;
int main()
{
    /*this is an transpositon example*/
    Matrix<float,-1,-1> A(3,3);
    A << 1,2,3,
         4,5,6,
         7,8,9;
    /* Matrix support copy assignment constructor*/
    Matrix<float,-1,-1> B = A.transpose();

    cout << "Now A is:" <<endl;
    cout << A<< endl;
    cout << "It's transposition is:" << endl;
    cout << B << endl;
    return 0;
}

程序执行结果

Now A is:
1 2 3
4 5 6
7 8 9
It's transposition is:
1 4 7
2 5 8
3 6 9

as well as conjugation

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

using namespace std;
using namespace Eigen;
int main()
{
    /*conjugation example*/
    Matrix<float,-1,-1> A(3,3);
    A << 1,2,3,
         4,5,6,
         7,8,9;
    Matrix<float,-1,-1> B = A.conjugate();
    cout << "Now A is:" <<endl;
    cout << A<< endl;
    cout << "It's conjugation is:" << endl;
    cout << B << endl;
    return 0;
}

程序执行结果

Now A is:
1 2 3
4 5 6
7 8 9
It's conjugation is:
1 2 3
4 5 6
7 8 9

and this is Adjoint

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

using namespace std;
using namespace Eigen;
int main()
{
    /*Adjoint example*/
    Matrix<float,-1,-1> A(3,3);
    A << 1,2,3,
         4,5,6,
         7,8,9;
    Matrix<float,-1,-1> B = A.adjoint();

    cout << "Now A is:" <<endl;
    cout << A<< endl;
    cout << "It's adjoint is:" << endl;
    cout << B << endl;
    return 0;
}

程序执行结果

Now A is:
1 2 3
4 5 6
7 8 9
It's adjoint is:
1 4 7
2 5 8
3 6 9

Dot production and cross production

点成和叉乘是在向量运算中有着很重要的地位。同样Eigen也提供了相应的向量点乘和叉乘的运算成员函数(Matrix)下面我们就通过代码实例进行了解

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

using namespace std;
using namespace Eigen;
int main()
{
    RowVector3d A,B;
    A << 1,0,0;
    B << 0,1,0;
    cout << "Vector A is:"<< endl;
    cout << A <<endl;
    cout << "Vector B is:" << endl;
    cout << B << endl;
    cout <<"A . B" <<endl;
    cout << A.dot(B) << endl;
    cout << "A x B" <<endl;
    cout << A.cross(B) << endl;
    return 0;
}

程序执行结果

Vector A is:
1 0 0
Vector B is:
0 1 0
A . B
0
A x B
0 0 1

Vector方法的定义

在调用一些专属于Vector的方法时,我们应该注意,Eigen在Matrix这个模板类中做了一些偏特化的处理。

例如下面的这行代码

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

using namespace std;
using namespace Eigen;
int main()
{
    Matrix<double,-1,-1> A(1,3),B(1,3);//定义出错,该模板参数没有进行特化
    A << 1,0,0;
    B << 0,1,0;
    cout << "Vector A is:"<< endl;
    cout << A <<endl;
    cout << "Vector B is:" << endl;
    cout << B << endl;
    cout <<"A . B" <<endl;
    cout << A.dot(B) << endl;
    cout << "A x B" <<endl;
    cout << A.cross(B) << endl;
    return 0;
}

我们动态定义出来的向量将无法使用一些专属于Vector的方法。虽然在字面上来看,这与RowVector3d定义没什么不同,但是Eigen对Vector做了模板偏特化处理。也就是说,RowVector3d不再是仅仅的typedef的问题,而是在模板特化的问题。(的确Eigen时tyepdef Matrix<double,1,3> RowVector3d)但是对于Matrix<double,1,3>这组模板做了偏特化的处理。进而是他能够使用一些专属的特化的函数。

程序执行结果

D:\CPP\EigenTest\Eigen\src\Core\Dot.h:74: error: static_assert failed due to requirement 'Matrix<double, -1, -1, 0, -1, -1>::IsVectorAtCompileTime' "YOU_TRIED_CALLING_A_VECTOR_METHOD_ON_A_MATRIX"
  EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

更改的建议

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

using namespace std;
using namespace Eigen;
int main()
{
    Matrix<double,1,3> A,B;//该模板参数进行了特化
    A << 1,0,0;
    B << 0,1,0;
    cout << "Vector A is:"<< endl;
    cout << A <<endl;
    cout << "Vector B is:" << endl;
    cout << B << endl;
    cout <<"A . B" <<endl;
    cout << A.dot(B) << endl;
    cout << "A x B" <<endl;
    cout << A.cross(B) << endl;
    return 0;
}

Inverse(求逆)

可以说,在线性代数中,最重要的问题就是矩阵的求逆,这是求解线性方程组的条件。

A x = b Ax = b => x = A 1 b x = A^{-1} b

下面是代码实例

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

using namespace std;
using namespace Eigen;
int main()
{
    Matrix<double,-1,-1> A(3,3);
    A << 1,2,3,
         4,5,6,
         7,8,9;
    cout <<A.inverse() << endl;
    return 0;
}

创建矩阵和向量的建议

如果想使用动态的矩阵,我们可以用MatrixXd等去创建我们想要的类型的矩阵。也可以使用Matrix<T,-1,-1>去创建任意类型的矩阵。但是,我们要注意,一旦我们想使用向量,我们应该尽量避免使用上一个方法进行创建。因为通过上一个方法创建出来的向量没有经过类模板的特化处理,所以在使用一些成员函数时,会造成不必要的困扰。所以向量的创建我们尽量去指定其类模板参数中的行数列数

猜你喜欢

转载自blog.csdn.net/hbn13343302533/article/details/96449784