See the wikipedia page on Genetic Algorithms

Example

Imports

import util.Random.nextDouble
import util.Random.nextInt
import shapeless._
import syntax.singleton._
import record._
import cats.implicits._
import axle.ml._

Define a random rabbit generator and fitness function

case class Rabbit(a: Int, b: Double, c: Double, d: Double, e: Double, f: Double, g: Double, h: Double)
// defined class Rabbit

val gen = Generic[Rabbit]
// gen: shapeless.Generic[Rabbit]{type Repr = shapeless.::[Int,shapeless.::[Double,shapeless.::[Double,shapeless.::[Double,shapeless.::[Double,shapeless.::[Double,shapeless.::[Double,shapeless.::[Double,shapeless.HNil]]]]]]]]} = anon$macro$9$1@79773b6e

// val pMutation = 0.003

implicit val rabbitSpecies = new Species[gen.Repr] {

  def random() = {
    val rabbit = Rabbit(
      1 + nextInt(2),
      5 + 20 * nextDouble(),
      1 + 4 * nextDouble(),
      3 + 10 * nextDouble(),
      10 + 5 * nextDouble(),
      2 + 2 * nextDouble(),
      3 + 5 * nextDouble(),
      2 + 10 * nextDouble())
    gen.to(rabbit)
  }

  def fitness(rg: gen.Repr): Double = {
    val rabbit = gen.from(rg)
    import rabbit._
    a * 100 + 100.0 * b + 2.2 * (1.1 * c + 0.3 * d) + 1.3 * (1.4 * e - 3.1 * f + 1.3 * g) - 1.4 * h
  }

}
// rabbitSpecies: axle.ml.Species[gen.Repr] = $anon$1@dcce071

Run the genetic algorithm

import spire.implicits._
// import spire.implicits._

val ga = GeneticAlgorithm(populationSize = 100, numGenerations = 100)
// ga: axle.ml.GeneticAlgorithm[gen.Repr,this.Out] = GeneticAlgorithm(100,100)

val log = ga.run()
// log: axle.ml.GeneticAlgorithmLog[gen.Repr] = GeneticAlgorithmLog(Vector(2 :: 24.980161350031135 :: 4.858622253941833 :: 11.665040144987167 :: 14.795637448999656 :: 2.1492945509626757 :: 7.99003730462035 :: 2.0175569325883673 :: HNil, 2 :: 24.980161350031135 :: 4.858622253941833 :: 11.665040144987167 :: 10.748435466027786 :: 2.1492945509626757 :: 7.99003730462035 :: 2.0175569325883673 :: HNil, 2 :: 24.980161350031135 :: 4.858622253941833 :: 11.665040144987167 :: 14.795637448999656 :: 2.1492945509626757 :: 7.99003730462035 :: 2.0175569325883673 :: HNil, 2 :: 24.980161350031135 :: 4.858622253941833 :: 6.3630747144225985 :: 14.795637448999656 :: 2.1492945509626757 :: 7.99003730462035 :: 2.0175569325883673 :: HNil, 2 :: 24.980161350031135 :: 4.858622253941833 :: 12.126979166700131 :: 12.4548...

val winner = log.winners.last
// winner: gen.Repr = 2 :: 24.980161350031135 :: 4.858622253941833 :: 12.75210545285702 :: 14.67406413664153 :: 2.1492945509626757 :: 7.99003730462035 :: 2.0175569325883673 :: HNil

Plot the min, average, and max fitness function by generation

import scala.collection.immutable.TreeMap
// import scala.collection.immutable.TreeMap

import axle.eqTreeMap
// import axle.eqTreeMap

import axle.visualize._
// import axle.visualize._

val plot = Plot(
  () => List("min" -> log.mins, "ave" -> log.aves, "max" -> log.maxs),
  connect = true,
  colorOf = (label: String) => label match {
    case "min" => Color.black
    case "ave" => Color.blue
    case "max" => Color.green },
  title = Some("GA Demo"),
  xAxis = Some(0d),
  xAxisLabel = Some("generation"),
  yAxis = Some(0),
  yAxisLabel = Some("fitness"))
// plot: axle.visualize.Plot[String,Int,Double,scala.collection.immutable.TreeMap[Int,Double]] = Plot(<function0>,true,true,700,600,50,4,20,50,80,Courier New,12,false,Palatino,20,<function1>,Some(GA Demo),None,Some(0.0),Some(generation),Some(0),Some(fitness))

import axle.web._
// import axle.web._

svg(plot, "ga.svg")

ga