public NeatGenomeAcyclicBuilder(MetaNeatGenome <T> metaNeatGenome)
 {
     Debug.Assert(null != metaNeatGenome && metaNeatGenome.IsAcyclic);
     _metaNeatGenome     = metaNeatGenome;
     _graphDepthAnalysis = new AcyclicGraphDepthAnalysis();
     _workingIdSet       = new HashSet <int>();
 }
Exemple #2
0
 /// <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;
        }
Exemple #4
0
        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);
        }
Exemple #5
0
        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);
        }
Exemple #6
0
 public static INeatGenomeBuilder <T> Create(
     MetaNeatGenome <T> metaNeatGenome)
 {
     if (metaNeatGenome.IsAcyclic)
     {
         return(new NeatGenomeAcyclicBuilder <T>(metaNeatGenome));
     }
     // else
     return(new NeatGenomeBuilder <T>(metaNeatGenome));
 }
Exemple #7
0
        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);
        }
Exemple #10
0
        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>();
 }
Exemple #12
0
        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)
                        );
                }
            }
        }
Exemple #13
0
 /// <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);
                }
            }
        }