遗传算法(matlab实现)
计算智能理论与方法课程作业
遗传算法求解如下问题: MIN f ( x ) = ( x − 3 ) 2 x ∈ { 0 , 1 , 2 , 3 , 4 , 5 , … , 15 } \text { MIN } f(x)=(\mathrm{x}-3)^{2} \quad \mathrm{x} \in\{0,1,2,3,4,5, \ldots, 15\} MIN f(x)=(x−3)2x∈{0,1,2,3,4,5,…,15}
迭代个体数目为4,采用格雷码和二进制编码,变异概率取编码长度倒数,筛选方式为轮盘赌和锦标赛算法。
一、执行效果
其中蓝色曲线为原函数,红色圆点为父代,蓝色圆点为筛选后的子代,最后红色三角点为迭代筛选结果。
二、算法流程图与实现
1. 算法流程图
2. 算法实现
-
编码与解码
-
二进制与十进制的相互转化
- 十进制转二进制
% 十进制转二进制 function [bin] = my_dec2bin(dec,nums) % bin:输出的二进制数据,dec:输入的十进制数据,nums:编码位数 cols = size(dec, 2); bin = zeros(nums, cols); % 初始化二进制矩阵 for i = 1:cols % 计算二进制表示 num = dec(1, i); for j = nums:-1:1 bin(i, j) = mod(num, 2); % 计算余数并填充到矩阵 num = floor(num / 2); % 整数除以2 end end end
- 二进制转十进制
% 二进制转十进制 function [x] = my_bin2dec(mat) % x:十进制输出,mat:二进制输入 rows = size(mat, 1); cols = size(mat, 2); x = zeros(rows,1); for ir = 1:rows for ic = 1:cols if mat(ir,ic) x(ir,1) = x(ir,1) + 2^(cols-ic); end end end end
-
编码与解码
基于前面的二进制十进制转换函数实现对十进制与二进制码/格雷码的编码与解码,其中参数WayOfCoding用于设置编码方式。
- 编码
% 编码 function [x_DNA] = encode(x,WayOfCoding) x_bin = my_dec2bin(x,4); if WayOfCoding == 1 % 二进制编码 x_DNA = x_bin; elseif WayOfCoding == 0 % 格雷码编码 x_r1 = my_dec2bin(bitshift(x, -1),4); % 右移一位在编码为二进制 % 计算格雷码 x_DNA = xor(x_bin,x_r1); end end
- 解码
% 解码 function [x] = decode(x_DNA,WayOfCoding) rows = size(x_DNA,1); cols = size(x_DNA,2); if WayOfCoding==1 % 二进制解码 x = my_bin2dec(x_DNA); elseif WayOfCoding==0 % 格雷码解码 % 转化为二进制码 x_bin = zeros(rows, cols); for i = 1:rows x_bin(i,1) = x_DNA(i,1); % 最高位 % 逐位进行异或运算 for j = 2:cols x_bin(i,j) = xor(x_bin(i,j-1), x_DNA(i,j)); end end x = my_bin2dec(x_bin); end end
-
交叉与变异
将4个父代的基因通过一个4x4的矩阵描述,通过对矩阵的行元素进行操作实现基于的交叉与变异。
基于如下公式进行交叉操作:
{ y ( i 1 ) ( 1 : r − 1 ) = x ( i 1 ) ( 1 : r − 1 ) y ( i 2 ) ( 1 : r − 1 ) = x ( i 2 ) ( 1 : r − 1 ) + { y ( i 1 ) ( r : D ) = x ( i 2 ) ( r : D ) y ( i 2 ) ( r : D ) = x ( i 1 ) ( r : D ) \left\{\begin{array}{l}\boldsymbol{y}^{\left(i_{1}\right)}(1: r-1)=\boldsymbol{x}^{\left(i_{1}\right)}(1: r-1) \\\boldsymbol{y}^{\left(i_{2}\right)}(1: r-1)=\boldsymbol{x}^{\left(i_{2}\right)}(1: r-1)\end{array}+\left\{\begin{array}{l}\boldsymbol{y}^{\left(i_{1}\right)}(r: D)=\boldsymbol{x}^{\left(i_{2}\right)}(r: D) \\\boldsymbol{y}^{\left(i_{2}\right)}(r: D)=\boldsymbol{x}^{\left(i_{1}\right)}(r: D)\end{array}\right.\right. {y(i1)(1:r−1)=x(i1)(1:r−1)y(i2)(1:r−1)=x(i2)(1:r−1)+{y(i1)(r:D)=x(i2)(r:D)y(i2)(r:D)=x(i1)(r:D)
% 交叉 % --确定交叉端 r_index=[2,3,4]; r1 = r_index(randi(3)); r2 = r_index(randi(3)); % --交叉后的子代echild_mat child_mat = father_mat; % --交换片段1 ex_part = child_mat(1, r1:4); child_mat(1, r1:4) = child_mat(2, r1:4); child_mat(2, r1:4) = ex_part; % --交换片段2 ex_part = child_mat(3, r2:4); child_mat(3, r2:4) = child_mat(4, r2:4); child_mat(4, r2:4) = ex_part;
变异操作采用随机选择一个基因位点进行取反操作。
% 变异 for i_muta = 1:4 if rand()<Pm % ---变异位置 timesofmuta = timesofmuta + 1; r_m_index=[1,2,3,4]; r_m = r_m_index(randi(4)); child_mat(i_muta, r_m) = ~child_mat(i_muta, r_m); end end
-
选择
筛选前需要将子代与父代进行合并,再计算其表现型
% (4) 合并子代与父代 all_mat = [father_mat;child_mat]; % 垂直拼接 % (5) 解码 x_childs = decode(all_mat,WayOfcoding); % (6) 子代表现形 y_childs = f(x_childs);
基于表现型进行筛选,采用轮盘赌和锦标赛算法模拟自然选择。
- 轮盘赌算法
依据个体的表现形算出被选择的概率,通过轮盘赌算法选出新的子代。代码实现如下:
% 归一化 P_d = 1./(y_childs+0.0001); P_Sum = sum(P_d, 'all'); P_Child = P_d/P_Sum; % 计算累计密度 Pf_Child = zeros(1,8); for pi = 1:8 for pc = 1:pi Pf_Child(pi) = Pf_Child(pi) + P_Child(pc); end end % 轮盘赌,选择下一批迭代个体 for in = 1:4 Pr = rand(); for pif = 1:8 if Pf_Child(pif) >= Pr x_father(in) = x_childs(pif); break; end end end
- 锦标赛算法
父代子代二选一,算法数学描述为:
S = { s ( 1 ) , s ( 2 ) , … , s ( 2 M ) } = { x ( 1 ) , x ( 2 ) , … , x ( M ) , y ( 1 ) , y ( 2 ) , … , y ( M ) } , x ( i ) = { s ( i ) if s ( i ) is better than s ( i + M ) S ( i + M ) else \begin{array}{l}\boldsymbol{S}=\left\{\boldsymbol{s}^{(1)}, \boldsymbol{s}^{(2)}, \ldots, \boldsymbol{s}^{(2 M)}\right\}=\left\{\boldsymbol{x}^{(1)}, \boldsymbol{x}^{(2)}, \ldots, \boldsymbol{x}^{(M)}, \boldsymbol{y}^{(1)}, \boldsymbol{y}^{(2)}, \ldots, \boldsymbol{y}^{(M)}\right\}, \\\boldsymbol{x}^{(i)}=\left\{\begin{array}{lc}\boldsymbol{s}^{(i)} & \text { if } \boldsymbol{s}^{(i)} \text { is better than } \boldsymbol{s}^{(i+M)} \\\boldsymbol{S}^{(i+M)} & \text { else }\end{array}\right.\end{array} S={s(1),s(2),…,s(2M)}={x(1),x(2),…,x(M),y(1),y(2),…,y(M)},x(i)={s(i)S(i+M) if s(i) is better than s(i+M) else
代码实现:
% 子代,父代二选一 for ij = 1:Nums if y_childs(ij) > y_childs(ij+Nums) x_father(ij) = x_childs(ij+Nums); else x_father(ij) = x_childs(ij); end end
最后选择出新的子代,重复上述过进行迭代直到满足结束条件(达到迭代次数/多代不变)。
结果分析
循环运行500次,计算平均运行时间、最优解率、平均最优解、标准差、相对标准差;
-
测试结果(1)
编码方式:二进制编码
选择方式:轮盘赌迭代次数 平均运行时间(s) 最优解率(%) 平均最优解 标准差 相对标准差(%) _______ _____________ __________ _________ _______ ___________ 10 8.5748e-05 63.8 3.294 0.76729 23.294
-
测试结果(2)
编码方式:格雷码编码
选择方式:轮盘赌迭代次数 平均运行时间(s) 最优解率(%) 平均最优解 标准差 相对标准差(%) _______ _____________ __________ _________ _______ ___________ 10 0.00012561 87.4 3.044 0.77412 25.431
-
测试结果(3)
编码方式:格雷码编码
选择方式:锦标赛迭代次数 平均运行时间(s) 最优解率(%) 平均最优解 标准差 相对标准差(%) _______ _____________ __________ _________ _______ ___________ 10 0.00011234 74.2 3.07 0.90262 29.401
-
测试结果(4)
编码方式:二进制编码
选择方式:锦标赛迭代次数 平均运行时间(s) 最优解率(%) 平均最优解 标准差 相对标准差(%) _______ _____________ __________ _________ _______ ___________ 10 8.5653e-05 60 3.178 0.71227 22.413
-
测试结果(5)
编码方式:格雷码编码
选择方式:轮盘赌迭代次数 平均运行时间(s) 最优解率(%) 平均最优解 标准差 相对标准差(%) _______ _____________ __________ _________ _______ ___________ 35 0.0004159 99.6 3.006 0.09992 3.324
结论
在实验中, 通过上述有限的测试数据,在迭代次数有限的情况下,格雷码编码方式优于二进制编码,轮盘赌略优于锦标赛。在迭代次数35次,采用格雷码编码方式结合轮盘赌选择算法时最优解率可实现99.5%以上,相对标准差达到3%以下,平均运行时间4ms。
源码:https://github.com/Esasoon/Algorithms/tree/main/Genetic_Algorithm