func (d Classic) decode(g neat.Genome) (net neat.Network, err error) { // Identify the genes nodes, conns := g.GenesByPosition() // Create the neurons nmap := make(map[int]int) neurons := make([]network.Neuron, len(nodes)) for i, ng := range nodes { nmap[ng.Innovation] = i neurons[i] = network.Neuron{NeuronType: ng.NeuronType, ActivationType: ng.ActivationType, X: ng.X, Y: ng.Y} } // Create the synapses //forward := true // Keep track of conenctions to determine if this is a feed-forward only network synapses := make([]network.Synapse, 0, len(conns)) for _, cg := range conns { if cg.Enabled { //src, tgt := nodes[nmap[cg.Source]], nodes[nmap[cg.Target]] //forward = forward && src.Y < tgt.Y synapses = append(synapses, network.Synapse{ Source: nmap[cg.Source], Target: nmap[cg.Target], Weight: cg.Weight, }) } } net, err = network.New(neurons, synapses) return }
func updateComplexity(v *Web, pop neat.Population) { // Build complexity slice x := make([]float64, len(pop.Genomes)) for i, g := range pop.Genomes { x[i] = float64(g.Complexity()) } var b neat.Genome max := -1.0 for _, g := range pop.Genomes { if g.Fitness > max { b = g max = g.Fitness } } // Append the record min, _ := stats.Min(x) max, _ = stats.Max(x) mean, _ := stats.Mean(x) v.complexity = append(v.complexity, [4]float64{ min, mean, max, float64(b.Complexity()), }) }
// Compares two genomes and returns their compatibility distance // // The number of excess and disjoint genes between a pair of genomes is a natural measure of their // compatibility distance. The more disjoint two genomes are, the less evolutionary history they // share, and thus the less compatible they are. Therefore, we can measure the compatibility distance δ // of different structures in NEAT as a simple linear combination of the number of excess E and // disjoint D genes, as well as the average weight differences of matching genes W, including disabled genes: // see formula in paper // The coefficients c1, c2,and c3 allow us to adjust the importance of the three factors, and thefactor N, // the number of genes in the larger genome, normalizes for genome size (N can be set to 1 if both genomes // are small, i.e., consist of fewer than 20 genes (Stanley, 110) func (c Classic) Compare(g1, g2 neat.Genome) (float64, error) { // Determine N n := 1.0 if len(g1.Conns) > len(g2.Conns) && len(g1.Conns) >= 20 { n = float64(len(g1.Conns)) } else if len(g2.Conns) >= 20 { n = float64(len(g2.Conns)) } // Ensure connections are sorted _, conns1 := g1.GenesByInnovation() _, conns2 := g2.GenesByInnovation() // Calculate the components. This assumes both genomes' connections are sorted by their // innovation number (which is true if the NEAT library created them) var d, e, w, x float64 i := 0 j := 0 for i < len(conns1) || j < len(conns2) { switch { case i == len(conns1): e += 1 j += 1 case j == len(conns2): e += 1 i += 1 default: c1 := conns1[i] c2 := conns2[j] switch { case c1.Innovation < c2.Innovation: d += 1 i += 1 case c1.Innovation > c2.Innovation: d += 1 j += 1 default: // Same innovation number w += math.Abs(c1.Weight - c2.Weight) x += 1 i += 1 j += 1 } } } // Return the compatibility distance n = 1 // NOTE: The variable N mentioned in the paper does not seem to be used in any implemenation δ := c.ExcessCoefficient()*e/n + c.DisjointCoefficient()*d/n if x > 0 { δ += c.WeightCoefficient() * w / x } return δ, nil }
func (c Classic) Mutate(g *neat.Genome) error { old := g.Complexity() if err := c.Complexify.Mutate(g); err != nil { return err } if g.Complexity() == old { if err := c.Weight.Mutate(g); err != nil { return err } if err := c.Trait.Mutate(g); err != nil { return err } } return nil }
func (c Complete) Mutate(g *neat.Genome) error { old := g.Complexity() if err := c.Phased.Mutate(g); err != nil { return err } if g.Complexity() == old { if err := c.Weight.Mutate(g); err != nil { return err } if err := c.Trait.Mutate(g); err != nil { return err } if err := c.Activation.Mutate(g); err != nil { return err } } return nil }
func createOffspring(ctx neat.Context, cfg ClassicSettings, cross bool, rng *rand.Rand, pool map[int]Improvements, cnts map[int]int, next *neat.Population) (err error) { var child neat.Genome for idx, cnt := range cnts { l := pool[idx] for i := 0; i < cnt; i++ { p1, p2 := pickParents(cfg, cross, rng, l, pool) if p1.ID == p2.ID { child = neat.CopyGenome(p1) } else { child, err = ctx.Crosser().Cross(p1, p2) if err != nil { return } } child.ID = ctx.NextID() child.Birth = next.Generation err = ctx.Mutator().Mutate(&child) next.Genomes = append(next.Genomes, child) } } return }