avatarThe Pragmatic Programmers

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

1571

Abstract

r">7</span>, <span class="hljs-number">11</span>, <span class="hljs-number">6</span>, <span class="hljs-number">8</span>] ​ weight_limit = <span class="hljs-number">40</span> ​ ​ potential_profits = ​ chromosome.genes ​ |<span class="hljs-type">> Enum</span>.zip(profits) ​ |<span class="hljs-type">> Enum</span>.map(​fn​ {c, p} -> c * p ​<span class="hljs-keyword">end</span>​) ​ |<span class="hljs-type">> Enum</span>.<span class="hljs-built_in">sum</span>() ​ ​ over_limit? = ​ chromosome.genes ​ |<span class="hljs-type">> Enum</span>.zip(weights) ​ |<span class="hljs-type">> Enum</span>.map(​fn​ {c, w} -> c * w ​<span class="hljs-keyword">end</span>​) ​ |<span class="hljs-type">> Enum</span>.<span class="hljs-built_in">sum</span>() ​ |<span class="hljs-type">> Kernel</span>.>(weight_limit) ​ ​ profits = ​<span class="hljs-keyword">if</span>​ over_limit?, ​<span class="hljs-built_in">do</span>​: <span class="hljs-number">0</span>, ​<span class="hljs-keyword">else</span>​: potential_profits ​ profits ​ ​<span class="hljs-keyword">end</span></pre></div><p id="0156">In this snippet, you define problem-specific constants: profits, weights, and weight_limit. Then you calculate the potential profit in the same way you did in your previous fitness function. Next, you calculate the total weight and determine whether or not it exceeds weight_limit. Finally, you return a profit based on your penalty.</p><p id="7f2e">Now, you can try running your algorithm again:</p><div id="a407"

Options

<pre>​ ​$ ​​mix​​ ​​<span class="hljs-keyword">run</span><span class="language-bash">​​ ​​scripts/cargo.exs​</span>

​ Current Best: <span class="hljs-number">39</span></pre></div><p id="1ffa">After awhile, you might notice your algorithm stops improving but doesn’t stop running. You may have anticipated this. With your new penalty, but old termination criteria, your algorithm will never stop running because it can never reach the maximum possible profits.</p><p id="12a1">Theoretically, you could calculate your new potential max, but that defeats the purpose of using a genetic algorithm. Instead, you need to know when to stop your algorithm, even when you don’t know what the best solution looks like.</p><p id="8700"><i>👈 <a href="https://readmedium.com/introducing-penalty-functions-dd8545482e4c">Introducing Penalty Functions</a> | <a href="https://readmedium.com/table-of-contents-879fc8614df">TOC</a> | <a href="https://readmedium.com/defining-termination-criteria-d350e21b7319">Defining Termination Criteria</a> 👉</i></p><p id="5669"><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="8758"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*U2E2a23SuM4520w9CUXSWw.jpeg"><figcaption></figcaption></figure></article></body>

Applying a Penalty to the Shipping Problem

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

👈 Introducing Penalty Functions | TOC | Defining Termination Criteria 👉

Now that you understand penalty functions, you need to apply them in the context of your cargo problem. You’ll implement a very basic penalty: if a solution exceeds the weight limit, its fitness is 0. Otherwise, its fitness is equal to the profit it yields.

To implement this penalty, change your fitness function to look like this:

​ ​def​ fitness_function(chromosome) ​do​
​   profits = [6, 5, 8, 9, 6, 7, 3, 1, 2, 6]
​   weights = [10, 6, 8, 7, 10, 9, 7, 11, 6, 8]
​   weight_limit = 40
​ 
​   potential_profits =
​     chromosome.genes
​     |> Enum.zip(profits)
​     |> Enum.map(​fn​ {c, p} -> c * p ​end​)
​     |> Enum.sum()
​ 
​   over_limit? =
​     chromosome.genes
​     |> Enum.zip(weights)
​     |> Enum.map(​fn​ {c, w} -> c * w ​end​)
​     |> Enum.sum()
​     |> Kernel.>(weight_limit)
​ 
​   profits = ​if​ over_limit?, ​do​: 0, ​else​: potential_profits
​   profits
​ ​end

In this snippet, you define problem-specific constants: profits, weights, and weight_limit. Then you calculate the potential profit in the same way you did in your previous fitness function. Next, you calculate the total weight and determine whether or not it exceeds weight_limit. Finally, you return a profit based on your penalty.

Now, you can try running your algorithm again:

​ ​$ ​​mix​​ ​​run​​ ​​scripts/cargo.exs​
​ Current Best: 39

After awhile, you might notice your algorithm stops improving but doesn’t stop running. You may have anticipated this. With your new penalty, but old termination criteria, your algorithm will never stop running because it can never reach the maximum possible profits.

Theoretically, you could calculate your new potential max, but that defeats the purpose of using a genetic algorithm. Instead, you need to know when to stop your algorithm, even when you don’t know what the best solution looks like.

👈 Introducing Penalty Functions | TOC | Defining Termination Criteria 👉

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