View Javadoc
1   package net.bmahe.genetics4j.neat.mutation.chromosome;
2   
3   import java.util.ArrayList;
4   import java.util.HashSet;
5   import java.util.List;
6   import java.util.Objects;
7   import java.util.Set;
8   import java.util.random.RandomGenerator;
9   import java.util.stream.Stream;
10  
11  import org.apache.commons.lang3.Validate;
12  import org.apache.logging.log4j.LogManager;
13  import org.apache.logging.log4j.Logger;
14  
15  import net.bmahe.genetics4j.core.chromosomes.Chromosome;
16  import net.bmahe.genetics4j.core.mutation.chromosome.ChromosomeMutationHandler;
17  import net.bmahe.genetics4j.core.spec.chromosome.ChromosomeSpec;
18  import net.bmahe.genetics4j.core.spec.mutation.MutationPolicy;
19  import net.bmahe.genetics4j.neat.Connection;
20  import net.bmahe.genetics4j.neat.chromosomes.NeatChromosome;
21  import net.bmahe.genetics4j.neat.spec.NeatChromosomeSpec;
22  import net.bmahe.genetics4j.neat.spec.mutation.DeleteNode;
23  
24  public class NeatChromosomeDeleteNodeMutationHandler implements ChromosomeMutationHandler<NeatChromosome> {
25  
26  	public static final Logger logger = LogManager.getLogger(NeatChromosomeDeleteNodeMutationHandler.class);
27  
28  	private final RandomGenerator randomGenerator;
29  
30  	public NeatChromosomeDeleteNodeMutationHandler(final RandomGenerator _randomGenerator) {
31  		Objects.requireNonNull(_randomGenerator);
32  
33  		this.randomGenerator = _randomGenerator;
34  	}
35  
36  	@Override
37  	public boolean canHandle(final MutationPolicy mutationPolicy, final ChromosomeSpec chromosome) {
38  		Objects.requireNonNull(mutationPolicy);
39  		Objects.requireNonNull(chromosome);
40  
41  		return mutationPolicy instanceof DeleteNode && chromosome instanceof NeatChromosomeSpec;
42  	}
43  
44  	@Override
45  	public NeatChromosome mutate(final MutationPolicy mutationPolicy, final Chromosome chromosome) {
46  		Objects.requireNonNull(mutationPolicy);
47  		Objects.requireNonNull(chromosome);
48  		Validate.isInstanceOf(DeleteNode.class, mutationPolicy);
49  		Validate.isInstanceOf(NeatChromosome.class, chromosome);
50  
51  		final var neatChromosome = (NeatChromosome) chromosome;
52  		final var minValue = neatChromosome.getMinWeightValue();
53  		final var maxValue = neatChromosome.getMaxWeightValue();
54  
55  		final var oldConnections = neatChromosome.getConnections();
56  
57  		final Set<Integer> inoutNodes = new HashSet<>();
58  		inoutNodes.addAll(neatChromosome.getInputNodeIds());
59  		inoutNodes.addAll(neatChromosome.getOutputNodeIds());
60  
61  		final List<Integer> allNodeValues = neatChromosome.getConnections()
62  				.stream()
63  				.flatMap(connection -> Stream.of(connection.fromNodeIndex(), connection.toNodeIndex()))
64  				.filter(nodeIndex -> inoutNodes.contains(nodeIndex) == false)
65  				.toList();
66  
67  		final Set<Integer> nodeValues = Set.copyOf(allNodeValues);
68  
69  		final List<Connection> newConnections = switch (nodeValues.size()) {
70  			case 0 -> new ArrayList<>(oldConnections);
71  			default -> {
72  				final int nodeIndexToRemove = nodeValues.size() > 1 ? randomGenerator.nextInt(nodeValues.size() - 1) : 0;
73  
74  				final int nodeValueToRemove = nodeValues.stream().skip(nodeIndexToRemove).findFirst().get();
75  
76  				yield oldConnections.stream()
77  						.filter(
78  								connection -> connection.fromNodeIndex() != nodeValueToRemove
79  										&& connection.toNodeIndex() != nodeValueToRemove)
80  						.toList();
81  			}
82  		};
83  
84  		return new NeatChromosome(neatChromosome.getNodeLayout(), minValue, maxValue, newConnections);
85  	}
86  }