C++下的Eigen库学习笔记

C++下的Eigen库笔记

01 安装教程

1.1 Windows下基于Visual Studio的Eigen配置教程

  • 解压然后放在一个不会经常移动的地址,

    在解决方案管理器一栏中选定项目名称->单击菜单栏中的项目->选择属性->VC++目录->包含目录

    包含该路径就可以,注意该路径目录的下级目录应为一系列子文件,否则包含时候找不到,参见参考资源[1]。

  • Eigen库有不同的模块,需要对应的功能包含对应的头文件即可,详情见参考资源[2]。

1.2 Ubuntu下基于VScode的Eigen配置教程

在官网下载压缩包

下载文件解压缩后,文件格式大致如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QRbOzjw0-1666150352018)(assets/image-20221006215332834.png)]

具体安装方法,参见INSTALL文件

Installation instructions for Eigen
***********************************

Explanation before starting
***************************

Eigen consists only of header files, hence there is nothing to compile
before you can use it. Moreover, these header files do not depend on your
platform, they are the same for everybody.

Method 1. Installing without using CMake
****************************************

You can use right away the headers in the Eigen/ subdirectory. In order
to install, just copy this Eigen/ subdirectory to your favorite location.
If you also want the unsupported features, copy the unsupported/
subdirectory too.

Method 2. Installing using CMake
********************************

Let's call this directory 'source_dir' (where this INSTALL file is).
Before starting, create another directory which we will call 'build_dir'.

Do:

  cd build_dir
  cmake source_dir
  make install

The "make install" step may require administrator privileges.

You can adjust the installation destination (the "prefix")
by passing the -DCMAKE_INSTALL_PREFIX=myprefix option to cmake, as is
explained in the message that cmake prints at the end.


1.2.1 方法1: 直接移动目录

注意把其放置在一个不会轻易移动全英目录下

直接包含头文件即可

其余操作如写CMakeLists.txt 和json文件和其他程序相同

如果用到一些不常用的unsupported文件夹功能 ,其步骤类似

(推荐,按需要安装,不会安装多余的)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-38Jh1izQ-1666150352019)(assets/image-20221007135944572.png)]

1.2.2 方法2:Cmake构建

优点是 一次安装,一劳永逸,安装功能比较全

(可能安装文件较多,具体的没分析过其相应的安装CmakeLists文件)

make install的默认安装位置 /usr/local/bin

这样之后就可以写#include"Eigen/Dense"了,(貌似是/usr/local/bin默认会进行搜索~)

02 使用教程

在测试过程中需要包含对应的库文件

#include 
#include
using namespace Eigen;

官网 https://eigen.tuxfamily.org/index.php?title=Main_Page

2.1 Matrix基础用法

2.1.1 矩阵的定义方法

  • 内部原理

    此处可见一个局限性,只能对应二维数组,不能建立高维数组

//通过矩阵类模板实现,带有默认参数,参数解析见参考资源[2]
Matrix 
  • 类似知识点回顾
//函数模板声明与定义
template              
T2 test(T1 tmp, T2 tmp1) {

	T2 tmp2 = tmp + tmp1;

	return tmp2;
}
//类模板
template 
class Person {
public: 
    Person(NameType name, AgeType age) { 
        this->mName = name; this->mAge = age; 
    }
    void showPerson() { 
            cout << "name: " << this->mName << " age: " << this->mAge << endl; 
    }
public: 
    NameType mName; 
    AgeType mAge; 
};

//和tuple定义变量的方法进行对比
tuple tuple_var;

// 和vector进行对比
vector> v1;
  • 分为动态数组和静态数组两类
/*
静态矩阵 Matrix2d
动态数组 MatrixXd

静态列向量 Vector2f
动态列向量 VectorXd

静态行向量 RowVector2f
动态行向量 RowVectorXd
*/

// 只定义了常用大小的矩阵和向量
Matrix5d Matrix_01; //报错,未定义
Vector5d Vector_01; //报错,未定义

// 也可以自行定义
void test() {
	typedef Matrix Matrix5d;
	Matrix5d Matrix_01;
}

2.1.2 矩阵初始化

#include 
#include
using namespace Eigen;

void test() {

	Matrix3i matrix_01;       // 大小为3*3的int型矩阵
	MatrixXf matrix_02(2,3);  // 大小为2*3的float型矩阵
	MatrixXd matrix_03;        // double型矩阵
	MatrixXd matrix_04;        // double型矩阵
	MatrixXd matrix_05;      // double型矩阵
	MatrixXd matrix_06;       // double型矩阵
	MatrixXd matrix_07(3,4);       // 大小为3*4的double型矩阵
	Vector3i Vector_01;       // 大小为3*1的int型列向量
	Vector3d Vector_02;       // 大小为3*1的double型列向量
	VectorXd Vector_03;       // 大小为X*1的int型列向量
	RowVectorXd Vector_04;       // 大小为1*X的double型行向量
	RowVector3d Vector_05;       // 大小为1*3的double型行向量

	// 赋值方法一,用>>输入初始化,必须指定大小
	matrix_01<< 1, 2, 3, 4, 5, 6, 7, 8, 9;
	matrix_02<< 1, 2, 3, 4, 5, 6;
	Vector_01<< 1,2,3 ;

	// 赋值方法二,对于以Vextor3d方式指定大小的向量可以花括号输入,
	// 矩阵不可以和未指定大小、以其他方式指定大小的向量如“VectorXd Vector_02(3)”不可以 
	Vector_02 = { 4,5,6 };
	//VectorXd Vector_02 = { 4,5,6 };       // 报错
    //VectorXd Vector_02(3); vector_02= { 4,5,6 };       // 报错
	//matrix_02 = { 1, 2, 3, 4, 5, 6  }; // 报错
	
    // 赋值方法三,对于以Vextor3d方式指定大小的向量可以小括号的形式输入
	typedef Matrix < double, 7, 1> Vector7d;
	Vector7d Vector_06(1, 2, 3, 4, 5, 6, 7);
    
	// 赋值方法四,用特殊函数初始化
	// 注意左侧和右侧对应的类型需要统一
    // 向量同样的定义方式
	matrix_03 = MatrixXd::Zero(3, 4);  // 全0矩阵,大写的Z
	matrix_04 = MatrixXd::Ones(3, 4);  // 全1矩阵
	matrix_05 = MatrixXd::Identity(3, 4); // 单位阵
	matrix_06 = MatrixXd::Random(3, 4);   // 随机矩阵


	// 赋值方法四,从txt中读取
	// 此种方式,必须提前指定大小,否则会报错
	ifstream infile;
	infile.open("C:\\Users\\123\\Desktop\\C++下的Eigen库学习笔记\\matrix.txt", ios::in);
	int numRow = 3;
	int numCol = 4;
	for (int ii = 0; ii < numRow; ii++) {
		for (int jj = 0; jj < numCol; jj++) {
			double temp;
			infile >> temp;
			matrix_07(ii,jj) = temp;
		}
	}
	infile.close();

	// 打印
	cout << "matrix_01的值为:" << endl << matrix_01 << endl;
	cout << "matrix_02的值为:" << endl << matrix_02 << endl;
	cout << "matrix_03的值为:" << endl << matrix_03 << endl;
	cout << "matrix_04的值为:" << endl << matrix_04 << endl;
	cout << "matrix_05的值为:" << endl << matrix_05 << endl;
	cout << "matrix_06的值为:" << endl << matrix_06 << endl;
	cout << "matrix_07的值为:" << endl << matrix_07 << endl;
	cout << "Vector_01的值为:" << endl << Vector_01 << endl;
	cout << "Vector_02的值为:" << endl << Vector_02 << endl;
	cout << "Vector_03的值为:" << endl << Vector_03 << endl;
	cout << "Vector_04的值为:" << endl << Vector_04 << endl;
	cout << "Vector_05的值为:" << endl << Vector_05 << endl;
	cout << "Vector_06的值为:" << endl << Vector_06 << endl;
}
  • 特别注意

    • 空矩阵
    // 空矩阵
    void test02() {
    	MatrixXd matrix_01(0, 0);
        cout << "matrix_01的值为:" << endl << matrix_01 << endl;
    	cout << "行数:  " << matrix_01.rows() << endl;
    	cout << "列数:  " << matrix_01.cols() << endl;
    	cout << "元素个数:  " << matrix_01.size() << endl;    
        
        MatrixXd matrix_02(3, 0);
    	cout << "matrix_02的值为:" << endl << matrix_02 << endl;
    	cout << "行数:  " << matrix_02.rows() << endl;
    	cout << "列数:  " << matrix_02.cols() << endl;
    	cout << "元素个数:  " << matrix_02.size() << endl;
        
    }
    
    • 对于<<输入必须指定大小
    void test01() {
    	Vector3d Vector_01;      // 可以运行
    	//VectorXd Vector_01(3);       // 可以运行
    	//VectorXd Vector_01;       // 报错
    	Vector_01 << 4, 5, 6 ;
    	cout << Vector_01 << endl;
    }
    void test02() {
    	Matrix2d matrix_01;      // 可以运行
    	//MatrixXd matrix_01(2,2);       // 可以运行
    	//MatrixXd matrix_01;       // 报错
    	matrix_01 <<1,2,3, 4 ;
    	cout << matrix_01 << endl;
    }
    
    • 以Vector3d vector_01方式指定大小的向量可以用{}输入,以VectorXd vector_01(3)方式指定大小不可以
    void test() {
    	Vector3d Vector_01;
    	//VectorXd Vector_01(3);       // 报错,THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE
    	Vector_01 = { 4, 5, 6 };
    	cout << Vector_01 << endl;
    }
    

2.1.3 矩阵类型转换

// 转换原则:
// 1.行向量和列向量可以互相转换
// 2.行向量和列向量可以转为矩阵
// 3.向量型矩阵可以转为向量,但需要行列类型相对应,否则报错
void test999() {

    VectorXd vector_01(4);
    vector_01 << 1, 2, 3, 4;

    // 行向量和列向量可以互相转换
    // 注意,函数传递参数时如果以引用的方式传入,则不会进行自动转换
    // 需要向量的形式相对应
    RowVectorXd vector_02;
    vector_02 = vector_01;

    // 行向量和列向量可以转为矩阵
    MatrixXd  matrix_01 = vector_01;
    MatrixXd  matrix_02 = vector_02;
    
    //向量型矩阵可以转为向量,但需要行列类型相对应,否则报错
    VectorXd vector_03 = matrix_01; // matrix_01只有一列 RowVectorXd vector_03; 会报错
    RowVectorXd vector_04 = matrix_02; //matrix_01只有一行  VectorXd vector_03; 会报错

    cout << "vector_01的值为:" << endl << vector_01 << endl;
    cout << "vector_02的值为:" << endl << vector_02 << endl;
    cout << "vector_03的值为:" << endl << vector_03 << endl;
    cout << "vector_04的值为:" << endl << vector_04 << endl;
    cout << "matrix_01的值为:" << endl << matrix_01 << endl;
    cout << "matrix_02的值为:" << endl << matrix_02 << endl;

}

  • 函数传参时,如果以引用的方式传入,向量的类型需要对应

VectorXd  test01(RowVectorXd v1, VectorXd v2) {	
	return v1 + v2;
}
VectorXd  test02(VectorXd v1, RowVectorXd& v2) {
	return v1 + v2;
}

int main() {
	VectorXd v1(4);
	v1 << 1, 2, 3, 4;
	VectorXd v2(4);
	v2 << 1, 2, 3, 4;
	RowVectorXd v3(4);
	v2 << 1, 2, 3, 4;	
	
	cout << test111(v1, v2) << endl;
	// cout << test222(v1, v2) << endl;  //类型不对应,报错
	cout << test222(v1, v3) << endl;
	
}

2.1.4 高维矩阵

// 有待研究 @TODO
void test01() {
	// 报错,参见矩阵模板定义可以知道,只有定义二维数组;
    // MatrixXd matrix_01(2, 3, 4);
	// matrix_01 << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24;
	// cout << "matrix_01的值为:" << endl << matrix_01 << endl;
}

// 采用tuple函数和vector容器,可以多个矩阵组成高维度矩阵(各矩阵大小可以不同)
// 缺点是切片索引时不如Matlab高维数据灵活
void test02() {
	
	MatrixXd matrix_01(2, 3);
	MatrixXd matrix_02(2, 3);
	MatrixXd matrix_03(2, 2);
	matrix_01 << 1, 2, 3, 4, 5, 6;
	matrix_02 << 11, 12, 13, 14, 15, 16;
	matrix_03 << 31, 32, 33, 34;
	// 方式一,构建一个大小为2*3*3的矩阵,适合小矩阵
	tuple matrix_3dim_01=make_tuple(matrix_01,matrix_02,matrix_03);
	
	// 方式二,采用vector容器
	vector matrix_3dim_02;
	matrix_3dim_02.push_back(matrix_01);
	matrix_3dim_02.push_back(matrix_02);
	matrix_3dim_02.push_back(matrix_03);

	MatrixXd matrix_04 = get<2>(matrix_3dim_01);
	MatrixXd matrix_05 = matrix_3dim_02[2];

	cout << "matrix_01的值为:" << endl << matrix_01 << endl;
	cout << "matrix_02的值为:" << endl << matrix_02 << endl;
	cout << "matrix_03的值为:" << endl << matrix_03 << endl;
	cout << "matrix_04的值为:" << endl << matrix_04 << endl;
	cout << "matrix_05的值为:" << endl << matrix_05 << endl;
}

2.1.5 矩阵的大小与尺寸

//常规矩阵
void test01() {
	// 大小为3*4的double型矩阵
	MatrixXd matrix_01(2, 3);
	matrix_01 << 1, 2, 3, 4, 5, 6;
	cout << "行数:  " << matrix_01.rows() << endl;
	cout << "列数:  " << matrix_01.cols() << endl;
	cout << "元素个数:  " << matrix_01.size() << endl;
    
	// 不会改变matrix_01,需要赋值给一个新的变量
	matrix_01.transpose();
	cout << "matrix_01的值为:" << endl << matrix_01 << endl;
	// 会改变matrix_01
	matrix_01.transposeInPlace();
	cout << "matrix_01的值为:" << endl << matrix_01 << endl;
	// 会改变尺寸
	MatrixXd matrix_02 = matrix_01.transpose();
	cout << "matrix_02的值为:" << endl << matrix_02 << endl;
    
}

// 空矩阵
void test02() {
	MatrixXd matrix_01(0, 0);
	cout << "matrix_01的值为:" << endl << matrix_01 << endl;
	cout << "行数:  " << matrix_01.rows() << endl;
	cout << "列数:  " << matrix_01.cols() << endl;
	cout << "元素个数:  " << matrix_01.size() << endl;    
}

2.1.6 矩阵元素索引与切片(查)

  • 常规操作
void test() {
	/* 注意索引从零开始,用()进行索引,向量还可以用[]进行索引*/
	MatrixXd matrix_01(4, 5); 
	matrix_01 << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
		11,12, 13, 14, 15, 16, 17, 18, 19, 20;	
	VectorXd vector_01(4);
	vector_01 << 1, 2, 3, 4;

	// 读取某个元素
	double var_01 = matrix_01(0, 2);
	double var_02 = vector_01(2);
	double var_03 = vector_01[2];
    
	// 读取某行或某列元素,可以用行向量或列矩阵接收都可以
	VectorXd Vector_01 = matrix_01.row(0);  
	VectorXd Vector_02 = matrix_01.col(0);

	// 读取某个块儿矩阵
	// 表示从矩阵(i, j)元素开始,取p行q列个元素组成新矩阵
	//写法一 matrix.block(i,j, p, q) :
	//写法二 matrix.block(i, j)	
	MatrixXd matrix_02 = matrix_01.block<2, 3>(0, 0);
	MatrixXd matrix_03 = matrix_01.block(0, 0, 2, 3);

	// 读取某行列的区间元素
    // 行列类型需要对应,读取行定义RowVectorXd,读取列定义VectorXd
	// 第m行第a列到第b列, matrix_01.block(m-1, a-1, 1, b-a+1)
	// 第n列第a行到第b行, matrix_01.block(a-1, n-1, b-a+1,1)
	RowVectorXd Vector_03 = matrix_01.block(1, 2, 1, 3); //读取第2行3-5个元素,从2行第3个读取一个1*3的行向量  
	VectorXd Vector_04 = matrix_01.block(1, 1, 3, 1); //读取第2列2-4个元素,从第2列第2个元素读取一个3*1的列向量

	cout << "matrix_01的值为:" << endl << matrix_01 << endl;
	cout << "matrix_02的值为:" << endl << matrix_02 << endl;
	cout << "matrix_03的值为:" << endl << matrix_03 << endl;
	cout << "Vector_01的值为:" << endl << Vector_01 << endl;
	cout << "Vector_02的值为:" << endl << Vector_02 << endl;
	cout << "Vector_03的值为:" << endl << Vector_03 << endl;
	cout << "Vector_04的值为:" << endl << Vector_04 << endl;
	cout << "var_01的值为:" << endl << var_01 << endl;
	cout << "var_02的值为:" << endl << var_02 << endl;
    cout << "var_03的值为:" << endl << var_03 << endl;
}

一个索引时需要注意的点

// 有时经常需要用一个向量的值作为索引
// 注意向量的类型需要转为int
MatrixXd m(5,5);
VectorXd v(5);

doueble val=m(3,(int)v(0)); // 注意,v是一个double,需要转成int
  • 角操作
// 矩阵角操作
// 左上角、左下角、右上角、右下角
// 前q行、后q行、前q列、后q列
// 具体函数参见参考文献[2]
void test05() {	
	MatrixXd matrix_01(4, 4);
	matrix_01 << 1, 2, 3, 4,
				 5, 6, 7, 8,
				 9, 10, 11, 12,
				 13, 14, 15, 16;
	MatrixXd matrix_02=matrix_01.topLeftCorner<2, 2>();
	MatrixXd matrix_03 = matrix_01.topRows<2>();
	// 回顾block的写法,需要知道大小
	MatrixXd matrix_04 = matrix_01.block(0, 0, 2, 2); //左上角
	MatrixXd matrix_05 = matrix_01.block(0, 0, 2, 4);  //前两行
	cout << "matrix_01的值为:" << endl << matrix_01 << endl;
	cout << "matrix_02的值为:" << endl << matrix_02 << endl;
	cout << "matrix_03的值为:" << endl << matrix_03 << endl;
	cout << "matrix_04的值为:" << endl << matrix_04 << endl;
	cout << "matrix_05的值为:" << endl << matrix_05 << endl;
}

2.1.7 向量的索引(查)

void test() {
	//顺序n个元素
	VectorXd vector_01(6);
	vector_01 << 1, 2, 3, 4, 5, 6;	
	int i = 2;
	int n = 4;
	// 前n个元素
	VectorXd vector_02=vector_01.head(n);
	//后n个元素
	VectorXd vector_03 = vector_01.tail(n);
	//第i个位置起截取n个元素
	VectorXd vector_04 = vector_01.segment(i, n);

	cout << "vector_01的值为:" << endl << vector_01 << endl;
	cout << "vector_02的值为:" << endl << vector_02 << endl;
	cout << "vector_03的值为:" << endl << vector_03 << endl;
	cout << "vector_04的值为:" << endl << vector_04 << endl;
}

2.1.8 矩阵元素更改(改)

void test() {
	MatrixXi matrix_01(3, 4);
	matrix_01 << 1, 2, 3, 4,
		5, 6, 7, 8,
		9, 10, 11, 12;
	cout << "原始matrix_01的值为:" << endl << matrix_01 << endl;
	matrix_01(0, 0) = 100;
	cout << "更改元素后matrix_01的值为:" << endl << matrix_01 << endl;
	RowVectorXi rowVector_01(4);
	rowVector_01 << 1, 2, 3, 4;
	matrix_01.row(1) = rowVector_01;
	cout << "更改行元素后matrix_01的值为:" << endl << matrix_01 << endl;
	int aa = 100;
	int bb = 200;
	matrix_01.block(2, 2, 1, 2) << aa, bb;
	cout << "更改块元素后matrix_01的值为:" << endl << matrix_01 << endl;
}

2.1.9 矩阵行列的删除(删)

  • 删除向量某个位置的元素,返回一个新的向量

    采用下面的方法即可,向量是特殊的矩阵

  • 删除矩阵某些,返回一个新的矩阵

#include   // 包含头文件

// 传入待删除的行数索引向量
MatrixXd deleteMatrixRows(MatrixXd matrix_pre, VectorXd rows2delete) {

    // 将待待删除的行数索引向量转为保存的行数
    vector index2save; // 需包含vector头文件
    for (int ii = 0; ii < matrix_pre.rows(); ii++) {
        bool saveFlag = true;
        
        for (int jj= 0; jj < rows2delete.size(); jj++) {

            // 检查rows2delete中元素,超限返回空矩阵
            // 可将此语句注释,仅匹配正确值
            if (rows2delete[jj] > matrix_pre.rows()-1|| rows2delete[jj] <0) {
                cout << "待删除向量中索引超限!! " << endl;
                MatrixXd matrix_temp(0, 0);
                return matrix_temp;
            }

            if (ii == rows2delete[jj]) {
                saveFlag = false;
                break;
            }          
        }
        if (saveFlag) {
            index2save.push_back(ii);
        }
    }

    MatrixXd matrix_after(index2save.size(), matrix_pre.cols());
    for (int tt = 0; tt < index2save.size(); tt++) {
        matrix_after.row(tt) = matrix_pre.row(index2save[tt]);
    }

    return matrix_after;
}

void test01() {

    MatrixXd matrix_01(4, 4);
    matrix_01 << 1, 2, 3, 4,
        5, 6, 7, 8,
        9, 10, 11, 12,
        13, 14, 15, 16;
    // 正常删除
    VectorXd v1(2);
    v1 << 1, 3;
    MatrixXd matrix_02 = deleteMatrixRows(matrix_01, v1);
    cout << matrix_02 << endl;

    // 返回一个空矩阵
    VectorXd v2(4);
    v2 << 0, 1, 2, 3;
    MatrixXd matrix_03 = deleteMatrixRows(matrix_01, v2);
    cout << matrix_03 << endl;

    //  索引超限,报错!
    VectorXd v3(3);
    v3 << -1, 2, 3;
    MatrixXd matrix_04 = deleteMatrixRows(matrix_01, v3);
    cout << matrix_04 << endl;
}

// 删除向量某个位置的元素,返回一个新的向量
void test02() {

    VectorXd vector_01(4);
    vector_01 << 1, 2, 3, 4;
    
    // 正常删除
    VectorXd v1(2);
    v1 << 1, 3;
    VectorXd  vector_02 = deleteMatrixRows(vector_01, v1);
    cout << vector_02 << endl;

    // 返回一个空向量
    VectorXd v2(4);
    v2 << 0, 1, 2, 3;
    VectorXd  vector_03 = deleteMatrixRows(vector_01, v2);
    cout << vector_03 << endl;

    //  索引超限,会进行提示!
    //  由矩阵类型转换的知识可知
    // 索引超限时return的矩阵需要改和接收类型相对应,否则报错

    VectorXd v3(3);
    v3 << -1, 2, 3;
    VectorXd  vector_04 = deleteMatrixRows(vector_01, v3);
    cout << vector_04 << endl;

}
  • 删除矩阵某些,返回一个新的矩阵
// 传入待删除的列数索引向量
MatrixXd deleteMatrixColumns(MatrixXd matrix_pre, VectorXd columns2delete) {

    // 将待待删除的行数索引向量转为保存的行数
    vector index2save;
    for (int ii = 0; ii < matrix_pre.cols(); ii++) {
        bool saveFlag = true;

        for (int jj = 0; jj < columns2delete.size(); jj++) {

            // 检查columns2delete中元素,超限返回空矩阵
            // 可将此语句注释,仅匹配正确值
            if (columns2delete[jj] > matrix_pre.rows() - 1 || columns2delete[jj] < 0) {
                cout << "待删除向量中索引超限!! " << endl;
                MatrixXd matrix_temp(0, 0);
                return matrix_temp;
            }

            if (ii == columns2delete[jj]) {
                saveFlag = false;
                break;
            }
        }
        if (saveFlag) {
            index2save.push_back(ii);
        }
    }

    MatrixXd matrix_after(matrix_pre.rows(), index2save.size());
    for (int tt = 0; tt < index2save.size(); tt++) {
        matrix_after.col(tt) = matrix_pre.col(index2save[tt]);
    }

    return matrix_after;
}


void test01() {

    MatrixXd matrix_01(4, 4);
    matrix_01 << 1, 2, 3, 4,
        5, 6, 7, 8,
        9, 10, 11, 12,
        13, 14, 15, 16;
    // 正常删除
    VectorXd v1(2);
    v1 <<  1, 3;
    MatrixXd matrix_02=deleteMatrixColumns(matrix_01, v1);
    cout << matrix_02 << endl;

    // 返回一个空矩阵
    VectorXd v2(4);
    v2 << 0,1, 2,3;
    MatrixXd matrix_03 = deleteMatrixColumns(matrix_01, v2);
    cout << matrix_03 << endl;

    //  索引超限,报错!
    VectorXd v3(3);
    v3 << 4, 2, 3;
    MatrixXd matrix_04 = deleteMatrixColumns(matrix_01, v3);
    cout << matrix_04<< endl;

}

  • 常常ismember返回的结果相结合,删除某些特定和的行列(ismember功能见2.3.2)

    删除向量特定元素同理,向量是特殊的矩阵

// ismemberFlag是一个大小为矩阵matrix_pre行数或列数的向量

MatrixXd deleteMatrixRows(MatrixXd matrix_pre, VectorXd ismemberFlag) {

    vector index2save; // 需包含vector头文件
    for (int ii = 0; ii < matrix_pre.rows(); ii++) {
        // 此处 ==-1 还是 !=-1需要根据实际判定
        if (ismemberFlag[ii] == -1) {
            index2save.push_back(ii);
        }

        //if (ismemberFlag[ii] != -1) {
        //    index2save.push_back(ii);
        //}
    }

    MatrixXd matrix_after(index2save.size(), matrix_pre.cols());
    for (int jj = 0; jj < index2save.size(); jj++) {
        matrix_after.row(jj) = matrix_pre.row(index2save[jj]);
    }

    return matrix_after;
}


MatrixXd deleteMatrixColumns(MatrixXd matrix_pre, VectorXd ismemberFlag) {

    vector index2save; // 需包含vector头文件
    for (int ii = 0; ii < matrix_pre.cols(); ii++) {
        // 此处 ==-1 还是 !=-1需要根据实际判定
        if (ismemberFlag[ii] == -1) {
            index2save.push_back(ii);
        }

        //if (ismemberFlag[ii] != -1) {
        //    index2save.push_back(ii);
        //}
    }

    MatrixXd matrix_after(matrix_pre.rows(),index2save.size());
    for (int jj = 0; jj < index2save.size(); jj++) {
        matrix_after.col(jj) = matrix_pre.col(index2save[jj]);
    }

    return matrix_after;
}

void test() {
    MatrixXd matrix_01(4, 4);
    matrix_01 << 1, 2, 3, 4,
    	5, 6, 7, 8,
    	9, 10, 11, 12,
    	13, 14, 15, 16;
      
    Vector4d vector_01;
    vector_01<<-1,2, 4,-1;  

    MatrixXd matrix_02 = deleteMatrixRows(matrix_01,vector_01);
    MatrixXd matrix_03 = deleteMatrixColumns(matrix_01, vector_01);

    cout << "matrix_01的值为:" << endl << matrix_01 << endl;
    cout << "matrix_02的值为:" << endl << matrix_02 << endl;
    cout << "matrix_03的值为:" << endl << matrix_03 << endl;

}

2.1.10 矩阵四则运算

void test() {
	MatrixXd matrix_01(3, 4);
	matrix_01 << 1, 2, 3, 4,
				 5, 6, 7, 8,
				 9, 10,11, 12;

	// 加减,类型和维度都要对应,不具备广播特性
	MatrixXd matrix_02 = matrix_01 + MatrixXd::Random(3, 4);	// 
	MatrixXd matrix_03 = matrix_01 + 5 * MatrixXd::Ones(3, 4); 
	//MatrixXd matrix_02 = matrix_01 + MatrixXi::Random(3, 4);	// 报错,int矩阵和double矩阵,类型不对应,
	//MatrixXd matrix_03= matrix_01 + 5;  // 报错,维度不对应,不具备广播特性
		
	// 乘除常数
	MatrixXd matrix_04 = matrix_01 * 2; 
	MatrixXd matrix_05 = MatrixXd::Ones(3, 4)/5; 
	
	// 矩阵乘法 大小m*n与大小n*s得到m*s的矩阵
	MatrixXd matrix_06 = matrix_01 * MatrixXd::Ones(4, 2);

	// 矩阵逐元素相乘,具体参见Array用法
	//MatrixXd matrix_07 = matrix_01 * MatrixXd::Ones(3, 4);

	// 矩阵除法A/B= A*inv(B)
	MatrixXd matrix_temp = MatrixXd::Random(4, 4);
	MatrixXd matrix_08 = matrix_01 * matrix_temp.inverse();

	cout << "matrix_01的值为:" << endl << matrix_01 << endl;
	cout << "matrix_02的值为:" << endl << matrix_02 << endl;
	cout << "matrix_03的值为:" << endl << matrix_03 << endl;
	cout << "matrix_04的值为:" << endl << matrix_04 << endl;
	cout << "matrix_05的值为:" << endl << matrix_05 << endl;
	cout << "matrix_06的值为:" << endl << matrix_06 << endl;
	//cout << "matrix_07的值为:" << endl << matrix_07 << endl;
	cout << "matrix_08的值为:" << endl << matrix_08 << endl;
}      

2.1.11 矩阵四则运算特别注意

  • 结论:参与运算的矩阵类型最好定义为double型
  • double数据输入int矩阵会丢失数据
void test() {
	MatrixXi matrix_01(2, 3);
	matrix_01 << 1.2, 2.1, 3.3,
		4.2, 5.6, 6.7;
	cout << "matrix_01的值为:" << endl << matrix_01 << endl;
}
  • int类型矩阵除法运算丢失精度
void test09() {	  
	MatrixXi matrix_01(2,3);
	matrix_01 << 10, 12, 7, 14, 4, 3;
	matrix_01 = matrix_01 / 5;
	cout << "matrix_01的值为:" << endl << matrix_01 << endl;
	//输出 2,2,1;2,0,0
}
  • 矩阵的类型必须保持一致,否则报错
// double矩阵无法转为int矩阵;int矩阵也无法转为double矩阵
void test() {
	MatrixXd matrix_01(2, 3);
	matrix_01 << 1.2, 2.1, 3.3,
		4.2, 5.6, 6.7;
	cout << "matrix_01的值为:" << endl << matrix_01 << endl;
	MatrixXi matrix_02 = matrix_01 / 5;
}
  • int类型矩阵无法求逆,会报错
void test() {
    MatrixXi matrix_01(2, 2);
    matrix_01 << 1, 2, 3, 4;
    cout << matrix_01.inverse() << endl;
}

2.1.12 向量的内积向量积

void test() {

	Vector3d vector_01;
	Vector3d vector_02;
	vector_01 << 1, 2, 3;
	vector_02 << 4, 5, 6;

	//点积=标量积=数量积=内积(任意维度的向量都可以计算)
	double var_01 = vector_01.dot(vector_02);

	//向量积,(只能够对三维向量使用)
	Vector3d vector_03=vector_01.cross(vector_02);

	cout << "vector_01的值为:" << endl << vector_01 << endl;
	cout << "vector_02的值为:" << endl << vector_02 << endl;
	cout << "vector_03的值为:" << endl << vector_03 << endl;
	cout << "var_01的值为:" << endl << var_01 << endl;
}

2.1.13 矩阵与向量的内部运算

// 和、积、均值、最大值、最小值、行列式、逆矩阵
// 矩阵范数(向量模值)
void test() {

	MatrixXd matrix_01(2, 2);
	matrix_01 << 1, 2, 3, 4; 
    VectorXd vector_01(3);
	vector_01 << 1, 2, 3;

	double matrix_sum = matrix_01.sum();
	double matrix_prod = matrix_01.prod();
	double matrix_mean = matrix_01.mean();
	double matrix_min = matrix_01.minCoeff();
	double matrix_max = matrix_01.maxCoeff();
    double matrix_trace = matrix_01.trace();	
	double matrix_det = matrix_01.determinant();
    double matrix_norm = matrix_01.norm();
    MatrixXd matrix_inv = matrix_01.inverse();	
    double vector_norm = vector_01.norm();
    
	cout << "矩阵元素的和为: " << matrix_sum << endl;
	cout << "矩阵元素的乘积为: " << matrix_prod<< endl;
	cout << "矩阵元素的均值为:   " << matrix_mean<< endl;
	cout << "矩阵元素的最小值为: " << matrix_min << endl;
	cout << "矩阵元素的最大值为:" << matrix_max << endl;
	cout << "矩阵的迹为: " << endl << matrix_trace  << endl;
	cout << "矩阵的行列式为: " << endl << matrix_det << endl;
    cout << "矩阵的2范数为: " << endl << matrix_norm << endl;
	cout << "矩阵的逆矩阵为: " << endl << matrix_inv << endl;   
    cout << "向量的模值为: " << endl << matrix_norm << endl;
}

2.1.14 函数参数与返回值

MatrixXd functionTest(MatrixXd matrix_01) {

	MatrixXd matrix_temp(4, 4);
	matrix_temp << 1, 2, 3, 4,
		5, 6, 7, 8,
		9, 10, 11, 12,
		13, 14, 15, 16;
	MatrixXd matrix_02 = matrix_01 + matrix_temp;
	return matrix_02;
}

void test() {
	MatrixXd matrix_01(4, 4);
	matrix_01<< 1, 2, 3, 4,
		5, 6, 7, 8,
		9, 10, 11, 12,
		13, 14, 15, 16;
	MatrixXd matrix_02 = functionTest(matrix_01);
	cout << "matrix_01的值为:" << endl << matrix_01 << endl;
	cout << "matrix_02的值为:" << endl << matrix_02 << endl;
}   

2.1.15 调试的Bug

  • 很恶心的一点就是不能显示报错的行数,有错误的时候报错根本不知道哪个函数,仅有一个具体的错误可以对应查看
void test01() {
	// 出错的函数
	MatrixXd matrix_01(2, 3);
	MatrixXi matrix_02 = matrix_01 * 2;  // 类型不一致
}
void test02() {
	//正常的函数
}
int main() {
	test02(); //运行test02还是会报错
	return 0;
}

2.2 Matrix高阶函数与用法

复共轭、特征分解等

@TODO

2.3 常用功能函数(个人编写)

2.3.1 求两个向量并集

// 返回一个向量,对两个向量进行求并集,并完成去重和排序
#include  // 包含set容器

VectorXd fun_union(VectorXd v1, VectorXd v2)
{
    Eigen::VectorXd v;
    set set_union;  //去重+排序
    for (int i = 0; i < v1.size(); i++){
        set_union.insert(v1[i]);
    }
    for (int i = 0; i < v2.size(); i++){
        set_union.insert(v2[i]);
    }

    v.resize(set_union.size());

    int i = 0;
    for (set::iterator it = set_union.begin(); it != set_union.end(); it++, i++){
        v[i] = *it;
    }

    return v;
}


void test() {

    RowVector4d v1 = { 1,2,3,4 };

    VectorXd v2(5);
    v2 << 2, 3, 4, 5,9;

    RowVectorXd v3 = fun_union(v1, v2);  //可以行列类型转换
    cout << v3 << endl;

}

2.3.2 求两个向量交集

// 返回一个向量,对两个向量进行求交集,并完成去重和排序
VectorXd util_fun_intersect(VectorXd v1, VectorXd v2)
{
    VectorXd v;
    set set_intersect;

    for (int i = 0; i < v1.size(); i++) {
        for (int j = 0; j < v2.size(); j++) {
            if (v1[i] == v2[j]) {
                set_intersect.insert(v1[i]);
                break;
            }
        }
    }


    v.resize(set_intersect.size());
    int i = 0;
    for (set::iterator ite = set_intersect.begin(); ite != set_intersect.end(); ite++, i++)
    {
        v[i] = *ite;
    }
    return v;
}


int main() {
    Vector4d v1 = { 1,2,3,2 } ;
    Vector3d v2 = { 2,3,5 };
    //VectorXd v2(0);
    
    VectorXd v3= util_fun_intersect(v1, v2);
    cout << v3 << endl;

}

2.3.2 求两个向量差集

//工具函数,求差集,返回v1中存在但v2中不存在的元素,并进行去重和排序
Eigen::VectorXd util_fun_setdiff(Eigen::VectorXd v1, Eigen::VectorXd v2)
{
	Eigen::VectorXd v;
	set set_setdiff;

	for (int i = 0; i < v1.size(); i++) {
		bool existFlag = true;
		for (int j = 0; j < v2.size(); j++) {
			if (v1[i] == v2[j]) {				
				existFlag = false;
				break;
			}
		}
		if (existFlag) {
			set_setdiff.insert(v1[i]);
		}
	}

	v.resize(set_setdiff.size());
	int i = 0;
	for (set::iterator ite = set_setdiff.begin(); ite != set_setdiff.end(); ite++, i++)
	{
		v[i] = *ite;
	}
	return v;
}


void test() {

	Vector4d v1 = { 1,2,3,4 };

	Vector3d v2 = { 7,2,4 };

	VectorXd v3 = util_fun_setdiff(v1, v2);

	cout << v3 << endl;

}

2.3.4 元素是否在向量中

// 类似Matlab的find功能,
// 在向量中查找是否有某个元素,如果有返回索引(注意比位置小1)
VectorXd fun_find(VectorXd v1, double val) {

	vector v_temp;

	for (int ii = 0; ii < v1.size(); ii++){
		if (v1(ii) == val) {
			v_temp.push_back(ii);
		}
	}

	VectorXd v2(v_temp.size());
	for (int ii = 0; ii < v_temp.size(); ii++) {
		v2(ii) = v_temp[ii];
	}

	return v2;

}

void test() {
	VectorXd v1(6);
	v1 << 1, 2, 3, 3, 4, 5;

	VectorXd v2 = fun_find(v1, 3);
	cout << v2 << endl;
}

2.3.5 向量元素是否在另一个向量内

// 类似Matlab的ismember功能,Pyhton的isin函数
// 此函数功能:
// 判断v1中的变量在v2中是否存在
// 返回一个大小同v1的向量,
// 如果不存在该变量,返回-1
// 如果存在,返回该变量在向量v2中的位置(如果有多个,返回最小索引)
VectorXd fun_ismember(VectorXd v1, VectorXd v2)
{
    bool exist = false;
    VectorXd v;
    v.resize(v1.size());
    for (int ii = 0; ii < v1.size(); ii++){
        exist = false;
        int jj;  // 后边还要用 要定义在外部
        for ( jj = 0; jj < v2.size(); jj++){
            if (v1[ii] == v2[jj])
            {
                exist = true;
                break;
            }
        }
        if (exist){
            v[ii] = jj;
        }
        else{
            v[ii] = -1;
        }
    }

    return v;
}


void test() {

    RowVector4d v1 = { 1,2,3,4 };

    VectorXd v2(5);
    v2 << 2, 3, 4, 5,9;

    RowVectorXd v3 = fun_ismember(v1, v2);  //可以行列类型转换
    cout << v3 << endl;

}

2.4 Array基础用法

2.4.1 Array定义方法

  • 写在前面

Array主要核心定义和语法与Matrix高度类似,主要对不同点进行介绍。

学习Array主要把握官方文档的“coeffience-wise”,Array是对逐系数(元素)进行操作的。

对数组内部每个元素进行的操作都可以用Array进行操作。

如果需要经常操作线性代数的操作,偶尔需要逐元素操作,可以用Matrix进行操作,在需要时进行转换即可。

  • 内部原理
template
class Array{}
  • 自行定义
void test() {
	typedef Array Array23d; //自行定义
	Array23d arr_01;
	arr_01 << 1, 2, 3, 4,5,6;
	cout << "arr_01的值为:" << endl << arr_01 << endl;

}
  • 常用的逐元素操作
//向上向下四舍五入取整、绝对值、指数、三角函数等,具体参见参考资源[2]
void test() {

	ArrayXXd arr_01(2, 2);
	arr_01 << 1.1, 2.2, 3.5, 4.7;
	
	Array22d arr_02 = round(arr_01);
	Array22d arr_03=arr_01.round();
	Array22d arr_04 = exp(arr_01);
	Array22d arr_05 = arr_01.exp();

	cout << "arr_01的值为:" << endl << arr_01 << endl;
	cout << "arr_02的值为:" << endl << arr_02 << endl;
	cout << "arr_03的值为:" << endl << arr_03 << endl;
	cout << "arr_04的值为:" << endl << arr_04 << endl;
	cout << "arr_05的值为:" << endl << arr_05 << endl;
}
  • 和Matrix定义的一个小区别
void test() {
	// 注意维度区别,第一种写法是一个2*1的列数组,后两个是2*2的矩阵
	Array2d arr_01; //typedef Eigen::Array Eigen::Array2d
    Array22d arr_01; //typedef Eigen::Array Eigen::Array22d
	Matrix2d matrix_01; // typedef Eigen::Matrix Eigen::Matrix2d
}

2.4.2 Array四则运算

//体会和Matrix的不同
void test() {

	ArrayXXd arr_01(2, 2);
	Array22d arr_02;

	arr_01 << 1, 2, 3, 4;
	arr_02 << 5, 6, 7, 8;

	// 加减
	Array22d arr_03=arr_01+2;

	// 乘除
	Array22d arr_04 = arr_01 * arr_02;

	cout << "arr_01的值为:" << endl << arr_01 << endl;
	cout << "arr_02的值为:" << endl << arr_02 << endl;
	cout << "arr_03的值为:" << endl << arr_03 << endl;
	cout << "arr_04的值为:" << endl << arr_04 << endl
}

2.4.1 Array与Matrix转换

void test() {
	ArrayXXd arr_01(2,3); 
	ArrayXXd arr_02(2, 3);
	MatrixXd matrix_01(2,3); 

	arr_01 << 1, 2, 3, 4, 5, 6;
	matrix_01 = arr_01.matrix();
	arr_02 = matrix_01.array();

	cout << "arr_01的值为:" << endl << arr_01 << endl;
	cout << "arr_02的值为:" << endl << arr_02 << endl;
	cout << "matrix_01的值为:" << endl << matrix_01 << endl;
}

2.5 Map类的用法

2.5.1 和C++原生(Raw)数组结合

// 有待研究 @TODO
// 参见参考链接[2]
void test() {

	double matrix_01[2][3] = { 1,2,3,4,5,6 };
	MatrixXd matrix_02(2, 3);

	// matrix_02 = matrix_01;  // 会报错
	
	// 打印
	cout << "matrix_01的值为:" << endl << matrix_01 << endl;
	cout << "matrix_02的值为:" << endl << matrix_02 << endl;
}

2.6 Cmake调用Eigen

参考链接

文档1

https://blog.csdn.net/juluwangriyue/article/details/122162035?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EOPENSEARCH%7ERate-1-122162035-blog-126857577.pc_relevant_multi_platform_whitelistv3&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EOPENSEARCH%7ERate-1-122162035-blog-126857577.pc_relevant_multi_platform_whitelistv3&utm_relevant_index=1

文档2

https://blog.csdn.net/geerniya/article/details/103202562?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-103202562-blog-122162035.topnsimilarv1&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-103202562-blog-122162035.topnsimilarv1&utm_relevant_index=1

@TODO

03 参考链接

[1] CSDN笔记 安装

https://blog.csdn.net/weixin_47442149/article/details/126031623?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166124765716781667857113%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=166124765716781667857113&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~pc_rank_34-5-126031623-null-null.142v42pc_rank_34,185v2control&utm_term=eigen%E5%BA%93%E9%85%8D%E7%BD%AE&spm=1018.2226.3001.4187

[2] CSDN笔记

https://blog.csdn.net/s12k39/article/details/108381018?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-108381018-blog-122906472.pc_relevant_multi_platform_whitelistv3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-108381018-blog-122906472.pc_relevant_multi_platform_whitelistv3&utm_relevant_index=5

[3] 参考笔记

https://blog.csdn.net/naibula/article/details/122906472?spm=1001.2101.3001.6650.8&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-8-122906472-blog-121171378.t5_layer_eslanding_S_0&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-8-122906472-blog-121171378.t5_layer_eslanding_S_0&utm_relevant_index=15

你可能感兴趣的:(Eigen,C++,c++)