avatarThe Pragmatic Programmers

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

1833

Abstract

r">2</span>) ​ population ​ |<span class="hljs-type">> Enum</span>.reduce([], ​ ​fn​ {p1, p2}, acc -> ​ {c1, c2} = <span class="hljs-built_in">apply</span>(crossover_fn, [p1, p2]) ​ [c1, c2 | <span class="hljs-type">acc</span>] ​ ) ​ |<span class="hljs-type">> Enum</span>.map(& repair_chromosome(&<span class="hljs-number">1</span>)) ​ ​<span class="hljs-keyword">end</span></pre></div><p id="2ee8">The addition of Enum.map/2 will go through each chromosome in the population and call repair_chromosome/1, which is a function that will repair chromosomes. Now, implement the repair_chromosome/1 function like this:</p><div id="3bd9"><pre>​ ​<span class="hljs-function"><span class="hljs-keyword">def</span><span class="hljs-title">repair_chromosome</span></span>(chromosome) ​<span class="hljs-keyword">do</span>​ ​ genes = <span class="hljs-title class_">MapSet</span>.new(chromosome.genes) ​ new_genes = repair_helper(chromosome, <span class="hljs-number">8</span>) ​ %<span class="hljs-title class_">Chromosome</span>{chromosome | ​<span class="hljs-symbol">genes:</span>​ new_genes} ​ ​<span class="hljs-keyword">end</span>​ ​ ​<span class="hljs-function"><span class="hljs-keyword">defp</span><span class="hljs-title">repair_helper</span></span>(chromosome, k) ​<span class="hljs-keyword">do</span>​ ​ ​<span class="hljs-keyword">if</span><span class="hljs-title class_">MapSet</span>.size(chromosome) >= k ​<span class="hljs-keyword">do</span>​ ​ <span class="hljs-title class_">MapSet</span>.to_list(chromosome) ​ ​<span class="hljs-keyword">else</span>​ ​ num = ​<span class="hljs-symbol">:rand</span>​.uniform(<span class="hljs-number">8</span>) ​ repair_helper(<span class="hljs-title class_">MapSet</span>.put(chromosome, num), k) ​ ​<spa

Options

n class="hljs-keyword">end</span>​ ​ ​<span class="hljs-keyword">end</span></pre></div><p id="fea7">Here, you use a MapSet to get the unique elements of the provided chromosome. Next, you pass it into a recursive helper. The helper function will generate random numbers and attempt to put them into the MapSet until the chromosome is the appropriate length.</p><p id="394a">Now, if you change crossover/1 back to use single_point_crossover/2, you can run scripts/nqueens.exs and obtain a solution:</p><div id="76c6"><pre>​ ​$ ​​mix​​ ​​<span class="hljs-keyword">run</span><span class="language-bash">​​ ​​scripts/nqueens.exs​</span> ​ Current Best: <span class="hljs-number">8</span> ​ [<span class="hljs-number">3</span>, <span class="hljs-number">6</span>, <span class="hljs-number">2</span>, <span class="hljs-number">7</span>, <span class="hljs-number">1</span>, <span class="hljs-number">4</span>, <span class="hljs-number">0</span>, <span class="hljs-number">5</span>]</pre></div><p id="4c31"><i>👈 <a href="https://readmedium.com/crossing-over-more-than-two-parents-73c47c6c71e6">Crossing Over More Than Two Parents</a> | <a href="https://readmedium.com/table-of-contents-879fc8614df">TOC</a> | <a href="https://readmedium.com/what-you-learned-6ed431057372">What You Learned</a> 👉</i></p><p id="aa78"><i>Genetic Algorithms in Elixir by Sean Moriarity can be purchased in other book formats <a href="https://pragprog.com/titles/smgaelixir">directly from the Pragmatic Programmers</a>. If you notice a code error or formatting mistake, please let us know <a href="https://readmedium.com/how-to-report-errata-4e164674347a">here</a> so that we can fix it.</i></p><figure id="7102"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*U2E2a23SuM4520w9CUXSWw.jpeg"><figcaption></figcaption></figure></article></body>

Implementing Chromosome Repairment

Genetic Algorithms in Elixir — by Sean Moriarity (54 / 101)

👈 Crossing Over More Than Two Parents | TOC | What You Learned 👉

Sometimes, you’re limited in the crossover strategy you can use. In Chapter 4, Evaluating Solutions and Populations, you explored a solution to the N-queens problem that wouldn’t work because you used single-point crossover. One approach that works around limitations in crossover strategies is the concept of chromosome repairment. Chromosome repairment is the process of ensuring solutions remain valid after crossover or mutation. In the case of N-queens, using single-point crossover ruins the integrity of the permutation. This means after crossover takes place, you have to go in and individually repair every chromosome.

Chromosome repairment isn’t necessary if you choose a crossover strategy that maintains the integrity of your permutation; however, if you’re restricted to using specific crossover strategies, then it will be necessary. To implement chromosome repairment into your genetic algorithm, add the following to crossover/1 in lib/genetic.ex:

​ ​def​ crossover(population, opts \\ []) ​do​
​   crossover_fn = Keyword.get(opts,
​                              ​:crossover_type​,
​                              Toolbox.Crossover.single_point/2)
​   population
​   |> Enum.reduce([],
​       ​fn​ {p1, p2}, acc ->
​         {c1, c2} = apply(crossover_fn, [p1, p2])
​         [c1, c2 | acc]
​     )
​   |> Enum.map(& repair_chromosome(&1))
​ ​end

The addition of Enum.map/2 will go through each chromosome in the population and call repair_chromosome/1, which is a function that will repair chromosomes. Now, implement the repair_chromosome/1 function like this:

​ ​defrepair_chromosome(chromosome) ​do​
​   genes = MapSet.new(chromosome.genes)
​   new_genes = repair_helper(chromosome, 8)
​   %Chromosome{chromosome | ​genes:​ new_genes}
​ ​end​
​ ​defprepair_helper(chromosome, k) ​do​
​   ​ifMapSet.size(chromosome) >= k ​do​
​     MapSet.to_list(chromosome)
​   ​else​
​     num = ​:rand​.uniform(8)
​     repair_helper(MapSet.put(chromosome, num), k)
​   ​end​
​ ​end

Here, you use a MapSet to get the unique elements of the provided chromosome. Next, you pass it into a recursive helper. The helper function will generate random numbers and attempt to put them into the MapSet until the chromosome is the appropriate length.

Now, if you change crossover/1 back to use single_point_crossover/2, you can run scripts/nqueens.exs and obtain a solution:

​ ​$ ​​mix​​ ​​run​​ ​​scripts/nqueens.exs​
​ Current Best: 8
​ [3, 6, 2, 7, 1, 4, 0, 5]

👈 Crossing Over More Than Two Parents | TOC | What You Learned 👉

Genetic Algorithms in Elixir by Sean Moriarity can be purchased in other book formats directly from the Pragmatic Programmers. If you notice a code error or formatting mistake, please let us know here so that we can fix it.

Smgaelixir
Recommended from ReadMedium