tiger_sim.exs (3165B)
1 defmodule TigerSimulation do 2 alias Types.Chromosome 3 @behaviour Problem 4 @traits 8 5 6 # representing tiger genotype: 7 # 8 # | traits | 0 | 1 | 9 # +------------------+------------+------------+ 10 # | size | smaller | larger | 11 # | swimming ability | low | high | 12 # | fur color | light | dark | 13 # | fat stores | less | more | 14 # | activity period | diurnal | nocturnal | 15 # | hunting range | smaller | larger | 16 # | fur thickness | less thick | more thick | 17 # | tail length | smaller | larger | 18 19 @impl true 20 def genotype do 21 genes = Enum.map(1..@traits, fn _ -> Enum.random(0..1) end) 22 %Chromosome{genes: genes, size: @traits} 23 end 24 25 # scores for each trait: 26 # 27 # | traits | tropical | tundra | 28 # +------------------+----------+--------+ 29 # | size | 0.0 | 1.0 | 30 # | swimming ability | 3.0 | 3.0 | 31 # | fur color | 2.0 | -2.0 | 32 # | fat stores | -1.0 | 1.0 | 33 # | activity period | 0.5 | 0.5 | 34 # | hunting range | 1.0 | 2.0 | 35 # | fur thickness | -1.0 | 1.0 | 36 # | tail length | 0.0 | 0.0 | 37 38 @impl true 39 def fitness_function(chromosome) do 40 tropic_scores = [0.0, 3.0, 2.0, -1.0, 0.5, 1.0, -1.0, 0.0] 41 # tundra_scores = [1.0, 3.0, -2.0, 1.0, 0.5, 2.0, 1.0, 0.0] 42 traits = chromosome.genes 43 44 traits 45 |> Enum.zip(tropic_scores) 46 |> Enum.map(fn {t, s} -> t * s end) 47 |> Enum.sum() 48 end 49 50 @impl true 51 def terminate?(_population, generation), do: generation == 150 52 53 def average_tiger(population) do 54 genes = Enum.map(population, & &1.genes) 55 fitness = Enum.map(population, & &1.fitness) 56 ages = Enum.map(population, & &1.age) 57 num_tigers = length(population) 58 59 avg_fitness = Enum.sum(fitness) / num_tigers 60 avg_age = Enum.sum(ages) / num_tigers 61 62 avg_genes = 63 genes 64 |> Enum.zip() 65 |> Enum.map(fn t -> Enum.sum(Tuple.to_list(t)) / num_tigers end) 66 67 %Chromosome{genes: avg_genes, age: avg_age, fitness: avg_fitness, size: length(avg_genes)} 68 end 69 end 70 71 {tiger, _generation} = 72 Genetic.run(TigerSimulation, 73 population_size: 100, 74 selection_rate: 0.8, 75 mutation_rate: 0.05, 76 survival_rate: 0.2, 77 mutation_type: &Toolbox.Mutation.flip/2, 78 crossover_type: &Toolbox.Crossover.single_point/3 79 # statistics: %{average_tiger: &TigerSimulation.average_tiger/1} 80 ) 81 82 IO.puts("\nbest(?) tropical tiger: #{inspect(tiger.genes)}") 83 # IO.puts("\nbest(?) tundra tiger: #{inspect(tiger.genes)}") 84 85 genealogy = Utilities.Genealogy.get_tree() 86 {:ok, dot} = Graph.Serializers.DOT.serialize(genealogy) 87 {:ok, dotfile} = File.open("tiger_simulation.dot", [:write]) 88 :ok = IO.binwrite(dotfile, dot) 89 :ok = File.close(dotfile) 90 91 stats = 92 :ets.tab2list(:statistics) 93 |> Enum.sort_by(fn {gen, _stats} -> gen end) 94 |> Enum.map(fn {gen, stats} -> [gen, stats.mean_fitness] end) 95 96 {:ok, _} = 97 Gnuplot.plot( 98 [ 99 [:set, :title, "mean fitness versus generation (tiger_sim)"], 100 [:plot, "-", :with, :points] 101 ], 102 [stats] 103 )