Customizing Mutation in Your Framework

Just like in Chapter 5, Selecting the Best, and Chapter 6, Generating New Solutions, you’ll need to slightly modify your framework to allow you to customize mutation hyperparameters. These hyperparameters are mutation strategy and mutation rate.

In this section, you’ll create a mutation toolbox and modify your framework to allow you to easily customize mutation in your algorithms.

Creating the Toolbox

First, you need to create a mutation toolbox, just like you created a selection and crossover toolbox. Create a new file in toolbox called mutation.ex.

Next, create the Toolbox.Mutation module, like this:

 defmodule​ Toolbox.Mutation ​do
  alias Types.Chromosome
 
 # ...
 end

You’ll be working a lot with the Chromosome struct in this module, so you’ll want to create an alias. Now, whenever you implement a new mutation strategy, you’ll add it to your mutation toolbox.

Changing Mutation Strategy

Open up genetic.ex and navigate to the mutation/2 function. It looks like this:

 def​ mutation(population, opts \ []) ​do
  population
  |> Enum.map(
 fn​ chromosome ->
 if​ ​:rand​.uniform() < 0.05 ​do
  %Chromosome{​genes:​ Enum.shuffle(chromosome.genes)}
 else
  chromosome
 end
 end
  )
 end

Remember, opts is a Keyword representing the options you can pass to your algorithm when you call Genetic.run/2. First, you need to extract a mutation strategy from opts, like this:

 mutate_fn = Keyword.get(opts, ​:mutation_type​, &Toolbox.Mutation.flip/1)

Right now, the default is called flip mutation, which is a mutation strategy you’ll implement in the next section. You can change this default to another method if you prefer.

Next, you need to apply your mutation strategy to chromosomes in the population. Change the body of Enum.map/2 to look like this:

 |> Enum.map(
 fn​ chromosome ->
 if​ ​:rand​.uniform() < 0.05 ​do
» apply(mutate_fn, [chromosome])
 else
  chromosome
 end
  )

Here you use apply/2 to apply your extracted mutation strategy to chromosome. The mutation strategies you’ll implement in this chapter accept a chromosome and return the mutated chromosome, so apply/2 returns a mutated version of chromosome.

Adjusting Mutation Rate

You also need a way to control the mutation rate of your algorithm. Start by extracting :mutation_rate from opts:

 mutate_fn = Keyword.get(opts, ​:mutation_type​, &Toolbox.Mutation.flip/1)
 rate = Keyword.get(opts, ​:mutation_rate​, 0.05)

0.05 represents a mutation rate of 5%, which is a good default.

Next, you need to change Enum.map/2 to only mutate chromosomes according to rate. To do this, change the if-condition to look like this:

 |> Enum.map(
 fn​ chromosome ->
»if​ ​:rand​.uniform() < rate ​do
  apply(mutate_fn, [chromosome])
 else
  chromosome
 end
  )

Your new mutation/2 function should look like this:

 def​ mutation(population, opts \ []) ​do
» mutate_fn = Keyword.get(opts, ​:mutation_type​, &Toolbox.Mutation.scramble/1)
» rate = Keyword.get(opts, ​:mutation_rate​, 0.05)
  population
  |> Enum.map(
 fn​ chromosome ->
»if​ ​:rand​.uniform() < rate ​do
» apply(mutate_fn, [chromosome])
 else
  chromosome
 end
 end
  )
 end
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset