C ++中犰狳矩阵尺寸的动态参数化 [英] Dynamic parameterization of Armadillo matrix dimensions in 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屋!