public NeatGenomeAcyclicBuilder(MetaNeatGenome <T> metaNeatGenome) { Debug.Assert(null != metaNeatGenome && metaNeatGenome.IsAcyclic); _metaNeatGenome = metaNeatGenome; _graphDepthAnalysis = new AcyclicGraphDepthAnalysis(); _workingIdSet = new HashSet <int>(); }
/// <summary> /// Construct with the given NEAT genome metadata. /// </summary> /// <param name="metaNeatGenome">NEAT genome metadata.</param> /// <param name="validateAcyclic">Enable acyclic graph validation.</param> /// <remarks> /// If the caller can guarantee that calls to Create() will provide acyclic graphs only, then /// <paramref name="validateAcyclic"/> can be set to false to avoid the cost of the cyclic graph check (which is relatively expensive to perform). /// </remarks> public NeatGenomeBuilderAcyclic(MetaNeatGenome <T> metaNeatGenome, bool validateAcyclic) { Debug.Assert(metaNeatGenome is object && metaNeatGenome.IsAcyclic); _metaNeatGenome = metaNeatGenome; _graphDepthAnalysis = new AcyclicGraphDepthAnalysis(validateAcyclic); _workingIdSet = new HashSet <int>(); }
/// <summary> /// Constructs with the provided ID, birth generation and gene arrays. /// </summary> internal NeatGenome( MetaNeatGenome <T> metaNeatGenome, int id, int birthGeneration, ConnectionGenes <T> connGenes, int[] hiddenNodeIdArr, INodeIdMap nodeIndexByIdMap, DirectedGraph digraph, int[] connectionIndexMap) { #if DEBUG NeatGenomeAssertions <T> .AssertIsValid( metaNeatGenome, id, birthGeneration, connGenes, hiddenNodeIdArr, nodeIndexByIdMap, digraph, connectionIndexMap); #endif this.MetaNeatGenome = metaNeatGenome; this.Id = id; this.BirthGeneration = birthGeneration; this.ConnectionGenes = connGenes; this.HiddenNodeIdArray = hiddenNodeIdArr; this.NodeIndexByIdMap = nodeIndexByIdMap; this.DirectedGraph = digraph; this.ConnectionIndexMap = connectionIndexMap; }
public static DirectedGraph CreateDirectedGraph <T>( MetaNeatGenome <T> metaNeatGenome, ConnectionGenes <T> connGenes, INodeIdMap nodeIndexByIdMap) where T : struct { // Extract/copy the neat genome connectivity graph into an array of DirectedConnection. // Notes. // The array contents will be manipulated, so copying this avoids modification of the genome's // connection gene list. // The IDs are substituted for node indexes here. CopyAndMapIds( connGenes._connArr, nodeIndexByIdMap, out ConnectionIdArrays connIdArrays); // Construct a new DirectedGraph. var digraph = new DirectedGraph( connIdArrays, metaNeatGenome.InputNodeCount, metaNeatGenome.OutputNodeCount, nodeIndexByIdMap.Count); return(digraph); }
public static void AssertIsValid( MetaNeatGenome <T> metaNeatGenome, int id, int birthGeneration, ConnectionGenes <T> connGenes, int[] hiddenNodeIdArr, INodeIdMap nodeIndexByIdMap, DirectedGraph digraph, int[] connectionIndexMap) { // Mandatory ref tests. Debug.Assert(null != metaNeatGenome); Debug.Assert(null != connGenes); Debug.Assert(null != hiddenNodeIdArr); Debug.Assert(null != nodeIndexByIdMap); Debug.Assert(null != digraph); // Acyclic graph checks. if (metaNeatGenome.IsAcyclic) { AssertAcyclicGraph(metaNeatGenome, digraph, connectionIndexMap); } // Node counts. AssertNodeCounts(metaNeatGenome, hiddenNodeIdArr, nodeIndexByIdMap, digraph); // Hidden node IDs. Debug.Assert(ConnectionGenesUtils.ValidateHiddenNodeIds(hiddenNodeIdArr, connGenes._connArr, metaNeatGenome.InputOutputNodeCount)); // Connections. AssertConnections(connGenes, digraph, nodeIndexByIdMap, connectionIndexMap); }
public static INeatGenomeBuilder <T> Create( MetaNeatGenome <T> metaNeatGenome) { if (metaNeatGenome.IsAcyclic) { return(new NeatGenomeAcyclicBuilder <T>(metaNeatGenome)); } // else return(new NeatGenomeBuilder <T>(metaNeatGenome)); }
private static void AssertNodeCounts( MetaNeatGenome <T> metaNeatGenome, int[] hiddenNodeIdArr, INodeIdMap nodeIndexByIdMap, DirectedGraph digraph) { int totalNodeCount = metaNeatGenome.InputNodeCount + metaNeatGenome.OutputNodeCount + hiddenNodeIdArr.Length; Debug.Assert(digraph.InputCount == metaNeatGenome.InputNodeCount); Debug.Assert(digraph.OutputCount == metaNeatGenome.OutputNodeCount); Debug.Assert(digraph.TotalNodeCount == totalNodeCount); Debug.Assert(nodeIndexByIdMap.Count == totalNodeCount); }
private static bool ValidateNodeCounts( MetaNeatGenome <T> metaNeatGenome, int[] hiddenNodeIdArr, INodeIdMap nodeIndexByIdMap, DirectedGraph digraph) { int totalNodeCount = metaNeatGenome.InputNodeCount + metaNeatGenome.OutputNodeCount + hiddenNodeIdArr.Length; return(digraph.InputCount == metaNeatGenome.InputNodeCount && digraph.OutputCount == metaNeatGenome.OutputNodeCount && digraph.TotalNodeCount == totalNodeCount && nodeIndexByIdMap.Count == totalNodeCount); }
private static bool IsValid_Acyclic( MetaNeatGenome <T> metaNeatGenome, GraphDepthInfo depthInfo) { // DepthInfo is mandatory for acyclic graphs. if (null == depthInfo) { return(false); } // Test that all input nodes are at depth zero. // Any input node with a non-zero depth must have an input connection, and this is not supported. if (!ArrayUtils.Equals(depthInfo._nodeDepthArr, 0, 0, metaNeatGenome.InputNodeCount)) { return(false); } // TODO: More acyclic graph validation. return(true); }
public static void AssertIsValid( MetaNeatGenome <T> metaNeatGenome, int id, int birthGeneration, ConnectionGenes <T> connGenes, int[] hiddenNodeIdArr, INodeIdMap nodeIndexByIdMap, DirectedGraph digraph, int[]?connectionIndexMap) { // Check for mandatory object references. Debug.Assert(metaNeatGenome is object); Debug.Assert(connGenes is object); Debug.Assert(hiddenNodeIdArr is object); Debug.Assert(nodeIndexByIdMap is object); Debug.Assert(digraph is object); // Basic check on ID and birth generation. Debug.Assert(id >= 0); Debug.Assert(birthGeneration >= 0); // Acyclic graph checks. if (metaNeatGenome.IsAcyclic) { AssertAcyclicGraph(metaNeatGenome, digraph, connectionIndexMap); } // Node counts. AssertNodeCounts(metaNeatGenome, hiddenNodeIdArr, nodeIndexByIdMap, digraph); // Hidden node IDs. Debug.Assert(ConnectionGenesUtils.ValidateHiddenNodeIds(hiddenNodeIdArr, connGenes._connArr, metaNeatGenome.InputOutputNodeCount)); // Connections. AssertConnections(connGenes, digraph, nodeIndexByIdMap, connectionIndexMap); }
public NeatGenomeBuilder(MetaNeatGenome <T> metaNeatGenome) { Debug.Assert(null != metaNeatGenome && !metaNeatGenome.IsAcyclic); _metaNeatGenome = metaNeatGenome; _workingIdSet = new HashSet <int>(); }
private static void AssertAcyclicGraph( MetaNeatGenome <T> metaNeatGenome, DirectedGraph digraph, int[]?connectionIndexMap) { Debug.Assert(digraph is DirectedGraphAcyclic); Debug.Assert(connectionIndexMap is object); // Cast to an acyclic digraph. var acyclicDigraph = (DirectedGraphAcyclic)digraph; // Layer info checks. LayerInfo[] layerArr = acyclicDigraph.LayerArray; Debug.Assert(layerArr is object && layerArr.Length > 0); // Layer zero is the input layer, thus the number of nodes in this layer should be at least the number of input nodes. // Note. Any node with no incoming connections is also assigned to layer zero, therefore there can be non-input nodes in // this layer too. Debug.Assert(layerArr[0].EndNodeIdx >= metaNeatGenome.InputNodeCount); // EndNodeIdx is strictly increasing, as is EndConnectionIdx. // Note. There is always at least one node in a layer (otherwise the layer would not exist). for (int i = 1; i < layerArr.Length; i++) { Debug.Assert(layerArr[i - 1].EndNodeIdx < layerArr[i].EndNodeIdx); } // EndConnectionIdx is strictly increasing, except for the last layer which has no connections by definition (if // there was a connection it would result in one more layer!). for (int i = 1; i < layerArr.Length - 1; i++) { Debug.Assert(layerArr[i - 1].EndConnectionIdx < layerArr[i].EndConnectionIdx); } // The last layer has no connections, by definition. // Note. In principle there can be a single layer, i.e. a bunch of nodes with no connections between them; // it's nonsensical, but it's not disallowed. int lastLayerIdx = layerArr.Length - 1; if (lastLayerIdx > 0) { Debug.Assert(layerArr[lastLayerIdx].EndConnectionIdx == layerArr[lastLayerIdx - 1].EndConnectionIdx); } // Reconstruct a GraphDepthInfo from the layer info. GraphDepthInfo depthInfo = BuildGraphDepthInfo(layerArr, digraph.TotalNodeCount); int[] nodeDepthArr = depthInfo._nodeDepthArr; // Connection tests. int connIdx = 0; int[] srcIdArr = digraph.ConnectionIdArrays._sourceIdArr; int[] tgtIdArr = digraph.ConnectionIdArrays._targetIdArr; // Loop the layer infos. for (int layerIdx = 0; layerIdx < layerArr.Length; layerIdx++) { LayerInfo layerInfo = layerArr[layerIdx]; // EndNodeIdx should never be negative or higher than the total node count. Debug.Assert(layerInfo.EndNodeIdx >= 0 && layerInfo.EndNodeIdx <= digraph.TotalNodeCount); // Loop the connections in the current layer. for (; connIdx < layerInfo.EndConnectionIdx; connIdx++) { int srcId = srcIdArr[connIdx]; int tgtId = tgtIdArr[connIdx]; // The connections in the current layer should all have a source node in this layer. Debug.Assert(nodeDepthArr[srcId] == layerIdx); // The target node should normally be in a higher layer. However, layer zero is a special case because it // contains not only the input nodes, but can also contain hidden nodes that are not reachable from an input node. // // Thus, the connections in layer zero should have either: // a) an input source node in this layer, and a target node in a layer with a higher layer index, or, // b) a hidden source node in this layer, and a target node that can be in any layer, including layer zero // if the target node is also unreachable from an input node (i.e. via another connectivity path). Debug.Assert( (layerIdx == 0 && (srcId >= digraph.InputCount || nodeDepthArr[tgtId] > 0)) || (layerIdx > 0 && nodeDepthArr[tgtId] > layerIdx) ); } } }
/// <summary> /// Construct with the given NEAT genome metadata. /// </summary> /// <param name="metaNeatGenome">NEAT genome metadata.</param> public NeatGenomeBuilderCyclic(MetaNeatGenome <T> metaNeatGenome) { Debug.Assert(metaNeatGenome is object && !metaNeatGenome.IsAcyclic); _metaNeatGenome = metaNeatGenome; _workingIdSet = new HashSet <int>(); }
public NeatGenomeBuilder(MetaNeatGenome <T> metaNeatGenome) { Debug.Assert(null != metaNeatGenome && !metaNeatGenome.IsAcyclic); _metaNeatGenome = metaNeatGenome; }
public static bool IsValid( MetaNeatGenome <T> metaNeatGenome, int id, int birthGeneration, ConnectionGenes <T> connGenes, int[] hiddenNodeIdArr, INodeIdMap nodeIndexByIdMap, DirectedGraph digraph, int[] connectionIndexMap) { // Mandatory ref tests. if (null == metaNeatGenome || null == connGenes || null == hiddenNodeIdArr || null == nodeIndexByIdMap || null == digraph) { return(false); } // Acyclic/cyclic specific checks. if (metaNeatGenome.IsAcyclic) { if (digraph.GetType() != typeof(AcyclicDirectedGraph) || null == connectionIndexMap) { return(false); } } else { if (digraph.GetType() != typeof(DirectedGraph)) { return(false); } } // DepthInfo relates to acyclic graphs only, and is mandatory for acyclic graphs. // TODO: Enable once NeatGenomeAcyclicBuilder is finished. //if(metaNeatGenome.IsAcyclic) //{ // if(!IsValid_Acyclic(metaNeatGenome, depthInfo)) { // return false; // } //} // Node counts. if (!ValidateNodeCounts(metaNeatGenome, hiddenNodeIdArr, nodeIndexByIdMap, digraph)) { return(false); } // Hidden node IDs. if (!ConnectionGenesUtils.ValidateHiddenNodeIds(hiddenNodeIdArr, connGenes._connArr, metaNeatGenome.InputOutputNodeCount)) { return(false); } // Connections. if (!ValidateConnections(connGenes, digraph, nodeIndexByIdMap, connectionIndexMap)) { return(false); } // All tests passed. return(true); }
private static void AssertAcyclicGraph( MetaNeatGenome <T> metaNeatGenome, DirectedGraph digraph, int[] connectionIndexMap) { Debug.Assert(digraph is AcyclicDirectedGraph); Debug.Assert(null != connectionIndexMap); // Cast to an acyclic digraph. var acyclicDigraph = (AcyclicDirectedGraph)digraph; // Layer info checks. LayerInfo[] layerArr = acyclicDigraph.LayerArray; Debug.Assert(null != layerArr && layerArr.Length > 0); // Layer 0 is the input layer, thus the number of nodes in this layer should be at least the number of input nodes. // Note. Any node with no incoming connections is assigned to layer 0, therefore there can be non input nodes in // this layer too. Debug.Assert(layerArr[0].EndNodeIdx >= metaNeatGenome.InputNodeCount); // EndNodeIdx is strictly increasing, as is EndConnectionIdx. // Note. There is always at least one node in a layer (otherwise the layer would not exist). for (int i = 1; i < layerArr.Length; i++) { Debug.Assert(layerArr[i - 1].EndNodeIdx < layerArr[i].EndNodeIdx); } // EndConnectionIdx is strictly increasing, except for the last layer which has no connections by definition (if // there was a connection it would result in one more layer!). for (int i = 1; i < layerArr.Length - 1; i++) { Debug.Assert(layerArr[i - 1].EndConnectionIdx < layerArr[i].EndConnectionIdx); } // The last layer has no connections, by definition. // Note. In principle there can be a single layer, i.e. a bunch of nodes with no connections between them; // it's nonsensical, but it's not disallowed. int lastLayerIdx = layerArr.Length - 1; if (lastLayerIdx > 0) { Debug.Assert(layerArr[lastLayerIdx].EndConnectionIdx == layerArr[lastLayerIdx - 1].EndConnectionIdx); } // Reconstruct a GraphDepthInfo from the layer info. GraphDepthInfo depthInfo = BuildGraphDepthInfo(layerArr, digraph.TotalNodeCount); int[] nodeDepthArr = depthInfo._nodeDepthArr; // Connection tests. int connIdx = 0; int[] srcIdArr = digraph.ConnectionIdArrays._sourceIdArr; int[] tgtIdArr = digraph.ConnectionIdArrays._targetIdArr; // Loop the layer infos. for (int layerIdx = 0; layerIdx < layerArr.Length; layerIdx++) { LayerInfo layerInfo = layerArr[layerIdx]; // EndNodeIdx should never be negative or higher than the total node count. Debug.Assert(layerInfo.EndNodeIdx >= 0 && layerInfo.EndNodeIdx <= digraph.TotalNodeCount); // The connections in this layer should all have a source node in this layer, and a target node in a layer // with a higher layer index. for (; connIdx < layerInfo.EndConnectionIdx; connIdx++) { int srcId = srcIdArr[connIdx]; int tgtId = tgtIdArr[connIdx]; Debug.Assert(nodeDepthArr[srcId] == layerIdx); Debug.Assert(nodeDepthArr[tgtId] > layerIdx); } } }