遗传算法(或者客户永远是王者-常常是傻瓜)

(第2版,修正了错别字-希望大家...)

哈Ha!

现在他坐在那里,为一个朋友制作了遗传算法的原型。 启发分享,以及其他一些想法...

给定(客户订购):在某个王国中,仓库有100个牢房。 货物在里面。 如何取数量X以便将所有涉及的单元排空? 嗯,也就是说,您具有一个单元格类型[34、10、32、32、33、41、44、4、28、23、22、28、29、14、28、15、38、49、30、24, 18、9、15、8、17、9、2、7、30、29、29、2、28、23、19、4、15、30、38、3、14、21、43、50、29, 14,17,12,25,15,23,28,47,38,29,7,36,45,25,6,25,11,10,1,19,37,24,27,50,12, 1,1,44,22,48,13,46,49,11,33,29,4,19,33,12,3,47,27,26,45,40,37,21,2,8, 41,5,1,9,5]-如何拨号,例如40

好吧,你可以破产,肯定有什么聪明的,但是你可以用遗传算法来解决...


第一个问题:为什么要动脑筋,因为如果您只浏览列表,则需要从前两个单元格中提取-但是,第二个将是其余的。 而且您不必走太远。 但是要知道,客户是一位完美主义者,他希望它像药房一样。 大概在一个值得金重的牢房仓库里。 它发生了。

第二个问题:如果按升序排序,则肯定可以刷更多的单元格...在我们的示例中,有很多单元格少于十个单元格。 可能,客户也不想;)我也遇到过这样的人:我是老板。 他们告诉您-这样做,不要问问题。

(嗯,不是我的客户,否则我将再次对人的思想失去信心...)

好吧,上帝与他同在,每个人都有自己的优先级...然后我们将讨论遗传算法-我们必须以某种方式解决该问题...我们将用Java编写。

对于那些以前从未真正听说过的人:模仿自然母亲。
  1. 编码行为
  2. 我们借助合适的基准来检查每个选项的工作情况
  3. 最好地将其属性传递给下一代


在自然界的最后一步,有两个组成部分:交换(染色体相同部分之间的字符交换)和突变(遗传密码的自发改变)。 嗨,高中;)

仅此而已。 我们将编码从哪个单元格获取,从哪个单元格获取。 我们有100个单元,这意味着我们的染色体将包含100个真/假元素,为此我选择了String,其中将写入零和一。 当然,他们将是100。

基准测试是此过程中最重要的事情。 大自然正在寻找一个利基市场,而计算机自然将在基准测试中寻找一个漏洞,以愚弄它并生存下来。 太好了,说实话...

说了这么多,像这样:

private static int benchmark(String chromosome, boolean verbose) { int sum = 0; char[] cArr = chromosome.toCharArray(); for (int i = 0; i < cnt_bins; i++) { if (cArr[i] == '1') { sum += stock[i]; if (verbose) System.out.println("storage bin " + i + ":\t+" + stock[i] + "\t= " + sum); } if (sum == target_qty) { return 0; } } return Math.abs(target_qty - sum); } 


这个想法是,我们离期望的数字40越远,效果越差。 如果我们获得40分,那么我们在染色体上不会走得更远,我们赢了。 当然,我们将按升序排序-罚分越少越好。

第一代是随机创建的:

 // create 1st generation for (int i = 0; i < generation_size; i++) { StringWriter sw = new StringWriter(); for (int j = 0; j < cnt_bins; j++) { // take stock from this bin? sw.append(rnd.nextBoolean() ? "1" : "0"); } chromosomes.add(sw.toString()); sw.close(); } 


实际上,由于遗传算法可以达到目标,但并不总是可以实现,因此限制世代数很重要。

 for (int generationNo = 0; generationNo < maxGenerationCnt; generationNo++) { // evaluate List<SimpleEntry<String, Integer>> evaluated = new ArrayList<>(); for (int i = 0; i < chromosomes.size(); i++) { evaluated.add( new SimpleEntry<String, Integer>(chromosomes.get(i), benchmark(chromosomes.get(i), false))); } // ...    , .  ... } System.out.println("No solution found after " + maxGenerationCnt + " iterations"); 


排序,留下最好的:

 ... // sort evaluated = evaluated.stream().sorted((e1, e2) -> Integer.compare(e1.getValue(), e2.getValue())) .collect(Collectors.toList()); System.out.println("Generation " + generationNo + "; Best / last parent / worst: " + evaluated.get(0).getValue() + " / " + evaluated.get(best_size).getValue() + " / " + evaluated.get(evaluated.size() - 1).getValue()); if (evaluated.get(0).getValue() == 0) { System.out.println("Solution found"); benchmark(evaluated.get(0).getKey(), true); System.exit(0); } // leave only the best evaluated = evaluated.subList(0, best_size); ... 


我们繁殖繁殖,恢复人口规模。 也就是说,我们随机选择父母,组合相同的符号(如果幸运的话,请参阅交换标志),变异(变异标志),等待奇迹...

 // replication List<String> parents = evaluated.stream().map(e -> e.getKey()).collect(Collectors.toList()); chromosomes.clear(); while (chromosomes.size() < generation_size) { int parent1 = rnd.nextInt(evaluated.size()); int parent2 = rnd.nextInt(evaluated.size()); char[] cArr1 = parents.get(parent1).toCharArray(); char[] cArr2 = parents.get(parent2).toCharArray(); for (int i = 0; i < cnt_bins; i++) { boolean exchange = rnd.nextDouble() < exchange_rate; if (exchange) { char c1 = cArr1[i]; char c2 = cArr2[i]; // exchange both values cArr1[i] = c2; cArr2[i] = c1; } // mutation boolean mutation = rnd.nextDouble() < mutation_rate; if (mutation) { cArr1[i] = rnd.nextBoolean() ? '1' : '0'; } mutation = rnd.nextDouble() < mutation_rate; if (mutation) { cArr2[i] = rnd.nextBoolean() ? '1' : '0'; } } chromosomes.add(new String(cArr1)); chromosomes.add(new String(cArr2)); } 


好吧,这是给你一个奇迹:
目标值:40
库存:[34、10、32、32、33、41、44、4、28、23、22、28、29、14、28、15、38、49、30、24、18、9、15、8 ,17、9、2、7、30、29、29、2、28、23、19、4、15、30、38、3、14、21、43、50、29、14、17、12、25 ,15,23,28,47,38,29,7,36,45,25,6,25,11,10,1,19,37,24,27,50,12,1,1,44,22 ,48、13、46、49、11、33、29、4、19、33、12、3、47、27、26、45、40、37、21、2、8、41、5、1、9 ,5]
第0代; 最好/最后一个父母/最坏:705/991/1580
第1代; 最好/最后一个父母/最差:576/846/1175
第2代; 最好/最后一个父母/最坏:451/722/1108
第三代; 最好/最后一个父母/最差:0/613/904
找到解决方案
储物箱7:+4 = 4
储物箱10:+22 = 26
储物箱13:+14 = 40


这是整个代码
 package ypk; import java.io.IOException; import java.io.StringWriter; import java.util.AbstractMap.SimpleEntry; import java.util.stream.Collectors; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Random; public class YPK { private static int generation_size = 1000; private static int best_size = 200; private static int cnt_bins = 100; private static int max_stock = 50; private static double exchange_rate = .2; private static double mutation_rate = .01; private static Random rnd = new Random(); private static int target_qty = rnd.nextInt(cnt_bins * max_stock / 5); // some quantity private static List<String> chromosomes = new ArrayList<>(); private static int maxGenerationCnt = 20; private static int[] stock = new int[cnt_bins]; public static void main(String[] args) throws IOException { System.out.println("Target value: " + target_qty); // create sample stock stock = new int[cnt_bins]; for (int i = 0; i < cnt_bins; i++) { stock[i] = rnd.nextInt(max_stock) + 1; } System.out.println("Stock: " + Arrays.toString(stock)); // create 1st generation for (int i = 0; i < generation_size; i++) { StringWriter sw = new StringWriter(); for (int j = 0; j < cnt_bins; j++) { // take stock from this bin? sw.append(rnd.nextBoolean() ? "1" : "0"); } chromosomes.add(sw.toString()); sw.close(); } for (int generationNo = 0; generationNo < maxGenerationCnt; generationNo++) { // evaluate List<SimpleEntry<String, Integer>> evaluated = new ArrayList<>(); for (int i = 0; i < chromosomes.size(); i++) { evaluated.add( new SimpleEntry<String, Integer>(chromosomes.get(i), benchmark(chromosomes.get(i), false))); } // sort evaluated = evaluated.stream().sorted((e1, e2) -> Integer.compare(e1.getValue(), e2.getValue())) .collect(Collectors.toList()); System.out.println("Generation " + generationNo + "; Best / last parent / worst: " + evaluated.get(0).getValue() + " / " + evaluated.get(best_size).getValue() + " / " + evaluated.get(evaluated.size() - 1).getValue()); if (evaluated.get(0).getValue() == 0) { System.out.println("Solution found"); benchmark(evaluated.get(0).getKey(), true); System.exit(0); } // leave only the best evaluated = evaluated.subList(0, best_size); // replication List<String> parents = evaluated.stream().map(e -> e.getKey()).collect(Collectors.toList()); chromosomes.clear(); while (chromosomes.size() < generation_size) { int parent1 = rnd.nextInt(evaluated.size()); int parent2 = rnd.nextInt(evaluated.size()); char[] cArr1 = parents.get(parent1).toCharArray(); char[] cArr2 = parents.get(parent2).toCharArray(); for (int i = 0; i < cnt_bins; i++) { boolean exchange = rnd.nextDouble() < exchange_rate; if (exchange) { char c1 = cArr1[i]; char c2 = cArr2[i]; // exchange both values cArr1[i] = c2; cArr2[i] = c1; } // mutation boolean mutation = rnd.nextDouble() < mutation_rate; if (mutation) { cArr1[i] = rnd.nextBoolean() ? '1' : '0'; } mutation = rnd.nextDouble() < mutation_rate; if (mutation) { cArr2[i] = rnd.nextBoolean() ? '1' : '0'; } } chromosomes.add(new String(cArr1)); chromosomes.add(new String(cArr2)); } } System.out.println("No solution found after " + maxGenerationCnt + " iterations"); } private static int benchmark(String chromosome, boolean verbose) { int sum = 0; char[] cArr = chromosome.toCharArray(); for (int i = 0; i < cnt_bins; i++) { if (cArr[i] == '1') { sum += stock[i]; if (verbose) System.out.println("storage bin " + i + ":\t+" + stock[i] + "\t= " + sum); } if (sum == target_qty) { return 0; } } return Math.abs(target_qty - sum); } } 



最后:如果您混淆了参数-太多的突变,太小的人口规模等等。 -会停滞甚至产生所有最差的结果。

顺便说一句,这个问题通常已经随机解决了,不需要下一代:)如果您想使计算机的寿命复杂化,请从基准中删除此回报:

 if (sum == target_qty) { return 0; } 


这会使任务复杂化,并使计算机遭受一些冲击。

祝你好运

m_OO_m

Source: https://habr.com/ru/post/zh-CN465797/


All Articles