AddNodePolicyHandler.java

1
package net.bmahe.genetics4j.neat.mutation;
2
3
import java.util.random.RandomGenerator;
4
5
import org.apache.commons.lang3.Validate;
6
7
import net.bmahe.genetics4j.core.chromosomes.Chromosome;
8
import net.bmahe.genetics4j.core.mutation.GenericMutatorImpl;
9
import net.bmahe.genetics4j.core.mutation.MutationPolicyHandler;
10
import net.bmahe.genetics4j.core.mutation.MutationPolicyHandlerResolver;
11
import net.bmahe.genetics4j.core.mutation.Mutator;
12
import net.bmahe.genetics4j.core.mutation.chromosome.ChromosomeMutationHandler;
13
import net.bmahe.genetics4j.core.spec.AbstractEAConfiguration;
14
import net.bmahe.genetics4j.core.spec.AbstractEAExecutionContext;
15
import net.bmahe.genetics4j.core.spec.mutation.MutationPolicy;
16
import net.bmahe.genetics4j.core.util.ChromosomeResolverUtils;
17
import net.bmahe.genetics4j.neat.spec.mutation.AddNode;
18
19
/**
20
 * Mutation policy handler for NEAT (NeuroEvolution of Augmenting Topologies) add-node mutations.
21
 * 
22
 * <p>AddNodePolicyHandler manages the structural mutation that adds new hidden nodes to NEAT neural networks by
23
 * splitting existing connections. This is one of the most important structural mutations in NEAT as it enables the
24
 * evolution of increasingly complex network topologies.
25
 * 
26
 * <p>Add-node mutation process:
27
 * <ol>
28
 * <li><strong>Connection selection</strong>: Choose an existing enabled connection to split</li>
29
 * <li><strong>Connection disabling</strong>: Disable the original connection</li>
30
 * <li><strong>Node creation</strong>: Create a new hidden node between the connection endpoints</li>
31
 * <li><strong>Connection replacement</strong>: Create two new connections through the new node</li>
32
 * <li><strong>Innovation tracking</strong>: Assign innovation numbers to new connections</li>
33
 * <li><strong>Weight preservation</strong>: Set weights to preserve network function</li>
34
 * </ol>
35
 * 
36
 * <p>Key characteristics:
37
 * <ul>
38
 * <li><strong>Topology complexity</strong>: Increases network depth and node count</li>
39
 * <li><strong>Function preservation</strong>: Maintains network behavior through careful weight setting</li>
40
 * <li><strong>Innovation tracking</strong>: New connections receive unique innovation numbers</li>
41
 * <li><strong>Gradual growth</strong>: Incrementally increases network complexity</li>
42
 * </ul>
43
 * 
44
 * <p>Network transformation:
45
 * <ul>
46
 * <li><strong>Before</strong>: Direct connection A → B with weight W</li>
47
 * <li><strong>After</strong>: Path A → NewNode → B with weights W₁ and W₂</li>
48
 * <li><strong>Weight strategy</strong>: Often W₁ = 1.0, W₂ = W to preserve function</li>
49
 * <li><strong>Node placement</strong>: New node gets next available index</li>
50
 * </ul>
51
 * 
52
 * <p>Common usage patterns:
53
 * 
54
 * <pre>{@code
55
 * // Create add-node mutation policy
56
 * AddNode addNodePolicy = AddNode.of(0.05); // 5% mutation rate
57
 * 
58
 * // Create policy handler
59
 * RandomGenerator randomGen = RandomGenerator.getDefault();
60
 * AddNodePolicyHandler<Double> handler = new AddNodePolicyHandler<>(randomGen);
61
 * 
62
 * // Check if handler can process the policy
63
 * boolean canHandle = handler.canHandle(resolver, addNodePolicy);
64
 * 
65
 * // Create mutator for the policy
66
 * Mutator mutator = handler.createMutator(executionContext, configuration, resolver, addNodePolicy);
67
 * 
68
 * // Apply mutation to population
69
 * List<Individual<Double>> mutatedPopulation = mutator.mutate(configuration, population);
70
 * }</pre>
71
 * 
72
 * <p>Integration with NEAT algorithm:
73
 * <ul>
74
 * <li><strong>Innovation management</strong>: Coordinates with InnovationManager for new connections</li>
75
 * <li><strong>Chromosome mutation</strong>: Delegates to NeatChromosomeAddNodeMutationHandler</li>
76
 * <li><strong>Population evolution</strong>: Applied based on configured mutation probability</li>
77
 * <li><strong>Complexity growth</strong>: Primary mechanism for increasing network complexity</li>
78
 * </ul>
79
 * 
80
 * <p>Structural impact:
81
 * <ul>
82
 * <li><strong>Hidden layer growth</strong>: Creates new hidden nodes that can form layers</li>
83
 * <li><strong>Computational depth</strong>: Increases potential computational complexity</li>
84
 * <li><strong>Feature detection</strong>: New nodes can detect intermediate features</li>
85
 * <li><strong>Representation power</strong>: Enhances network's representational capacity</li>
86
 * </ul>
87
 * 
88
 * <p>Performance considerations:
89
 * <ul>
90
 * <li><strong>Conservative application</strong>: Typically applied less frequently than weight mutations</li>
91
 * <li><strong>Innovation caching</strong>: Leverages InnovationManager for efficient tracking</li>
92
 * <li><strong>Memory efficiency</strong>: Minimal allocation during mutation operations</li>
93
 * <li><strong>Function preservation</strong>: Weight setting strategies maintain network behavior</li>
94
 * </ul>
95
 * 
96
 * @param <T> the fitness value type (typically Double)
97
 * @see AddNode
98
 * @see net.bmahe.genetics4j.neat.mutation.chromosome.NeatChromosomeAddNodeMutationHandler
99
 * @see MutationPolicyHandler
100
 * @see InnovationManager
101
 */
102
public class AddNodePolicyHandler<T extends Comparable<T>> implements MutationPolicyHandler<T> {
103
104
	private final RandomGenerator randomGenerator;
105
106
	/**
107
	 * Constructs a new add-node policy handler with the specified random generator.
108
	 * 
109
	 * <p>The random generator is used for stochastic decisions during mutation application, including selection of
110
	 * individuals to mutate and selection of connections to split.
111
	 * 
112
	 * @param _randomGenerator random number generator for stochastic mutation operations
113
	 * @throws IllegalArgumentException if randomGenerator is null
114
	 */
115
	public AddNodePolicyHandler(final RandomGenerator _randomGenerator) {
116
		Validate.notNull(_randomGenerator);
117
118 1 1. <init> : Removed assignment to member variable randomGenerator → KILLED
		this.randomGenerator = _randomGenerator;
119
	}
120
121
	/**
122
	 * Determines whether this handler can process the given mutation policy.
123
	 * 
124
	 * <p>This handler specifically processes AddNode mutation policies, which configure the parameters for adding new
125
	 * hidden nodes to NEAT neural networks.
126
	 * 
127
	 * @param mutationPolicyHandlerResolver resolver for nested mutation policies
128
	 * @param mutationPolicy                the mutation policy to check
129
	 * @return true if the policy is an AddNode instance, false otherwise
130
	 * @throws IllegalArgumentException if any parameter is null
131
	 */
132
	@Override
133
	public boolean canHandle(final MutationPolicyHandlerResolver<T> mutationPolicyHandlerResolver,
134
			final MutationPolicy mutationPolicy) {
135
		Validate.notNull(mutationPolicyHandlerResolver);
136
		Validate.notNull(mutationPolicy);
137
138 2 1. canHandle : replaced boolean return with true for net/bmahe/genetics4j/neat/mutation/AddNodePolicyHandler::canHandle → KILLED
2. canHandle : replaced boolean return with false for net/bmahe/genetics4j/neat/mutation/AddNodePolicyHandler::canHandle → KILLED
		return mutationPolicy instanceof AddNode;
139
	}
140
141
	/**
142
	 * Creates a concrete mutator for add-node mutations.
143
	 * 
144
	 * <p>This method resolves the appropriate chromosome mutation handlers for NEAT chromosomes and creates a generic
145
	 * mutator that applies add-node mutations according to the specified policy parameters.
146
	 * 
147
	 * <p>Mutator creation process:
148
	 * <ol>
149
	 * <li>Extract population mutation probability from the policy</li>
150
	 * <li>Resolve chromosome-specific mutation handlers</li>
151
	 * <li>Create generic mutator with resolved components</li>
152
	 * <li>Return configured mutator ready for population application</li>
153
	 * </ol>
154
	 * 
155
	 * @param eaExecutionContext            execution context containing NEAT-specific components
156
	 * @param eaConfiguration               evolutionary algorithm configuration
157
	 * @param mutationPolicyHandlerResolver resolver for chromosome mutation handlers
158
	 * @param mutationPolicy                the add-node mutation policy
159
	 * @return a configured mutator for applying add-node mutations
160
	 * @throws IllegalArgumentException if any parameter is null
161
	 */
162
	@Override
163
	public Mutator createMutator(final AbstractEAExecutionContext<T> eaExecutionContext,
164
			final AbstractEAConfiguration<T> eaConfiguration,
165
			final MutationPolicyHandlerResolver<T> mutationPolicyHandlerResolver, MutationPolicy mutationPolicy) {
166
		Validate.notNull(eaExecutionContext);
167
		Validate.notNull(eaConfiguration);
168
		Validate.notNull(mutationPolicy);
169
		Validate.notNull(mutationPolicyHandlerResolver);
170
171
		final AddNode addNodeMutationPolicy = (AddNode) mutationPolicy;
172 1 1. createMutator : removed call to net/bmahe/genetics4j/neat/spec/mutation/AddNode::populationMutationProbability → SURVIVED
		final double populationMutationProbability = addNodeMutationPolicy.populationMutationProbability();
173
174
		final ChromosomeMutationHandler<? extends Chromosome>[] chromosomeMutationHandlers = ChromosomeResolverUtils
175 1 1. createMutator : removed call to net/bmahe/genetics4j/core/util/ChromosomeResolverUtils::resolveChromosomeMutationHandlers → KILLED
				.resolveChromosomeMutationHandlers(eaExecutionContext, eaConfiguration, mutationPolicy);
176
177 2 1. createMutator : removed call to net/bmahe/genetics4j/core/mutation/GenericMutatorImpl::<init> → KILLED
2. createMutator : replaced return value with null for net/bmahe/genetics4j/neat/mutation/AddNodePolicyHandler::createMutator → KILLED
		return new GenericMutatorImpl(randomGenerator,
178
				chromosomeMutationHandlers,
179
				mutationPolicy,
180
				populationMutationProbability);
181
	}
182
}

Mutations

118

1.1
Location : <init>
Killed by : net.bmahe.genetics4j.neat.mutation.AddNodePolicyHandlerTest.[engine:junit-jupiter]/[class:net.bmahe.genetics4j.neat.mutation.AddNodePolicyHandlerTest]/[method:createMutator()]
Removed assignment to member variable randomGenerator → KILLED

138

1.1
Location : canHandle
Killed by : net.bmahe.genetics4j.neat.mutation.AddNodePolicyHandlerTest.[engine:junit-jupiter]/[class:net.bmahe.genetics4j.neat.mutation.AddNodePolicyHandlerTest]/[method:canHandleRequireMutation()]
replaced boolean return with true for net/bmahe/genetics4j/neat/mutation/AddNodePolicyHandler::canHandle → KILLED

2.2
Location : canHandle
Killed by : net.bmahe.genetics4j.neat.mutation.AddNodePolicyHandlerTest.[engine:junit-jupiter]/[class:net.bmahe.genetics4j.neat.mutation.AddNodePolicyHandlerTest]/[method:canHandleRequireMutation()]
replaced boolean return with false for net/bmahe/genetics4j/neat/mutation/AddNodePolicyHandler::canHandle → KILLED

172

1.1
Location : createMutator
Killed by : none
removed call to net/bmahe/genetics4j/neat/spec/mutation/AddNode::populationMutationProbability → SURVIVED
Covering tests

175

1.1
Location : createMutator
Killed by : net.bmahe.genetics4j.neat.mutation.AddNodePolicyHandlerTest.[engine:junit-jupiter]/[class:net.bmahe.genetics4j.neat.mutation.AddNodePolicyHandlerTest]/[method:createMutator()]
removed call to net/bmahe/genetics4j/core/util/ChromosomeResolverUtils::resolveChromosomeMutationHandlers → KILLED

177

1.1
Location : createMutator
Killed by : net.bmahe.genetics4j.neat.mutation.AddNodePolicyHandlerTest.[engine:junit-jupiter]/[class:net.bmahe.genetics4j.neat.mutation.AddNodePolicyHandlerTest]/[method:createMutator()]
removed call to net/bmahe/genetics4j/core/mutation/GenericMutatorImpl::<init> → KILLED

2.2
Location : createMutator
Killed by : net.bmahe.genetics4j.neat.mutation.AddNodePolicyHandlerTest.[engine:junit-jupiter]/[class:net.bmahe.genetics4j.neat.mutation.AddNodePolicyHandlerTest]/[method:createMutator()]
replaced return value with null for net/bmahe/genetics4j/neat/mutation/AddNodePolicyHandler::createMutator → KILLED

Active mutators

Tests examined


Report generated by PIT 1.20.3