NeatNodeLayout.java
package net.bmahe.genetics4j.neat.spec;
import java.util.List;
/**
* Describes the stable external node identities and hidden-node namespace of a NEAT chromosome.
*
* <p>Input and output lists preserve declaration order. That order defines the mapping between external vectors and
* node IDs, while the IDs themselves are opaque and may be sparse. The hidden-node range is half-open: its lower bound
* is inclusive and its upper bound is exclusive.
*
* <p>Implementations must provide non-empty input and output lists containing unique, non-negative, disjoint IDs. No
* external ID may fall inside the hidden-node range. Implementations should also provide value semantics when they are
* used as chromosome layouts.
*
* @see ContiguousNeatNodeLayout
* @see ExplicitNeatNodeLayout
*/
public interface NeatNodeLayout {
/** Exclusive upper bound of the non-negative {@code int} node-ID domain. */
long MAX_NODE_ID_EXCLUSIVE = (long) Integer.MAX_VALUE + 1L;
/**
* Returns input node IDs in external vector order.
*
* @return an ordered, non-empty list of input node IDs
*/
List<Integer> inputNodeIds();
/**
* Returns output node IDs in external vector order.
*
* @return an ordered, non-empty list of output node IDs
*/
List<Integer> outputNodeIds();
/**
* Returns the first ID reserved for hidden nodes.
*
* @return the inclusive hidden-node range start
*/
long hiddenNodeIdStartInclusive();
/**
* Returns the exclusive end of the hidden-node namespace.
*
* @return the exclusive hidden-node range end
*/
long hiddenNodeIdEndExclusive();
/** @return the number of declared input nodes */
default int numInputs() {
return inputNodeIds().size();
}
/** @return the number of declared output nodes */
default int numOutputs() {
return outputNodeIds().size();
}
/**
* Tests whether an ID identifies an input node.
*
* @param nodeId node ID to test
* @return {@code true} when the ID is a declared input
*/
default boolean isInput(final int nodeId) {
return inputNodeIds().contains(nodeId);
}
/**
* Tests whether an ID identifies an output node.
*
* @param nodeId node ID to test
* @return {@code true} when the ID is a declared output
*/
default boolean isOutput(final int nodeId) {
return outputNodeIds().contains(nodeId);
}
/**
* Tests whether an ID identifies either an input or output node.
*
* @param nodeId node ID to test
* @return {@code true} when the ID is external
*/
default boolean isExternal(final int nodeId) {
return isInput(nodeId) || isOutput(nodeId);
}
/**
* Tests whether an ID belongs to the reserved hidden-node range.
*
* @param nodeId node ID to test
* @return {@code true} when the ID is in the hidden-node namespace
*/
default boolean isHidden(final int nodeId) {
return nodeId >= hiddenNodeIdStartInclusive() && nodeId < hiddenNodeIdEndExclusive();
}
/**
* Tests semantic compatibility with another layout.
*
* <p>Compatible layouts declare identical ordered input and output IDs and the same hidden-node range. Their
* concrete
* implementation classes do not need to match.
*
* @param other layout to compare
* @return {@code true} when chromosomes using the layouts can safely be combined
*/
default boolean isCompatibleWith(final NeatNodeLayout other) {
return other != null && inputNodeIds().equals(other.inputNodeIds())
&& outputNodeIds().equals(other.outputNodeIds())
&& hiddenNodeIdStartInclusive() == other.hiddenNodeIdStartInclusive()
&& hiddenNodeIdEndExclusive() == other.hiddenNodeIdEndExclusive();
}
/**
* Creates a traditional contiguous layout with the remainder of the non-negative {@code int} domain reserved for
* hidden nodes.
*
* @param numInputs number of input nodes; must be positive
* @param numOutputs number of output nodes; must be positive
* @return a validated contiguous layout
*/
static NeatNodeLayout contiguous(final int numInputs, final int numOutputs) {
final long hiddenStart = (long) numInputs + numOutputs;
return contiguous(numInputs, numOutputs, hiddenStart, MAX_NODE_ID_EXCLUSIVE);
}
/**
* Creates a contiguous external layout with an explicit hidden-node range.
*
* @param numInputs number of input nodes; must be positive
* @param numOutputs number of output nodes; must be positive
* @param hiddenNodeIdStartInclusive inclusive hidden-node range start
* @param hiddenNodeIdEndExclusive exclusive hidden-node range end
* @return a validated contiguous layout
*/
static NeatNodeLayout contiguous(final int numInputs, final int numOutputs, final long hiddenNodeIdStartInclusive,
final long hiddenNodeIdEndExclusive) {
return new ContiguousNeatNodeLayout(numInputs, numOutputs, hiddenNodeIdStartInclusive, hiddenNodeIdEndExclusive);
}
/**
* Creates a layout with explicitly ordered external IDs and a dedicated hidden-node range.
*
* @param inputNodeIds input IDs in vector order
* @param outputNodeIds output IDs in vector order
* @param hiddenNodeIdStartInclusive inclusive hidden-node range start
* @param hiddenNodeIdEndExclusive exclusive hidden-node range end
* @return a validated explicit layout
*/
static NeatNodeLayout explicit(final List<Integer> inputNodeIds, final List<Integer> outputNodeIds,
final long hiddenNodeIdStartInclusive, final long hiddenNodeIdEndExclusive) {
return new ExplicitNeatNodeLayout(inputNodeIds,
outputNodeIds,
hiddenNodeIdStartInclusive,
hiddenNodeIdEndExclusive);
}
}