Example #1
0
        private static void AssertConnections(
            ConnectionGenes <T> connGenes,
            DirectedGraph digraph,
            INodeIdMap nodeIndexByIdMap,
            int[]?connectionIndexMap)
        {
            // Connection counts.
            Debug.Assert(connGenes._connArr.Length == digraph.ConnectionIdArrays.Length);

            // Connection order.
            Debug.Assert(SortUtils.IsSortedAscending(connGenes._connArr));
            Debug.Assert(IsSortedAscending(digraph.ConnectionIdArrays));

            // Connection node ID mappings.
            DirectedConnection[] connArr = connGenes._connArr;
            int[] srcIdArr = digraph.ConnectionIdArrays._sourceIdArr;
            int[] tgtIdArr = digraph.ConnectionIdArrays._targetIdArr;

            for (int i = 0; i < connGenes._connArr.Length; i++)
            {
                // Determine the index of the equivalent connection in the digraph.
                int genomeConnIdx = (connectionIndexMap is null) ? i : connectionIndexMap[i];

                Debug.Assert(nodeIndexByIdMap.Map(connArr[genomeConnIdx].SourceId) == srcIdArr[i]);
                Debug.Assert(nodeIndexByIdMap.Map(connArr[genomeConnIdx].TargetId) == tgtIdArr[i]);
            }
        }
Example #2
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);
        }
Example #3
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);
        }
Example #4
0
        /// <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;
        }
        /// <summary>
        /// Create a NeatGenome with the given meta data and connection genes.
        /// </summary>
        /// <param name="id">Genome ID.</param>
        /// <param name="birthGeneration">Birth generation.</param>
        /// <param name="connGenes">Connection genes.</param>
        /// <returns>A new NeatGenome instance.</returns>
        public NeatGenome <T> Create(
            int id,
            int birthGeneration,
            ConnectionGenes <T> connGenes)
        {
            // Determine the set of node IDs, and create a mapping from node IDs to node indexes.
            int[] hiddenNodeIdArr = ConnectionGenesUtils.CreateHiddenNodeIdArray(connGenes._connArr, _metaNeatGenome.InputOutputNodeCount, _workingIdSet);

            return(Create(id, birthGeneration, connGenes, hiddenNodeIdArr));
        }
 /// <summary>
 /// Create a NeatGenome with the given meta data, connection genes and supplementary data.
 /// </summary>
 /// <param name="id">Genome ID.</param>
 /// <param name="birthGeneration">Birth generation.</param>
 /// <param name="connGenes">Connection genes.</param>
 /// <param name="hiddenNodeIdArr">An array of the hidden node IDs in the genome, in ascending order.</param>
 /// <param name="digraph">A DirectedGraph that mirrors the structure described by the connection genes.</param>
 /// <param name="acyclicInfoCache">Cached info related to acyclic digraphs only.</param>
 /// <returns>A new NeatGenome instance.</returns>
 public NeatGenome <T> Create(
     int id, int birthGeneration,
     ConnectionGenes <T> connGenes,
     int[] hiddenNodeIdArr,
     INodeIdMap nodeIndexByIdMap,
     DirectedGraph digraph,
     int[] connectionIndexMap)
 {
     return(new NeatGenome <T>(_metaNeatGenome, id, birthGeneration, connGenes, hiddenNodeIdArr, nodeIndexByIdMap, digraph, connectionIndexMap));
 }
        /// <summary>
        /// Create a NeatGenome with the given meta data, connection genes and supplementary data.
        /// </summary>
        /// <param name="id">Genome ID.</param>
        /// <param name="birthGeneration">Birth generation.</param>
        /// <param name="connGenes">Connection genes.</param>
        /// <param name="hiddenNodeIdArr">An array of the hidden node IDs in the genome, in ascending order.</param>
        /// <returns>A new NeatGenome instance.</returns>
        public NeatGenome <T> Create(
            int id, int birthGeneration,
            ConnectionGenes <T> connGenes,
            int[] hiddenNodeIdArr)
        {
            int inputCount       = _metaNeatGenome.InputNodeCount;
            int outputCount      = _metaNeatGenome.OutputNodeCount;
            int inputOutputCount = _metaNeatGenome.InputOutputNodeCount;

            // Create a mapping from node IDs to node indexes.
            Dictionary <int, int> nodeIdxById = BuildNodeIndexById(hiddenNodeIdArr);

            // Create a DictionaryNodeIdMap.
            DictionaryNodeIdMap nodeIndexByIdMap = new DictionaryNodeIdMap(inputCount, nodeIdxById);

            // Create a digraph from the genome.
            DirectedGraph digraph = NeatGenomeBuilderUtils.CreateDirectedGraph(
                _metaNeatGenome, connGenes, nodeIndexByIdMap);

            // Calc the depth of each node in the digraph.
            GraphDepthInfo depthInfo = _graphDepthAnalysis.CalculateNodeDepths(digraph);

            // Create a weighted acyclic digraph.
            // Note. This also outputs connectionIndexMap. For each connection in the acyclic graph this gives
            // the index of the same connection in the genome; this is because connections are re-ordered based
            // on node depth in the acyclic graph.
            AcyclicDirectedGraph acyclicDigraph = AcyclicDirectedGraphBuilderUtils.CreateAcyclicDirectedGraph(
                digraph,
                depthInfo,
                out int[] newIdByOldId,
                out int[] connectionIndexMap,
                ref _timesortWorkArr,
                ref _timesortWorkVArr);

            // TODO: Write unit tests to cover this!
            // Update nodeIdxById with the new depth based node index allocations.
            // Notes.
            // The current nodeIndexByIdMap maps node IDs (also know as innovation IDs in NEAT) to a compact
            // ID space in which any gaps have been removed, i.e. a compacted set of IDs that can be used as indexes,
            // i.e. if there are N nodes in total then the highest node ID will be N-1.
            //
            // Here we map the new compact IDs to an alternative ID space that is also compact, but ensures that nodeIDs
            // reflect the depth of a node in the acyclic graph.
            UpdateNodeIndexById(nodeIdxById, hiddenNodeIdArr, newIdByOldId);

            // Create the neat genome.
            return(new NeatGenome <T>(
                       _metaNeatGenome, id, birthGeneration,
                       connGenes,
                       hiddenNodeIdArr,
                       nodeIndexByIdMap,
                       acyclicDigraph,
                       connectionIndexMap));
        }
 /// <summary>
 /// Create a NeatGenome with the given meta data, connection genes and supplementary data.
 /// </summary>
 /// <param name="id">Genome ID.</param>
 /// <param name="birthGeneration">Birth generation.</param>
 /// <param name="connGenes">Connection genes.</param>
 /// <param name="hiddenNodeIdArr">An array of the hidden node IDs in the genome, in ascending order.</param>
 /// <returns>A new NeatGenome instance.</returns>
 public NeatGenome <T> Create(
     int id, int birthGeneration,
     ConnectionGenes <T> connGenes,
     int[] hiddenNodeIdArr,
     INodeIdMap nodeIndexByIdMap)
 {
     // Note. Not required for acyclic graphs.
     // In acyclic graphs nodeIndexByIdMap is so closely related/tied to digraph and connectionIndexMap that
     // these three objects exist as a logical unit, i.e. we get all three or none at all.
     throw new NotImplementedException();
 }
        /// <summary>
        /// Create a NeatGenome with the given meta data, connection genes and supplementary data.
        /// </summary>
        /// <param name="id">Genome ID.</param>
        /// <param name="birthGeneration">Birth generation.</param>
        /// <param name="connGenes">Connection genes.</param>
        /// <param name="hiddenNodeIdArr">An array of the hidden node IDs in the genome, in ascending order.</param>
        /// <returns>A new NeatGenome instance.</returns>
        public NeatGenome <T> Create(
            int id, int birthGeneration,
            ConnectionGenes <T> connGenes,
            int[] hiddenNodeIdArr)
        {
            // Create a mapping from node IDs to node indexes.
            INodeIdMap nodeIndexByIdMap = DirectedGraphUtils.CompileNodeIdMap_InputOutputCount_HiddenNodeIdArr(
                _metaNeatGenome.InputOutputNodeCount, hiddenNodeIdArr);

            return(Create(id, birthGeneration, connGenes, hiddenNodeIdArr, nodeIndexByIdMap));
        }
        /// <summary>
        /// Create a NeatGenome with the given meta data, connection genes and supplementary data.
        /// </summary>
        /// <param name="id">Genome ID.</param>
        /// <param name="birthGeneration">Birth generation.</param>
        /// <param name="connGenes">Connection genes.</param>
        /// <param name="hiddenNodeIdArr">An array of the hidden node IDs in the genome, in ascending order.</param>
        /// <returns>A new NeatGenome instance.</returns>
        public NeatGenome <T> Create(
            int id, int birthGeneration,
            ConnectionGenes <T> connGenes,
            int[] hiddenNodeIdArr,
            INodeIdMap nodeIndexByIdMap)
        {
            // Create a digraph from the genome.
            DirectedGraph digraph = NeatGenomeBuilderUtils.CreateDirectedGraph(
                _metaNeatGenome, connGenes, nodeIndexByIdMap);

            return(new NeatGenome <T>(_metaNeatGenome, id, birthGeneration, connGenes, hiddenNodeIdArr, nodeIndexByIdMap, digraph, null));
        }
        /// <summary>
        /// Create a NeatGenome with the given meta data, connection genes and supplementary data.
        /// </summary>
        /// <param name="id">Genome ID.</param>
        /// <param name="birthGeneration">Birth generation.</param>
        /// <param name="connGenes">Connection genes.</param>
        /// <param name="hiddenNodeIdArr">An array of the hidden node IDs in the genome, in ascending order.</param>
        /// <param name="digraph">A DirectedGraph that mirrors the structure described by the connection genes.</param>
        /// <param name="connectionIndexMap">Mapping from genome connection indexes (in NeatGenome.ConnectionGenes) to reordered connections, based on depth based
        /// node index allocations.</param>
        /// <returns>A new NeatGenome instance.</returns>
        public NeatGenome <T> Create(
            int id, int birthGeneration,
            ConnectionGenes <T> connGenes,
            int[] hiddenNodeIdArr,
            INodeIdMap nodeIndexByIdMap,
            DirectedGraph digraph,
            int[] connectionIndexMap)
        {
            // This should always be null when evolving cyclic genomes/graphs.
            Debug.Assert(null == connectionIndexMap);

            return(new NeatGenome <T>(_metaNeatGenome, id, birthGeneration, connGenes, hiddenNodeIdArr, nodeIndexByIdMap, digraph, null));
        }
        private static bool ValidateConnections(
            ConnectionGenes <T> connGenes,
            DirectedGraph digraph,
            INodeIdMap nodeIndexByIdMap,
            int[] connectionIndexMap)
        {
            // Connection counts.
            if (connGenes._connArr.Length != digraph.ConnectionIdArrays.Length)
            {
                return(false);
            }

            // Connection order.
            if (!SortUtils.IsSortedAscending(connGenes._connArr) ||
                !IsSortedAscending(digraph.ConnectionIdArrays))
            {
                return(false);
            }

            // Connection node ID mappings.
            DirectedConnection[] connArr = connGenes._connArr;
            int[] srcIdArr = digraph.ConnectionIdArrays._sourceIdArr;
            int[] tgtIdArr = digraph.ConnectionIdArrays._targetIdArr;

            for (int i = 0; i < connGenes._connArr.Length; i++)
            {
                DirectedConnection connGene = connArr[i];

                // Determine the index of he equivalent connection in the digraph.
                int genomeConnIdx = (null == connectionIndexMap) ? i : connectionIndexMap[i];

                if (nodeIndexByIdMap.Map(connArr[genomeConnIdx].SourceId) != srcIdArr[i] ||
                    nodeIndexByIdMap.Map(connArr[genomeConnIdx].TargetId) != tgtIdArr[i])
                {
                    return(false);
                }
            }

            return(true);
        }
Example #13
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 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);
        }