1 package net.bmahe.genetics4j.neat.mutation.chromosome;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.Objects;
6 import java.util.random.RandomGenerator;
7
8 import net.bmahe.genetics4j.neat.Connection;
9 import net.bmahe.genetics4j.neat.InnovationManager;
10 import net.bmahe.genetics4j.neat.NodeIdManagerRegistry;
11 import net.bmahe.genetics4j.neat.chromosomes.NeatChromosome;
12 import net.bmahe.genetics4j.neat.spec.mutation.AddNode;
13
14 public class NeatChromosomeAddNodeMutationHandler extends AbstractNeatChromosomeConnectionMutationHandler<AddNode> {
15
16 private final RandomGenerator randomGenerator;
17 private final InnovationManager innovationManager;
18 private final NodeIdManagerRegistry nodeIdManagerRegistry;
19
20 public NeatChromosomeAddNodeMutationHandler(final RandomGenerator randomGenerator,
21 final InnovationManager innovationManager) {
22 this(randomGenerator, innovationManager, new NodeIdManagerRegistry());
23 }
24
25 public NeatChromosomeAddNodeMutationHandler(final RandomGenerator _randomGenerator,
26 final InnovationManager _innovationManager,
27 final NodeIdManagerRegistry _nodeIdManagerRegistry) {
28 super(AddNode.class, _randomGenerator);
29 Objects.requireNonNull(_randomGenerator);
30 Objects.requireNonNull(_innovationManager);
31 Objects.requireNonNull(_nodeIdManagerRegistry);
32
33 this.randomGenerator = _randomGenerator;
34 this.innovationManager = _innovationManager;
35 this.nodeIdManagerRegistry = _nodeIdManagerRegistry;
36 }
37
38 @Override
39 protected List<Connection> mutateConnection(final AddNode mutationPolicy, final NeatChromosome neatChromosome,
40 final Connection oldConnection, final int i) {
41
42
43
44
45
46 if (oldConnection.isEnabled() == false) {
47 return List.of(Connection.copyOf(oldConnection));
48 }
49
50 final List<Connection> connections = new ArrayList<>();
51
52 final var disabledConnection = Connection.builder().from(oldConnection).isEnabled(false).build();
53
54 final var nodeIdManager = nodeIdManagerRegistry.managerFor(neatChromosome.getNodeLayout());
55 nodeIdManager.registerExistingNodeIds(
56 neatChromosome.getConnections()
57 .stream()
58 .flatMap(
59 connection -> java.util.stream.Stream.of(connection.fromNodeIndex(), connection.toNodeIndex()))
60 .toList());
61 final int newNodeValue = nodeIdManager.nodeIdForSplit(oldConnection.innovation());
62
63 connections.add(disabledConnection);
64
65 final boolean firstConnectionAlreadyExists = neatChromosome.getConnections()
66 .stream()
67 .anyMatch(
68 connection -> connection.fromNodeIndex() == oldConnection.fromNodeIndex()
69 && connection.toNodeIndex() == newNodeValue);
70 if (firstConnectionAlreadyExists == false) {
71 final int firstInnovation = innovationManager.computeNewId(oldConnection.fromNodeIndex(), newNodeValue);
72 final var firstConnection = Connection.builder()
73 .from(oldConnection)
74 .weight(1.0f)
75 .toNodeIndex(newNodeValue)
76 .innovation(firstInnovation)
77 .build();
78 connections.add(firstConnection);
79 }
80
81 final boolean secondConnectionAlreadyExists = neatChromosome.getConnections()
82 .stream()
83 .anyMatch(
84 connection -> connection.fromNodeIndex() == newNodeValue
85 && connection.toNodeIndex() == oldConnection.toNodeIndex());
86 if (secondConnectionAlreadyExists == false) {
87 final int secondInnovation = innovationManager.computeNewId(newNodeValue, oldConnection.toNodeIndex());
88 final var secondConnection = Connection.builder()
89 .from(oldConnection)
90 .fromNodeIndex(newNodeValue)
91 .innovation(secondInnovation)
92 .build();
93 connections.add(secondConnection);
94 }
95
96 return connections;
97 }
98
99 }