├── GA ├── my_fitness.m ├── my_ga.m └── test_ga.m └── README.md /GA/my_fitness.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuai-Xie/genetic-algorithm/625c6fcde2824288d8b208c5790be7a2eed64540/GA/my_fitness.m -------------------------------------------------------------------------------- /GA/my_ga.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuai-Xie/genetic-algorithm/625c6fcde2824288d8b208c5790be7a2eed64540/GA/my_ga.m -------------------------------------------------------------------------------- /GA/test_ga.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuai-Xie/genetic-algorithm/625c6fcde2824288d8b208c5790be7a2eed64540/GA/test_ga.m -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## [遗传算法 - 简书](http://www.jianshu.com/p/8a965c04c787#) 2 | 3 | 遗传算法的理论是根据达尔文进化论而设计出来的算法: 人类是朝着好的方向(最优解)进化,进化过程中,会自动选择优良基因,淘汰劣等基因。 4 | 5 | [**遗传算法**](https://zh.wikipedia.org/wiki/%E9%81%97%E4%BC%A0%E7%AE%97%E6%B3%95)(英语:genetic algorithm (GA) )是计算数学中用于解决最佳化的搜索算法,是[进化算法](https://zh.wikipedia.org/wiki/%E8%BF%9B%E5%8C%96%E7%AE%97%E6%B3%95)的一种。进化算法最初是借鉴了[进化生物学](https://zh.wikipedia.org/wiki/%E8%BF%9B%E5%8C%96%E7%94%9F%E7%89%A9%E5%AD%A6)中的一些现象而发展起来的,这些现象包括**遗传、突变、自然选择、杂交**等。 6 | 7 | 8 | [搜索算法](http://baike.baidu.com/item/%E6%90%9C%E7%B4%A2%E7%AE%97%E6%B3%95)的共同特征为: 9 | 1. 首先组成一组候选解 10 | 1. 依据某些适应性条件测算这些候选解的[适应度](http://baike.baidu.com/item/%E9%80%82%E5%BA%94%E5%BA%A6) 11 | 1. 根据[适应度](http://baike.baidu.com/item/%E9%80%82%E5%BA%94%E5%BA%A6)保留某些候选解,放弃其他候选解 12 | 1. 对保留的候选解进行某些操作,生成新的候选解 13 | 14 | 15 | ![遗传算法流程](http://upload-images.jianshu.io/upload_images/1877813-4b08f7f282e0e277.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 16 | 17 | 18 | **遗传算法的一般步骤** 19 | 1. **my_fitness函数** 评估每条染色体所对应个体的适应度 20 | 2. 升序排列适应度评估值,选出 **前 parent_number 个** 个体作为 **待选 parent 种群**(适应度函数的值越小越好) 21 | 3. 从 **待选 parent 种群** 中随机选择 2 个个体作为父方和母方。 22 | 4. 抽取父母双方的染色体,进行交叉,产生 2 个子代。(交叉概率) 23 | 5. 对子代(**parent + 生成的 child**)的染色体进行变异。(变异概率) 24 | 6. 重复3,4,5步骤,直到新种群(**parent_number + child_number**)的产生。 25 | 26 | 循环以上步骤直至找到满意的解。 27 | 28 | **名词解释** 29 | - 交叉概率:两个个体进行交配的概率。例如,交配概率为0.8,则80%的“夫妻”会生育后代。 30 | - 变异概率:所有的基因中发生变异的占总体的比例。 31 | 32 | 33 | ## GA函数 34 | ```matlab 35 | function [best_fitness, elite, generation, last_generation] = my_ga( ... 36 | number_of_variables, ... % 求解问题的参数个数 37 | fitness_function, ... % 自定义适应度函数名 38 | population_size, ... % 种群规模(每一代个体数目) 39 | parent_number, ... % 每一代中保持不变的数目(除了变异) 40 | mutation_rate, ... % 变异概率 41 | maximal_generation, ... % 最大演化代数 42 | minimal_cost ... % 最小目标值(函数值越小,则适应度越高) 43 | ) 44 | 45 | % 累加概率 46 | % 假设 parent_number = 10 47 | % 分子 parent_number:-1:1 用于生成一个数列 48 | % 分母 sum(parent_number:-1:1) 是一个求和结果(一个数) 49 | % 50 | % 分子 10 9 8 7 6 5 4 3 2 1 51 | % 分母 55 52 | % 相除 0.1818 0.1636 0.1455 0.1273 0.1091 0.0909 0.0727 0.0545 0.0364 0.0182 53 | % 累加 0.1818 0.3455 0.4909 0.6182 0.7273 0.8182 0.8909 0.9455 0.9818 1.0000 54 | % 55 | % 运算结果可以看出 56 | % 累加概率函数是一个从0到1增长得越来越慢的函数 57 | % 因为后面加的概率越来越小(数列是降虚排列的) 58 | cumulative_probabilities = cumsum((parent_number:-1:1) / sum(parent_number:-1:1)); % 1个长度为parent_number的数列 59 | 60 | % 最佳适应度 61 | % 每一代的最佳适应度都先初始化为1 62 | best_fitness = ones(maximal_generation, 1); 63 | 64 | % 精英 65 | % 每一代的精英的参数值都先初始化为0 66 | elite = zeros(maximal_generation, number_of_variables); 67 | 68 | % 子女数量 69 | % 种群数量 - 父母数量(父母即每一代中不发生改变的个体) 70 | child_number = population_size - parent_number; % 每一代子女的数目 71 | 72 | % 初始化种群 73 | % population_size 对应矩阵的行,每一行表示1个个体,行数=个体数(种群数量) 74 | % number_of_variables 对应矩阵的列,列数=参数个数(个体特征由这些参数表示) 75 | population = rand(population_size, number_of_variables); 76 | 77 | last_generation = 0; % 记录跳出循环时的代数 78 | 79 | 80 | % 后面的代码都在for循环中 81 | for generation = 1 : maximal_generation % 演化循环开始 82 | 83 | % feval把数据带入到一个定义好的函数句柄中计算 84 | % 把population矩阵带入fitness_function函数计算 85 | cost = feval(fitness_function, population); % 计算所有个体的适应度(population_size*1的矩阵) 86 | 87 | % index记录排序后每个值原来的行数 88 | [cost, index] = sort(cost); % 将适应度函数值从小到大排序 89 | 90 | % index(1:parent_number) 91 | % 前parent_number个cost较小的个体在种群population中的行数 92 | % 选出这部分(parent_number个)个体作为父母,其实parent_number对应交叉概率 93 | population = population(index(1:parent_number), :); % 先保留一部分较优的个体 94 | % 可以看出population矩阵是不断变化的 95 | 96 | % cost在经过前面的sort排序后,矩阵已经改变为升序的 97 | % cost(1)即为本代的最佳适应度 98 | best_fitness(generation) = cost(1); % 记录本代的最佳适应度 99 | 100 | % population矩阵第一行为本代的精英个体 101 | elite(generation, :) = population(1, :); % 记录本代的最优解(精英) 102 | 103 | % 若本代的最优解已足够好,则停止演化 104 | if best_fitness(generation) < minimal_cost; 105 | last_generation = generation; 106 | break; 107 | end 108 | 109 | % 交叉变异产生新的种群 110 | 111 | % 染色体交叉开始 112 | for child = 1:2:child_number % 步长为2是因为每一次交叉会产生2个孩子 113 | 114 | % cumulative_probabilities长度为parent_number 115 | % 从中随机选择2个父母出来 (child+parent_number)%parent_number 116 | mother = find(cumulative_probabilities > rand, 1); % 选择一个较优秀的母亲 117 | father = find(cumulative_probabilities > rand, 1); % 选择一个较优秀的父亲 118 | 119 | % ceil(天花板)向上取整 120 | % rand 生成一个随机数 121 | % 即随机选择了一列,这一列的值交换 122 | crossover_point = ceil(rand*number_of_variables); % 随机地确定一个染色体交叉点 123 | 124 | % 假如crossover_point=3, number_of_variables=5 125 | % mask1 = 1 1 1 0 0 126 | % mask2 = 0 0 0 1 1 127 | mask1 = [ones(1, crossover_point), zeros(1, number_of_variables - crossover_point)]; 128 | mask2 = not(mask1); 129 | 130 | % 获取分开的4段染色体 131 | % 注意是 .* 132 | mother_1 = mask1 .* population(mother, :); % 母亲染色体的前部分 133 | mother_2 = mask2 .* population(mother, :); % 母亲染色体的后部分 134 | 135 | father_1 = mask1 .* population(father, :); % 父亲染色体的前部分 136 | father_2 = mask2 .* population(father, :); % 父亲染色体的后部分 137 | 138 | % 得到下一代 139 | population(parent_number + child, :) = mother_1 + father_2; % 一个孩子 140 | population(parent_number+child+1, :) = mother_2 + father_1; % 另一个孩子 141 | 142 | end % 染色体交叉结束 143 | 144 | 145 | % 染色体变异开始 146 | 147 | % 变异种群 148 | mutation_population = population(2:population_size, :); % 精英不参与变异,所以从2开始 149 | 150 | number_of_elements = (population_size - 1) * number_of_variables; % 全部基因数目 151 | number_of_mutations = ceil(number_of_elements * mutation_rate); % 变异的基因数目(基因总数*变异率) 152 | 153 | % rand(1, number_of_mutations) 生成number_of_mutations个随机数(范围0-1)组成的矩阵(1*number_of_mutations) 154 | % 数乘后,矩阵每个元素表示发生改变的基因的位置(元素在矩阵中的一维坐标) 155 | mutation_points = ceil(number_of_elements * rand(1, number_of_mutations)); % 确定要变异的基因 156 | 157 | % 被选中的基因都被一个随机数替代,完成变异 158 | mutation_population(mutation_points) = rand(1, number_of_mutations); % 对选中的基因进行变异操作 159 | 160 | population(2:population_size, :) = mutation_population; % 发生变异之后的种群 161 | 162 | % 染色体变异结束 163 | 164 | end % 演化循环结束 165 | ``` 166 | ## 适应度函数 167 | 适应度函数由解决的问题决定。 168 | 举一个平方和的例子。 169 | 170 | ![简单的平方和问题](http://upload-images.jianshu.io/upload_images/1877813-e51446138a407db0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 171 | 172 | 求函数的最小值,其中每个变量的取值区间都是 [-1, +1]。 173 | 问题的最优解:每个 x_i 都等于0。 174 | 175 | ```matlab 176 | function y = my_fitness(population) 177 | % population是随机数[0,1]矩阵,下面的操作改变范围为[-1,1] 178 | population = 2 * (population - 0.5); 179 | y = sum(population.^2, 2); % 行的平方和 180 | ``` 181 | 182 | ## 测试 183 | ```matlab 184 | clear; 185 | close all; 186 | 187 | % 调用 my_ga 进行计算 188 | % 求解问题的参数个数 10 189 | % 自定义适应度函数名 my_fitness 190 | % 种群规模 100 191 | % 每一代中保持不变的数目 50 (即交叉率0.5) 192 | % 变异概率 0.1 (1/10的个体发生变异) 193 | % 最大演化代数 10000 10000代 194 | % 最小目标值 1.0e-6 个体适应度函数值 < 0.000001结束 195 | [best_fitness, elite, generation, last_generation] = my_ga(10, 'my_fitness', 100, 50, 0.1, 10000, 1.0e-6); 196 | 197 | 198 | % 输出后10行 199 | % disp(best_fitness(9990:10000,:)); 200 | % disp(elite(9990:10000,:)) 201 | % 这样是不合适的,因为GA常常在中间就跳出循环了 202 | 203 | % 这样才是合适的输出 204 | disp(last_generation); 205 | i_begin = last_generation - 9; 206 | disp(best_fitness(i_begin:last_generation,:)); 207 | % 将elite值转化为问题范围内 208 | my_elite = elite(i_begin:last_generation,:); 209 | my_elite = 2 * (my_elite - 0.5); 210 | disp(my_elite); 211 | 212 | % 最佳适应度的演化情况 213 | figure 214 | loglog(1:generation, best_fitness(1:generation), 'linewidth',2) 215 | xlabel('Generation','fontsize',15); 216 | ylabel('Best Fitness','fontsize',15); 217 | set(gca,'fontsize',15,'ticklength',get(gca,'ticklength')*2); 218 | 219 | % 最优解的演化情况 220 | figure 221 | semilogx(1 : generation, 2 * elite(1 : generation, :) - 1) 222 | xlabel('Generation','fontsize',15); 223 | ylabel('Best Solution','fontsize',15); 224 | set(gca,'fontsize',15,'ticklength',get(gca,'ticklength')*2); 225 | ``` 226 | ## 输出 227 | 注意:这些值都是不确定的。 228 | ```matlab 229 | >> test_ga 230 | 2035 // last_generation 跳出循环 231 | 232 | // best_fitness 后10行 233 | 0.268244559363828 234 | 0.268244559363828 235 | 0.268244559363828 236 | 0.268244559363828 237 | 0.268244559363828 238 | 0.268244559363828 239 | 0.268244559363828 240 | 0.268244559363828 241 | 0.268244559363828 242 | 0.063540829423325 243 | 244 | // elite 后10行,最后一行为想要的解 245 | Columns 1 through 7 246 | 247 | -0.000383439136218 -0.000401508032900 0.000097444596325 0.000337256996077 -0.000064973174152 0.000120384223563 0.000117039829849 248 | -0.000383439136218 -0.000401508032900 0.000097444596325 0.000337256996077 -0.000064973174152 0.000120384223563 0.000117039829849 249 | -0.000383439136218 -0.000401508032900 0.000097444596325 0.000337256996077 -0.000064973174152 0.000120384223563 0.000117039829849 250 | -0.000383439136218 -0.000401508032900 0.000097444596325 0.000337256996077 -0.000064973174152 0.000120384223563 0.000117039829849 251 | -0.000383439136218 -0.000401508032900 0.000097444596325 0.000337256996077 -0.000064973174152 0.000120384223563 0.000117039829849 252 | -0.000383439136218 -0.000401508032900 0.000097444596325 0.000337256996077 -0.000064973174152 0.000120384223563 0.000117039829849 253 | -0.000383439136218 -0.000401508032900 0.000097444596325 0.000337256996077 -0.000064973174152 0.000120384223563 0.000117039829849 254 | -0.000383439136218 -0.000401508032900 0.000097444596325 0.000337256996077 -0.000064973174152 0.000120384223563 0.000117039829849 255 | -0.000383439136218 -0.000401508032900 0.000097444596325 0.000337256996077 -0.000064973174152 0.000120384223563 0.000117039829849 256 | -0.000383439136218 -0.000401508032900 0.000097444596325 0.000337256996077 -0.000064973174152 0.000120384223563 0.000117039829849 257 | 258 | Columns 8 through 10 259 | 260 | -0.000362645135942 -0.001433818552852 0.000176675571817 261 | -0.000362645135942 -0.001433818552852 0.000176675571817 262 | -0.000362645135942 -0.001433818552852 0.000176675571817 263 | -0.000362645135942 -0.001433818552852 0.000176675571817 264 | -0.000362645135942 -0.001433818552852 0.000176675571817 265 | -0.000362645135942 -0.001433818552852 0.000176675571817 266 | -0.000362645135942 -0.001433818552852 0.000176675571817 267 | -0.000362645135942 -0.001433818552852 0.000176675571817 268 | -0.000362645135942 -0.001433818552852 0.000176675571817 269 | -0.000362645135942 -0.000093799483467 0.000176675571817 270 | ``` 271 | 272 | ## 趋势图 273 | 274 | 最佳适应度函数的值 275 | 276 | ![Best_Fitness - Generation](http://upload-images.jianshu.io/upload_images/1877813-93767bded3307b2d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 277 | 278 | elite 的变化趋势,10条折线 -> 10个变量 279 | 280 | ![Best_Solution - Generation](http://upload-images.jianshu.io/upload_images/1877813-78593e09815a718b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 281 | 282 | ## 文章参考 283 | [科学网 - 一个用matlab实现的50行的遗传算法程序](http://blog.sciencenet.cn/blog-3102863-1029280.html) 284 | --------------------------------------------------------------------------------