| 1 | package net.bmahe.genetics4j.neat.spec; | |
| 2 | ||
| 3 | import java.util.Objects; | |
| 4 | ||
| 5 | import org.apache.commons.lang3.Validate; | |
| 6 | import org.immutables.value.Value; | |
| 7 | ||
| 8 | import net.bmahe.genetics4j.core.spec.chromosome.ChromosomeSpec; | |
| 9 | ||
| 10 | /** | |
| 11 | * Specification for NEAT (NeuroEvolution of Augmenting Topologies) neural network chromosomes. | |
| 12 | * | |
| 13 | * <p>A specification defines the stable identities and vector order of the network's input and output nodes, the | |
| 14 | * namespace available to hidden nodes, and the bounds applied to connection weights. Chromosome factories and genetic | |
| 15 | * operators use the same {@link NeatNodeLayout} throughout an evolutionary run so structural mutations do not relabel | |
| 16 | * existing nodes. | |
| 17 | * | |
| 18 | * <p>Contiguous layouts preserve the traditional NEAT numbering scheme. Inputs start at zero, outputs immediately | |
| 19 | * follow the inputs, and hidden-node IDs start after the outputs: | |
| 20 | * | |
| 21 | * <pre>{@code | |
| 22 | * NeatChromosomeSpec xorSpec = NeatChromosomeSpec.of( | |
| 23 | * 2, // input IDs [0, 1] | |
| 24 | * 1, // output ID [2] | |
| 25 | * -1.0f, // minimum connection weight | |
| 26 | * 1.0f); // maximum connection weight | |
| 27 | * }</pre> | |
| 28 | * | |
| 29 | * <p>Explicit layouts support stable, ordered, non-contiguous external IDs and a dedicated hidden-node range: | |
| 30 | * | |
| 31 | * <pre>{@code | |
| 32 | * NeatNodeLayout layout = NeatNodeLayout.explicit( | |
| 33 | * List.of(10, 1_000, 1_001), // ordered input IDs | |
| 34 | * List.of(102_000), // ordered output IDs | |
| 35 | * 1_000_000, // hidden range start, inclusive | |
| 36 | * 2_000_000); // hidden range end, exclusive | |
| 37 | * | |
| 38 | * NeatChromosomeSpec sparseSpec = new NeatChromosomeSpec.Builder().nodeLayout(layout) | |
| 39 | * .minWeightValue(-2.0f) | |
| 40 | * .maxWeightValue(2.0f) | |
| 41 | * .build(); | |
| 42 | * }</pre> | |
| 43 | * | |
| 44 | * <p>Declaration order is significant: it defines how input and output vectors map to node IDs. Node IDs themselves | |
| 45 | * are opaque identities and need not be contiguous. A valid layout contains at least one input and one output, uses | |
| 46 | * unique non-negative external IDs, keeps input and output IDs disjoint, and reserves a non-empty hidden-node range | |
| 47 | * that does not overlap external IDs. | |
| 48 | * | |
| 49 | * <p>The minimum connection weight must be strictly less than the maximum. Factories use these bounds when creating | |
| 50 | * initial connections, and mutation operators use them when changing connection weights. | |
| 51 | * | |
| 52 | * @see NeatNodeLayout | |
| 53 | * @see net.bmahe.genetics4j.neat.chromosomes.NeatChromosome | |
| 54 | * @see net.bmahe.genetics4j.neat.chromosomes.factory.NeatConnectedChromosomeFactory | |
| 55 | * @see net.bmahe.genetics4j.core.spec.EAConfiguration | |
| 56 | */ | |
| 57 | @Value.Immutable | |
| 58 | public abstract class NeatChromosomeSpec implements ChromosomeSpec { | |
| 59 | ||
| 60 | /** | |
| 61 | * Returns the stable external node identities and hidden-node namespace for chromosomes created from this | |
| 62 | * specification. | |
| 63 | * | |
| 64 | * @return the node layout | |
| 65 | */ | |
| 66 | @Value.Parameter | |
| 67 | public abstract NeatNodeLayout nodeLayout(); | |
| 68 | ||
| 69 | /** | |
| 70 | * Returns the minimum allowed connection weight. | |
| 71 | * | |
| 72 | * @return the inclusive lower bound for connection weights | |
| 73 | */ | |
| 74 | @Value.Parameter | |
| 75 | public abstract float minWeightValue(); | |
| 76 | ||
| 77 | /** | |
| 78 | * Returns the maximum allowed connection weight. | |
| 79 | * | |
| 80 | * @return the inclusive upper bound for connection weights | |
| 81 | */ | |
| 82 | @Value.Parameter | |
| 83 | public abstract float maxWeightValue(); | |
| 84 | ||
| 85 | /** | |
| 86 | * Returns the number of input nodes declared by {@link #nodeLayout()}. | |
| 87 | * | |
| 88 | * @return the positive number of input nodes | |
| 89 | */ | |
| 90 | public int numInputs() { | |
| 91 |
3
1. numInputs : replaced int return with 0 for net/bmahe/genetics4j/neat/spec/NeatChromosomeSpec::numInputs → KILLED 2. numInputs : removed call to net/bmahe/genetics4j/neat/spec/NeatChromosomeSpec::nodeLayout → KILLED 3. numInputs : removed call to net/bmahe/genetics4j/neat/spec/NeatNodeLayout::numInputs → KILLED |
return nodeLayout().numInputs(); |
| 92 | } | |
| 93 | ||
| 94 | /** | |
| 95 | * Returns the number of output nodes declared by {@link #nodeLayout()}. | |
| 96 | * | |
| 97 | * @return the positive number of output nodes | |
| 98 | */ | |
| 99 | public int numOutputs() { | |
| 100 |
3
1. numOutputs : removed call to net/bmahe/genetics4j/neat/spec/NeatChromosomeSpec::nodeLayout → KILLED 2. numOutputs : removed call to net/bmahe/genetics4j/neat/spec/NeatNodeLayout::numOutputs → KILLED 3. numOutputs : replaced int return with 0 for net/bmahe/genetics4j/neat/spec/NeatChromosomeSpec::numOutputs → KILLED |
return nodeLayout().numOutputs(); |
| 101 | } | |
| 102 | ||
| 103 | @Value.Check | |
| 104 | protected void check() { | |
| 105 | Objects.requireNonNull(nodeLayout()); | |
| 106 | Validate.isTrue(minWeightValue() < maxWeightValue(), "Minimum weight must be less than maximum weight"); | |
| 107 | } | |
| 108 | ||
| 109 | /** Builds immutable NEAT chromosome specifications. */ | |
| 110 | public static class Builder extends ImmutableNeatChromosomeSpec.Builder { | |
| 111 | } | |
| 112 | ||
| 113 | /** | |
| 114 | * Creates a specification using the supplied node layout and connection-weight bounds. | |
| 115 | * | |
| 116 | * @param nodeLayout stable external IDs and hidden-node namespace | |
| 117 | * @param minWeightValue minimum allowed connection weight | |
| 118 | * @param maxWeightValue maximum allowed connection weight | |
| 119 | * @return a validated immutable chromosome specification | |
| 120 | * @throws NullPointerException if {@code nodeLayout} is {@code null} | |
| 121 | * @throws IllegalArgumentException if {@code minWeightValue} is not less than {@code maxWeightValue} | |
| 122 | */ | |
| 123 | public static NeatChromosomeSpec of(final NeatNodeLayout nodeLayout, final float minWeightValue, | |
| 124 | final float maxWeightValue) { | |
| 125 |
9
1. of : replaced call to net/bmahe/genetics4j/neat/spec/NeatChromosomeSpec$Builder::nodeLayout with receiver → KILLED 2. of : replaced call to net/bmahe/genetics4j/neat/spec/NeatChromosomeSpec$Builder::maxWeightValue with receiver → KILLED 3. of : replaced call to net/bmahe/genetics4j/neat/spec/NeatChromosomeSpec$Builder::minWeightValue with receiver → KILLED 4. of : replaced return value with null for net/bmahe/genetics4j/neat/spec/NeatChromosomeSpec::of → KILLED 5. of : removed call to net/bmahe/genetics4j/neat/spec/NeatChromosomeSpec$Builder::<init> → KILLED 6. of : removed call to net/bmahe/genetics4j/neat/spec/NeatChromosomeSpec$Builder::build → KILLED 7. of : removed call to net/bmahe/genetics4j/neat/spec/NeatChromosomeSpec$Builder::maxWeightValue → KILLED 8. of : removed call to net/bmahe/genetics4j/neat/spec/NeatChromosomeSpec$Builder::nodeLayout → KILLED 9. of : removed call to net/bmahe/genetics4j/neat/spec/NeatChromosomeSpec$Builder::minWeightValue → KILLED |
return new Builder().nodeLayout(nodeLayout).minWeightValue(minWeightValue).maxWeightValue(maxWeightValue).build(); |
| 126 | } | |
| 127 | ||
| 128 | /** | |
| 129 | * Creates a specification using the traditional contiguous node layout. | |
| 130 | * | |
| 131 | * <p>Input IDs are {@code [0, numInputs)}, output IDs are {@code [numInputs, numInputs + numOutputs)}, and the | |
| 132 | * hidden-node namespace starts at {@code numInputs + numOutputs}. | |
| 133 | * | |
| 134 | * @param numInputs number of input nodes; must be positive | |
| 135 | * @param numOutputs number of output nodes; must be positive | |
| 136 | * @param minWeightValue minimum allowed connection weight | |
| 137 | * @param maxWeightValue maximum allowed connection weight | |
| 138 | * @return a validated immutable chromosome specification | |
| 139 | * @throws IllegalArgumentException if either node count is not positive or the weight bounds are not ordered | |
| 140 | */ | |
| 141 | public static NeatChromosomeSpec of(final int numInputs, final int numOutputs, final float minWeightValue, | |
| 142 | final float maxWeightValue) { | |
| 143 |
3
1. of : replaced return value with null for net/bmahe/genetics4j/neat/spec/NeatChromosomeSpec::of → KILLED 2. of : removed call to net/bmahe/genetics4j/neat/spec/NeatNodeLayout::contiguous → KILLED 3. of : removed call to net/bmahe/genetics4j/neat/spec/NeatChromosomeSpec::of → KILLED |
return of(NeatNodeLayout.contiguous(numInputs, numOutputs), minWeightValue, maxWeightValue); |
| 144 | } | |
| 145 | } | |
Mutations | ||
| 91 |
1.1 2.2 3.3 |
|
| 100 |
1.1 2.2 3.3 |
|
| 125 |
1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 9.9 |
|
| 143 |
1.1 2.2 3.3 |