微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

将 MATLAB 结构体返回给 C++ 并访问元素

如何解决将 MATLAB 结构体返回给 C++ 并访问元素

我正在尝试从 C++ 运行 MATLAB,并将结构体中的 MATLAB 输出返回到 C++。该结构可以包含任意数量的东西,包括不同维度和长度的数组。有一个类似的问题 here,但答案没有提供足够的细节让我理解和推断。

我正在使用 MatlabEngine.hppMatlabDataArray.hpp 运行 MATLAB。我需要返回很多输出并尝试了其他方法,但这些方法并不能完全满足我的要求。使用结构似乎是最合乎逻辑/可读性的做事方式。我将尝试用以下示例来解释我的情况,希望这些示例的编写方式对遇到类似问题的其他人最有用。

MWE 1 - 返回 n × n 数组

MATLAB 代码
function output = simple_fun1(a,bc)
% Takes input values of a and an array [a,b]
b = bc(1);
c = bc(2);
sum = a+b+c;
prod = a*b*c;
output = [sum,prod; 3,4];

这可以使用 C++ 代码运行:

C++ 代码
#include "MatlabEngine.hpp"
#include "MatlabDataArray.hpp"
#include <iostream>

int main()
{
  using namespace matlab::engine;
  matlab::data::ArrayFactory factory; // Create MATLAB data array factory

  std::unique_ptr<MATLABEngine> matlabPtr = startMATLAB(); // Start MATLAB engine

  matlabPtr->eval(u"addpath(genpath('C:/Users/...your path here...'))"); // Add the path to where MATLAB functions are.

  std::vector<double> bc{ 10,13};
  std::vector<matlab::data::Array> args({
    factory.CreateScalar<double>(7),factory.CreateArray({ 1,2 },bc.cbegin(),bc.cend())
  });
  
  matlab::data::TypedArray<double> results = matlabPtr->feval(u"simple_fun1",args); // Run simple_fun1
  
  std::cout << "Sum: " << results[0][0] << std::endl;
  std::cout << "Prod: " << results[0][1] << std:endl;
  std::cout << "Three: " << results[1][0] << std::endl;
}

这适用于 n x n 数组的单个返回。但是如果我想单独返回数据,即 function [sum,prod] = simple_fun1(a,bc) 它不起作用。

MWE2 - 返回多个输出

我已经设法使用元组返回多个输出,但是我只能访问数组的第一个元素(如果它是数组输出),因为我无法定义 MATLAB 数组的元组。例如

MATLAB 代码
function [sum,prod] = simple_fun2(a,b]
b = bc(1);
c = bc(2);
sum = a+b+c;
prod = a*b*c;
C++ 代码
  std::tuple<double,double> results;
  results = matlabPtr->feval< std::tuple<double,double>>(u"simple_fun2",double(7),std::vector<double>{ 10,13}); // Just as another example of how to enter inputs in case that's helpful for anyone.
  double s;
  double p;
  std::tie(s,p) = results;
  std::cout << "Sum: " << s << ",Prod: " << p << std::endl;

返回结构

相反,我想编写我的 MATLAB 函数,使其返回一个结构体,这有望简化传递大量数据的代码,并允许数据具有不同的维度。但是,我一直无法创建一个工作示例。

MATLAB 代码
function output = simple_fun3(a,bc)
b = bc(1);
c = bc(2);
output.sum = a+b+c;
output.prod = a*b*c;
output.a_sq = a*a;
output.b_sq = b*b;
C++ 代码
#include "MatlabEngine.hpp"
#include "MatlabDataArray.hpp"
#include <iostream>

int main()
{
  using namespace matlab::engine;
  matlab::data::ArrayFactory factory; // Create MATLAB data array factory

  std::unique_ptr<MATLABEngine> matlabPtr = startMATLAB(); // Start MATLAB engine

  matlabPtr->eval(u"addpath(genpath('C:/Users/...your path here...'))"); // Add the path to where MATLAB functions are.

  std::vector<double> bc{ 10,bc.cend())
  });
  
  matlab::data::StructArray my_matlab_struct = factory.createStructArray(matlab::data::ArrayDimensions{ 1,4},std::vector<std::string>{'sum','prod','a_sq','b_sq'});
  my_matlab_struct = matlabPtr->feval(u"simple_fun3",args);

上面的 C++ 代码不起作用,我不明白结构是如何定义的;即 ArrayDimensions 是什么维度。任何帮助表示赞赏。谢谢

解决方法

经过多次搜索,我设法解决了问题并在 C++ 和 MATLAB 之间传递了结构。该解决方案基于 this,但由于缺少命名空间,链接中的代码不起作用。因此,我将解决方案放在下面。注意:该解决方案假设您已经设置了 MATLAB 和 C++ 来相互连接,这可能是一个完全不同的过程,具体取决于您的 MATLAB 版本,如果您使用的是 Visual Studio,那么您的 Visual Studio 版本也是如此。

将结构体从 C++ 传递给 MATLAB

不是我最初问题的一部分,但这可能对某人有用。

#include "MatlabEngine.hpp"
#include "MatlabDataArray.hpp"

#include <iostream>
#pragma comment (lib,"libmat.lib")
#pragma comment (lib,"libmx.lib")
#pragma comment (lib,"libmex.lib")
#pragma comment (lib,"libeng.lib")

int main()
{
  using namespace matlab::engine;
  matlab::data::ArrayFactory factory; // Create MATLAB data array factory
  std::unique_ptr<MATLABEngine> matlabPtr = startMATLAB(); // Start MATLAB engine
  
  matlabPtr->eval(u"addpath(genpath('Insert the path of any MATLAB functions you plan to use'))")
  
  matlab::data::StructArray my_structure = factory.createStructArray({1,1},{"x","y","z"}); // Create a structure with one element and fields x,y,z
  my_structure[0]["x"] = factory.createArray({1,3},{1.,2.,3.});
  my_structure[0]["y"] = factory.createArray({1,4.,9.});
  my_structure[0]["z"] = factory.createArray({1,8.,27.});
  
  matlabPtr->setVariable(u"Mstruct",my_structure); // pass structure to matlab workspace
  matlabPtr->eval(u"Mstruct") // show the structure exists.
  // The array can be passed to a function using feval
}

获取函数返回的结构

下面的代码假设 MATLAB 引擎已经设置,并从一个名为 matlab_fun 的 MATLAB 脚本返回一个结构体,该脚本接受输入 args

  matlab::data::StructArray my_matlab_struct = matlabPtr->feval(u"matlab_fun",args);
  matlab::data::ArrayDimensions dims = my_matlab_struct.getDimensions();
  std::cout << "Structure is: " << dims[0] << " by " << dims[1] << std::endl;
  size_t numFields = my_matlab_struct.getNumberOfFields();
  std::cout << "Structure has " << numFields << " fields." << std::endl;

  matlab::data::Range<matlab::data::ForwardIterator,matlab::data::MATLABFieldIdentifier const> fields = my_matlab_struct.getFieldNames();
  
  for (int i=0; i<numFields; i++){
    matlab::data::TypedArray<double> data = my_matlab_struct[0][fields.begin()[i]]; // [0] for the first element of the structure. Iterates over the fields.
    matlab::data::ArrayDimensions data_dims = data.getDimensions();
    for (int j=0; j<data_dims[0];j++){
      for (int k=0; k<data_dims[1];k++){
        std::cout << data[j][k] << " ";
      }
      std::cout << std::endl;
    }
  }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。