IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    C++调用MATLAB引擎求解线性方程组

    远行发表于 2015-04-12 05:13:45
    love 0

    以前写过一篇C++调用MATLAB引擎计算特征向量,里面讲了如何配置环境等等。现在又有一个新的需求,求解线性系统。又想起了MATLAB这个工具,于是又写了个小类。这里要求解的是AX=B。其中,A是m*n的矩阵,X是n维行向量,B是m维列向量。MATLAB里面求解很简单X=A\B。

    该类的头文件如下:

    //求解线性系统AX = B.
    	//A是Row*Column的矩阵,B是Row*1的列向量
    	class CLinearSystem
    	{
    	public:
    		CLinearSystem() {}
    		CLinearSystem(double* pMatrixA, int nRow, int nColumn, double* pColumnB);
    		~CLinearSystem() {}
    
    	public:
    		void GetResult(double* pX);//pX保证能输出m_nColumn个元素
    
    	private:
    		double* m_pMatrixA;
    		double* m_pColumnB;
    		int m_nRow;
    		int m_nColumn;
    	};
    

    源文件如下:

    #include "stdafx.h"
    #include "LinearSystem.h"
    #include 
    #include "engine.h"
    #pragma comment(lib, "libeng.lib")
    #pragma comment(lib, "libmx.lib")
    #pragma comment(lib, "libmat.lib")
    
    	CLinearSystem::CLinearSystem(double* pMatrixA, int nRow, int nColumn, double* pColumnB)
    		: m_pMatrixA(pMatrixA), m_nRow(nRow), m_nColumn(nColumn), m_pColumnB(pColumnB)
    	{
    
    	}
    
    	void CLinearSystem::GetResult(double* pX)
    	{
    		assert(pX != NULL);
    
    		Engine *ep = NULL;
    		if (!(ep = engOpen(NULL)))//打开matlab引擎
    		{
    			fprintf(stderr, "\nCan't start MATLAB engine\n");
    			return;
    		}
    
    		mxArray* matrixA = mxCreateDoubleMatrix(m_nRow, m_nColumn, mxREAL);
    		//matlab里面的矩阵是列主顺序,这里需要变换位置
    		double* pA = mxGetPr(matrixA);
    		for (int j = 0; j < m_nColumn; ++j)
    		{
    			for (int i = 0; i < m_nRow; ++i)
    			{
    				*pA++ = *(m_pMatrixA + i * m_nColumn + j);
    			}
    		}
    
    		mxArray* columnB = mxCreateDoubleMatrix(m_nRow, 1, mxREAL);
    		memcpy(mxGetPr(columnB), m_pColumnB, sizeof(double) * m_nRow * 1);
    
    		engPutVariable(ep, "A", matrixA);
    		engPutVariable(ep, "B", columnB);
    		engEvalString(ep, "X = A\\B;");
    
    		mxArray* rowX = engGetVariable(ep, "X"); //返回计算结果
    		memcpy(pX, mxGetPr(rowX), sizeof(double) * m_nColumn);
    
    		mxDestroyArray(matrixA);
    		mxDestroyArray(columnB);
    		mxDestroyArray(rowX);
    		engClose(ep);
    	}
    

    该类里面就一个计算结果的函数。实现的过程也很简单,打开MATLAB引擎,创建了对应的矩阵和向量,计算表达式。注意,”X = A\\B;”中必须加转义\。另外,MATLAB中的矩阵是列主序的,也就是按照列存储的。所以,从C++的矩阵变换到MATLAB矩阵需要重新设置值,而不是简单的拷贝内存。
      如果,A是巨大的稀疏矩阵,那么就应该创建稀疏矩阵来计算了。测试代码如下:

    //测试线性系统
    int nRow = 3, nColumn = 2;
    double pA[3][2] = {{4, 5}, {1, 2}, {3, 1}};
    double pB[3] = {3, 15, 12};
    CLinearSystem ls((double*)pA, nRow, nColumn, pB);
    double pX[2];
    ls.GetResult(pX);
    printf("%f %f\n", pX[0], pX[1]);
    

    输出为:3.000000 -0.600000

    前面说了,系数矩阵的事情,现在代码进行了更新,加入了稀疏矩阵,A可以是稀疏矩阵传入,B的话没有当做稀疏矩阵传入了。不过,在调用MATLAB代码时候还是得作为稀疏矩阵。具体代码如下,就不细说了。

    #pragma once
    
    #ifndef LIBYX_LINEAR_SYSTEM_H
    #define LIBYX_LINEAR_SYSTEM_H
    
    #include "MatlabSparseMatrix.h"
    
    namespace LibYX
    {
    	//求解线性系统AX = B.
    	//A是Row*Column的矩阵,B是Row*1的列向量
    	class CLinearSystem
    	{
    	public:
    		CLinearSystem() {}
    		CLinearSystem(double* pMatrixA, int nRow, int nColumn, double* pColumnB);
    		CLinearSystem(MatlabSparseInfor* pSI, int nNum, int nRow, int nColumn, double* pColumnB);
    		~CLinearSystem() {}
    
    	public:
    		void GetResult(double* pX);//pX保证能输出m_nColumn个元素
    		void GetResultSparse(double* pX);//中间过程使用稀疏矩阵计算结果
    
    	private:
    		double* m_pMatrixA;
    		double* m_pColumnB;
    		int m_nRow;
    		int m_nColumn;
    
    	private://稀疏矩阵形式输入A
    		MatlabSparseInfor* m_pSI;
    		int m_nNum;
    	};
    };
    
    #endif
    
    #include "stdafx.h"
    #include "LinearSystem.h"
    #include 
    #include "engine.h"
    #pragma comment(lib, "libeng.lib") 
    #pragma comment(lib, "libmx.lib")
    #pragma comment(lib, "libmat.lib")
    
    namespace LibYX
    {
    	CLinearSystem::CLinearSystem(double* pMatrixA, int nRow, int nColumn, double* pColumnB)
    		: m_pMatrixA(pMatrixA), m_nRow(nRow), m_nColumn(nColumn), m_pColumnB(pColumnB)
    	{
    
    	}
    
    	CLinearSystem::CLinearSystem(MatlabSparseInfor* pSI, int nNum, int nRow, int nColumn, double* pColumnB)
    		: m_pSI(pSI), m_nNum(nNum), m_nRow(nRow), m_nColumn(nColumn), m_pColumnB(pColumnB)
    	{
    
    	}
    
    	void CLinearSystem::GetResult(double* pX)
    	{
    		assert(pX != NULL);
    
    		Engine *ep = NULL;
    		if (!(ep = engOpen(NULL)))//打开matlab引擎
    		{
    			fprintf(stderr, "\nCan't start MATLAB engine\n");
    			return;
    		}
    
    		mxArray* matrixA = mxCreateDoubleMatrix(m_nRow, m_nColumn, mxREAL);
    		//matlab里面的矩阵是列主顺序,这里需要变换位置
    		double* pA = mxGetPr(matrixA);
    		for (int j = 0; j < m_nColumn; ++j)
    		{
    			for (int i = 0; i < m_nRow; ++i)
    			{
    				*pA++ = *(m_pMatrixA + i * m_nColumn + j);
    			}
    		}
    
    		mxArray* columnB = mxCreateDoubleMatrix(m_nRow, 1, mxREAL);
    		memcpy(mxGetPr(columnB), m_pColumnB, sizeof(double) * m_nRow * 1);
    
    		engPutVariable(ep, "A", matrixA);
    		engPutVariable(ep, "B", columnB);
    		engEvalString(ep, "X = A\\B;");
    
    		mxArray* rowX = engGetVariable(ep, "X"); //返回计算结果
    		memcpy(pX, mxGetPr(rowX), sizeof(double) * m_nColumn);
    
    		mxDestroyArray(matrixA);
    		mxDestroyArray(columnB);
    		mxDestroyArray(rowX);
    		engClose(ep);
    	}
    
    	void CLinearSystem::GetResultSparse(double* pX)
    	{
    		Engine *ep = NULL;
    		if (!(ep = engOpen(NULL)))//打开matlab引擎
    		{
    			fprintf(stderr, "\nCan't start MATLAB engine\n");
    			return;
    		}
    
    		//以下代码构造稀疏系数矩阵
    		mxArray* sm = mxCreateSparse(m_nRow, m_nColumn, m_nNum, mxREAL);
    		double* pr = mxGetPr(sm);
    		mwIndex* ir = mxGetIr(sm); 
    		mwIndex* jc = mxGetJc(sm); 
    
    		int k = 0;
    		int nLastC = -1;
    		for (int i = 0; i < m_nNum; ++i)
    		{
    			pr[i] = m_pSI[i].v;
    			ir[i] = m_pSI[i].r;
    
    			if (m_pSI[i].c != nLastC)
    			{
    				jc[k] = i;
    				nLastC = m_pSI[i].c;
    				++k;
    			}
    		}
    		jc[k] = m_nNum;
    
    		//以下代码构造稀疏列
    		mxArray* columnB = mxCreateSparse(m_nRow, 1, m_nRow, mxREAL);
    		pr = mxGetPr(columnB);
    		ir = mxGetIr(columnB); 
    		jc = mxGetJc(columnB); 
    
    		jc[0] = 0;
    		for (int i = 0; i < m_nRow; ++i)
    		{
    			pr[i] = m_pColumnB[i];
    			ir[i] = i;
    		}
    		jc[1] = m_nRow;
    
    		//将构造的稀疏矩阵传入MATLAB命令中
    		engPutVariable(ep, "sm", sm);
    		engPutVariable(ep, "columnB", columnB);
    		engEvalString(ep, "X = sm\\columnB;");
    
    		mxArray* rowX = engGetVariable(ep, "X"); //返回计算结果
    		memcpy(pX, mxGetPr(rowX), sizeof(double) * m_nColumn);
    
    		mxDestroyArray(rowX);
    		mxDestroyArray(columnB);
    		mxDestroyArray(sm);
    		engClose(ep);
    	}
    };
    
    您可能也喜欢:

    使用C++调用MATLAB引擎计算稀疏矩阵的特征向量

    使用Eigen解稀疏线性方程组

    使用Matlab计算稀疏矩阵的特征向量

    extern "C"的理解

    uva 327 - Evaluating Simple C Expressions
    无觅


沪ICP备19023445号-2号
友情链接