前一段时间在工作中遇到这样一个实际问题,项目主体部分是用C++写的,但其中有一小部分算法是用MATLAB写的。于是乎,我第一想法是如何用C++把MATLAB中的代码实现出来。
这时,一位前辈语重心长地和我说:“可以去网上找一下MATLAB Coder。”
当时听完一脸懵逼,什么是MATLAB Coder?它有什么用?
于是在网上查阅了一些资料之后,发现MATLAB Coder实际上是MATLAB自带的一个应用程序。这个应用程序的牛X之处在于它可以直接将MATLAB代码转换成C/C++代码。
就在我以为使用MATLAB Coder可以轻松地转换时,但是在实际使用过程中依然遇到一些雷区,这些雷区是在网上查不到。
为了防止小伙伴继续“踩雷”,今天详细地讲解一下如何使用MATLAB Coder将MATLAB代码转换成C/C++代码?如何避免一些“雷区”?
01 | 准备工作在使用MATLAB Coder前,我们需要先对MATLAB代码进行一些处理,主要包括:
(1)删除MATLAB代码中所有的注释(这是第一个“雷区”,必须要把MATLAB代码中注释全部删干净,否则无法成功转换)。
(2)删除MATLAB代码中画图和打印部分的代码,简而言之,就是把什么plot、disp之类的代码全部删除掉。如果不删除这些代码,则会导致无法成功转换,这是第二个“雷区”。
(3)如果在MATLAB代码中想要把一个未知行(列)数的数据储存在矩阵中,常规的做法是先令这个储存的矩阵A为空。
A=[];
假设要添加的若干行数据,每次添加的数据都为B。然后可以用如下的代码将要添加的数据添加进来。
A=[A;B];
这其实是最容易忽视的一个“雷区”,C/C++不允许你MATLAB存在这么牛X的方法,因此如果MATLAB代码中存在上述类型添加数据的代码,那么是无法成功转换的。
解决方案:先求出究竟需要添加多少行数据?然后再添加数据。
假设经计算需要添加m行数据,且添加数据的列数都为n,那么可以先初始化储存的矩阵A,然后再通过计数器的方式循环添加数据。
1,n);
02 | 封装主函数
因为主函数为脚本函数,在转换之前需要先将脚本函数转换为一个常规的函数,即有明确输入和输出的函数。
以遗传算法(GA)求解旅行商问题(TSP)MATLAB代码讲解这篇推文的主函数为例,原来主函数的代码如下:
%
% @作者:随心390
% @微信公众号:优化算法交流地
%
tic
clear
clc
%% 输入数据
x=[38.24,39.57,40.56,36.26,33.48,37.56,38.42,37.52,41.23,41.17,36.08,38.47,38.15,37.51,35.49,39.36,38.09,36.09,40.44,40.33,40.37,37.57];
y=[20.42,26.15,25.32,23.12,10.54,12.19,13.11,20.44,9.100,13.05,-5.210,15.13,15.35,15.17,14.32,19.56,24.36,23,13.57,14.15,14.23,22.56];
vertexs=[x;y]';
n=length(x); %城市数目
h=pdist(vertexs);
dist=squareform(h); %距离矩阵
%% 遗传算法参数设置
NIND=50; %种群大小
MAXGEN=1000; %迭代次数
Pc=0.8; %交叉概率
Pm=0.2; %变异概率
pSwap=0.2; %选择交换结构的概率
pReversion=0.5; %选择逆转结构的概率
pInsertion=1-pSwap-pReversion; %选择插入结构的概率
N=n; %染色体长度=城市数目
%% 种群初始化
Chrom=InitPop(NIND,N);
%% 优化
gen=1; %计数器
bestChrom=Chrom(1,:); %初始全局最优个体
bestL=RouteLength(bestChrom,dist);%初始全局最优个体的总距离
BestChrom=zeros(MAXGEN,N); %记录每次迭代过程中全局最优个体
BestL=zeros(MAXGEN,1); %记录每次迭代过程中全局最优个体的总距离
while gen<=MAXGEN
%二元锦标赛选择
SelCh=BinaryTourment_Select(Chrom,dist);
%OX交叉
SelCh=Recombin(SelCh,Pc);
%变异
SelCh=Mutate(SelCh,Pm,pSwap,pReversion,pInsertion);
%将Chrom更新为SelCh
Chrom=SelCh;
%计算当前代所有个体总距离
Obj=ObjFunction(Chrom,dist);
%找出当前代中最优个体
[minObj,minIndex]=min(Obj);
%将当前代中最优个体与全局最优个体进行比较,如果当前代最优个体更好,则将全局最优个体进行替换
if minObj<=bestL
bestChrom=Chrom(minIndex,:);
bestL=minObj;
end
%记录每一代全局最优个体,及其总距离
BestChrom(gen,:)=bestChrom;
BestL(gen,:)=bestL;
%显示外层循环每次迭代的信全局最优路线的总距离
disp(['第' num2str(gen) '次迭代:全局最优路线总距离 = ' num2str(bestL)]);
%画出每次迭代的全局最优路线图
figure(1);
PlotRoute(bestChrom,x,y)
pause(0.01);
%计数器加1
gen=gen+1;
end
%% 打印每次迭代的全局最优个体的总距离变化趋势图
figure;
plot(BestL,'LineWidth',1);
title('优化过程')
xlabel('迭代次数');
ylabel('总距离');
toc
封装之后的主函数如下:
%% 封装后的主函数
%输入x,y:城市的x,y坐标
%输入NIND:种群大小
%输入MAXGEN:迭代次数
%输入Pc:交叉概率
%输入Pm:变异概率
%输入pSwap:选择交换结构的概率
%输入pReversion:选择逆转结构的概率
%输入pInsertion:选择插入结构的概率
%输出bestChrom:全局最优个体
function bestChrom=GA_TSP(x,y,NIND,MAXGEN,Pc,Pm,pSwap,pReversion,pInsertion)
%% 输入数据vertexs=[x;y]';n=length(x); %城市数目h=pdist(vertexs);dist=squareform(h); %距离矩阵N=n; %染色体长度=城市数目
%% 种群初始化Chrom=InitPop(NIND,N);
%% 优化gen=1; %计数器bestChrom=Chrom(1,:); %初始全局最优个体bestL=RouteLength(bestChrom,dist);%初始全局最优个体的总距离BestChrom=zeros(MAXGEN,N); %记录每次迭代过程中全局最优个体BestL=zeros(MAXGEN,1); %记录每次迭代过程中全局最优个体的总距离while gen<=MAXGEN
%二元锦标赛选择SelCh=BinaryTourment_Select(Chrom,dist);
%OX交叉SelCh=Recombin(SelCh,Pc);
%变异SelCh=Mutate(SelCh,Pm,pSwap,pReversion,pInsertion);
%将Chrom更新为SelChChrom=SelCh;
%计算当前代所有个体总距离Obj=ObjFunction(Chrom,dist);
%找出当前代中最优个体
[minObj,minIndex]=min(Obj);
%将当前代中最优个体与全局最优个体进行比较,如果当前代最优个体更好,则将全局最优个体进行替换if minObj<=bestLbestChrom=Chrom(minIndex,:);bestL=minObj;end
%记录每一代全局最优个体,及其总距离BestChrom(gen,:)=bestChrom;BestL(gen,:)=bestL;
%显示外层循环每次迭代的信全局最优路线的总距离disp(['第' num2str(gen) '次迭代:全局最优路线总距离 = ' num2str(bestL)]);
%画出每次迭代的全局最优路线图figure(1);PlotRoute(bestChrom,x,y)pause(0.01);
%计数器加1gen=gen+1;end
%% 打印每次迭代的全局最优个体的总距离变化趋势图figure;plot(BestL,'LineWidth',1);title('优化过程')xlabel('迭代次数');ylabel('总距离');end
03 | 新建一个脚本函数
在封装完主函数后,删除掉原来的脚本函数GA_TSP。再新建一个脚本函数TEST,在这个脚本函数中给出封装后的主函数的输入数据,具体代码如下:
clear
clc
x=[38.24,39.57,40.56,36.26,33.48,37.56,38.42,37.52,41.23,41.17,36.08,38.47,38.15,37.51,35.49,39.36,38.09,36.09,40.44,40.33,40.37,37.57];
y=[20.42,26.15,25.32,23.12,10.54,12.19,13.11,20.44,9.100,13.05,-5.210,15.13,15.35,15.17,14.32,19.56,24.36,23,13.57,14.15,14.23,22.56];
NIND=50;
MAXGEN=1000;
Pc=0.8;
Pm=0.2;
pSwap=0.2;
pReversion=0.5;
pInsertion=1-pSwap-pReversion;
bestChrom=GA_TSP(x,y,NIND,MAXGEN,Pc,Pm,pSwap,pReversion,pInsertion);
04 | 开始转换
这里我们已经将注释、画图和打印部分的代码全部删除完毕。
STEP1:点击MATLAB Coder
STEP2:添加封装后的GA_TSP函数。
STEP3:根据提示修改代码
这里我们将OX函数进行修改,修改后的OX函数代码如下:
function [a,b]=OX(a,b)L=length(a);while 1r=randi([1,L],1,2);r1=r(1);r2=r(2);if r1~=r2s=min([r1,r2]);e=max([r1,r2]);a0=zeros(1,L+e-s+1);b0=zeros(1,L+e-s+1);a0(1:e-s+1)=b(s:e);a0(e-s+2:L+e-s+1)=a;b0(1:e-s+1)=a(s:e);b0(e-s+2:L+e-s+1)=b;for i=1:length(a0)aindex=find(a0==a0(i));bindex=find(b0==b0(i));if length(aindex)>1a0(aindex(2))=[];endif length(bindex)>1b0(bindex(2))=[];endif i==length(a)breakendenda=a0;b=b0;breakendend
STEP4:重复前3步操作,在STEP2点击NEXT后,直接来到定义输入变量类型这一步。
STEP5:检验运行环境
发现又报错了,按照要求修改OX函数,这次报错的原因是OX函数代码中的第10行和第11行,这两行代码是常见的第三个“雷区”,修改后的OX函数如下:
function [a0,b0]=OX(a,b)L=length(a);while 1r=randi([1,L],1,2);r1=r(1);r2=r(2);if r1~=r2s=min([r1,r2]);e=max([r1,r2]);a0=zeros(1,L+e-s+1);b0=zeros(1,L+e-s+1);a0(1:e-s+1)=b(s:e);a0(e-s+2:L+e-s+1)=a;b0(1:e-s+1)=a(s:e);b0(e-s+2:L+e-s+1)=b;for i=1:length(a0)aindex=find(a0==a0(i));bindex=find(b0==b0(i));if length(aindex)>1a0(aindex(2))=[];endif length(bindex)>1b0(bindex(2))=[];endif i==length(a)breakendendbreakendend
继续重复前几步到STEP5,又发现了新的报错。
报错信息是C中if语句中的条件不能像MATLAB这么写,于是对Mutate函数做出一些修改,修改后的函数如下:
function SelCh=Mutate(SelCh,Pm,pSwap,pReversion,pInsertion)NSel=size(SelCh,1);for i=1:NSelif Pm>=randindex=Roulette(pSwap,pReversion,pInsertion);route1=SelCh(i,:);flag=zeros(1,3);flag(1)= index==1;flag(2)= index==2;flag(3)= index==3;if flag(1)route2=Swap(route1);elseif flag(2)route2=Reversion(route1);elseroute2=Insertion(route1);endSelCh(i,:)=route2;endend
再一次重复前几步到STEP5,这一次终于成功了。
STEP6:点击Gnerate生成C代码,在MATLAB代码文件夹下多了2个文件和1个文件夹,转换出的C代码在codegen文件夹->lib文件夹->GA_TSP文件夹下。
至此,使用MATLAB Coder应用程序成功将遗传算法(GA)求解旅行商问题(TSP)MATLAB代码讲解这篇推文的MATLAB代码转换为C代码。
各位小伙伴可参与免费送付费代码,第二波这篇推文的活动,免费领取付费代码。
点击下方小程序写留言
写留言
![a385caa67b73bd545e631f496a3e7102.png](https://i-blog.csdnimg.cn/blog_migrate/c05dde214de93599a6c379b96cf5ffbb.png)
![a385caa67b73bd545e631f496a3e7102.png](https://i-blog.csdnimg.cn/blog_migrate/c05dde214de93599a6c379b96cf5ffbb.png)
往期精选
号内搜索
头脑风暴优化(BSO)算法求解旅行商问题(TSP)(附MATLAB代码)
一种新颖的交叉算子——头脑风暴优化(BSO)算法求解旅行商问题(TSP)预备知识
头脑风暴优化(BSO)算法(附MATLAB代码)
如何自学智能优化算法?
遗传模拟退火算法求解旅行商(TSP)问题MATLAB代码讲解
遗传模拟退火算法求解旅行商(TSP)问题
车辆路径问题(VRP)合集
旅行商问题(TSP)合辑
MATLAB导入txt文件技巧大全
遗传算法(GA)求解旅行商问题(TSP)MATLAB代码讲解
- 遗传算法求解0-1背包问题(附matlab源代码)
- 模拟退火(SA)算法求解旅行商 (TSP)问题MATLAB代码讲解
- 多目标优化 | 基于NSGA-II的多目标0-1背包问题求解(附matlab代码)
- 多目标优化 | NSGA-II进阶教程(全网首个三目标优化教程)
- 机器学习 | 基于遗传算法的BP神经网络优化算法(附MATLAB代码)
- 遗传算法求解车间调度问题(附MATLAB代码)
- 多目标优化 | NSGA-II
- word转换为pdf后图片失真的解决办法(全网首发)
- 机器学习 | 简单实现Bp神经网络
- 二维装箱问题之BL法修正版(附MATLAB代码)
- 快速入门文献管理软件-EndNote X9
- 最小二乘法(附MATLAB代码)
- NSGA-II多目标优化算法讲解(附MATLAB代码)
- 基于人工势场法的机器人二维路径规划(附MATLAB代码)
- 基于粒子群算法的多目标搜索算法讲解(附MATLAB代码)
- 蚁群算法通俗讲解(附MATLAB代码)
- 混合粒子群算法通俗讲解(附MATLAB代码)
知乎 | bilibili:随心390
![4ea7cb8b33a84e3c0e1fa08e05e10703.png](https://i-blog.csdnimg.cn/blog_migrate/cd2fcce961ad6c0b1aa4c451ddb690be.jpeg)
![5f8d73a0958f34d1629d33857cec9e77.png](https://i-blog.csdnimg.cn/blog_migrate/29f687801fa862c6c15ae62d3c2082d9.png)
![126a98b859b2daa308af5cca1348160e.gif](https://i-blog.csdnimg.cn/blog_migrate/46847ee7ae55f0c94e7becca10b1f5be.gif)
![61390164ceb62f386d0995aab0c50c1b.gif](https://i-blog.csdnimg.cn/blog_migrate/b90670ad8f3b665cdac27b1c81aa184c.gif)