View Javadoc
1   package net.bmahe.genetics4j.neat.spec;
2   
3   import java.util.List;
4   import java.util.Objects;
5   import java.util.stream.IntStream;
6   
7   import org.apache.commons.lang3.Validate;
8   
9   /**
10   * Node layout using the traditional contiguous NEAT external IDs.
11   *
12   * <p>Inputs occupy {@code [0, numInputs)} and outputs occupy {@code [numInputs, numInputs + numOutputs)}. The
13   * configured
14   * hidden-node range must not overlap those external IDs.
15   */
16  public class ContiguousNeatNodeLayout implements NeatNodeLayout {
17  
18  	private final int numInputs;
19  	private final int numOutputs;
20  	private final long hiddenNodeIdStartInclusive;
21  	private final long hiddenNodeIdEndExclusive;
22  
23  	/**
24  	 * Creates a contiguous node layout.
25  	 *
26  	 * @param _numInputs                  number of input nodes; must be positive
27  	 * @param _numOutputs                 number of output nodes; must be positive
28  	 * @param _hiddenNodeIdStartInclusive inclusive hidden-node range start
29  	 * @param _hiddenNodeIdEndExclusive   exclusive hidden-node range end
30  	 * @throws IllegalArgumentException if the counts or hidden-node range are invalid, or if the ranges overlap
31  	 */
32  	public ContiguousNeatNodeLayout(final int _numInputs,
33  			final int _numOutputs,
34  			final long _hiddenNodeIdStartInclusive,
35  			final long _hiddenNodeIdEndExclusive) {
36  		Validate.isTrue(_numInputs > 0, "Number of inputs must be positive");
37  		Validate.isTrue(_numOutputs > 0, "Number of outputs must be positive");
38  		final long externalEnd = (long) _numInputs + _numOutputs;
39  		Validate.isTrue(externalEnd <= Integer.MAX_VALUE, "External node IDs exceed the int domain");
40  		NeatNodeLayoutValidation.validate(
41  				IntStream.range(0, _numInputs).boxed().toList(),
42  					IntStream.range(_numInputs, _numInputs + _numOutputs).boxed().toList(),
43  					_hiddenNodeIdStartInclusive,
44  					_hiddenNodeIdEndExclusive);
45  
46  		numInputs = _numInputs;
47  		numOutputs = _numOutputs;
48  		hiddenNodeIdStartInclusive = _hiddenNodeIdStartInclusive;
49  		hiddenNodeIdEndExclusive = _hiddenNodeIdEndExclusive;
50  	}
51  
52  	@Override
53  	public int numInputs() {
54  		return numInputs;
55  	}
56  
57  	@Override
58  	public int numOutputs() {
59  		return numOutputs;
60  	}
61  
62  	@Override
63  	public long hiddenNodeIdStartInclusive() {
64  		return hiddenNodeIdStartInclusive;
65  	}
66  
67  	@Override
68  	public long hiddenNodeIdEndExclusive() {
69  		return hiddenNodeIdEndExclusive;
70  	}
71  
72  	@Override
73  	public List<Integer> inputNodeIds() {
74  		return IntStream.range(0, numInputs).boxed().toList();
75  	}
76  
77  	@Override
78  	public List<Integer> outputNodeIds() {
79  		return IntStream.range(numInputs, numInputs + numOutputs).boxed().toList();
80  	}
81  
82  	@Override
83  	public boolean isInput(final int nodeId) {
84  		return nodeId >= 0 && nodeId < numInputs;
85  	}
86  
87  	@Override
88  	public boolean isOutput(final int nodeId) {
89  		return nodeId >= numInputs && nodeId < numInputs + numOutputs;
90  	}
91  
92  	@Override
93  	public int hashCode() {
94  		return Objects.hash(hiddenNodeIdEndExclusive, hiddenNodeIdStartInclusive, numInputs, numOutputs);
95  	}
96  
97  	@Override
98  	public boolean equals(final Object obj) {
99  		if (this == obj) {
100 			return true;
101 		}
102 		if (obj instanceof ContiguousNeatNodeLayout other) {
103 			return hiddenNodeIdEndExclusive == other.hiddenNodeIdEndExclusive
104 					&& hiddenNodeIdStartInclusive == other.hiddenNodeIdStartInclusive && numInputs == other.numInputs
105 					&& numOutputs == other.numOutputs;
106 		}
107 		return false;
108 	}
109 
110 	@Override
111 	public String toString() {
112 		return "ContiguousNeatNodeLayout [numInputs=" + numInputs + ", numOutputs=" + numOutputs
113 				+ ", hiddenNodeIdStartInclusive=" + hiddenNodeIdStartInclusive + ", hiddenNodeIdEndExclusive="
114 				+ hiddenNodeIdEndExclusive + "]";
115 	}
116 }