如何传递 matlab::data::TypedArray<double> 作为指针在 MATLAB mex 文件中构造犰狳矩阵?

Posted

技术标签:

【中文标题】如何传递 matlab::data::TypedArray<double> 作为指针在 MATLAB mex 文件中构造犰狳矩阵?【英文标题】:How to pass matlab::data::TypedArray<double> as pointer to construct Armadillo matrix in MATLAB mex file? 【发布时间】:2021-01-14 20:21:09 【问题描述】:

请有更多经验的人告诉我如何达到上述目的?

这肯定是一件小事;然而,经过许多日日夜夜的尝试、研究和上网阅读,我仍然无法理解它。

设置:

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

ma​​in.cpp

包含 MATLAB 和 C++ 之间的通用 IO 接口 将两个 double 数组(每个数组的维度:ncols:168,nrows:2)和两个 double const doubles 输入 C++ 它通过调用 foo() 执行一些基于 Armadillo 的循环(这部分并不那么重要,因此省略) 返回 outp,它是一个“只是一个普通的”双精度标量 没有什么花哨或复杂的。

sub.cpp

这仅适用于 foo() 循环部分。 问题是两个 arma::mat mYarma::mat mD 矩阵没有使用指向辅助内存的指针以某种方式正确填充,如在下面的犰狳文档。 http://arma.sourceforge.net/docs.html#adv_constructors_mat

sub.hpp

只是一个简单的头文件。

我将非常感谢提前提供任何帮助、提示或建设性的 cmets。

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

            double* darrY = matlab::data::TypedArray<double>(std::move(inputs[0])).release().get();
            double* darrD = matlab::data::TypedArray<double>(std::move(inputs[1])).release().get();
            const double csT = inputs[2][0];
            const double csKy = inputs[3][0];

            // 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 inputs parameters to armadillo matrices using the armadillo's so called advanced matrix constructor:
    // mat(ptr_aux_mem, n_rows, n_cols, copy_aux_mem = true, strict = false)
    // Fixme: parameterize n_rows, n_colss
    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

【问题讨论】:

【参考方案1】:

MATLAB Central 也有类似的问题。换行

double* darrY = matlab::data::TypedArray<double>(std::move(inputs[0])).release().get();
double* darrD = matlab::data::TypedArray<double>(std::move(inputs[1])).release().get();

TypedArray<double> matrix1 = std::move(inputs[0]);
TypedArray<double> matrix2 = std::move(inputs[1]);
buffer_ptr_t<double> Y = matrix1.release();
buffer_ptr_t<double> D = matrix2.release();
double* darrY = Y.get();
double* darrD = D.get();

似乎解决了这个问题。当我调试你的代码时,看起来两个矩阵由于某种原因得到了相同的地址。

【讨论】:

@RolenClaes 感谢您的回答,看起来很有希望!我会尽快检查它,如果它有效(非常像这种情况),那么我会接受你的正确答案。 (很抱歉在 @ 符号之后更改为名字/姓氏的顺序。否则不允许这样做...)您是使用英特尔 MKL 编译带有犰狳的 mex 文件,还是使用 OpenBLAS(或其他线性代数)编译包)与犰狳一起提供的静态/动态库?问的原因是因为使用 OpenBLAS 调试非常脆弱。 (我将 Visual Studio Code 附加到正在运行的 MATLAB 进程。) 效果很好,我已经使用英特尔 MKL “从头开始”编译了犰狳。 Savyasachi Singh 提供的参考链接中还有一个替代解决方案。 @RolenClaes 再次感谢您的回答。请问你怎么能用犰狳编译mex文件?通过“从头开始”编译,您的意思是不使用 MATLAB 的 mex 命令吗?我之所以问到目前为止我已经使用了 mex 命令,但我还不能使用英特尔 MKL 静态/动态链接对其进行编译,即使我尝试“按书”做所有事情 = 使用英特尔® oneAPI MKL 链接线路顾问。这就是为什么我不得不求助于 OpenBLAS。我认为有一种更优雅的方式可以用 Armadillo 编译 mex 文件,它适合与 MATLAB 交互。 我用提供的 CMake(使用 MKL)编译了犰狳并安装了“libarmadillo.so”文件。 Mex 在 Matlab 中通过“mex CFLAGS='$CFLAGS -ggdb -O0 -larmadillo' myMex.cpp”编译,我使用的是 Ubuntu 20.04、Matlab 2020b 和 Armadillo 9.700.2 @RolenClaes 感谢您的详细回答。谢谢!那好吧。我正在使用带有 minGW64 编译器的 Windows 10。我还调整了犰狳配置头,但我仍然缺少一些东西。我猜在 Ubuntu(一般是 Linux)上,使用 Intel MKL 正确完成 mex 编译会更直接,或者可能只适合我。

以上是关于如何传递 matlab::data::TypedArray<double> 作为指针在 MATLAB mex 文件中构造犰狳矩阵?的主要内容,如果未能解决你的问题,请参考以下文章

C#中的枚举类型如何传递参数呢?

QT中两个类之间如何进行值传递?如何一个类里面定义了一个数组a[270],怎么传递给另一个类?

如何在两页面之间传递JSON数据

HttpURLConnection如何传递参数?

Android如何在Activity和Service之间传递数据

两个HTML页面如何传递数据?