手机版 欢迎访问it开发者社区(www.mfbz.cn)网站

当前位置: > 开发

【ALGO】启发式算法求解案例(1)

时间:2021/6/6 13:03:11|来源:|点击: 次

Navigator

  • Demo 1: GA
    • Code
  • Demo2: GA
  • Demo3: GA
  • Demo4: EP
    • EP
    • CEP
    • SPMEP
    • 对比进化算法和GA的求解
  • Reference

Demo 1: GA

求下列函数的极大值
f ( x ) = sin ⁡ x x × sin ⁡ y y , − 10 ≤ x , y ≤ 10 f(x)=\frac{\sin x}{x}\times \frac{\sin y}{y}, -10\leq x, y\leq 10 f(x)=xsinx×ysiny,10x,y10

Code

function [max_x, max_fval] = MLYGA2(func, LB, UB, popsize, iter_max, px, pm, esp)
    %func: 待优化的目标函数
    % LB: 自变量的下界
    % UB: 自变量的上界
    % popsize: 种群大小
    % iter_max: 最大迭代次数
    % px: 交叉概率
    % pm: 变异概率
    % epsl: 自变量离散精度
    if isempty(pm)
        pm=0.1;
    end
    if isempty(px)
        px=0.90;
    end
    if isempty(iter_max)
        iter_max=8000;
    end
    if isempty(popsize)
        popsize=50;
    end
    if isempty(LB) && isempty(UB)
        nvar = input('请输入变量的数目nvar=');
    else
        nvar = size(LB, 1);
    end
    CodeLen = nvar*max(ceil(log2((UB-LB)/esp+1))); % 根据自变量的离散精度,确定二进制编码串的长度
    x = zeros(popsize, CodeLen); % 种群编码的初始值
    for i=1:popsize
        x(i, :)=init(CodeLen); % 调用子程序初始化种群
        FitValue(i) = func(Decl(LB, UB, x(i, :), CodeLen)); % 计算个体适应值
    end
    
    for j=1:iter_max
        SumFitValue = sum(FitValue); % 所有个体的适应值之和
        Ave_x = FitValue/SumFitValue;
        Prob_Ave_x=0;
        Prob_Ave_x(1)=Ave_x(1);
        for i=2:popsize
            Prob_Ave_x(i)=Prob_Ave_x(i-1)+Ave_x(i);
        end
        % operators
        % FaSelection = 1; % 设置默认值
        for k=1:popsize
            rd = rand;
            for n=1:popsize
                if rd<=Prob_Ave_x(n)
                    FaSelection = n;  % 由轮盘赌策略选择父代
                    break;
                end
            end

            MoSelection=floor(rand() * (popsize-1))+1; % 随机确定母代
            PosCrossover = floor(rand() * (CodeLen-2))+1; % 随机确定交叉点的位置
            r1 = rand;
            % 发生交叉操作
            if r1<=px
                nx(k, 1:PosCrossover) = x(FaSelection, 1:PosCrossover);
                nx(k, (PosCrossover+1):CodeLen) = x(MoSelection, (PosCrossover+1):CodeLen);
                r2 = rand;
                % 进行变异操作
                if r2<=pm
                    PosMutation = round(rand()*(CodeLen-1)+1); % 变异元素的位置
                    nx(k, PosMutation) = ~nx(k, PosMutation);
                end
            % 否则直接继承父代
            else
                nx(k, :)=x(FaSelection, :);
            end
        end
        x = nx;
        for m=1:popsize
                % 计算适应度函数值
                FitValue(m)=func(Decl(LB, UB, x(m, :), CodeLen));
        end
        [~, index]=max(FitValue); % 目标函数为求取极大值
        best = x(index, :);
        x(popsize, :)=best;
    end
    max_x = Decl(LB, UB, best, CodeLen); 
    max_fval = func(max_x);
end

% 初始化函数, 进行二进制编码
function y = init(L)
        for i=1:L
                y(i) = round(rand());
        end
end

% 二进制编码转回十进制编码
function y=Decl(LB, UB, x, CodeLen)
        nvar = size(LB, 1);
        sublen = CodeLen/nvar;
        bit_w = 2.^(0:sublen); % 计算位权
        maxintval = 2^sublen-1;
        range = UB'-LB';
        start = 1;
        fin = sublen;
        for j = 1:nvar
                tvars(1:sublen)=x(start:fin);
                start = start+sublen;
                fin = fin+sublen;
                t_sum = 0;
                for k=1:sublen
                        t_sum = t_sum+bit_w(k)*tvars(sublen-k+1);
                end
                y(j)=(range(j)*(t_sum/maxintval))+LB(j);
        end
end

Demo2: GA

使用二进制编码,编写GA算法求解

function [max_x, max_fval] = MLYGA2(func, LB, UB, popsize, iter_max, px, pm, esp)
    %func: 待优化的目标函数
    % LB: 自变量的下界
    % UB: 自变量的上界
    % popsize: 种群大小
    % iter_max: 最大迭代次数
    % px: 交叉概率
    % pm: 变异概率
    % epsl: 自变量离散精度
    
    if isempty(pm)
        pm=0.1;
    end
    if isempty(px)
        px=0.90;
    end
    if isempty(iter_max)
        iter_max=8000;
    end
    if isempty(popsize)
        popsize=50;
    end
    if isempty(LB) && isempty(UB)
        nvar = input('请输入变量的数目nvar=');
    else
        nvar = size(LB, 1);
    end
    global fitall
    fitall = zeros(1, iter_max);
    CodeLen = nvar*max(ceil(log2((UB-LB)/esp+1))); % 根据自变量的离散精度,确定二进制编码串的长度
    x = zeros(popsize, CodeLen); % 种群编码的初始值
    for i=1:popsize
        x(i, :)=init(CodeLen); % 调用子程序初始化种群
        FitValue(i) = func(Decl(LB, UB, x(i, :), CodeLen)); % 计算个体适应值
    end
    
    for j=1:iter_max
        SumFitValue = sum(FitValue); % 所有个体的适应值之和
        Ave_x = FitValue/SumFitValue;
        Prob_Ave_x=0;
        Prob_Ave_x(1)=Ave_x(1);
        for i=2:popsize
            Prob_Ave_x(i)=Prob_Ave_x(i-1)+Ave_x(i);
        end
        % operators
        % FaSelection = 1; % 设置默认值
        for k=1:popsize
            rd = rand;
            for n=1:popsize
                if rd<=Prob_Ave_x(n)
                    FaSelection = n;  % 由轮盘赌策略选择父代
                    break;
                end
            end

            MoSelection=floor(rand() * (popsize-1))+1; % 随机确定母代
            PosCrossover = floor(rand() * (CodeLen-2))+1; % 随机确定交叉点的位置
            r1 = rand;
            % 发生交叉操作
            if r1<=px
                nx(k, 1:PosCrossover) = x(FaSelection, 1:PosCrossover);
                nx(k, (PosCrossover+1):CodeLen) = x(MoSelection, (PosCrossover+1):CodeLen);
                r2 = rand;
                % 进行变异操作
                if r2<=pm
                    PosMutation = round(rand()*(CodeLen-1)+1); % 变异元素的位置
                    nx(k, PosMutation) = ~nx(k, PosMutation);
                end
            % 否则直接继承父代
            else
                nx(k, :)=x(FaSelection, :);
            end
        end
        x = nx;
        for m=1:popsize
                % 计算适应度函数值
                FitValue(m)=func(Decl(LB, UB, x(m, :), CodeLen));
        end
        [bestV, index]=max(FitValue); % 目标函数为求取极大值
        best = x(index, :);
        x(popsize, :)=best;
        fitall(j)=bestV;
    end
    max_x = Decl(LB, UB, best, CodeLen); 
    max_fval = func(max_x);
end

% 初始化函数, 进行二进制编码
function y = init(L)
        for i=1:L
                y(i) = round(rand());
        end
end

% 二进制编码转回十进制编码
function y=Decl(LB, UB, x, CodeLen)
        nvar = size(LB, 1);
        sublen = CodeLen/nvar;
        bit_w = 2.^(0:sublen); % 计算位权
        maxintval = 2^sublen-1;
        range = UB'-LB';
        start = 1;
        fin = sublen;
        for j = 1:nvar
                tvars(1:sublen)=x(start:fin);
                start = start+sublen;
                fin = fin+sublen;
                t_sum = 0;
                for k=1:sublen
                        t_sum = t_sum+bit_w(k)*tvars(sublen-k+1);
                end
                y(j)=(range(j)*(t_sum/maxintval))+LB(j);
        end
end

GA_binary
使用MATLAB自带的GA工具箱求解

% 使用自带的GA工具箱求解
global fitall_ga;
fitall_ga = zeros(1, Ngen);
% ops = optimoptions('ga', 'Generations', Ngen, 'PlotFcn', @gaplotbestf);
ops = optimoptions('ga', 'Generations', Ngen, 'OutputFcn', @myout, 'CrossoverFraction', 0.2);
[max_x_ga, maxfval_ga, ~, output, population, scores] = ga(@obj_func_3x, 2, [], [], [], [], LB, UB, [], ops);
plot(1:output.generations, -fitall_ga(:, 1:output.generations));
grid on;

GA

Demo3: GA

求解下列函数的最小值
f ( x ) = − x 2 + 2 x + 0.5 , − 10 ≤ x , y ≤ 10 f(x)=-x^2+2x+0.5, -10\leq x, y\leq 10 f(x)=x2+2x+0.5,10x,y10
主函数

%%
[MinValue, MinFunc]=MLYGA3(@obj_func_3r, -10, 10, 0.001);
% GA工具箱求解
[x_ga, MinFunc_ga, ~, output, population, scores] = ga(@obj_func_3r, 1, [], [], [], [], -10, 10);

实数编码GA求解

function [MinValue, MinFunc] = MLYGA3(func, LB, UB, eps)
        %eps为精度
        n = ceil(log2((UB-LB)/eps+1));
        individual = {};
        for i=1:n
                individual = [individual; [0 1]];
        end
        individualCode = exhaus(individual); % 枚举所有可能排列
        % 染色体编码对应的10进制数
        individualCodeValue = zeros(1, 2^n);
        for i=1:2^n
                for j=1:n
                        individualCodeValue(i)=individualCodeValue(i)+individualCode(i, j)*2^(n-j);
                end
        end
        % 染色体编码对应给定定义域的实数(real-code)
        CodeValue=zeros(1, 2^n);
        for k=1:2^n
                CodeValue(k)=CodeValue(k)+LB+individualCodeValue(k)*(UB-LB)/(2^n-1);
        end
        % 始终令第一个值为最小值
        MinFunc=func(CodeValue(1));
        MinIndividual = individualCode(1);
        MinValue = CodeValue(1);
        for i=2:2^n
                FuncValue(i)=func(CodeValue(i));
                if FuncValue(i)<MinFunc
                        MinFunc=FuncValue(i);
                        MinIndividual = individualCode(i);
                        MinValue = CodeValue(i);
                end
        end
end

Demo4: EP

使用进化计算求解
f i ( x ) = ∑ i = 1 n [ x i 2 − 10 cos ⁡ ( 2 π x i ) + 10 ] , ∣ x i ∣ ≤ 5.12 f_i(x)=\sum_{i=1}^n[x_i^2-10\cos(2\pi x_i)+10], |x_i|\leq 5.12 fi(x)=i=1n[xi210cos(2πxi)+10],xi5.12
与遗传算法的出发点不同, 进化规划是从整体的角度出发来模拟生物的进化过程,在进化规划中不使用交叉等个体重组的算子,所以在进化规划中,个体的变异操作是唯一的个体最优搜索方法. 高斯变异算子是在变异过程中,通过计算每个个体适应度函数值的线性变换的平方根来获得该个体变异的标准差 σ i \sigma_i σi,并将每个分量上加上一个服从正态分布的随机数
X ( t + 1 ) = X ( t ) + N ( 0 , σ ) σ ( t + 1 ) = β F ( X ( t ) ) + γ x i ( t + 1 ) = x i ( t ) + N ( 0 , σ ( t + 1 ) ) \begin{aligned} &X(t+1)=X(t)+N(0, \sigma)\\ &\sigma(t+1)=\sqrt{\beta F(X(t))+\gamma}\\ &x_i(t+1)=x_i(t)+N(0, \sigma(t+1)) \end{aligned} X(t+1)=X(t)+N(0,σ)σ(t+1)=βF(X(t))+γ xi(t+1)=xi(t)+N(0,σ(t+1))

EP

进化规划中,选择操作是按照一种随机竞争的方式,根据适应度函数值从父代和子代的 2 N 2N 2N个个体中选择 N N N个较好的个体组成下一代种群。选择方法有按照概率选择,锦标赛选择和精英选择三种,常用的是锦标赛选择:

  1. N N N个父代个体组成的种群和经过一次变异运算后得到的 N N N个子代个体合并,组成一个共含有 2 N 2N 2N个个体的集合 I I I.
  2. 对每个个体 x i ∈ I x_i\in I xiI,从 I I I中随机选择 q q q个个体,并将 q q q个个体的适应度函数值与 x i x_i xi的适应度函数做比较,计算这 q ( q ≥ 1 ) q(q\geq 1) q(q1)个个体中适应度函数值比 x i x_i xi的适应度差的个体数量 w i w_i wi,并将 w i w_i wi作为 x i x_i xi的得分.
  3. 在所有 2 N 2N 2N个体都经过比较后,按每个个体的得分 w i w_i wi进行排序,选择 N N N个具有最高得分的个体作为下一代种群.

可以发现, q q q值是选择算子的关键,当 q q q值较大时,算子偏向确定性选择;当 q = 2 N q=2N q=2N时,算子确定从 2 N 2N 2N个个体中选择 N N N个适应度较高的个体,容易出现早熟等弊端. 而当 q q q值取值较小时,算子偏向于随机性选择,使得适应度的控制能力下降,导致大量低适应度值的个体被选出,造成种群退化.

CEP

自适应的标准进化规划算法

  1. 随机产生由 μ \mu μ个个体组成的种群,并设 k = 1 k=1 k=1,每个个体用一个实数对 ( x i , η i ) , ∀ i ∈ { 1 , 2 , … , μ } (x_i, \eta_i), \forall i\in\{1,2,\dots, \mu\} (xi,ηi),i{1,2,,μ}表示,其中 x i x_i xi是目标变量, η i \eta_i ηi是正态分布标准差.
  2. 计算种群中每个个体关于目标函数的适应度函数值,在求解函数最小问题中,适应度函数值即为目标函数值 f ( x i ) f(x_i) f(xi).
  3. 对于每个个体 ( x i , η i ) (x_i, \eta_i) (xi,ηi),通过以下方法产生唯一的后代 ( x i ′ , η i ′ ) (x_i',\eta_i') (xi,ηi).
    x i ′ ( j ) = x i ( j ) + η i ( j ) N j ( 0 , 1 ) η i ′ = η i ( j ) exp ⁡ ( τ ′ N ( 0 , 1 ) + τ N j ( 0 , 1 ) ) \begin{aligned} &x_i'(j)=x_i(j)+\eta_i(j)N_j(0, 1)\\ &\eta'_i=\eta_i(j)\exp(\tau'N(0, 1)+\tau N_j(0, 1)) \end{aligned} xi(j)=xi(j)+ηi(j)Nj(0,1)ηi=ηi(j)exp(τN(0,1)+τNj(0,1))

SPMEP

单点变异算法是在CEP算法的基础上对个体的变异方法进行改进,在每次迭代中,仅对每个父代个体中的一个分量执行变异操作,提高了计算效率. 在SPMEP算法中后代产生的方法为
x i ′ ( j i ) = x i ( j i ) + η i N i ( 0 , 1 ) η i ′ ( j ) = η i ( j ) exp ⁡ ( − α ) \begin{aligned} &x'_i(j_i)=x_i(j_i)+\eta_iN_i(0, 1)\\ &\eta'_i(j)=\eta_i(j)\exp(-\alpha) \end{aligned} xi(ji)=xi(ji)+ηiNi(0,1)ηi(j)=ηi(j)exp(α)
其中 α = 1.01 \alpha=1.01 α=1.01,SPMEP算法求解高维多模函数问题具有明显的优越性,该算法也具有良好的稳定性.

对比进化算法和GA的求解

function [minx, minf]=MLYEP(func, popsize, iter_max, LB, UB, type)
        global fitall
        nvar = size(LB, 1); % 得到变量的个数
        tau1=sqrt(2*nvar)^(-1); % CEP中的进化参数t1
        tau2=sqrt(2*sqrt(nvar))^(-1); % CEP中的进化参数t2
        q = round(0.9*popsize); % q值的设定,每次考虑90%的种群个体
        chome=zeros(popsize, nvar);
        for i=1:popsize
                for j=1:nvar
                        chome(:, j)=unifrnd(LB(j), UB(j), popsize, 1); % 初始化
                        chomeLambda(j)=(UB(j)-LB(j))/2;
                        chomeVar(j)=var(chome(:, j));
                end
                chomeV(i, 1)=func(chome(i, :)); % 计算适应度
                chomeSigma(i, 1)=sqrt(chomeV(i, 1));
        end
        [a, b]=sort(chomeV);
        chome=chome(b, :);
        chomeV=chomeV(b);
        chomeSigma=chomeSigma(b);
        minx=chome(1, :);
        minf=chomeV(1);
        for i=1:iter_max
                if type==1   % 标准
                        for j=1:popsize
                                for k=1:nvar
                                        newchome(j, k)=chome(j, k)+normrnd(0, chomeSigma(k), 1, 1);
                                        newchome(j, k)=boundtest(newchome(j, k), LB(k), UB(k)); % 进行边界检测
                                end
                        end
                elseif type==2  % 自适应, 使用一对实数对表示个体
                        for j=1:popsize
                                a = randn;
                                for k=1:nvar
                                        newchome(j, k)=chome(j, k)+randn*chomeVar(k);
                                        newchome(j, k)=boundtest(newchome(j, k), LB(k), UB(k));
                                        chomeVar(k)=chomeVar(k)*exp(tau1*a+tau2*randn);
                                end
                        end
                elseif type==3 % 单点变异
                        for j=1:popsize
                                b1 = ceil(nvar*rand);
                                if chomeLambda(b1)<1e-4
                                        chomeLambda(b1)=(UB(b1)-LB(b1))/2;
                                end
                                newchome(j, b1)=chome(j, b1)+chomeLambda(b1)*randn;
                                newchome(j, b1)=boundtest(newchome(j, b1), LB(b1), UB(b1));
                                chomeLambda(b1)=chomeLambda(b1)*exp(-1.01);
                        end
                end
                for j=1:popsize
                        newchomeV(j, 1)=func(newchome(j, :));
                end
                chome=EPSelect(chome, newchome, chomeV, newchomeV, q); % 选择子代
                for j=1:popsize
                        chomeV(j, 1)=func(chome(j, :));
                        chomeSigma(j, 1)=sqrt(chomeV(j, 1));
                end
                [~, b]=sort(chomeV); % 根据适应度值进行排序
                chome=chome(b, :);
                chomeV = chomeV(b);
                chomeSigma = chomeSigma(b);
                if minf>chomeV(1)
                        minx=chome(1, :);
                        minf=chomeV(1);
                end
                fitall(i)=minf;
        end
end

% 选择算子
function chome=EPSelect(old, new, oldF, newF, q)
        num=size(old, 1);
        total_chome=[old; new]; % 合并父代和子代
        total_F = [oldF; newF]; % 合并父代和子代的适应度函数
        competitor = randperm(2*num);
        for i=1:2*num
                score = 0;
                for j=1:q
                        if total_F(i)<total_F(competitor(j))
                                score = score+1;
                        end
                end
                templ(i)=score;
        end
        [~, b]=sort(templ, 'descend');
        total_chome=total_chome(b, :);
        chome=total_chome(1:num, :);
end

function y=boundtest(x, LB, UB)
        if x>=UB
                y=LB+(x-UB);
        elseif x<=LB
                y=UB-(LB-x);
        else
                y=x;
        end
end

SPMEP适应度曲线(EP和CEP陷入到了局部最优之中)
F1GA工具箱求解

%% GA求解
global fitall_ga;
fitall_ga = zeros(1, iter_max);
ops = optimoptions('ga', 'Generations', iter_max, 'OutputFcn', @myout);
[minx_ga, minf_ga, ~, output, population, scores]=ga(@obj_func_7x, 10, [], [], [], [], LB, UB,[],ops);
plot(1:output.generations, fitall_ga(:, 1:output.generations));
grid on;

F2

Reference

最优化方法及其Matlab实现

Copyright © 2002-2019 某某自媒体运营 版权所有