1 | package net.bmahe.genetics4j.neat.chromosomes.factory; | |
2 | ||
3 | import java.util.ArrayList; | |
4 | import java.util.List; | |
5 | import java.util.random.RandomGenerator; | |
6 | ||
7 | import org.apache.commons.lang3.Validate; | |
8 | ||
9 | import net.bmahe.genetics4j.core.chromosomes.factory.ChromosomeFactory; | |
10 | import net.bmahe.genetics4j.core.spec.chromosome.ChromosomeSpec; | |
11 | import net.bmahe.genetics4j.neat.Connection; | |
12 | import net.bmahe.genetics4j.neat.InnovationManager; | |
13 | import net.bmahe.genetics4j.neat.chromosomes.NeatChromosome; | |
14 | import net.bmahe.genetics4j.neat.spec.NeatChromosomeSpec; | |
15 | ||
16 | /** | |
17 | * Factory for creating fully-connected initial NEAT (NeuroEvolution of Augmenting Topologies) chromosomes. | |
18 | * | |
19 | * <p>NeatConnectedChromosomeFactory generates initial neural network chromosomes with direct connections | |
20 | * between all input and output nodes. This provides a minimal starting topology that ensures all inputs | |
21 | * can influence all outputs, creating a foundation for structural evolution through the NEAT algorithm. | |
22 | * | |
23 | * <p>Generated network characteristics: | |
24 | * <ul> | |
25 | * <li><strong>Full connectivity</strong>: Every input node connected to every output node</li> | |
26 | * <li><strong>No hidden nodes</strong>: Initial networks contain only input and output layers</li> | |
27 | * <li><strong>Random weights</strong>: Connection weights uniformly distributed within specified bounds</li> | |
28 | * <li><strong>Innovation tracking</strong>: All connections assigned unique innovation numbers</li> | |
29 | * </ul> | |
30 | * | |
31 | * <p>Network topology structure: | |
32 | * <ul> | |
33 | * <li><strong>Input layer</strong>: Nodes 0 to (numInputs - 1)</li> | |
34 | * <li><strong>Output layer</strong>: Nodes numInputs to (numInputs + numOutputs - 1)</li> | |
35 | * <li><strong>Connections</strong>: numInputs × numOutputs fully-connected bipartite graph</li> | |
36 | * <li><strong>Enabled state</strong>: All initial connections are enabled</li> | |
37 | * </ul> | |
38 | * | |
39 | * <p>Common usage patterns: | |
40 | * <pre>{@code | |
41 | * // Create factory with innovation manager | |
42 | * RandomGenerator randomGen = RandomGenerator.getDefault(); | |
43 | * InnovationManager innovationManager = new InnovationManager(); | |
44 | * NeatConnectedChromosomeFactory factory = new NeatConnectedChromosomeFactory( | |
45 | * randomGen, innovationManager | |
46 | * ); | |
47 | * | |
48 | * // Define network specification | |
49 | * NeatChromosomeSpec spec = NeatChromosomeSpec.of( | |
50 | * 3, // 3 input nodes | |
51 | * 2, // 2 output nodes | |
52 | * -1.0f, // minimum weight | |
53 | * 1.0f // maximum weight | |
54 | * ); | |
55 | * | |
56 | * // Generate initial chromosome | |
57 | * NeatChromosome chromosome = factory.generate(spec); | |
58 | * | |
59 | * // Result: 3×2 = 6 connections with random weights | |
60 | * // Connections: (0→3), (0→4), (1→3), (1→4), (2→3), (2→4) | |
61 | * }</pre> | |
62 | * | |
63 | * <p>Integration with NEAT evolution: | |
64 | * <ul> | |
65 | * <li><strong>Population initialization</strong>: Creates diverse initial population with same topology</li> | |
66 | * <li><strong>Weight diversity</strong>: Random weights provide behavioral variation</li> | |
67 | * <li><strong>Structural foundation</strong>: Minimal topology allows maximum structural exploration</li> | |
68 | * <li><strong>Innovation consistency</strong>: Same connection types get same innovation numbers across population</li> | |
69 | * </ul> | |
70 | * | |
71 | * <p>Innovation number management: | |
72 | * <ul> | |
73 | * <li><strong>Deterministic assignment</strong>: Same input-output pairs get same innovation numbers</li> | |
74 | * <li><strong>Population consistency</strong>: All individuals use same innovation numbers for same connections</li> | |
75 | * <li><strong>Crossover compatibility</strong>: Enables meaningful genetic recombination from generation 0</li> | |
76 | * <li><strong>Historical tracking</strong>: Foundation for tracking structural evolution</li> | |
77 | * </ul> | |
78 | * | |
79 | * <p>Weight initialization strategy: | |
80 | * <ul> | |
81 | * <li><strong>Uniform distribution</strong>: Weights uniformly sampled from [minWeight, maxWeight]</li> | |
82 | * <li><strong>Behavioral diversity</strong>: Different weight combinations create different behaviors</li> | |
83 | * <li><strong>Network stability</strong>: Bounded weights prevent extreme activation values</li> | |
84 | * <li><strong>Evolution readiness</strong>: Initial weights suitable for gradient-based optimization</li> | |
85 | * </ul> | |
86 | * | |
87 | * <p>Performance considerations: | |
88 | * <ul> | |
89 | * <li><strong>Linear time complexity</strong>: O(numInputs × numOutputs) generation time</li> | |
90 | * <li><strong>Memory efficiency</strong>: Minimal memory allocation during generation</li> | |
91 | * <li><strong>Innovation caching</strong>: InnovationManager provides O(1) innovation number lookup</li> | |
92 | * <li><strong>Thread safety</strong>: Safe for concurrent chromosome generation</li> | |
93 | * </ul> | |
94 | * | |
95 | * @see NeatChromosome | |
96 | * @see NeatChromosomeSpec | |
97 | * @see InnovationManager | |
98 | * @see ChromosomeFactory | |
99 | */ | |
100 | public class NeatConnectedChromosomeFactory implements ChromosomeFactory<NeatChromosome> { | |
101 | ||
102 | private final RandomGenerator randomGenerator; | |
103 | private final InnovationManager innovationManager; | |
104 | ||
105 | /** | |
106 | * Constructs a new connected chromosome factory with the specified components. | |
107 | * | |
108 | * <p>The random generator is used for weight initialization, providing behavioral | |
109 | * diversity in the initial population. The innovation manager ensures consistent | |
110 | * innovation number assignment across all generated chromosomes. | |
111 | * | |
112 | * @param _randomGenerator random number generator for weight initialization | |
113 | * @param _innovationManager innovation manager for tracking structural innovations | |
114 | * @throws IllegalArgumentException if randomGenerator or innovationManager is null | |
115 | */ | |
116 | public NeatConnectedChromosomeFactory(final RandomGenerator _randomGenerator, | |
117 | final InnovationManager _innovationManager) { | |
118 | Validate.notNull(_randomGenerator); | |
119 | Validate.notNull(_innovationManager); | |
120 | ||
121 |
1
1. <init> : Removed assignment to member variable randomGenerator → KILLED |
this.randomGenerator = _randomGenerator; |
122 |
1
1. <init> : Removed assignment to member variable innovationManager → KILLED |
this.innovationManager = _innovationManager; |
123 | } | |
124 | ||
125 | /** | |
126 | * Determines whether this factory can generate chromosomes for the given specification. | |
127 | * | |
128 | * <p>This factory specifically handles NeatChromosomeSpec specifications, which define | |
129 | * the input/output structure and weight bounds for NEAT neural networks. | |
130 | * | |
131 | * @param chromosomeSpec the chromosome specification to check | |
132 | * @return true if chromosomeSpec is a NeatChromosomeSpec, false otherwise | |
133 | * @throws IllegalArgumentException if chromosomeSpec is null | |
134 | */ | |
135 | @Override | |
136 | public boolean canHandle(final ChromosomeSpec chromosomeSpec) { | |
137 | Validate.notNull(chromosomeSpec); | |
138 | ||
139 |
2
1. canHandle : replaced boolean return with false for net/bmahe/genetics4j/neat/chromosomes/factory/NeatConnectedChromosomeFactory::canHandle → KILLED 2. canHandle : replaced boolean return with true for net/bmahe/genetics4j/neat/chromosomes/factory/NeatConnectedChromosomeFactory::canHandle → KILLED |
return chromosomeSpec instanceof NeatChromosomeSpec; |
140 | } | |
141 | ||
142 | /** | |
143 | * Generates a fully-connected NEAT chromosome based on the given specification. | |
144 | * | |
145 | * <p>This method creates a neural network chromosome with direct connections between | |
146 | * all input and output nodes. Each connection is initialized with a random weight | |
147 | * within the specified bounds and assigned a unique innovation number for genetic | |
148 | * tracking. | |
149 | * | |
150 | * <p>Generation process: | |
151 | * <ol> | |
152 | * <li>Extract network parameters from the chromosome specification</li> | |
153 | * <li>Create connections between all input-output node pairs</li> | |
154 | * <li>Assign innovation numbers to each connection type</li> | |
155 | * <li>Initialize connection weights randomly within bounds</li> | |
156 | * <li>Enable all connections for immediate network functionality</li> | |
157 | * <li>Construct and return the complete chromosome</li> | |
158 | * </ol> | |
159 | * | |
160 | * @param chromosomeSpec the NEAT chromosome specification defining network structure | |
161 | * @return a new fully-connected NEAT chromosome | |
162 | * @throws IllegalArgumentException if chromosomeSpec is null or not a NeatChromosomeSpec | |
163 | */ | |
164 | @Override | |
165 | public NeatChromosome generate(final ChromosomeSpec chromosomeSpec) { | |
166 | Validate.notNull(chromosomeSpec); | |
167 | Validate.isInstanceOf(NeatChromosomeSpec.class, chromosomeSpec); | |
168 | ||
169 | final NeatChromosomeSpec neatChromosomeSpec = (NeatChromosomeSpec) chromosomeSpec; | |
170 |
1
1. generate : removed call to net/bmahe/genetics4j/neat/spec/NeatChromosomeSpec::numInputs → KILLED |
final int numInputs = neatChromosomeSpec.numInputs(); |
171 |
1
1. generate : removed call to net/bmahe/genetics4j/neat/spec/NeatChromosomeSpec::numOutputs → KILLED |
final int numOutputs = neatChromosomeSpec.numOutputs(); |
172 |
1
1. generate : removed call to net/bmahe/genetics4j/neat/spec/NeatChromosomeSpec::minWeightValue → KILLED |
float minWeightValue = neatChromosomeSpec.minWeightValue(); |
173 |
1
1. generate : removed call to net/bmahe/genetics4j/neat/spec/NeatChromosomeSpec::maxWeightValue → KILLED |
float maxWeightValue = neatChromosomeSpec.maxWeightValue(); |
174 | ||
175 |
1
1. generate : removed call to java/util/ArrayList::<init> → KILLED |
final List<Connection> connections = new ArrayList<>(); |
176 |
5
1. generate : changed conditional boundary → KILLED 2. generate : Substituted 0 with 1 → KILLED 3. generate : removed conditional - replaced comparison check with false → KILLED 4. generate : negated conditional → KILLED 5. generate : removed conditional - replaced comparison check with true → KILLED |
for (int inputIndex = 0; inputIndex < numInputs; inputIndex++) { |
177 |
5
1. generate : removed conditional - replaced comparison check with true → TIMED_OUT 2. generate : Replaced integer addition with subtraction → KILLED 3. generate : removed conditional - replaced comparison check with false → KILLED 4. generate : negated conditional → KILLED 5. generate : changed conditional boundary → KILLED |
for (int outputIndex = numInputs; outputIndex < numInputs + numOutputs; outputIndex++) { |
178 | ||
179 |
2
1. generate : replaced call to net/bmahe/genetics4j/neat/InnovationManager::computeNewId with argument → KILLED 2. generate : removed call to net/bmahe/genetics4j/neat/InnovationManager::computeNewId → KILLED |
final int innovation = innovationManager.computeNewId(inputIndex, outputIndex); |
180 |
1
1. generate : removed call to net/bmahe/genetics4j/neat/Connection::builder → KILLED |
final Connection connection = Connection.builder() |
181 |
2
1. generate : removed call to net/bmahe/genetics4j/neat/Connection$Builder::fromNodeIndex → KILLED 2. generate : replaced call to net/bmahe/genetics4j/neat/Connection$Builder::fromNodeIndex with receiver → KILLED |
.fromNodeIndex(inputIndex) |
182 |
2
1. generate : removed call to net/bmahe/genetics4j/neat/Connection$Builder::toNodeIndex → KILLED 2. generate : replaced call to net/bmahe/genetics4j/neat/Connection$Builder::toNodeIndex with receiver → KILLED |
.toNodeIndex(outputIndex) |
183 |
3
1. generate : Substituted 1 with 0 → KILLED 2. generate : removed call to net/bmahe/genetics4j/neat/Connection$Builder::innovation → KILLED 3. generate : replaced call to net/bmahe/genetics4j/neat/Connection$Builder::innovation with receiver → KILLED |
.innovation(innovation) |
184 |
2
1. generate : removed call to net/bmahe/genetics4j/neat/Connection$Builder::isEnabled → KILLED 2. generate : replaced call to net/bmahe/genetics4j/neat/Connection$Builder::isEnabled with receiver → KILLED |
.isEnabled(true) |
185 |
4
1. generate : removed call to net/bmahe/genetics4j/neat/Connection$Builder::weight → KILLED 2. generate : replaced call to java/util/random/RandomGenerator::nextFloat with argument → KILLED 3. generate : removed call to java/util/random/RandomGenerator::nextFloat → KILLED 4. generate : replaced call to net/bmahe/genetics4j/neat/Connection$Builder::weight with receiver → KILLED |
.weight(randomGenerator.nextFloat(minWeightValue, maxWeightValue)) |
186 |
1
1. generate : removed call to net/bmahe/genetics4j/neat/Connection$Builder::build → KILLED |
.build(); |
187 |
1
1. generate : removed call to java/util/List::add → KILLED |
connections.add(connection); |
188 | } | |
189 | } | |
190 | ||
191 |
2
1. generate : replaced return value with null for net/bmahe/genetics4j/neat/chromosomes/factory/NeatConnectedChromosomeFactory::generate → KILLED 2. generate : removed call to net/bmahe/genetics4j/neat/chromosomes/NeatChromosome::<init> → KILLED |
return new NeatChromosome(numInputs, numOutputs, minWeightValue, maxWeightValue, connections); |
192 | } | |
193 | } | |
Mutations | ||
121 |
1.1 |
|
122 |
1.1 |
|
139 |
1.1 2.2 |
|
170 |
1.1 |
|
171 |
1.1 |
|
172 |
1.1 |
|
173 |
1.1 |
|
175 |
1.1 |
|
176 |
1.1 2.2 3.3 4.4 5.5 |
|
177 |
1.1 2.2 3.3 4.4 5.5 |
|
179 |
1.1 2.2 |
|
180 |
1.1 |
|
181 |
1.1 2.2 |
|
182 |
1.1 2.2 |
|
183 |
1.1 2.2 3.3 |
|
184 |
1.1 2.2 |
|
185 |
1.1 2.2 3.3 4.4 |
|
186 |
1.1 |
|
187 |
1.1 |
|
191 |
1.1 2.2 |