// Evolve implements the inner loop of the evolutionary algorithm. // The population calls the Evolve method of each genome, in parallel. Then, // each receiver returns a value to replace it in the next generation. func Evolve(current evo.Genome, matingPool []evo.Genome) evo.Genome { // Selection: // Select each parent using a simple random binary tournament mom := sel.BinaryTournament(matingPool...).(*tsp) dad := sel.BinaryTournament(matingPool...).(*tsp) // Crossover: // Edge recombination child := &tsp{gene: pool.Get().([]int)} perm.EdgeX(child.gene, mom.gene, dad.gene) // Mutation: // There is an n% chance for the gene to have n random swaps // and an n% chance to undergo n steps of a greedy 2-opt hillclimber for rand.Float64() < 0.1 { perm.RandSwap(child.gene) } for rand.Float64() < 0.1 { child.TwoOpt() } // Replacement: // Only replace if the child is better or equal if current.Fitness() > child.Fitness() { return current } return child }
// Evolution implements the body of the evolution loop. func Evolution(q evo.Genome, suitors []evo.Genome) evo.Genome { // Crossover: // We're implementing a diffusion model. For each member of the population, // we receive a small mating pool containing only our neighbors. We choose // a mate using a random binary tournament and create a child with // partially mapped crossover. mom := q.(*queens) dad := sel.BinaryTournament(suitors...).(*queens) child := &queens{gene: make([]int, len(mom.gene))} perm.PMX(child.gene, mom.gene, dad.gene) // Mutation: // Perform n random swaps where n is taken from an exponential distribution. // mutationCount := math.Ceil(rand.ExpFloat64() - 0.5) for i := float64(0); i < 5; i++ { j := rand.Intn(len(child.gene)) k := rand.Intn(len(child.gene)) child.gene[j], child.gene[k] = child.gene[k], child.gene[j] } // Replacement: // Only replace if the child is better or equal. if q.Fitness() > child.Fitness() { return q } return child }