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

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

问题描述

标题总结了更准确的目标,即动态检索传递给犰狳矩阵的 MATLAB 数组的维数.

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

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

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);

这绝对是一个常见的用例,但是当从 MATLAB 提供的数组的维数可能是任意的(n > 2)时,我仍然找不到一种很好的方法来实现它.

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::TypedArraygetDimensions() 成员函数,它检索 matlab::data::ArrayDimensions基本上是一个 std::vector.

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

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

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];

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

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?

我非常感谢知识渊博的 SO 成员提供的任何帮助、提示或建设性意见.提前致谢.

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

设置:

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

Two C++ source files and a header file:

ma​​in.cpp

  • 包含 MATLAB 和 C++ 之间的通用 IO 接口
  • 将两个 double 数组和两个 double const double 送入 C++
  • 它通过调用 foo()
  • 执行一些基于犰狳的循环(这部分不是那么重要,因此省略)
  • 返回outp,它是一个简单的"双精度标量
  • 没有什么花哨或复杂的东西.
  • 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

  • 这仅适用于 foo() 循环部分.
  • This is only for the foo() looping part.

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", 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

推荐答案

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

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]);
}

然后调用它

 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) 

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

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