frogfish 发表于 2007-7-3 22:21

遗传算法解非线性方程组

下边是用遗传算法解非线性方程组的程序。
程序用MATLAB语言编写。之所以选择MATLB,是因为它简单,但又功能强大。写1行MATLAB程序,相当于写10行C++程序。在编写算法阶段,最好用MATLAB语言,算法验证以后,要进入工程阶段,再把它翻译成C++语言。
本程序的算法很简单,只具有示意性,不能用于实战。
非线性方程组的实例在函数(2)nonLinearSumError1(x)中,你可以用这个实例做样子构造你自己待解的非线性方程组。
%注意:标准遗传算法的一个重要概念是,染色体是可能解的2进制顺序号,由这个序号在可能解的集合(解空间)中找到可能解

%程序的流程如下:
%程序初始化,随机生成一组可能解(第一批染色体)
%1: 由可能解的序号寻找解本身(关键步骤)
%2:把解代入非线性方程计算误差,如果误差符合要求,停止计算
%3:选择最好解对应的最优染色体
%4:保留每次迭代产生的最好的染色体,以防最好染色体丢失
%5: 把保留的最好的染色体holdBestChromosome加入到染色体群中
%6: 为每一条染色体(即可能解的序号)定义一个概率(关键步骤)
%7:按照概率筛选染色体(关键步骤)
%8:染色体杂交(关键步骤)
%9:变异
%10:到1

%这是遗传算法的主程序,它需要调用的函数如下。
%由染色体(可能解的2进制)顺序号找到可能解:
%(1)x=chromosome_x(fatherChromosomeGroup,oneDimensionSet,solutionSum);
%把解代入非线性方程组计算误差函数:(2)functionError=nonLinearSumError1(x);
%判定程是否得解函数:(3)=isSolution(x,funtionError,solutionSumError);
%选择最优染色体函数:
%(4)=best_worstChromosome(fatherChromosomeGroup,functionError);
%误差比较函数:从两个染色体中,选出误差较小的染色体
%(5)...
% =compareBestChromosome(holdBestChromosome,holdLeastFunctionError,...
% bestChromosome,leastFuntionError)
%为染色体定义概率函数,好的染色体概率高,坏染色体概率低
%(6)p=chromosomeProbability(functionError);
%按概率选择染色体函数:
%(7)slecteChromosomeGroup=selecteChromome(fatherChromosomeGroup,p);
%父代染色体杂交产生子代染色体函数
%(8)sonChrmosomeGroup=crossChromosome(slecteChromosomeGroup,2);
%防止染色体超出解空间的函数
%(9)chromosomeGroup=checkSequence(chromosomeGroup,solutionSum)
%变异函数
%(10)fatherChromosomeGroup=varianceCh(sonChromosomeGroup,0.8,solutionN);
%通过实验有如下结果:
%1。染色体应当多一些
%2。通过概率选择染色体,在迭代早期会有效选出优秀的染色体,使解的误差迅速降低,
%但随着迭代的进行,概率选择也会导致某种染色体在基因池中迅速增加,使染色体趋同,
%这就减少了物种的多样性,反而难以逼近解
%3。不用概率选择,仅采用染色体杂交,采用保留优秀染色体,也可以得到解

%%%%%%%%%%%%%%%%%%%%%%%%程序开始运行

clear,clc;%清理内存,清屏
circleN=200;%迭代次数
format long

%%%%%%%%%%%%%%%构造可能解的空间,确定染色体的个数、长度
solutionSum=4;leftBoundary=-10;rightBoundary=10;
distance=1;chromosomeSum=500;solutionSumError=0.1;
%solutionSum:非线性方程组的元数(待解变量的个数);leftBoundary:可能解的左边界;
%rightBoundary:可能解的右边界;distance:可能解的间隔,也是解的精度
%chromosomeSum:染色体的个数;solveSumError:解的误差
oneDimensionSet=leftBoundary:distance:rightBoundary;
%oneDimensionSet:可能解在一个数轴(维)上的集合
oneDimensionSetN=size(oneDimensionSet,2);%返回oneDimensionSet中的元素个数
solutionN=oneDimensionSetN^solutionSum;%解空间(解集合)中可能解的总数
binSolutionN=dec2bin(solutionN);%把可能解的总数转换成二进制数
chromosomeLength=size(binSolutionN,2);%由解空间中可能解的总数(二进制数)计算染色体的长度

%%%%%%%%%%%%%%%%程序初始化
%随机生成初始可能解的顺序号,+1是为了防止出现0顺序号
solutionSequence=fix(rand(chromosomeSum,1)*solutionN)+1;
for i=1:chromosomeSum%防止解的顺序号超出解的个数
if solutionSequence(i)>solutionN;
solutionSequence(i)=solutionN;
end
end
%染色体是解集合中的序号,它对应一个可能解
%把解的十进制序号转成二进制序号
fatherChromosomeGroup=dec2bin(solutionSequence,chromosomeLength);
holdLeastFunctionError=Inf;%可能解的最小误差的初值
holdBestChromosome=0;%对应最小误差的染色体的初值

%%%%%%%%%%%%%%%%%%开始计算
circle=0;
while circle<circleN%开始迭代求解
circle=circle+1;%记录迭代次数
%%%%%%%%%%%%%1:由可能解的序号寻找解本身(关键步骤)
x=chromosome_x(fatherChromosomeGroup,oneDimensionSet,solutionSum);
%%%%%%%%%%%%%2:把解代入非线性方程计算误差
functionError=nonLinearSumError1(x);%把解代入方程计算误差
=isSolution(x,functionError,solutionSumError);
%isSolution函数根据误差functionError判定方程是否已经解开,isTrue=1,方程得解。solution是方程的解
if isTrue==1
'方程得解'
solution
minError
circle
return%结束程序
end
%%%%%%%%%%%%%3:选择最好解对应的最优染色体
=best_worstChromosome(fatherChromosomeGroup,functionError);
%%%%%%%%%%%%%4:保留每次迭代产生的最好的染色体
%本次最好解与上次最好解进行比较,如果上次最好解优于本次最好解,保留上次最好解;
%反之,保留本次最好解。保留的最好染色体放在holdBestChromosome中
...
=compareBestChromosome(holdBestChromosome,holdLeastFunctionError,...
bestChromosome,leastFunctionError);
%circle
%minError
%solution
%holdLeastFunctionError

%%%%%%%%%%%%%%5:把保留的最好的染色体holdBestChromosome加入到染色体群中
order=round(rand(1)*chromosomeSum);
if order==0
order=1;
end
fatherChromosomeGroup(order,:)=holdBestChromosome;
functionError(order)=holdLeastFunctionError;

%%%%%%%%%%%%%%%6:为每一条染色体(即可能解的序号)定义一个概率(关键步骤)
%%%%%%%%%%%%%%%好的染色体概率高,坏的概率低。依据误差functionError计算概率
=chromosomeProbability(functionError);
if trueP =='Fail'
'可能解严重不适应方程,请重新开始'
return%结束程序
end
%%%%%%%%%%%%%%%7:按照概率筛选染色体(关键步骤)
%fa=bin2dec(fatherChromosomeGroup)%显示父染色体
%从父染体中选择优秀染色体
%selecteChromosomeGroup=selecteChromosome(fatherChromosomeGroup,p);
%%%%%%%%%%%%%%%8:染色体杂交(关键步骤)
%sle=bin2dec(selecteChromosomeGroup)%显示选择出来的解的序号(染色体)
%用概率筛选出的染色体selecteChromosomeGroup进行杂交,产生子代染色体
%sonChromosomeGroup=crossChromosome(selecteChromosomeGroup,2);
%不用概率筛选出的染色体selecteChromosomeGroup进行杂交,而直接用上一代(父代)的
sonChromosomeGroup=crossChromosome(fatherChromosomeGroup,2);
%cro=bin2dec(sonChromosomeGroup)%显示杂交后的子代染色体
sonChromosomeGroup=checkSequence(sonChromosomeGroup,solutionN);%检查杂交后的染色体是否越界
%%%%%%%%%%%%%%%9:变异
%不杂交直接变异
%fatherChromosomeGroup=varianceCh(fatherChromosomeGroup,0.1,solutionN);
%杂交后变异
fatherChromosomeGroup=varianceCh(sonChromosomeGroup,0.1,solutionN);
fatherChromosomeGroup=checkSequence(fatherChromosomeGroup,solutionN);%检查变异后的染色体是否越界
end

frogfish 发表于 2007-7-3 22:22

函数(1):由染色体(可能解的2进制)顺序号找到可能解
%这个函数找出染色体(可能解的序号)对应的可能解x
function x=chromosome_x(chromosomeGroup,oneDimensionSet,solutionSum)
%chromosomeGroup:染色体,也是可能解的二进制序号
%oneDimensionSet:一维数轴上的可能解
%solutionSum:非线性方程组的元数,也就是待解方程中未知变量的个数
=size(oneDimensionSet);
%oneDimensionSetN:一维数轴上可能解的个数
chromosomeSum=size(chromosomeGroup);%chromosomeSum:染色体的个数
xSequence=bin2dec(chromosomeGroup);%把可能解的二进制序号(染色体)转换成十进制序号
for i=1:chromosomeSum%i:染色体的编号
remainder=xSequence(i);
for j=1:solutionSum
dProduct=oneDimensionSetN^(solutionSum-j);%sNproduct:
quotient=remainder/dProduct;
remainder=mod(remainder,dProduct);%mod:取余函数
if remainder==0
oneDimensionSetOrder=quotient;
%oneDimensionSetOrder:可能解在数轴上的序号
else
oneDimensionSetOrder=fix(quotient)+1;%fix:取整函数
end
if oneDimensionSetOrder==0
oneDimensionSetOrder=oneDimensionSetN;
end
x(i,j)=oneDimensionSet(oneDimensionSetOrder);
end
end

frogfish 发表于 2007-7-3 22:22

函数(2):把解代入非线性方程组计算绝对误差函数:function funtionError=nonLinearSumError1(X)%方程的解是-7,5,1,-3
funtionError=...
[
abs(X(:,1).^2-sin(X(:,2).^3)+X(:,3).^2-exp(X(:,4))-50.566253390821)+...
abs(X(:,1).^3+X(:,2).^2-X(:,4).^2+327)+...
abs(cos(X(:,1).^4)+X(:,2).^4-X(:,3).^3-624.679868769613)+...
abs(X(:,1).^4-X(:,2).^3+2.^X(:,3)-X(:,4).^4-2197)
];

frogfish 发表于 2007-7-3 22:22

函数(3):判定程是否得解函数:
%判断方程是否解开
function =isSolution(x,functionError,precision)
=min(functionError);%找到最小误差,最小误差所对应的行号
solution=x(xi,:);
if minError<precision
isTrue=1;
else
isTrue=0;
end

frogfish 发表于 2007-7-3 22:23

%函数(4):选择最优染色体函数:
%找出最小误差所对应的最好染色体,最大误差所对应的最坏染色体
function =best_worstChromosome(chromosomeGroup,functionError)
=min(functionError);
%=max(functionError);
bestChromosome=chromosomeGroup(minErrorOrder,:);
%worstChromosome=chromosomeGroup(maxErrorOrder,:);

frogfish 发表于 2007-7-3 22:23

函数(5):误差比较函数:从两个染色体中,选出误差较小的染色体
%选择最好的基因保留下来
function ...
=compareBestChromosome(oldBestChromosome,oldLeastFunctionError,...
bestChromosome,leastFunctionError)
if oldLeastFunctionError>leastFunctionError
newLeastFunctionError=leastFunctionError;
newBestChromosome=bestChromosome;
else
newLeastFunctionError=oldLeastFunctionError;
newBestChromosome=oldBestChromosome;
end

frogfish 发表于 2007-7-3 22:23

函数(6):为染色体定义概率函数,好的染色体概率高,坏染色体概率低
%根据待解的非线性函数的误差计算染色体的概率
function =chromosomeProbability(x_Error)
InfN=sum(isinf(x_Error));%估计非线性方程计算的结果
NaNN=sum(isnan(x_Error));
if InfN>0 || NaNN>0
isP='Fail';
p=0;
return
else
isP='True';
errorReciprocal=1./x_Error;
sumReciprocal=sum(errorReciprocal);
p=errorReciprocal/sumReciprocal;%p:可能解所对应的染色体的概率
end

frogfish 发表于 2007-7-3 22:24

函数(7):按概率选择染色体函数:
function chromosome=selecteChromosome(chromosomeGroup,p)
cumuP=cumsum(p);%累积概率,也就是把每个染色体的概率映射到0~1的区间
=size(chromosomeGroup);
for i=1:chromosomeSum%这个循环产生概率值
rN=rand(1);
if rN==1
chromosome(i,:)=chromosomeGroup(chromosomeSum,:);
elseif (0<=rN) && (rN<cumuP(1))
chromosome(i,:)=chromosomeGroup(1,:);%第1条染色体被选中
else
for j=2:chromosomeSum%这个循环确定第1条以后的哪一条染色体被选中
if (cumuP(j-1)<=rN) && (rN<cumuP(j))
chromosome(i,:)=chromosomeGroup(j,:);
break
end
end
end
end

frogfish 发表于 2007-7-3 22:24

函数(8):父代染色体杂交产生子代染色体函数
function sonChromosome=crossChromosome(fatherChromosome,parameter)
=size(fatherChromosome);
%chromosomeSum:染色体的条数;chromosomeLength:染色体的长度
switch parameter
case 1%随机选择父染色体进行交叉重组
for i=1:chromosomeSum/2
crossDot=fix(rand(1)*chromosomeLength);%随机选择染色体的交叉点位
randChromosomeSequence1=round(rand(1)*chromosomeSum);
%随机产生第1条染色体的序号
randChromosomeSequence2=round(rand(1)*chromosomeSum);
%随机产生第2条染色体的序号,这两条染色体要进行杂交
if randChromosomeSequence1==0%防止产生0序号
randChromosomeSequence1=1;
end
if randChromosomeSequence2==0%防止产生0序号
randChromosomeSequence2=1;
end
if crossDot==0 || crossDot==1
sonChromosome(i*2-1,:)=fatherChromosome(randChromosomeSequence1,:);
sonChromosome(i*2,:)=fatherChromosome(randChromosomeSequence2,:);
else
%执行两条染色体的交叉
sonChromosome(i*2-1,:)=fatherChromosome(randChromosomeSequence1,:);
%把父染色体整条传给子染色体
sonChromosome(i*2-1,crossDot:chromosomeLength)=...
fatherChromosome(randChromosomeSequence2,crossDot:chromosomeLength)
%下一条父染色体上交叉点crossDot后的基因传给子染色体,完成前一条染色体的交叉
sonChromosome(i*2,:)=fatherChromosome(randChromosomeSequence2,:);
sonChromosome(i*2,crossDot:chromosomeLength)...
=fatherChromosome(randChromosomeSequence1,crossDot:chromosomeLength)
end
end
case 2 %父染色体的第i号与第chromosomeSum+1-i号交叉
for i=1:chromosomeSum/2
crossDot=fix(rand(1)*chromosomeLength);%随机选择染色体的交叉点位
if crossDot==0 || crossDot==1
sonChromosome(i*2-1,:)=fatherChromosome(i,:);
sonChromosome(i*2,:)=fatherChromosome(chromosomeSum+1-i,:);
else
%执行两条染色体的交叉
sonChromosome(i*2-1,:)=fatherChromosome(i,:);%把父染色体整条传给子染色体
sonChromosome(i*2-1,crossDot:chromosomeLength)...
=fatherChromosome(chromosomeSum+1-i,crossDot:chromosomeLength);
%下一条父染色体上交叉点crossDot后的基因传给子染色体,完成前一条染色体的交叉
sonChromosome(i*2,:)=fatherChromosome(chromosomeSum+1-i,:);
sonChromosome(i*2,crossDot:chromosomeLength)...
=fatherChromosome(i,crossDot:chromosomeLength);
end
end
case 3 %父染色体的第i号与第i+chromosomeSum/2号交叉
for i=1:chromosomeSum/2
crossDot=fix(rand(1)*chromosomeLength);%随机选择染色体的交叉点位
if crossDot==0 || crossDot==1
sonChromosome(i*2-1,:)=fatherChromosome(i,:);
sonChromosome(i*2,:)=fatherChromosome(i+chromosomeSum/2,:);
else
%执行两条染色体的交叉
sonChromosome(i*2-1,:)=fatherChromosome(i,:);%把父染色体整条传给子染色体
sonChromosome(i*2-1,crossDot:chromosomeLength)...
=fatherChromosome(i+chromosomeSum/2,crossDot:chromosomeLength);
%下一条父染色体上交叉点crossDot后的基因传给子染色体,完成前一条染色体的交叉
sonChromosome(i*2,:)=fatherChromosome(i+chromosomeSum/2,:);
sonChromosome(i*2,crossDot:chromosomeLength)...
=fatherChromosome(i,crossDot:chromosomeLength);
end
end
end

frogfish 发表于 2007-7-3 22:25

函数(9):防止染色体超出解空间的函数
%检测染色体(序号)是否超出解空间的函数
function chromosome=checkSequence(chromosomeGroup,solutionSum)
=size(chromosomeGroup);
decimalChromosomeSequence=bin2dec(chromosomeGroup);
for i=1:chromosomeSum %检测变异后的染色体是否超出解空间
if decimalChromosomeSequence(i)>solutionSum
chRs=round(rand(1)*solutionSum);
if chRs==0
chRs=1;
end
decimalChromosomeSequence(i)=chRs;
end
end
chromosome=dec2bin(decimalChromosomeSequence,chromosomeLength);

frogfish 发表于 2007-7-3 22:25

函数(10):变异函数
%基因变异.染色体群中的1/10变异。vR是变异概率。solutionN是解空间中全部可能解的个数
function aberranceChromosomeGroup=varianceCh(chromosomeGroup,vR,solutionN)
=size(chromosomeGroup);
if chromosomeSum<10
N=1;
else
N=round(chromosomeSum/10);
end

if rand(1)>vR %变异操作
for i=1:N
chromosomeOrder=round(rand(1)*chromosomeSum);%产生变异染色体序号
if chromosomeOrder==0
chromosomeOrder=1;
end
aberrancePosition=round(rand(1)*chromosomeLength);%产生变异位置
if aberrancePosition==0
aberrancePosition=1;
end
if chromosomeGroup(chromosomeOrder,aberrancePosition)=='1'
chromosomeGroup(chromosomeOrder,aberrancePosition)='0';%变异
else
chromosomeGroup(chromosomeOrder,aberrancePosition)='1';%变异
end
end
aberranceChromosomeGroup=chromosomeGroup;
else
aberranceChromosomeGroup=chromosomeGroup;
end

来自搜狐博客=〉人工智能

zwf100 发表于 2008-3-22 11:24

谢谢楼主分享

tranlynn_lau 发表于 2008-5-6 09:19

Thanks a lot.~~~~~~~~~~~~~

gxumwl 发表于 2008-6-27 11:15

谢谢楼主分享,敢问楼主有没有关于非线性二阶微分方程组的程序?
页: [1]
查看完整版本: 遗传算法解非线性方程组