C ++中犰狳矩阵尺寸的动态参数化 [英] Dynamic parameterization of Armadillo matrix dimensions in C++

查看:82
本文介绍了C ++中犰狳矩阵尺寸的动态参数化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

标题概述了更准确地动态检索传递给犰狳矩阵的MATLAB数组维数的目标.

我想将mY()和mD()的第二个和第三个参数更改为下面的参数化参数.

 //mat(ptr_aux_mem,n_rows,n_cols,copy_aux_mem = true,strict = false)arma :: mat mY(& dY [0],2,168,false);arma :: mat mD(& dD [0],2,168,false); 

这肯定是一个常见的用例,但是当从MATLAB馈送的数组的维数可以是任意的(n> 2)时,对于一般情况,我仍然找不到一种很好的方法来实现它./p>

对于矩阵(二维)案例,我可能会四处走动,但我觉得那还不够优雅(也可能效率不高).

恕我直言,要走的路必须是:

matlab :: data :: TypedArray< double> 具有 getDimensions()成员函数,该成员函数检索 matlab :: data :: ArrayDimensions 基本上是 std :: vector< size_t> .

索引通过 getDimensions()检索到的向量的第一和第二个元素,可以检索行数和列数,例如如下所示.

  unsigned int mYrows = matrixY.getDimensions()[0];unsigned int mYcols = matrixY.getDimensions()[1]; 

但是,在当前设置下,我无法通过sub.cpp的 foo()函数中的指针/引用来调用 getDimensions().如果可行,我既不想创建其他临时对象,也不想将其他参数传递给 foo().那怎么可能呢?

直觉一直告诉我,同样也必须有一个优雅的解决方案.也许使用多种间接方式?

我将非常感谢知识渊博的SO成员提供的任何帮助,提示或建设性意见.预先谢谢你.

设置:

两个C ++源文件和一个头文件:

main.cpp

  • 包含MATLAB和C ++之间的常规IO接口
  • 将两个double数组和两个double const double馈入C ++
  • 它通过调用 foo()
  • 进行一些基于Armadillo的循环(这一部分不是那么重要,因此省略了)
  • 返回 outp ,它是一个纯"标量双精度数
  • 没有幻想或复杂的东西.

sub.cpp

  • 这仅用于 foo()循环部分.

sub.hpp

  • 只是一个简单的头文件.

 //main.cpp//MATLAB API头文件#include"mex.hpp"#include"mexAdapter.hpp"//自定义标题#include"sub.hpp"//重载函数调用运算符,因此类充当函子MexFunction类:公共matlab :: mex :: Function {上市:void operator()(matlab :: mex :: ArgumentList输出,matlab :: mex :: ArgumentList输入){matlab :: data :: ArrayFactory工厂;//验证参数checkArguments(输出,输入);matlab :: data :: TypedArray< double>matrixY = std :: move(inputs [0]);matlab :: data :: TypedArray< double>matrixD = std :: move(inputs [1]);const double csT =输入[2] [0];const double csKy =输入[3] [0];buffer_ptr_t< double>mY = matrixY.release();buffer_ptr_t< double>mD = matrixD.release();double * darrY = mY.get();double * darrD = mD.get();//outp的数据类型为"just";一个普通的双精度数组,而不是一个双精度数组double outp = foo(darrY,darrD,csT,csKy);输出[0] = factory.createScalar(outp);void checkArguments(matlab :: mex :: ArgumentList输出,matlab :: mex :: ArgumentList输入){//创建指向MATLAB引擎的指针std :: shared_ptr< matlab :: engine :: MATLABEngine>matlabPtr = getEngine();//创建数组工厂,使我们可以用C ++创建MATLAB数组matlab :: data :: ArrayFactory工厂;//检查输入大小和类型如果(inputs [0] .getType()!= ArrayType :: DOUBLE ||输入[0] .getType()== ArrayType :: COMPLEX_DOUBLE){//如果类型不匹配,则将错误直接引发到MATLAB中matlabPtr-> feval(u错误",0,std :: vector< Array>({factory.createScalar(输入必须为双精度数组.")})));}//检查输出大小如果(outputs.size()> 1){matlabPtr-> feval(u错误",0,std :: vector< Array>({factory.createScalar(仅返回一个输出.")})));}}};//sub.cpp#include"sub.hpp"#include"armadillo"double foo(double * dY,double * dD,const double T,const double Ky){双和= 0;//将输入参数转换为犰狳类型//mat(ptr_aux_mem,n_rows,n_cols,copy_aux_mem = true,strict = false)arma :: mat mY(& dY [0],2,168,false);arma :: mat mD(& dD [0],2,168,false);//犰狳计算for(int t = 0; t< int(T); t ++){//一些基于犰狳的计算//每个循环增量通过其返回值求和}返回总和}//sub.hpp#ifndef SUB_H_INCLUDED#定义SUB_H_INCLUDEDdouble foo(double * dY,double * dD,const double T,const double Ky);#endif//SUB_H_INCLUDED 

解决方案

一种方法是使用函数将其转换为矩阵矩阵

  template< class T>arma :: Mat TgetMat(matlab :: data :: TypedArray< T> A){matlab :: data :: TypedIterator< T>它= A.begin();matlab :: data :: ArrayDimensions nDim = A.getDimensions();return arma :: MatT(it.operator->(),nDim [0],nDim [1]);} 

并通过

调用

  arma :: mat Y = getMat< double>(inputs [0]);arma :: mat D = getMat< double>(inputs [1]);...double outp = foo(Y,D,csT,csKy); 

,然后将 foo()更改为

  double foo(arma :: mat& dY,arma :: mat& dD,const double T,const double Ky) 

The title summarizes the goal that is more exactly to dynamically retrieve the number of dimensions of MATLAB arrays passed to armadillo matrices.

I would like to change the second and third arguments of mY() and mD() to parametric ones below.

// mat(ptr_aux_mem, n_rows, n_cols, copy_aux_mem = true, strict = false)
arma::mat mY(&dY[0], 2, 168, false);
arma::mat mD(&dD[0], 2, 168, false);

This must be definitely a common use case, but I still could not find a nice way of achieving it for the general case when the number of dimensions of the arrays feeding from MATLAB could be arbitrary (n > 2).

For the matrix (two dimensional) case, I could possibly hack my way around but I feel like that is not elegant enough (probably not efficient either).

IMHO, the way to go must be:

matlab::data::TypedArray<double> has getDimensions() member function which retrieves matlab::data::ArrayDimensions that is fundamentally a std::vector<size_t>.

Indexing the first and second element of the vector retrieved by getDimensions() one can retrieve the number of rows and columns, for instance like below.

unsigned int mYrows = matrixY.getDimensions()[0];
unsigned int mYcols = matrixY.getDimensions()[1];

However, with my current setup, I cannot get to call getDimensions() through pointers/references in the foo() function of sub.cpp. If it is feasible, I would neither like to create additional temporary objects nor passing other arguments to foo(). How it possible that way?

Intuition keeps telling me that there must be an elegant solution that way too. Maybe using multiple indirection?

I would highly appreciate any help, hints or constructive comments from more knowledgeable SO members. Thank you in advance.

Setup:

Two C++ source files and a header file:

main.cpp

  • contains the general IO interface between MATLAB and C++
  • feeds two double arrays and two double const doubles into C++
  • it does some Armadillo based looping (this part is not that important therefore omitted) by calling foo()
  • returns outp which is a "just a plain" scalar double
  • Nothing fancy or complicated.

sub.cpp

  • This is only for the foo() looping part.

sub.hpp

  • Just a simple header file.

// main.cpp
// MATLAB API Header Files
#include "mex.hpp"
#include "mexAdapter.hpp"

// Custom header
#include "sub.hpp"

// Overloading the function call operator, thus class acts as a functor
class MexFunction : public matlab::mex::Function {
    public:
        void operator()(matlab::mex::ArgumentList outputs,
                        matlab::mex::ArgumentList inputs){
            
            matlab::data::ArrayFactory factory;
            // Validate arguments
            checkArguments(outputs, inputs);

            matlab::data::TypedArray<double> matrixY = std::move(inputs[0]);
            matlab::data::TypedArray<double> matrixD = std::move(inputs[1]);
            const double csT = inputs[2][0];
            const double csKy = inputs[3][0];

            buffer_ptr_t<double> mY = matrixY.release();
            buffer_ptr_t<double> mD = matrixD.release();

            double* darrY = mY.get();
            double* darrD = mD.get();

            // data type of outp is "just" a plain double, NOT a double array
            double outp = foo(darrY, darrD, csT, csKy);

            outputs[0] = factory.createScalar(outp);

            void checkArguments(matlab::mex::ArgumentList outputs, matlab::mex::ArgumentList inputs){
            // Create pointer to MATLAB engine
            std::shared_ptr<matlab::engine::MATLABEngine> matlabPtr = getEngine();
            // Create array factory, allows us to create MATLAB arrays in C++
            matlab::data::ArrayFactory factory;
            // Check input size and types
            if (inputs[0].getType() != ArrayType::DOUBLE ||
                inputs[0].getType() == ArrayType::COMPLEX_DOUBLE)
            {
                // Throw error directly into MATLAB if type does not match
                matlabPtr->feval(u"error", 0,
                    std::vector<Array>({ factory.createScalar("Input must be double array.") }));
            }
            // Check output size
            if (outputs.size() > 1) {
                matlabPtr->feval(u"error", 0, 
                    std::vector<Array>({ factory.createScalar("Only one output is returned.") }));
                }
        }
};

// sub.cpp

#include "sub.hpp"
#include "armadillo"

double foo(double* dY, double* dD, const double T, const double Ky) {
    
    double sum = 0;

    // Conversion of input parameters to Armadillo types
    // mat(ptr_aux_mem, n_rows, n_cols, copy_aux_mem = true, strict = false)
    arma::mat mY(&dY[0], 2, 168, false);
    arma::mat mD(&dD[0], 2, 168, false);

    // Armadillo calculations

    for(int t=0; t<int(T); t++){

        // some armadillo based calculation
        // each for cycle increments sum by its return value 
    }

    return sum;
}

// sub.hpp

#ifndef SUB_H_INCLUDED
#define SUB_H_INCLUDED

double foo(double* dY, double* dD, const double T, const double Ky);

#endif // SUB_H_INCLUDED

解决方案

One way is to convert it to arma matrix using a function

template<class T>
arma::Mat<T> getMat( matlab::data::TypedArray<T> A)
{
  matlab::data::TypedIterator<T> it = A.begin();
  matlab::data::ArrayDimensions nDim = A.getDimensions();
  return arma::Mat<T>(it.operator->(), nDim[0], nDim[1]);
}

and call it by

 arma::mat Y = getMat<double>(inputs[0]);
 arma::mat D = getMat<double>(inputs[1]);
 ...
 double outp = foo(Y,D, csT, csKy);

and change foo() to

double foo( arma::mat& dY, arma::mat& dD, const double T, const double Ky) 

这篇关于C ++中犰狳矩阵尺寸的动态参数化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆