ExplicitNeatNodeLayout.java

package net.bmahe.genetics4j.neat.spec;

import java.util.List;
import java.util.Objects;

/**
 * Node layout with explicitly declared, ordered input and output IDs.
 *
 * <p>The constructor defensively copies both lists. IDs must be unique, non-negative, disjoint between inputs and
 * outputs, and outside the configured hidden-node range.
 */
public class ExplicitNeatNodeLayout implements NeatNodeLayout {

	private final List<Integer> inputNodeIds;
	private final List<Integer> outputNodeIds;
	private final long hiddenNodeIdStartInclusive;
	private final long hiddenNodeIdEndExclusive;

	/**
	 * Creates an explicit node layout.
	 *
	 * @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
	 * @throws NullPointerException     if either external-ID list or one of its elements is {@code null}
	 * @throws IllegalArgumentException if the external IDs or hidden-node range are invalid
	 */
	public ExplicitNeatNodeLayout(final List<Integer> _inputNodeIds,
			final List<Integer> _outputNodeIds,
			final long _hiddenNodeIdStartInclusive,
			final long _hiddenNodeIdEndExclusive) {
		inputNodeIds = List.copyOf(_inputNodeIds);
		outputNodeIds = List.copyOf(_outputNodeIds);
		NeatNodeLayoutValidation
				.validate(inputNodeIds, outputNodeIds, _hiddenNodeIdStartInclusive, _hiddenNodeIdEndExclusive);
		hiddenNodeIdStartInclusive = _hiddenNodeIdStartInclusive;
		hiddenNodeIdEndExclusive = _hiddenNodeIdEndExclusive;
	}

	@Override
	public List<Integer> inputNodeIds() {
		return inputNodeIds;
	}

	@Override
	public List<Integer> outputNodeIds() {
		return outputNodeIds;
	}

	@Override
	public long hiddenNodeIdStartInclusive() {
		return hiddenNodeIdStartInclusive;
	}

	@Override
	public long hiddenNodeIdEndExclusive() {
		return hiddenNodeIdEndExclusive;
	}

	@Override
	public int hashCode() {
		return Objects.hash(hiddenNodeIdEndExclusive, hiddenNodeIdStartInclusive, inputNodeIds, outputNodeIds);
	}

	@Override
	public boolean equals(final Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj instanceof ExplicitNeatNodeLayout other) {
			return hiddenNodeIdEndExclusive == other.hiddenNodeIdEndExclusive
					&& hiddenNodeIdStartInclusive == other.hiddenNodeIdStartInclusive
					&& inputNodeIds.equals(other.inputNodeIds) && outputNodeIds.equals(other.outputNodeIds);
		}
		return false;
	}

	@Override
	public String toString() {
		return "ExplicitNeatNodeLayout [inputNodeIds=" + inputNodeIds + ", outputNodeIds=" + outputNodeIds
				+ ", hiddenNodeIdStartInclusive=" + hiddenNodeIdStartInclusive + ", hiddenNodeIdEndExclusive="
				+ hiddenNodeIdEndExclusive + "]";
	}
}