通常非线性整数规划是一个具有指数复杂度的NP问题。如果约束较为复杂,MATLAB优化工具箱和一些优化软件如lingo等,常常无法应用,即使能应用也不能给出一个较为令人满意的解。这时就需要针对问题设计专门的优化算法。
将遗传算法应用于非线性规划,是提高最优化质量改善收敛效果的有效途径。下述遗传算法在非线性规划中的具体应用,设计并实现求解非线性规划问题的遗传算法。
例 标准遗传算法的一个重要 概念是染色体是可能解的二进制顺序号,由这个序号在可能解的集合(解空间)中找到可能解。运用遗传算法求解设定的非线性方程组。
分析:这是遗传算法由染色体(可能解的二进制)顺序号找到可能解,把解代入设定的非线性方程组计算误差函数,判定方程组是否有解函数,选择最优染色体函数。
解:遗传算法程序的流程如下:
主函数
%主函数%
clc;
clear all;
circleN = 200; %迭代次数
format long
%%%%%%%构造可能解的空间,确定染色体的个数、长度%%%%%%
solutionSum = 4;
leftBoundary= -10;
rightBoundary = 10;
distance= 1;
chromosomeSum = 500; %染色体的个数
solutionSumError = 0.1; %解的误差
oneDimensionSet =leftBoundary:distance:rightBoundary;
oneDimensionSetN = size(oneDimensionSet,2); %返回oneDimensionSet中的元素个数
solutionN = oneDimensionSetN^solutionSum; %解空间(解集合)中可能解的总数
binSolutionN = dec2bin(solutionN) ; %把可能解的总数转换成二进制数
chromosomeLength = size( binSolutionN,2); %由解空间中可能解的总数(二进制数)计算染色体的长度
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%程序初始化%%%%%%%%%%%%%%%%%%
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; %记录迭代次数
%%%%%%%%%%%%%由可能解的序号寻找解本身%%%%%%%%%%%%%%%
x = chromosome_x(fatherChromosomeGroup,oneDimensionSet,solutionSum);
%%%%%%%%%%%%%把解代入非线性方程计算误差%%%%%%%%%%%%%
functionError = nonLinearSumError1(x); %把解代入方程计算误差
[solution, minError, isTrue] = isSolution( x, functionError, solutionSumError);
if isTrue == 1
disp('方程得解')
disp(solution)
disp(minError)
disp(circle)
return %站束程序
end
%%%%%%%%%%%选择最优解对应的最优染色体%%%%%%%%%%%%%
[bestChromosome, leastFunctionError] = best_worstChromosome( fatherChromosomeGroup,functionError);
%%%%%%%%%%%保留每次选代产生的最优染色体%%%%%%%%%%%
[holdBestChromosome, holdLeastFunctionError]...
= compareBestChromosome(holdBestChromosome,holdLeastFunctionError,...
bestChromosome,leastFunctionError);
%%%%%%%%%%%把保留的最优染色体加入到染色体群中%%%%%%
order = round(rand(1) * chromosomeSum);
if order == 0
order = 1;
end
fatherChromosomeGroup(order,:) = holdBestChromosome;
functionError(order) = holdLeastFunctionError;
%%%%%%%%%%%%%为每一条染色体,即可能解的序号定义一个概率%%%%%%%%
[p,trueP] = chromosomeProbability(functionError);
if trueP == 'Fail'
disp( '可能解严重不适应方程,请重新开始');
return %结束程序
end
%%%%%%%%%%%%%按照概率筛选染色体%%%%%%%%%%
fa = bin2dec(fatherChromosomeGroup); %显示父染色体
%从父染体中选择优秀染色体
selecteChromosomeGroup = selecteChromosome(fatherChromosomeGroup,p);
%%%%%%%%%%%%%染色体杂交%%%%%%%%%%%
sle = bin2dec(selecteChromosomeGroup);
sonChromosomeGroup = crossChromosome(selecteChromosomeGroup, 2);
sonChromosomeGroup = crossChromosome(fatherChromosomeGroup, 2);
sonChromosomeGroup = checkSequence( sonChromosomeGroup, solutionN);
%检查杂交后的染色体是否越界
%%%%%%%%%%杂交后变异%%%%%%%%%%
fatherChromosomeGroup = varianceCh(sonChromosomeGroup, 0.1, solutionN);
fatherChromosomeGroup = checkSequence(fatherChromosomeGroup ,solutionN); %检查变异后的染色体是否越界
end
子函数
%由染色体(可能解的二进制)顺序号找到可能解
%这个函数找出染色体(可能解的序号)对应的可能解x
function x = chromosome_x( chromosomeGroup, oneDimensionSet, solutionSum )
%chromosomeGroup:染色体,也是可能解的二进制序号
%oneDinensionSet:一维数轴上的可能解
%solutionSum:非线性方程组的元数,也就是待解方程中未知变量的个数
[~, oneDimensionSetN] = size(oneDimensionSet);
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;
else
oneDimensionSetOrder = fix(quotient) + 1; %fix:取整函数
end
if oneDimensionSetOrder == 0
oneDimensionSetOrder = oneDimensionSetN;
end
x(i,j) = oneDimensionSet(oneDimensionSetOrder);
end
end
end
%把解代入非线性方程组计算绝对误差函数
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)
];
end
%判定程序是否得解函数
function [ solution, minError, isTrue] = isSolution( x, functionError, precision)
[minError, xi]= min( functionError); %找到最小误差,最小误差所对应的行号
solution= x(xi,:);
if minError < precision
isTrue= 1;
else
isTrue= 0;
end
end
%选择最优染色体函数
%找出最小误差所对应的最优染色体,最大误差所对应的最环染色体
function [ bestChromosome, leastFunctionError] = best_worstChromosome( chromosomeGroup,functionError)
[leastFunctionError, minErrorOrder] = min( functionError);
bestChromosome = chromosomeGroup( minErrorOrder, :);
end
%误差比较函数:从两个染色体中选出误差较小的染色体保留下来
function [newBestChromosome, newLeastFunctionError]...
= compareBestChromosome(oldBestChromosome, oldLeastFunctionError,...
bestChromosome, leastFunctionError)
if oldLeastFunctionError > leastFunctionError
newLeastFunctionError = leastFunctionError;
newBestChromosome = bestChromosome;
else
newLeastFunctionError = oldLeastFunctionError;
newBestChromosome = oldBestChromosome;
end
%按概率选择染色体函数
function chromosome = selecteChromosome(chromosomeGroup, p)
cumuP = cumsum(p); %累积概率,也就是把每个染色体的概率映射到0~1的区间
[chromosomeSum, chromosomeLength] = 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
end
%父代染色体杂交产生子代染色体函数
function sonChromosome = crossChromosome( fatherChromosome, parameter)
[chromosomeSum, chromosomeLength] = size( fatherChromosome);
%chromosomeSum:染色体的条数; chromosomeLength:染色体的长度
switch parameter
case 1 %随机选择父染色体进行交叉重组
for i= 1:chromosomeSum/2
crossDot = fix(rand(1) * chromosomeLength); %随机选择染色体的交叉点位
randChromosomeSequencel = round( rand(1) * chromosomeSun);
%随机产生第1条染色体的序号
randChromosomeSequence2 = round(rand(1) * chromosomeSum);
%随机产生第2条染色体的序号,这两条染色体要进行杂交
if randChromosomeSequencel == 0 %防止产生0序号
randChromosomeSequencel = 1;
end
if randChromosoneSequence2 == 0 %防止产生0序号
randChromosomeSequence2 = 1;
end
if crossDot == 0 || crossDot == 1
sonChromosome(i*2-1,:)= fatherChromosome( randChromosomeSequencel,:);
sonChromosome(i*2, :) = fatherChromosome( randChromosomeSequence2,:);
else
%执行两条染色体的交叉
sonChromosome(i*2-1,:) = fatherChromosome( randChromosomeSequencel,:);
%把父染色体整条传给子染色体
sonChromosome(i*2- 1, crossDot:chromosomeLength) = ...
fatherChromosome( randChromosomeSequence2, crossDot :chromosomeLength);
%下一条父染色体上交叉点crossDot后的基固传给子染色体,完成前一条染色体的交叉
sonChromosome(i*2,:) = fatherChromosome( randChromosomeSequence2,:);
sonChromosome(i*2, crossDot : chrcmosomeLength)...
= fatherChromosome(randChromosomeSequencel, crossDot :chromosomeLength);
end
end
case 2 %父染色体的第1号与第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(1*2-1,:) = fatherChromosome(1,:); %把父染色体整条传给子染色体
sonChromosome(i*2-1, crossDot : chromosomeLength)...
= fatherChromosome(i +chromosoneSua/2, crossDot : chromosomeLength);
%下一条父染色体上交叉点crossDot后的基因传给子染色体,完成前一条染色体的交叉
sonChronosone(i*2,:) = fatherChromosome(i +chromosomeSun/2, :);
sonChromosome(i*2, crossDot : chromosomeLength)...
= fatherChromosome(i, crossDot : chromosomeLength);
end
end
end
end
%防止染色体超出解空间的函数
%检测染色体(序号)是否超出解空间的函数
function chromosome = checkSequence( chromosomeGroup, solutionSum)
[chromosomeSum, chromosomeLength]= 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);
end
%变异函数
%基因变异。染色体群中的1/10变异,R是变异概率。solutionN是解空间中全部可能解的个数
function aberranceChromosomeGroup = varianceCh(chromosomeGroup, vR, solutionN)
[chromosomeSum, chromosomeLength] = 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
end
%为染色体定义概率函数,好染色体概率高,坏染色体概率低
%根据待解的非线性函数的误差计算染色体的概率
function [p, isP] = 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
end