Eigen使用demo

Eigen是一个高层次的C ++库,有效支持线性代数,矩阵和矢量运算,数值分析及其相关的算法

以下为Eigen库的具体实现功能说明

// Matrix-test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include <iostream>
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include<fstream>
#include <sstream>
#include<vector>
#include <string>


//这是基于eigen的矩阵使用demo,Eigen是一个高层次的C ++库,有效支持线性代数,矩阵和矢量运算,数值分析及其相关的算法。
//int main()中为常用规则   外部函数为部分具体功能(PCA、文本读写)服务




//以下4个函数为PCA算法功能函数
//样本均值化
void featurenormalize(Eigen::MatrixXd &X)  
{
	//样本均值化
   //计算每一维度均值
	Eigen::MatrixXd meanval = X.colwise().mean();
	Eigen::RowVectorXd meanvecRow = meanval;
	//样本均值化为0
	X.rowwise() -= meanvecRow;

}
//计算协方差
void computeCov(Eigen::MatrixXd &X, Eigen::MatrixXd &C)
{
	//计算协方差矩阵C = XTX / n-1;
	C = X.adjoint() * X;
	C = C.array() / X.rows() - 1;

}
//计算特征值和特征向量
void computeEig(Eigen::MatrixXd &C, Eigen::MatrixXd &vec, Eigen::MatrixXd &val)
{
	//计算特征值和特征向量,使用selfadjont按照对阵矩阵的算法去计算,可以让产生的vec和val按照有序排列
	Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eig(C);
	vec = eig.eigenvectors();
	val = eig.eigenvalues();
}
//获取所需的特征向量数
int computeDim(Eigen::MatrixXd &val)
{
	//计算损失率,确定降低维数
	int dim;
	double sum = 0;
	for (int i = val.rows() - 1; i >= 0; --i)
	{
		sum += val(i, 0);
		dim = i;
		if (sum / val.sum() >= 0.95)
			break;
	}
	return val.rows() - dim;
}



//以下2个函数仅服务于eigen对txt文本读写   
//确定文本的行数
int getFileRows(const char *fileName)
{
	int count = 1;
	std::ifstream fileStream; 
	std::string tmp;// 行数计数器
	fileStream.open(fileName, std::ios::in);//ios::in 表示以只读的方式读取文件
	if(!fileStream)//文件打开失败:返回-1
	{        	
		return -1;
	}    
	else//文件存在    
	{
		char c;
		while (fileStream.get(c))
		{
			if (c == '\n')
			{
				count++;
			}
		}
		fileStream.close();
		return count;

	}

}
//确定文本的列数
int getFileColumns(const char * fileName) 
{
	int count = 0;//计数器
	std::ifstream fileStream;
	fileStream.open(fileName, std::ios::_Nocreate);
	double tmp = 0;		// 列数计数器
	char c;			//当前位置的字符
	c = fileStream.peek();	
	while (('\n' != c) && (! fileStream.eof()))	// 指针指向的当前字符,仅观测,不移动指针位置   
	{          
		fileStream >> tmp;
		count++;
		c = fileStream.peek();
	}  	    
	fileStream.close();
	return count;
}



int main()
{
	//定义
	Eigen::Matrix3d a;             //定义三维(3*3)double型 矩阵; 注意”d”表示double类型,”f”表示float类型,”i”表示整数,”c”表示复数;
	a <<2,2,1,3,1,5,3,2,3;       //赋值操作
	Eigen::Vector4f b(1, 2, 3, 4);           //定义4*1 float型 列向量,并赋值; 赋值也可以: b<<1, 2, 3, 4;    
	Eigen::RowVector2d c(1, 2);                    //   定义1*2 double型 行向量并赋值
	Eigen::MatrixXd m_1 = Eigen::MatrixXd::Random(3, 4);  //MatrixXd->动态   MatrixXd::Random(3,4)表示产生一个元素类型为double的3*4的临时矩阵对象
	Eigen::MatrixXd m_3(2, 2); m_3 << 1, 2, 3, 4;          //->动态  初始化(设置临时2*2矩阵)并赋值
	Eigen::Matrix3d m_2 = Eigen::Matrix3d::Random();      //Matrix3d->静态
    Eigen::MatrixXd m_4;
    m_4=Eigen::MatrixXd(100,90);//设置矩阵大小
    m_4=Eigen::MatrixXd::Ones(100,90);//矩阵元素都设置为1
    m_4=Eigen::MatrixXd::Zero(100,90);//矩阵元素都设置为0
    m_4=Eigen::MatrixXd::Identity(100,100);//矩阵设置为单位阵
    //计算
	a * m_2;//矩阵乘法
	a + m_2;//矩阵加法
	a - m_2;//矩阵减法
	a.MatrixBase::transpose();//转置矩阵transpose(),
	a.determinant();//矩阵的行列式
	a.determinant()*a.inverse();//伴随矩阵   发现伴随矩阵函数adjoint() 使用有问题!!!!!!!
	a.inverse();//矩阵的逆inverse()
	a.diagonal();//取对角元素 组成一个列向量
	a.conjugate();//共轭矩阵
	//这些函数返回操作后的结果,而不会对原矩阵的元素进行直接操作,如果要让原矩阵进行转换,则需要使用响应的InPlace函数,如transpoceInPlace()等
		
	//a.arry():取出矩阵的所有元素,对每个元素进行操作
	a.array()+1.9;//元素都加上1.9  错误使用:a=a+1.9 !!!
	a.array() -= 2;//  即a.array()-2
	a.array().sin();//元素取sin
	a.array().exp();//指数e
	a.array().log();//取对数
	a.array().pow(2);//元素 ^2    	std::cout << a;
	a.array() / m_2.array();//两个矩阵对应点相除(对应点!!!)
	a.array()*m_2.array();//两个矩阵对应点相除(对应点!!!)
	
	
	//分块矩阵
	a.block<2,3>(1,0);  // 提出一个2*3分块矩阵,起始位置下标为原有矩阵(1,0)
	a.topRightCorner(2, 2);// 取右上角2*2矩阵
	a.bottomLeftCorner(2, 2);//取左下角角2*2矩阵  类似同理
	a.leftCols(2);//取左边2列
	a.rightCols(1);//取右边1列
	a.middleCols(0, 2);//中间从第0列向右数,取2列
	a.topRows(2);//从上向下取2行
	a.bottomRows(2);//从下向上取2行
	a.middleRows(0, 1);// 中间从第0行向下数,取1列
	
	//分块特例-vector 即向量的块操作
	b.head(2);     //获取向量的前n个元素
	b.tail(2);     //获取向量尾部的n个元素
	b.segment(1, 3);        //从第1元素开始 取3个元素   
	
	a.cwiseAbs();//取绝对值
	a.cwiseAbs2();  //元素平方(cwiseSqrt)
	Eigen::Vector3f v1(0, 2, 3), v2(1, 1, 4);
	v1.cwiseMin(v2);  //取两个中的min并赋给v1  同理cwiseMax取max	
	v1.cwiseProduct(v2);  //同位置元素相乘并赋给v1   1,2,12
	v1.cwiseQuotient(v2); //同位置元素相除并赋给v1   0,2,0.75 ( v1/v2 )
		
	a.colwise().minCoeff();        
	//colwise()把每一列变成了一个块,然后这些块组成了一个行向量即分别对每列进行处理  colwise.minCoeff() 取每列最小值   思想:降维->行向量
	a.rowwise().maxCoeff();        //同上   取行最大值 降维->列向量
	a.rowwise().mean();//mean 矩阵元素平均数

	a.sum(); //所有系数的和
	a.prod();//所有系数的积
	a.all();  //且运算 
	a.any(); //或运算      
	a.col(0); a.row(2);     //取出第几列、行   differ cols() and rows()
	a.cast<int>();//强制转换int型 向下取整
    a.reverse();//元素倒置(i,j)->(j,i)

	//特征值与特征向量 计算
	Eigen::Matrix3d chara_eigen;
	chara_eigen << 4, 6, 0, -3, -5, 0, -3, -6, 1;
	Eigen::EigenSolver<Eigen::Matrix3d> eigen_solver(chara_eigen);
	eigen_solver.eigenvalues();//求特征值   形式为二维向量(1,0)(1,0)(2,0)。真实值为1,1,2。
	eigen_solver.eigenvectors() ;//求特征向量  形式同上  结果已单位化


	//PCA矩阵算法使用
	//PCA算法 PCA的目的:能够对一个多样本的多维特征向量构成的矩阵进行分析,分析主成分并去除维度之间的相关性,
	//使线性相关的向量组变成线性无关的向量组。  并且可以对样本进行降维,降高维向量映射到低维度空间,同时确保维度之间的信息损失尽可能小。
	Eigen::MatrixXd Xchara_eigen(3,3);//样本矩阵
	Xchara_eigen<< -1, 1, 0, -4, 3, 0, 1, 0, 2;
	Eigen::MatrixXd cov_eigen(3,3); //协方差
	Eigen::MatrixXd vector_eigen;  //特征向量
	Eigen::MatrixXd value_eigen;  //特征值
	featurenormalize(Xchara_eigen);	//样本均值化
	computeCov(Xchara_eigen, cov_eigen);	//计算协方差
	computeEig(cov_eigen, vector_eigen, value_eigen);	//计算特征值和特征向量
	int dim = computeDim(value_eigen);//生成所需特征向量
	Eigen::MatrixXd result_eigen = Xchara_eigen * vector_eigen.rightCols(dim);//生成目标矩阵


	//SVD矩阵分解
	Eigen::JacobiSVD<Eigen::MatrixXd> svd(Xchara_eigen, Eigen::ComputeThinU | Eigen::ComputeThinV);
	Eigen::Matrix3d V = svd.matrixV(), U = svd.matrixU();  //矩阵V
	Eigen::Matrix3d  S = U.inverse() * Xchara_eigen * V.transpose().inverse(); // S = U^-1 * A * VT * -1  
	

	
	//稀疏矩阵的相关操作 添加#include <Eigen/Sparse>
	Eigen::SparseMatrix<double> SpMat; // 声明一个列优先的双精度稀疏矩阵类型
	Eigen::SparseMatrix<double, Eigen::RowMajor> mat(1000, 2000);//声明一个 1000x2000 行优先的压缩的稀疏矩阵(元素类型:double)
	Eigen::Triplet<double> T; //三元组(行,列,值)
	mat.innerSize(); //内维度   行优先,所以为列数
	mat.outerSize(); //外维度
	mat.selfadjointView<Eigen::Upper>();//从上三角部分生成一个全的伴随矩阵
	mat.selfadjointView<Eigen::Lower>();//从下三角部分生成一个全的伴随矩阵
	mat.setZero();//去除所有的非零元素 即矩阵非零元素都变为零
	mat.nonZeros();     // 非零元素的个数   
	mat.outerSize();    // 列优先的稀疏矩阵的行数,行优先的稀疏矩阵的列数
	mat.innerSize();    // 列优先的稀疏矩阵的列数,行优先的稀疏矩阵的行数
	mat.norm();          // 矩阵的欧式范数
	mat.squaredNorm();  //矩阵的平方范数(平方和)
	mat.isVector();     // 检查是否是稀疏向量或稀疏矩阵
	mat.isCompressed(); // 检查是否是压缩格式
	mat.makeCompressed(); //压缩剩余的空间
	mat.coeffRef(0, 0); //插入值


//txt 矩阵文件读写
	int cols_num = 0;int rows_num = 0;
	std::ifstream infile("D:\\STUDY\\Computer\\C_training\\egine\\Matrix-test\\data.txt");  //读取txt路径
		if (infile.is_open())
	{
		std::cout << "Open file successfully." << std::endl;
		rows_num =getFileRows("D:\\STUDY\\Computer\\C_training\\egine\\Matrix-test\\data.txt");//得到矩阵行数
		cols_num = getFileColumns("D:\\STUDY\\Computer\\C_training\\egine\\Matrix-test\\data.txt");//得到矩阵列数
		
	}
	else
	{
		std::cout << "Unable to open file" << std::endl;
	}
	
	Eigen::MatrixXd set_mat = Eigen::MatrixXd(rows_num, cols_num);  //生成目标矩阵(确定行列)
	double mat_data;
	std::vector<double> data_save;
	while (infile >> mat_data)
	{
		data_save.push_back(mat_data);  //存入所有元素于vector
	}
	int count = 0;
	for (int row = 0; row < rows_num; row++)
	{
		for (int col = 0; col < cols_num; col++)
		{
			set_mat(row, col) = data_save[count]; //元素转存入目标矩阵
			count++;
		}
	}
	std::cout << "\nshow:\n";
	std::cout << set_mat; 
	
        return 0;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值