// Adds a new node to the genome // // In the add node mutation, an existing connection is split and the new node placed where the old // connection used to be. The old connection is disabled and two new connections are added to the // genome. The connection between the first node in the chain and the new node is given a weight // of one, and the connection between the new node and the last node in the chain is given the // same weight as the connection being split. Splitting the connection in this way introduces a // nonlinearity (i.e. sigmoid function) where there was none before. Because the new node is // immediately integrated into the network, its effect on fitness can be evaluated right away. // Preexisting network structure is not destroyed and performs the same function, while the new // structure provides an opportunity to elaborate on the original behaviors. (Stanley, 35) func (m *Complexify) addNode(rng *rand.Rand, g *neat.Genome) { // Pick a connection to split var inno int var c0 neat.Connection found := false for k, conn := range g.Conns { c0 = conn inno = k // Ensure resultant node doesn't already exist found = true src := g.Nodes[c0.Source] tgt := g.Nodes[c0.Target] x := (src.X + tgt.X) / 2.0 y := (src.Y + tgt.Y) / 2.0 for _, node := range g.Nodes { if node.X == x && node.Y == y { found = false break } } if found { break } } if !found { return } c0.Enabled = false g.Conns[inno] = c0 // Add the new node src := g.Nodes[c0.Source] tgt := g.Nodes[c0.Target] n0 := neat.Node{NeuronType: neat.Hidden, ActivationType: m.HiddenActivation(), X: (src.X + tgt.X) / 2.0, Y: (src.Y + tgt.Y) / 2.0} n0.Innovation = m.ctx.Innovation(neat.NodeInnovation, n0.Key()) g.Nodes[n0.Innovation] = n0 // Add the new connections c1 := neat.Connection{Source: src.Innovation, Target: n0.Innovation, Enabled: true, Weight: 1.0} c1.Innovation = m.ctx.Innovation(neat.ConnInnovation, c1.Key()) g.Conns[c1.Innovation] = c1 c2 := neat.Connection{Source: n0.Innovation, Target: tgt.Innovation, Enabled: true, Weight: c0.Weight} c2.Innovation = m.ctx.Innovation(neat.ConnInnovation, c2.Key()) g.Conns[c2.Innovation] = c2 }
// Returns a modified weight func (m Weight) mutateWeight(rng *rand.Rand, c *neat.Connection) { c.Weight += rng.NormFloat64() /* if w < -m.WeightRange*2 { w = -m.WeightRange * 2 } else if w > m.WeightRange*2 { w = m.WeightRange * 2 } */ }
// Returns a new weight func (m Weight) replaceWeight(rng *rand.Rand, c *neat.Connection) { c.Weight = (rng.Float64()*2.0 - 1.0) * m.WeightRange() }