public INetworkDefinition CreateNetworkDefinition(IBlackBox blackbox, bool lengthCppnInput)
{
// Get the sequence of substrate connections. Either a pre-built list or a dynamically
// generated sequence.
IEnumerable<SubstrateConnection> connectionSequence = _connectionList ?? GetConnectionSequence();
// Iterate over substrate connections. Determine each connection's weight and create a list
// of network definition connections.
ISignalArray inputSignalArr = blackbox.InputSignalArray;
ISignalArray outputSignalArr = blackbox.OutputSignalArray;
ConnectionList networkConnList = new ConnectionList(_connectionCountHint);
int lengthInputIdx = _dimensionality + _dimensionality;
foreach(SubstrateConnection substrateConn in connectionSequence)
{
// Assign the connection's endpoint position coords to the CPPN/blackbox inputs. Note that position dimensionality is not fixed.
for(int i=0; i<_dimensionality; i++)
{
inputSignalArr[i] = substrateConn._srcNode._position[i];
inputSignalArr[i + _dimensionality] = substrateConn._tgtNode._position[i];
}
// Optional connection length input.
if(lengthCppnInput) {
inputSignalArr[lengthInputIdx] = CalculateConnectionLength(substrateConn._srcNode._position, substrateConn._tgtNode._position);
}
// Reset blackbox state and activate it.
blackbox.ResetState();
blackbox.Activate();
// Read connection weight from output 0.
double weight = outputSignalArr[0];
// Skip connections with a weight magnitude less than _weightThreshold.
double weightAbs = Math.Abs(weight);
if(weightAbs > _weightThreshold)
{
// For weights over the threshold we re-scale into the range [-_maxWeight,_maxWeight],
// assuming IBlackBox outputs are in the range [-1,1].
weight = (weightAbs - _weightThreshold) * _weightRescalingCoeff * Math.Sign(weight);
// Create network definition connection and add to list.
networkConnList.Add(new NetworkConnection(substrateConn._srcNode._id,
substrateConn._tgtNode._id, weight));
}
}
// Additionally we create connections from each hidden and output node to a bias node that is not defined at any
// position on the substrate. The motivation here is that a each node's input bias is independent of any source
// node (and associated source node position on the substrate). That we refer to a bias 'node' is a consequence of how input
// biases are handled in NEAT - with a specific bias node that other nodes can be connected to.
int setCount = _nodeSetList.Count;
for(int i=1; i<setCount; i++)
{
SubstrateNodeSet nodeSet = _nodeSetList[i];
foreach(SubstrateNode node in nodeSet.NodeList)
{
// Assign the node's position coords to the blackbox inputs. The CPPN inputs for source node coords are set to zero when obtaining bias values.
for(int j=0; j<_dimensionality; j++)
{
inputSignalArr[j] = 0.0;
inputSignalArr[j + _dimensionality] = node._position[j];
}
// Optional connection length input.
if(lengthCppnInput) {
inputSignalArr[lengthInputIdx] = CalculateConnectionLength(node._position);
}
// Reset blackbox state and activate it.
blackbox.ResetState();
blackbox.Activate();
// Read bias connection weight from output 1.
double weight = outputSignalArr[1];
// Skip connections with a weight magnitude less than _weightThreshold.
double weightAbs = Math.Abs(weight);
if(weightAbs > _weightThreshold)
{
// For weights over the threshold we re-scale into the range [-_maxWeight,_maxWeight],
// assuming IBlackBox outputs are in the range [-1,1].
weight = (weightAbs - _weightThreshold) * _weightRescalingCoeff * Math.Sign(weight);
// Create network definition connection and add to list. Bias node is always ID 0.
networkConnList.Add(new NetworkConnection(0, node._id, weight));
}
}
}
// Check for no connections.
// If no connections were generated then there is no point in further evaluating the network.
// However, null is a valid response when decoding genomes to phenomes, therefore we do that here.
if(networkConnList.Count == 0) {
return null;
}
// Construct and return a network definition.
NetworkDefinition networkDef = new NetworkDefinition(_inputNodeCount, _outputNodeCount,
_activationFnLibrary, _netNodeList, networkConnList);
// Check that the definition is valid and return it.
Debug.Assert(networkDef.PerformIntegrityCheck());
return networkDef;
}