将Matlab程序转化成C++程序

Posted AlphaPENPEN

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了将Matlab程序转化成C++程序相关的知识,希望对你有一定的参考价值。

在上一篇文章中,介绍了 Armadillo 线性代数库在 C++ 中的使用方法。说到线性代数的计算软件,自然要提一下 Matlab 。Matlab 在矩阵计算、数值分析和仿真等领域发挥着重要的作用。Matlab 的含义是 Matrix Laboratory (矩阵实验室)的缩写,所以它在矩阵运算的领域具有非常强大的功能。在上一篇文章中也提到,Armadillo 的许多语法和 Matlab 很相似,甚至在 Armadillo 设计的原初目标中就写到了是为了对标 Matlab 的线性代数的运算功能。那么能不能将 Matlab 关于矩阵运算的程序借助于 Armadillo 库转化成 C++ 程序呢?本文介绍了解决这一问题的一种方法。

在 https://github.com/jonathf/matlab2cpp 网站中,介绍了一个叫做 matlab2cpp 的 Python 库。仅从库的名字看上去,就知道这个库的作用是为了将 Matlab 程序转化成 C++ 程序。和其他的 Python 库一样,只需要使用 pip install 命令安装即可。这个库的使用方法比较有趣,下面通过几个例子来介绍它的使用方法。

一个简单的示例

function y = f(x) y = x + 4end
function g() x = [1, 2, 3] f(x)end

假设这个 Matlab 的程序名称为 example.m,上面这个程序是将一维行向量的每个元素都加上4。现在用 m2cpp example.m 命令,可以生成一个 example.m.py 文件,一个 example.m.hpp 文件,一个 example.m.log 文件。log 文件是转化过程中的日志,需要重点关注的是 example.m.hpp 和 example.m.py 这两个文件。下面是这两个文件的内容:

# Automatically translated using m2cpp 2.0 on 2021-01-25 20:39:40## encoding: utf-8## Supplement file## Valid inputs:## uword int float double cx_double# uvec ivec fvec vec cx_vec# urowvec irowvec frowvec rowvec cx_rowvec# umat imat fmat mat cx_mat# ucube icube fcube cube cx_cube## char string struct structs func_lambda
functions = { "f" : { "x" : "imat", "y" : "imat", }, "g" : { "x" : "imat", },}includes = [ '#include <armadillo>', 'using namespace arma ;',]

上面这个文件是一个 Python 程序,第1-15行的注释提供了关于这个文件的基本信息,以及 Armadillo 库中的矩阵类。在第一次运行 m2cpp example.m 命令的时候,生成的 Python 程序中的第19-20行的 x 和 y 变量后面的字符串是空的,这里需要使用者根据实际场景填入 x 和 y 的矩阵类。在这个程序中,填入的是 imat,表示这是一个整型矩阵类。第26行的 includes 里面则是包含的头文件,可以看到,程序会自动包含 armadillo ,并且使用命名空间。在填写完数据类型之后,需要再次使用 m2cpp example.m 命令重新生成 .hpp 文件,下面再看一下对应的 hpp 程序:

// Automatically translated using m2cpp 2.0 on 2021-01-25 20:39:40
#ifndef F_M_HPP#define F_M_HPP
#include <armadillo>using namespace arma ;
imat f(imat x) ;void g() ;
imat f(imat x){ imat y ; y = x+4 ; return y ;}
void g(){ imat x = {1, 2, 3} ; imat z = f(x) ; z.print("z:");}#endif

所谓的 .hpp 文件是将函数的声明和定义写在一起的文件,它的使用方法和 .h 文件一样,使用 #include 关键字包含进来就可以。但是在编译的时候,只需要编译 .cpp 文件,不需要再编译 .hpp 文件,降低了编译文件的数量。上面的 .hpp 文件就是从 Matlab 程序中转化过来的,如果读者看过上一篇文章的话,就觉得这个程序很熟悉了,这正是调用了 Armadillo 库的 C++ 程序。为了验证结果是否正确,在第23行添加了输出。下面是对应的 .cpp 程序:

#include "example.m.hpp"#include <iostream>using namespace std;
int main(){ g(); return 0;}

最后只需要按照上一篇文章中介绍的方法使用 g++ -std=c++11 example.cpp -larmadillo 命令编译这个程序即可。得到的结果如下图所示:

如果您去前面提到的 Github 网站看过了的话,就会发现上面介绍的实际上是网站上的例子。下面再介绍两个使用示例,第一个是关于矩阵的运算,第二个是关于 for 循环和 if 语句的使用。

矩阵的运算

m = 3n = 3s = zeros(m, n)w = ones(m, n)A = [1 6; 5 2]B = inv(A)C = A * B

上面是一个非常简单的进行矩阵运算的 Matlab 程序,第3行是产生全零矩阵,第4行是产生全1矩阵,第6行计算这个方阵的逆矩阵,第7行是检验计算的逆矩阵是否正确。下面是对应的 Python 程序和 .cpp 程序。

# Automatically translated using m2cpp 2.0 on 2021-01-25 22:15:52## encoding: utf-8## Supplement file## Valid inputs:## uword int float double cx_double# uvec ivec fvec vec cx_vec# urowvec irowvec frowvec rowvec cx_rowvec# umat imat fmat mat cx_mat# ucube icube fcube cube cx_cube## char string struct structs func_lambda
functions = { "main" : { "A" : "mat", "B" : "mat", "C" : "mat", "m" : "int", "n" : "int", "s" : "mat", "w" : "mat", },}includes = [ '#include <armadillo>', 'using namespace arma ;',]

同样的,第19-25行需要使用者自己手动填写数据类型,填写完之后,再次使用 m2cpp 的命令就可以产生相对应的 .cpp 文件:

// Automatically translated using m2cpp 2.0 on 2021-01-25 22:15:52
#include <armadillo>using namespace arma ;
int main(int argc, char** argv){ int m, n ; mat A, B, C, s, w ; m = 3 ; n = 3 ; s = arma::zeros<mat>(m, n) ; s.print("s:"); w = arma::ones<mat>(m, n) ; w.print("w:"); double _A [] = {1, 6, 5, 2} ; A = arma::strans(mat(_A, 2, 2, false)) ; A.print("A:"); B = inv(A) ; B.print("B:"); C = A*B ; C.print("C:"); return 0 ;}

上面这个程序是可以直接编译,然后执行的,运行的结果如下:

看到这里,读者可能会感到奇怪,为什么第一个示例中产生的是 .hpp 文件,而在这个示例中产生的是 .cpp 文件?这是因为在第一个示例的 Matlab 程序中,只有关于函数的定义,而在第二个示例中都是普通的语句,所以这两者还是稍微有些区别。

for 循环和 if 语句的使用

k=5;for m=1:k for n=1:k if m==n a(m,n)=2; else if abs(m-n)==2 a(m,n)=1; else a(m,n)=0; end end endenda

在上面这个 Matlab 程序中,最终会输出矩阵 a 的结果,下面是对应的 Python 程序:

# Automatically translated using m2cpp 2.0 on 2021-01-25 22:24:12## encoding: utf-8## Supplement file## Valid inputs:## uword int float double cx_double# uvec ivec fvec vec cx_vec# urowvec irowvec frowvec rowvec cx_rowvec# umat imat fmat mat cx_mat# ucube icube fcube cube cx_cube## char string struct structs func_lambda
functions = { "main" : { "a" : "imat", "k" : "int", "m" : "int", "n" : "int", },}includes = [ '#include "mconvert.h"', '#include <armadillo>', '#include <cmath>', 'using namespace arma ;',]

读者可以看到,在第25行的 include 里面,还另外包含了几个可能用到的头文件。下面是对应的 .cpp 文件:

// Automatically translated using m2cpp 2.0 on 2021-01-25 22:24:12
#include "mconvert.h"#include <armadillo>#include <cmath>using namespace arma ;
int main(int argc, char** argv){ int k, m, n ; k = 5 ; imat a(5,5); for (m=1; m<=k; m++) { for (n=1; n<=k; n++) { if (m==n) { a(m-1, n-1) = 2 ; } else { if (std::abs(m-n)==2) { a(m-1, n-1) = 1 ; } else { a(m-1, n-1) = 0 ; } } } } a.print("a:") ; return 0 ;}

这个程序也是可以直接编译并被运行的,运行结果如下图所示:

在上面我们看到了使用 matlab2cpp 库和 Armadillo 库可以实现 Matlab 程序向 C++ 程序的转化。但是这种转化并不都是自动完成的,中间还需要使用者根据实际情况填写数据类型。如果您在使用这个方法进行转化的过程中遇到了什么有趣的事情,欢迎和小编联系,小编的邮箱是:watahashiyasumi@qq.com。


某天上午,一位动漫群的群友询问了这个问题,促使我寻找了从 Matlab 程序向 C++ 程序转化的方法。然后在这个过程中发现了 Armadillo 库和 matlab2cpp 库,于是有了上一篇文章和这一篇文章。非常感谢群友 “c酱”的询问,才有了这两篇文章。在这篇文章的写作过程中,也得到了其他人的帮助,最后一个示例中的 Matlab 脚本是由另一位动漫群的群友 “一般男性”提供的,对此表示诚挚的感谢。


以上是关于将Matlab程序转化成C++程序的主要内容,如果未能解决你的问题,请参考以下文章

C++调用matlab数学函数问题

如何在matlab程序中实现二值图像转化成灰度图像?

在 Visual Studio 2010 (C++) 中集成 MATLAB 代码

使用 MATLAB coder 将代码从 Registration Estimator 应用程序导出到 C++

MATLAB教程案例91将MATLAB程序转化为C语言

C/C++程序通过动态链接库调用MATLAB程序