如何解决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],false);
这肯定是一个常见的用例,但是当从 MATLAB 提供的数组的维数可能是任意的 (n > 2) 时,我仍然找不到一种很好的方法来实现它。
>对于矩阵(二维)情况,我可能会绕过我的方式,但我觉得这不够优雅(也可能效率不高)。
恕我直言,要走的路必须是:
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 的 getDimensions()
函数中的指针/引用调用 foo()
。如果可行,我既不想创建额外的临时对象,也不想将其他参数传递给 foo()
。怎么可能?
我非常感谢知识渊博的 SO 成员提供的任何帮助、提示或建设性意见。提前致谢。
设置:
main.cpp
- 包含 MATLAB 和 C++ 之间的通用 IO 接口
- 将两个 double 数组和两个 double const double 送入 C++
- 它通过调用 foo() 执行一些基于犰狳的循环(这部分不是那么重要,因此省略)
- 返回outp,它是一个“简单的”双精度标量
- 没有什么花哨或复杂的东西。
sub.cpp
- 这仅适用于 foo() 循环部分。
sub.hpp
// 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",std::vector<Array>({ factory.createScalar("Input must be double array.") }));
}
// Check output size
if (outputs.size() > 1) {
matlabPtr->feval(u"error",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,strict = false)
arma::mat mY(&dY[0],false);
arma::mat mD(&dD[0],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,const double Ky);
#endif // SUB_H_INCLUDED
解决方法
一种方法是使用函数将其转换为 arma 矩阵
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]);
}
然后调用它
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)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。