封装c++与matlab引擎交互的数据结构:行优先矩阵类

来源:互联网 发布:战地4龙之谷灯笼算法 编辑:程序博客网 时间:2024/06/16 18:22

我们知道matlab中的矩阵是列优先存储的,而c++中的数据是行优先存储的,而习惯了使用c++的伙伴们,也习惯了行优先存储方式了啦(比如看一个二维数组,总会先看行序号,再看列序号)。所以在进行c++调用matlab引擎处理时,这会给两者矩阵数据传递会带来诸多的烦恼,这也是诸多程序bug的来源之一。关于c++调用matlab引擎编程,可参考我的另一篇文,网址为http://blog.csdn.net/feichizhongwu888/article/details/47277565。

下面举一个例子,说明c++的数据存储顺序和matlab的存储数据方式。

int main(){    //c++ matrix:2*5=10 elements    double a[10] = {0,1,2,3,4,5,6,7,8,9};    Engine* ep;    if(!(ep = engOpen(NULL)))    {        std::cout<<"can't start Matlab Engine!!"<<std::endl;        return EXIT_FAILURE;    }    engSetVisible(ep, true);
    //generating matlab matrix::aa    mxArray *aa = mxCreateDoubleMatrix(2, 5, mxREAL);    memcpy(mxGetPr(aa), a, 10 * sizeof(double));    engPutVariable(ep, "aa", aa);    std::cin.get();    engEvalString(ep, "clear;");    mxDestroyArray(aa);    engClose(ep);    return 0;}
c++中有一个2*5的矩阵,总共10个元素,存储在a[10]里面,如代码所示,之后,将a[10]元素全部传递给matlab变量aa,我们希望matlab能构造一个矩阵:第一行为{0,1,2,3,4}第二行为{5,6,7,8,9},但事实并非如此。程序输出结果,在matlab command window测试aa的值为:


你会发现0-9个元素,是纵向依次填充到2*5的matlab矩阵当中的,这是说明了matlab是列优先存储。


因此,如果你希望matlab构造你理想的矩阵,就必须在c++中就把所有矩阵数据,按照列存储方式,放在一个一维数组里面,再传输给matlab引擎。比如以上例子,你需要把a写成{0,5,1,6,2,7,3,8,4,9},实际上就是将a转置,在按行存储在c++一维数组里面,感兴趣的伙伴可以用手写写,再推敲推敲。(反正这个还是挺拗人的,尤其对我这种长久以来习惯行存储的人来说。)

看到这里,你也许会发现,如果我要操作1万*1万个元素的矩阵,万一哪一个元素给填错了,那该是多么凄惨的事情,就注定你的程序在matlab调用这块就会卡顿很久。因此呢,我于是想出一个办法,封装一个行优先的矩阵类TMatrix,而类内部是按照列优先存储的,哈哈,这就解决了这个问题。对于用户来讲,使用TMatrix来存放数据可以继续按照行优先方式赋值;另外一方面,底层维护的数据指针已经是列存储方式的了,就可以直接传送给matlab生成理想的矩阵了。

接下来,就要介绍一下TMatrix的原理和简单的使用了。

(1)TMatrix的原理

1.对于外界用户,继续按照行优先逻辑,存入和提取数据,类似二维数组。

2.底层维护一个数据指针,对于外界传入的数据,先进行转置,之后再放入这个指针指向的数据空间。

以下为TMatrix类的基本接口:

定义:理想的矩阵:表示正确的矩阵,我们想要的矩阵。

template<class DataType>class TMatrix{public:    TMatrix();    TMatrix(int _row, int _column);    TMatrix(int _row, int _column, DataType* _pMatrix_);    ~TMatrix();public:    void set_size(int _row, int _column);    DataType* data_ptr() { return this->pMatrix_; }    //user cognitive row and column    int row() { return this->column_; }    int column() { return this->row_; }    int length() { return this->row_ * this->column_ * sizeof(DataType); }    int size() { return this->row_ * this->column_; }    bool set_value(int _index_r, int _index_c, DataType _value);    DataType get_value(int _index_r, int _index_c);    void print();private:    int row_;    int column_;    DataType* pMatrix_;};

第一个构造函数

    TMatrix();
需要和

    void set_size(int _row, int _column);
一起使用,否则,数据空间为空。详细可见源码实现。


第二个构造函数

    TMatrix(int _row, int _column);
直接可得到一定_row*_column的数据空间,初值为0。


第三个构造函数

    TMatrix(int _row, int _column, DataType* _pMatrix_);
设计目的:从matlab获取变量到c++中,得到的数据是列存储的,我们就可以使用这个返回的数据指针来构造一个TMatrix对象。通过行优先存储的方式方便得访问TMatrix,进而准确地访问matlab返回的矩阵。这点,后面例子会说明,实际证明很好用。


函数

    void set_size(int _row, int _column);
可以重新设置TMatrix对象的行和列的长度,底层会重新构造一个新的数据空间。


函数

    DataType* data_ptr() { return this->pMatrix_; }
很重要,返回指向底层数据空间的指针,按照我们理想的矩阵的列存储方式存储。返回的指针可通过mencpy函数将空间的数据拷贝到matlab的mxArray空间。


函数

    int row() { return this->column_; }    int column() { return this->row_; }
各自返回,用户认为的矩阵的行和列数(即为理想的矩阵的行数和列数目)。


函数

    int length() { return this->row_ * this->column_ * sizeof(DataType); }    int size() { return this->row_ * this->column_; }
各自返回,数据空间的占用大小和数据空间的全部元素数目。


函数

   bool set_value(int _index_r, int _index_c, DataType _value);    DataType get_value(int _index_r, int _index_c);
是给TMatrix的数据存入数据,或取出数据。其中(_index_r,_index_c)表示一个元素的所在位置坐标,该位置为在理想的矩阵中的位置。


函数

    void print();
为输出基本的TMatrix信息,用于方便查看。输出矩阵为理想的矩阵排列。


(2)TMatrix简单使用例子

测试源代码:

int main(){    Engine* ep;    if(!(ep = engOpen(NULL)))    {        std::cout<<"can't start Matlab Engine!!"<<std::endl;        return EXIT_FAILURE;    }    engSetVisible(ep, true);    const int row = 6;    const int column = 10;    //TEST 1: TMatrix Initialization    CG::TMatrix<double> mat1(row, column);    int k = 1;    for(int i = 0; i < row; i++)    {        for(int j = 0; j < column; j++)        {            mat1.set_value(i, j, k++);        }    }    std::cout<<"Test 1: orgin data: "<<std::endl;    mat1.print();    //TEST 2:    mxArray *aa = mxCreateDoubleMatrix(row, column, mxREAL);    //get mat2.data_ptr() and transmit column-priority data to matlab workspace    memcpy(mxGetPr(aa), mat1.data_ptr(), mat1.length());    engPutVariable(ep, "aa", aa);    std::cout<<"Test 2: aa, see Matlab command window"<<std::endl;    //TEST 3:    mxArray* xx = engGetVariable(ep, "aa");    //get matrix from matlab workspace,then structure a row-priority TMatrix    CG::TMatrix<double> mat2(mxGetM(xx), mxGetN(xx), mxGetPr(xx));    std::cout<<"Test 3: data from matlab workspace: "<<std::endl;    mat2.print();    //TEST 4:access TMatrix    for(int i = 0; i < row; i++)    {        for(int j = 0; j < column; j++)        {            std::cout<<mat2.get_value(i, j)<<" ";        }        std::cout<<std::endl;    }    //END    std::cin.get();    engEvalString(ep, "clear;");    mxDestroyArray(aa);    mxDestroyArray(xx);    engClose(ep);    return 0;}

这边做了4个测试:

Test1:TMatrix对象mat按行优先初始化,并输出。

Test2:TMatrix数据拷贝给matlab矩阵aa,并在Matlab command window中查看aa的输出值。

Test3:从Matlab 空间获取变量aa的值,保存至新的mat2,并输出。

Test4: 按行优先初始化访问mat2的值。


测试输出结果如下:


Test1 - Test4输出窗口,其中Test2测试结果参考下图。



从结果上可以发现,Test1 -- Test4的所有结果都是一样的。

结论:通过TMatrix类,可实现完全的行优先数据存储,行优先访问,完全满足c++与matlab引擎交互的需要。


希望对大家有帮助。微笑















0 0
原创粉丝点击