将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 + 4
end
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
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:");
}
所谓的 .hpp 文件是将函数的声明和定义写在一起的文件,它的使用方法和 .h 文件一样,使用 #include 关键字包含进来就可以。但是在编译的时候,只需要编译 .cpp 文件,不需要再编译 .hpp 文件,降低了编译文件的数量。上面的 .hpp 文件就是从 Matlab 程序中转化过来的,如果读者看过上一篇文章的话,就觉得这个程序很熟悉了,这正是调用了 Armadillo 库的 C++ 程序。为了验证结果是否正确,在第23行添加了输出。下面是对应的 .cpp 程序:
using namespace std;
int main()
{
g();
return 0;
}
最后只需要按照上一篇文章中介绍的方法使用 g++ -std=c++11 example.cpp -larmadillo 命令编译这个程序即可。得到的结果如下图所示:
如果您去前面提到的 Github 网站看过了的话,就会发现上面介绍的实际上是网站上的例子。下面再介绍两个使用示例,第一个是关于矩阵的运算,第二个是关于 for 循环和 if 语句的使用。
矩阵的运算
m = 3
n = 3
s = 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
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
end
end
a
在上面这个 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
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++程序的主要内容,如果未能解决你的问题,请参考以下文章
在 Visual Studio 2010 (C++) 中集成 MATLAB 代码