导入
可视化虎的演化谱系
学习如何可视化您老虎演化框架中的谱系关系。
老虎进化框架
在上一章中,我们已将一些基本的追踪机制完整集成到遗传算法框架中。这些机制使我们能够追踪年龄、适应度以及遗传算法的几乎所有其他方面。我们还创建了一个用于追踪进化谱系的机制。
记住:谱系是整个进化过程的家族树。
在本课中,我们将学习如何导出谱系树,并使用第三方工具进行可视化。首先,打开 tiger_simulation.exs 文件。目前它的内容如下:
1defmodule TigerSimulation do 2 @behaviour Problem 3 alias Types.Chromosome 4 5 @impl true 6 def genotype do 7 genes = for _ <- 1..8, do: Enum.random(0..1) 8 %Chromosome{genes: genes, size: 8} 9 end 10 11 @impl true 12 def fitness_function(chromosome) do 13 tropic_scores = [0.0, 3.0, 2.0, 1.0, 0.5, 1.0, -1.0, 0.0] 14 tundra_scores = [1.0, 3.0, -2.0, -1.0, 0.5, 2.0, 1.0, 0.0] 15 traits = chromosome.genes 16 17 traits 18 |> Enum.zip(tundra_scores) 19 |> Enum.map(fn {t, s} -> t*s end) 20 |> Enum.sum() 21 end 22 23 @impl true 24 def terminate?(_population, generation), do: generation == 1000 25 26 def average_tiger(population) do 27 genes = Enum.map(population, & &1.genes) 28 fitnesses = Enum.map(population, & &1.fitness) 29 ages = Enum.map(population, & &1.age) 30 num_tigers = length(population) 31 32 avg_fitness = Enum.sum(fitnesses) / num_tigers 33 avg_age = Enum.sum(ages) / num_tigers 34 avg_genes = 35 genes 36 |> Enum.zip() 37 |> Enum.map(& Enum.sum(Tuple.to_list(&1)) / num_tigers) 38 39 %Chromosome{genes: avg_genes, age: avg_age, fitness: avg_fitness} 40 end 41end 42 43tiger = Genetic.run(TigerSimulation, 44 population_size: 20, 45 selection_rate: 0.9, 46 mutation_rate: 0.1, 47 statistics: %{average_tiger: &TigerSimulation.average_tiger/1}) 48 49IO.write("\n") 50IO.inspect(tiger) 51genealogy = Utilities.Genealogy.get_tree() 52 53IO.inspect(Graph.vertices(genealogy))
我们需要首先调整终止条件。目前,算法设置为在运行 1000 代后终止(如上述代码第 24 行所示)。为了本章的目的,我们将大幅减少这个数值,以便更轻松地可视化谱系。在此示例中,我们将代数减少到 1,种群规模减少到 2:
1defmodule TigerSimulation do 2 # ... 3 def terminate?(_population, generation), do: generation == 1 4 # ... 5end 6 7tiger = Genetic.run(TigerSimulation, 8 population_size: 2, 9 selection_rate: 1.0, 10 mutation_rate: 0.0, 11 statistics: %{average_tiger: &TigerSimulation.average_tiger/1})
接下来,我们需要将谱系树导出为 DOT 文件,如下所示:
1genealogy = Utilities.Genealogy.get_tree() 2 3{:ok, dot} = Graph.Serializers.DOT.serialize(genealogy) 4{:ok, dotfile} = File.open("tiger_simulation.dot", [:write]) 5:ok = IO.binwrite(dotfile, dot) 6:ok = File.close(dotfile)
在这段代码中,我们使用 libgraph API 将谱系树序列化为 DOT 格式的二进制数据。DOT 是一种标准的图结构序列化格式。然后我们创建一个新文件,并将序列化的图写入其中。
测试应用程序
我们可以运行以下应用来测试效果:
No configuration found for ID: be36387e6948034935c169da177e62ef5833bfd1cfc5c078d642d3e16b286a9f
注意:请注意,谱系本质上是从第一代的两个染色体开始并由此扩展出去的一棵树。
这种可视化方式非常有助于展示最适染色体随时间的变化过程。