A gene that represents a single connection between neurons in NEAT.
Inheritance: INetworkConnection
 /// <summary>
 /// Copy constructor.
 /// </summary>
 public ConnectionGene(ConnectionGene copyFrom)
 {
     _innovationId = copyFrom._innovationId;
     _sourceNodeId = copyFrom._sourceNodeId;
     _targetNodeId = copyFrom._targetNodeId;
     _weight = copyFrom._weight;
 }
        /// <summary>
        /// Creates a single randomly initialised genome.
        /// A random set of connections are made form the input to the output neurons, the number of
        /// connections made is based on the NeatGenomeParameters.InitialInterconnectionsProportion
        /// which specifies the proportion of all possible input-output connections to be made in
        /// initial genomes.
        ///
        /// The connections that are made are allocated innovation IDs in a consistent manner across
        /// the initial population of genomes. To do this we allocate IDs sequentially to all possible
        /// interconnections and then randomly select some proportion of connections for inclusion in the
        /// genome. In addition, for this scheme to work the innovation ID generator must be reset to zero
        /// prior to each call to CreateGenome(), and a test is made to ensure this is the case.
        ///
        /// The consistent allocation of innovation IDs ensure that equivalent connections in different
        /// genomes have the same innovation ID, and although this isn't strictly necessary it is
        /// required for sexual reproduction to work effectively - like structures are detected by comparing
        /// innovation IDs only.
        /// </summary>
        /// <param name="birthGeneration">The current evolution algorithm generation.
        /// Assigned to the new genome as its birth generation.</param>
        public NeatGenome CreateGenome(uint birthGeneration)
        {
            NeuronGeneList neuronGeneList       = new NeuronGeneList(_inputNeuronCount + _outputNeuronCount);
            NeuronGeneList inputNeuronGeneList  = new NeuronGeneList(_inputNeuronCount); // includes single bias neuron.
            NeuronGeneList outputNeuronGeneList = new NeuronGeneList(_outputNeuronCount);

            // Create a single bias neuron.
            uint biasNeuronId = _innovationIdGenerator.NextId;

            if (0 != biasNeuronId)
            {   // The ID generator must be reset before calling this method so that all generated genomes use the
                // same innovation ID for matching neurons and structures.
                throw new SharpNeatException("IdGenerator must be reset before calling CreateGenome(uint)");
            }

            // Note. Genes within nGeneList must always be arranged according to the following layout plan.
            //   Bias - single neuron. Innovation ID = 0
            //   Input neurons.
            //   Output neurons.
            //   Hidden neurons.
            NeuronGene neuronGene = CreateNeuronGene(biasNeuronId, NodeType.Bias);

            inputNeuronGeneList.Add(neuronGene);
            neuronGeneList.Add(neuronGene);

            // Create input neuron genes.
            for (int i = 0; i < _inputNeuronCount; i++)
            {
                neuronGene = CreateNeuronGene(_innovationIdGenerator.NextId, NodeType.Input);
                inputNeuronGeneList.Add(neuronGene);
                neuronGeneList.Add(neuronGene);
            }

            // Create output neuron genes.
            for (int i = 0; i < _outputNeuronCount; i++)
            {
                neuronGene = CreateNeuronGene(_innovationIdGenerator.NextId, NodeType.Output);
                outputNeuronGeneList.Add(neuronGene);
                neuronGeneList.Add(neuronGene);
            }

            // Define all possible connections between the input and output neurons (fully interconnected).
            int srcCount = inputNeuronGeneList.Count;
            int tgtCount = outputNeuronGeneList.Count;

            ConnectionDefinition[] connectionDefArr = new ConnectionDefinition[srcCount * tgtCount];

            for (int srcIdx = 0, i = 0; srcIdx < srcCount; srcIdx++)
            {
                for (int tgtIdx = 0; tgtIdx < tgtCount; tgtIdx++)
                {
                    connectionDefArr[i++] = new ConnectionDefinition(_innovationIdGenerator.NextId, srcIdx, tgtIdx);
                }
            }

            // Shuffle the array of possible connections.
            SortUtils.Shuffle(connectionDefArr, _rng);

            // Select connection definitions from the head of the list and convert them to real connections.
            // We want some proportion of all possible connections but at least one (Connectionless genomes are not allowed).
            int connectionCount = (int)NumericsUtils.ProbabilisticRound(
                (double)connectionDefArr.Length * _neatGenomeParamsComplexifying.InitialInterconnectionsProportion,
                _rng);

            connectionCount = Math.Max(1, connectionCount);

            // Create the connection gene list and populate it.
            ConnectionGeneList connectionGeneList = new ConnectionGeneList(connectionCount);

            for (int i = 0; i < connectionCount; i++)
            {
                ConnectionDefinition def           = connectionDefArr[i];
                NeuronGene           srcNeuronGene = inputNeuronGeneList[def._sourceNeuronIdx];
                NeuronGene           tgtNeuronGene = outputNeuronGeneList[def._targetNeuronIdx];

                ConnectionGene cGene = new ConnectionGene(def._innovationId,
                                                          srcNeuronGene.InnovationId,
                                                          tgtNeuronGene.InnovationId,
                                                          GenerateRandomConnectionWeight());
                connectionGeneList.Add(cGene);

                // Register connection with endpoint neurons.
                srcNeuronGene.TargetNeurons.Add(cGene.TargetNodeId);
                tgtNeuronGene.SourceNeurons.Add(cGene.SourceNodeId);
            }

            // Ensure connections are sorted.
            connectionGeneList.SortByInnovationId();

            // Create and return the completed genome object.
            return(CreateGenome(_genomeIdGenerator.NextId, birthGeneration,
                                neuronGeneList, connectionGeneList,
                                _inputNeuronCount, _outputNeuronCount, false));
        }
Esempio n. 3
0
        /// <summary>
        /// Reads a NeatGenome from XML.
        /// </summary>
        /// <param name="xr">The XmlReader to read from.</param>
        /// <param name="nodeFnIds">Indicates if node activation function IDs
        /// should be read. They are required for HyperNEAT genomes but not for NEAT</param>
        public static NeatGenome ReadGenome(XmlReader xr, bool nodeFnIds)
        {
            // Find <Network>.
            XmlIoUtils.MoveToElement(xr, false, __ElemNetwork);
            int initialDepth = xr.Depth;

            // Read genome ID attribute if present. Otherwise default to zero;
            // it's the caller's responsibility to check IDs are unique and
            // in-line with the genome factory's ID generators.
            string genomeIdStr = xr.GetAttribute(__AttrId);
            uint   genomeId;

            uint.TryParse(genomeIdStr, out genomeId);

            // Read birthGeneration attribute if present. Otherwise default to zero.
            string birthGenStr = xr.GetAttribute(__AttrBirthGeneration);
            uint   birthGen;

            uint.TryParse(birthGenStr, out birthGen);

            // Read fitness attribute if present. Otherwise default to zero.
            string fitnessStr = xr.GetAttribute(__AttrFitness);
            double fitness;

            double.TryParse(fitnessStr, out fitness);

            // Find <Nodes>.
            XmlIoUtils.MoveToElement(xr, true, __ElemNodes);

            // Create a reader over the <Nodes> sub-tree.
            int inputNodeCount  = 0;
            int outputNodeCount = 0;
            int regulatoryCount = 0;
            int localInCount    = 0;
            int localOutCount   = 0;
            // Used to count local input and output neurons (which are not
            // found in the base module = 0)
            int            activeModule = 1;
            NeuronGeneList nGeneList    = new NeuronGeneList();

            using (XmlReader xrSubtree = xr.ReadSubtree())
            {
                // Re-scan for the root <Nodes> element.
                XmlIoUtils.MoveToElement(xrSubtree, false);

                // Move to first node elem.
                XmlIoUtils.MoveToElement(xrSubtree, true, __ElemNode);

                // Read node elements.
                do
                {
                    NodeType neuronType =
                        NetworkXmlIO.ReadAttributeAsNodeType(xrSubtree, __AttrType);
                    uint id         = XmlIoUtils.ReadAttributeAsUInt(xrSubtree, __AttrId);
                    int  functionId = GetFunctionId(neuronType);
                    int  module     = XmlIoUtils.ReadAttributeAsInt(xrSubtree, __AttrModule);
                    int  pandemonium;
                    // If we have a regulatory neuron, we read its pandemonium label
                    if (neuronType == NodeType.Regulatory)
                    {
                        pandemonium = XmlIoUtils.ReadAttributeAsInt(xrSubtree, __AttrPandemonium);
                    }
                    // Otherwise it is simply -1
                    else
                    {
                        pandemonium = -1;
                    }
                    double[] auxState = null;
                    if (nodeFnIds)
                    {   // Read activation fn ID.
                        functionId = XmlIoUtils.ReadAttributeAsInt(xrSubtree,
                                                                   __AttrActivationFunctionId);

                        // Read aux state as comma seperated list of real values.
                        auxState = XmlIoUtils.ReadAttributeAsDoubleArray(xrSubtree,
                                                                         __AttrAuxState);
                    }

                    NeuronGene nGene = new NeuronGene(id, neuronType, functionId,
                                                      module, pandemonium, auxState);
                    nGeneList.Add(nGene);

                    // Track the number of input and output nodes.
                    switch (neuronType)
                    {
                    case NodeType.Input:
                        ++inputNodeCount;
                        break;

                    case NodeType.Output:
                        ++outputNodeCount;
                        break;

                    case NodeType.Regulatory:
                        ++regulatoryCount;
                        break;

                    case NodeType.Local_Input:
                        if (module == activeModule)
                        {
                            ++localInCount;
                        }
                        else
                        {
                            // Found a new module, discard previous count
                            activeModule  = module;
                            localInCount  = 1;
                            localOutCount = 0;
                        }
                        break;

                    case NodeType.Local_Output:
                        // Here we do not care about the correct module,
                        // because that has been considered in the local input
                        // count (and local input always comes first).
                        ++localOutCount;
                        break;
                    }
                }while(xrSubtree.ReadToNextSibling(__ElemNode));
            }

            // Find <Connections>.
            XmlIoUtils.MoveToElement(xr, false, __ElemConnections);

            // Create a reader over the <Connections> sub-tree.
            ConnectionGeneList cGeneList = new ConnectionGeneList();

            using (XmlReader xrSubtree = xr.ReadSubtree())
            {
                // Re-scan for the root <Connections> element.
                XmlIoUtils.MoveToElement(xrSubtree, false);

                // Move to first connection elem.
                string localName = XmlIoUtils.MoveToElement(xrSubtree, true);
                if (localName == __ElemConnection)
                {   // We have at least one connection.
                    // Read connection elements.
                    do
                    {
                        uint           id      = XmlIoUtils.ReadAttributeAsUInt(xrSubtree, __AttrId);
                        uint           srcId   = XmlIoUtils.ReadAttributeAsUInt(xrSubtree, __AttrSourceId);
                        uint           tgtId   = XmlIoUtils.ReadAttributeAsUInt(xrSubtree, __AttrTargetId);
                        double         weight  = XmlIoUtils.ReadAttributeAsDouble(xrSubtree, __AttrWeight);
                        int            module  = XmlIoUtils.ReadAttributeAsInt(xrSubtree, __AttrModule);
                        bool           protect = XmlIoUtils.ReadAttributeAsBool(xrSubtree, __AttrProtected);
                        ConnectionGene cGene   = new ConnectionGene(id, srcId, tgtId,
                                                                    weight, module,
                                                                    protect);
                        cGeneList.Add(cGene);
                    }while(xrSubtree.ReadToNextSibling(__ElemConnection));
                }
            }

            // Move the reader beyond the closing tags </Connections> and </Network>.
            do
            {
                if (xr.Depth <= initialDepth)
                {
                    break;
                }
            }while(xr.Read());

            // Construct and return loaded NeatGenome. We construct it first
            // so we can access its properties before leaving.
            bool rebuildConnectivity = true;
            // Integrity will fail if we attempt to create the genome before
            // updating some of the statistics (counts for each type of neurons,
            // etc). It can be done after that step!
            bool       shouldAssertIntegrity = false;
            NeatGenome genome = new NeatGenome(null, genomeId, birthGen, nGeneList,
                                               cGeneList, rebuildConnectivity,
                                               shouldAssertIntegrity);

            if (genomeFactory != null)
            {
                // Note genomeFactory is not fully initialized yet, but it is needed to create
                // an EvaluationInfo structure.
                genome.GenomeFactory = genomeFactory;
                genome.EvaluationInfo.SetFitness(fitness);
            }

            // We update count variables. While it is true most are static
            // variables, loading genomes is done only once, so we can afford
            // to count them for each genome.
            genome.Input      = inputNodeCount;
            genome.Output     = outputNodeCount;
            genome.Regulatory = regulatoryCount;
            genome.LocalIn    = localInCount;
            genome.LocalOut   = localOutCount;
            // We use base for neurons InHiddenModules
            genome.NeuronGeneList.LocateLastBase();
            genome.InHiddenModulesFromLoad();
            genome.ActiveConnectionsFromLoad();

            // Before this was done only once after creating all genomes. However,
            // we need these values if we want to perform an integrity check.
            // The performance overhead is negligible (specially in a one-time method)
            // and reliability is increased this way.
            genome.NeuronGeneList.LocateLastBase();
            genome.NeuronGeneList.LocateFirstIndex();
            genome.ConnectionGeneList.LocateFirstId();

            Debug.Assert(genome.PerformIntegrityCheck());
            return(genome);
        }
        /// <summary>
        /// Add a ConnectionGene to the builder, but only if the connection is not already present (as determined by it's neuron ID endpoints).
        /// </summary>
        /// <param name="connectionGene">The connection to add.</param>
        /// <param name="parentGenome">The conenction's parent genome. This is used to obtain NeuronGene(s) for the connection endpoints.</param>
        /// <param name="overwriteExisting">A flag that indicates if this connection should take precedence oevr an existing connection with
        /// the same endpoints.</param>
        public void TryAddGene(ConnectionGene connectionGene, NeatGenome parentGenome, bool overwriteExisting)
        {
            // Check if a matching gene has already been added.
            ConnectionEndpointsStruct connectionKey = new ConnectionEndpointsStruct(connectionGene.SourceNodeId, connectionGene.TargetNodeId);
            
            ConnectionGene existingConnectionGene;
            if(!_connectionGeneDictionary.TryGetValue(connectionKey, out existingConnectionGene))
            {   // Add new connection gene.
                ConnectionGene connectionGeneCopy = new ConnectionGene(connectionGene);
                _connectionGeneDictionary.Add(connectionKey, connectionGeneCopy);

                // Insert connection gene into a list. Use more efficient approach (append to end) if we know the gene belongs at the end.
                if(connectionGeneCopy.InnovationId > _highestConnectionGeneId) {
                    _connectionGeneList.Add(connectionGeneCopy);
                    _highestConnectionGeneId = connectionGeneCopy.InnovationId;
                } else {
                    _connectionGeneList.InsertIntoPosition(connectionGeneCopy);
                }

                // Add neuron genes (if not already added).
                // Source neuron.
                NeuronGene srcNeuronGene;
                if(!_neuronDictionary.TryGetValue(connectionGene.SourceNodeId, out srcNeuronGene))
                {
                    srcNeuronGene = parentGenome.NeuronGeneList.GetNeuronById(connectionGene.SourceNodeId);
                    srcNeuronGene = new NeuronGene(srcNeuronGene, false); // Make a copy.
                    _neuronDictionary.Add(srcNeuronGene.Id, srcNeuronGene);
                }

                // Target neuron.
                NeuronGene tgtNeuronGene;
                if(!_neuronDictionary.TryGetValue(connectionGene.TargetNodeId, out tgtNeuronGene))
                {
                    tgtNeuronGene = parentGenome.NeuronGeneList.GetNeuronById(connectionGene.TargetNodeId);
                    tgtNeuronGene = new NeuronGene(tgtNeuronGene, false); // Make a copy.
                    _neuronDictionary.Add(tgtNeuronGene.Id, tgtNeuronGene);
                }

                // Register connectivity with each neuron.
                srcNeuronGene.TargetNeurons.Add(tgtNeuronGene.Id);
                tgtNeuronGene.SourceNeurons.Add(srcNeuronGene.Id);
            }
            else if(overwriteExisting)
            {   // The genome we are building already has a connection with the same neuron endpoints as the one we are
                // trying to add. It didn't match up during correlation because it has a different innovation number, this
                // is possible because the innovation history buffers throw away old innovations in a FIFO manner in order
                // to prevent them from bloating.

                // Here the 'overwriteExisting' flag is set so the gene we are currently trying to add is probably from the
                // fitter parent, and therefore we want to use its connection weight in place of the existing gene's weight.
                existingConnectionGene.Weight = connectionGene.Weight;
            }
        }
        /// <summary>
        /// Reads a NeatGenome from XML.
        /// </summary>
        /// <param name="xr">The XmlReader to read from.</param>
        /// <param name="nodeFnIds">Indicates if node activation function IDs should be read. They are required
        /// for HyperNEAT genomes but not for NEAT</param>
        public static NeatGenome ReadGenome(XmlReader xr, bool nodeFnIds)
        {
            // Find <Network>.
            XmlIoUtils.MoveToElement(xr, false, __ElemNetwork);
            int initialDepth = xr.Depth;

            // Read genome ID attribute if present. Otherwise default to zero; it's the caller's responsibility to
            // check IDs are unique and in-line with the genome factory's ID generators.
            string genomeIdStr = xr.GetAttribute(__AttrId);
            uint   genomeId;

            uint.TryParse(genomeIdStr, out genomeId);

            // Read birthGeneration attribute if present. Otherwise default to zero.
            string birthGenStr = xr.GetAttribute(__AttrBirthGeneration);
            uint   birthGen;

            uint.TryParse(birthGenStr, out birthGen);

            // Find <Nodes>.
            XmlIoUtils.MoveToElement(xr, true, __ElemNodes);

            // Create a reader over the <Nodes> sub-tree.
            int            inputNodeCount  = 0;
            int            outputNodeCount = 0;
            NeuronGeneList nGeneList       = new NeuronGeneList();

            using (XmlReader xrSubtree = xr.ReadSubtree())
            {
                // Re-scan for the root <Nodes> element.
                XmlIoUtils.MoveToElement(xrSubtree, false);

                // Move to first node elem.
                XmlIoUtils.MoveToElement(xrSubtree, true, __ElemNode);

                // Read node elements.
                do
                {
                    NodeType neuronType = NetworkXmlIO.ReadAttributeAsNodeType(xrSubtree, __AttrType);
                    uint     id         = XmlIoUtils.ReadAttributeAsUInt(xrSubtree, __AttrId);
                    int      functionId = 0;
                    double[] auxState   = null;
                    if (nodeFnIds)
                    {   // Read activation fn ID.
                        functionId = XmlIoUtils.ReadAttributeAsInt(xrSubtree, __AttrActivationFunctionId);

                        // Read aux state as comma separated list of real values.
                        auxState = XmlIoUtils.ReadAttributeAsDoubleArray(xrSubtree, __AttrAuxState);
                    }

                    NeuronGene nGene = new NeuronGene(id, neuronType, functionId, auxState);
                    nGeneList.Add(nGene);

                    // Track the number of input and output nodes.
                    switch (neuronType)
                    {
                    case NodeType.Input:
                        inputNodeCount++;
                        break;

                    case NodeType.Output:
                        outputNodeCount++;
                        break;
                    }
                }while(xrSubtree.ReadToNextSibling(__ElemNode));
            }

            // Find <Connections>.
            XmlIoUtils.MoveToElement(xr, false, __ElemConnections);

            // Create a reader over the <Connections> sub-tree.
            ConnectionGeneList cGeneList = new ConnectionGeneList();

            using (XmlReader xrSubtree = xr.ReadSubtree())
            {
                // Re-scan for the root <Connections> element.
                XmlIoUtils.MoveToElement(xrSubtree, false);

                // Move to first connection elem.
                string localName = XmlIoUtils.MoveToElement(xrSubtree, true);
                if (localName == __ElemConnection)
                {   // We have at least one connection.
                    // Read connection elements.
                    do
                    {
                        uint           id     = XmlIoUtils.ReadAttributeAsUInt(xrSubtree, __AttrId);
                        uint           srcId  = XmlIoUtils.ReadAttributeAsUInt(xrSubtree, __AttrSourceId);
                        uint           tgtId  = XmlIoUtils.ReadAttributeAsUInt(xrSubtree, __AttrTargetId);
                        double         weight = XmlIoUtils.ReadAttributeAsDouble(xrSubtree, __AttrWeight);
                        ConnectionGene cGene  = new ConnectionGene(id, srcId, tgtId, weight);
                        cGeneList.Add(cGene);
                    }while(xrSubtree.ReadToNextSibling(__ElemConnection));
                }
            }

            // Move the reader beyond the closing tags </Connections> and </Network>.
            do
            {
                if (xr.Depth <= initialDepth)
                {
                    break;
                }
            }while(xr.Read());

            // Construct and return loaded NeatGenome.
            return(new NeatGenome(null, genomeId, birthGen, nGeneList, cGeneList, inputNodeCount, outputNodeCount, true));
        }
        /// <summary>
        ///     TODO
        /// </summary>
        /// <param name="birthGeneration">
        ///     The current evolution algorithm generation.
        ///     Assigned to the new genome as its birth generation.
        /// </param>
        public override NeatGenome CreateGenome(uint birthGeneration)
        {
            NeuronGeneList neuronGeneList = new NeuronGeneList(_inputNeuronCount + _outputNeuronCount);
            NeuronGeneList inputNeuronGeneList = new NeuronGeneList(_inputNeuronCount); // includes single bias neuron.
            NeuronGeneList outputNeuronGeneList = new NeuronGeneList(_outputNeuronCount);

            // Create a single bias neuron.
            uint biasNeuronId = _innovationIdGenerator.NextId;
            if (0 != biasNeuronId)
            {   // The ID generator must be reset before calling this method so that all generated genomes use the
                // same innovation ID for matching neurons and structures.
                throw new SharpNeatException("IdGenerator must be reset before calling CreateGenome(uint)");
            }

            // Note. Genes within nGeneList must always be arranged according to the following layout plan.
            //   Bias - single neuron. Innovation ID = 0
            //   Input neurons.
            //   Output neurons.
            //   Hidden neurons.
            NeuronGene neuronGene = CreateNeuronGene(biasNeuronId, NodeType.Bias);
            inputNeuronGeneList.Add(neuronGene);
            neuronGeneList.Add(neuronGene);

            // Create input neuron genes.
            for (int i = 0; i < _inputNeuronCount; i++)
            {
                neuronGene = CreateNeuronGene(_innovationIdGenerator.NextId, NodeType.Input);
                inputNeuronGeneList.Add(neuronGene);
                neuronGeneList.Add(neuronGene);
            }

            // Create output neuron genes.
            for (int i = 0; i < _outputNeuronCount; i++)
            {
                neuronGene = CreateNeuronGene(_innovationIdGenerator.NextId, NodeType.Output);
                outputNeuronGeneList.Add(neuronGene);
                neuronGeneList.Add(neuronGene);
            }

            // Define all possible connections between the input and output neurons (fully interconnected).
            int srcCount = inputNeuronGeneList.Count;
            int tgtCount = outputNeuronGeneList.Count;
            ConnectionDefinition[] connectionDefArr = new ConnectionDefinition[srcCount * tgtCount];

            for (int srcIdx = 0, i = 0; srcIdx < srcCount; srcIdx++)
            {
                for (int tgtIdx = 0; tgtIdx < tgtCount; tgtIdx++)
                {
                    connectionDefArr[i++] = new ConnectionDefinition(_innovationIdGenerator.NextId, srcIdx, tgtIdx);
                }
            }

            // Shuffle the array of possible connections.
            Utilities.Shuffle(connectionDefArr, _rng);

            // Select connection definitions from the head of the list and convert them to real connections.
            // We want some proportion of all possible connections but at least one (Connectionless genomes are not allowed).
            int connectionCount = (int)Utilities.ProbabilisticRound(
                (double)connectionDefArr.Length * _neatGenomeParamsComplexifying.InitialInterconnectionsProportion,
                _rng);
            connectionCount = Math.Max(1, connectionCount);

            // Create the connection gene list and populate it.
            ConnectionGeneList connectionGeneList = new ConnectionGeneList(connectionCount);

            #region Add connection to bisas short connections
            NeuronGene srcNeuronGeneACBias = inputNeuronGeneList[0];
            if (!srcNeuronGeneACBias.TargetNeurons.Contains(outputNeuronGeneList[2].InnovationId))
            {
                NeuronGene tgtNeuronGeneAC = outputNeuronGeneList[2];
                ConnectionGene biasGene = new ConnectionGene(_innovationIdGenerator.NextId,
                                                            srcNeuronGeneACBias.InnovationId,
                                                            tgtNeuronGeneAC.InnovationId,
                                                            Math.Abs(GenerateRandomConnectionWeight()));
                connectionGeneList.Add(biasGene);

                // Register connection with endpoint neurons.
                srcNeuronGeneACBias.TargetNeurons.Add(biasGene.TargetNodeId);
                tgtNeuronGeneAC.SourceNeurons.Add(biasGene.SourceNodeId);
            }
            double conW = GenerateRandomConnectionWeight();
            for (int i = 5; i <= 6; i++)
            {
                NeuronGene srcNeuronGeneAC = inputNeuronGeneList[i];
                if (!srcNeuronGeneAC.TargetNeurons.Contains(outputNeuronGeneList[2].InnovationId))
                {
                    NeuronGene tgtNeuronGeneAC = outputNeuronGeneList[2];
                    ConnectionGene biasGene = new ConnectionGene(_innovationIdGenerator.NextId,
                                                                srcNeuronGeneAC.InnovationId,
                                                                tgtNeuronGeneAC.InnovationId,
                                                                -Math.Abs(conW));
                    connectionGeneList.Add(biasGene);

                    // Register connection with endpoint neurons.
                    srcNeuronGeneAC.TargetNeurons.Add(biasGene.TargetNodeId);
                    tgtNeuronGeneAC.SourceNeurons.Add(biasGene.SourceNodeId);
                }

                srcNeuronGeneAC = inputNeuronGeneList[i];
                if (!srcNeuronGeneAC.TargetNeurons.Contains(outputNeuronGeneList[5].InnovationId))
                {
                    NeuronGene tgtNeuronGeneAC = outputNeuronGeneList[5];
                    ConnectionGene biasGene = new ConnectionGene(_innovationIdGenerator.NextId,
                                                                srcNeuronGeneAC.InnovationId,
                                                                tgtNeuronGeneAC.InnovationId,
                                                                -Math.Abs(conW));
                    connectionGeneList.Add(biasGene);

                    // Register connection with endpoint neurons.
                    srcNeuronGeneAC.TargetNeurons.Add(biasGene.TargetNodeId);
                    tgtNeuronGeneAC.SourceNeurons.Add(biasGene.SourceNodeId);
                }
            }
            #endregion

            #region Add connection to bisas connection strength based on distance
            for (int i = 5; i <= 6; i++)
            {
                NeuronGene srcNeuronGeneAC = inputNeuronGeneList[i];
                if (!srcNeuronGeneAC.TargetNeurons.Contains(outputNeuronGeneList[0].InnovationId))
                {
                    NeuronGene tgtNeuronGeneAC = outputNeuronGeneList[0];
                    ConnectionGene biasGene = new ConnectionGene(_innovationIdGenerator.NextId,
                                                                srcNeuronGeneAC.InnovationId,
                                                                tgtNeuronGeneAC.InnovationId,
                                                                Math.Abs(GenerateRandomConnectionWeight()));
                    connectionGeneList.Add(biasGene);

                    // Register connection with endpoint neurons.
                    srcNeuronGeneAC.TargetNeurons.Add(biasGene.TargetNodeId);
                    tgtNeuronGeneAC.SourceNeurons.Add(biasGene.SourceNodeId);
                }
            }
            #endregion
            for (int i = 0; i < connectionCount; i++)
            {
                ConnectionDefinition def = connectionDefArr[i];
                NeuronGene srcNeuronGene = inputNeuronGeneList[def._sourceNeuronIdx];
                NeuronGene tgtNeuronGene = outputNeuronGeneList[def._targetNeuronIdx];

                ConnectionGene cGene = new ConnectionGene(def._innovationId,
                                                        srcNeuronGene.InnovationId,
                                                        tgtNeuronGene.InnovationId,
                                                        GenerateRandomConnectionWeight());
                if (!srcNeuronGene.TargetNeurons.Contains(cGene.TargetNodeId))
                {
                    connectionGeneList.Add(cGene);

                    // Register connection with endpoint neurons.
                    srcNeuronGene.TargetNeurons.Add(cGene.TargetNodeId);
                    tgtNeuronGene.SourceNeurons.Add(cGene.SourceNodeId);
                }
            }

            // Ensure connections are sorted.
            connectionGeneList.SortByInnovationId();

            // Create and return the completed genome object.
            return CreateGenome(_genomeIdGenerator.NextId, birthGeneration,
                                neuronGeneList, connectionGeneList,
                                _inputNeuronCount, _outputNeuronCount, false);
        }
        /// <summary>
        /// Add a ConnectionGene to the builder, but only if the connection is
        /// not already present (as determined by it's neuron ID endpoints).
        /// </summary>
        /// <param name="connectionGene">The connection to add.</param>
        /// <param name="parentGenome">The conenction's parent genome. This is
        /// used to obtain NeuronGene(s) for the connection endpoints.</param>
        /// <param name="overwriteExisting">A flag that indicates if this
        /// connection should take precedence oevr an existing connection with
        /// the same endpoints.</param>
        public void TryAddGene(ConnectionGene connectionGene,
                               NeatGenome parentGenome, bool overwriteExisting)
        {
            // Check if a matching gene has already been added.
            ConnectionEndpointsStruct connectionKey =
                new ConnectionEndpointsStruct(connectionGene.SourceNodeId,
                                              connectionGene.TargetNodeId);

            ConnectionGene existingConnectionGene;

            if (!_connectionGeneDictionary.TryGetValue(connectionKey, out existingConnectionGene))
            {   // Add new connection gene.
                ConnectionGene connectionGeneCopy = new ConnectionGene(connectionGene);
                _connectionGeneDictionary.Add(connectionKey, connectionGeneCopy);

                // Insert connection gene into a list. Use more efficient approach
                // (append to end) if we know the gene belongs at the end.
                if (connectionGeneCopy.InnovationId > _highestConnectionGeneId)
                {
                    _connectionGeneList.Add(connectionGeneCopy);
                    _highestConnectionGeneId = connectionGeneCopy.InnovationId;
                }
                else
                {
                    _connectionGeneList.InsertIntoPosition(connectionGeneCopy);
                }

                // Add neuron genes (if not already added).
                // Source neuron.
                NeuronGene srcNeuronGene;
                if (!_neuronDictionary.TryGetValue(connectionGene.SourceNodeId,
                                                   out srcNeuronGene))
                {
                    srcNeuronGene = parentGenome.NeuronGeneList.
                                    GetNeuronByIdAll(connectionGene.SourceNodeId);
                    srcNeuronGene = new NeuronGene(srcNeuronGene, false); // Make a copy.
                    _neuronDictionary.Add(srcNeuronGene.Id, srcNeuronGene);
                }

                // Target neuron.
                NeuronGene tgtNeuronGene;
                if (!_neuronDictionary.TryGetValue(connectionGene.TargetNodeId,
                                                   out tgtNeuronGene))
                {
                    tgtNeuronGene = parentGenome.NeuronGeneList.
                                    GetNeuronByIdAll(connectionGene.TargetNodeId);
                    tgtNeuronGene = new NeuronGene(tgtNeuronGene, false); // Make a copy.
                    _neuronDictionary.Add(tgtNeuronGene.Id, tgtNeuronGene);
                }

                // Register connectivity with each neuron.
                srcNeuronGene.TargetNeurons.Add(tgtNeuronGene.Id);
                tgtNeuronGene.SourceNeurons.Add(srcNeuronGene.Id);
            }
            else if (overwriteExisting)
            {
                // The genome we are building already has a connection with the
                // same neuron endpoints as the one we are trying to add. It
                // didn't match up during correlation because it has a different
                // innovation number, this is possible because the innovation
                // history buffers throw away old innovations in a FIFO manner
                // in order to prevent them from bloating.

                // Here the 'overwriteExisting' flag is set so the gene we are
                // currently trying to add is probably from the fitter parent,
                // and therefore we want to use its connection weight in place
                // of the existing gene's weight.
                existingConnectionGene.Weight = connectionGene.Weight;
            }
        }
        /// <summary>
        /// Reads a NeatGenome from XML.
        /// </summary>
        /// <param name="xr">The XmlReader to read from.</param>
        /// <param name="nodeFnIds">Indicates if node activation function IDs should be read. They are required
        /// for HyperNEAT genomes but not for NEAT</param>
        public static NeatGenome ReadGenome(XmlReader xr, bool nodeFnIds)
        {
            // Find <Network>.
            XmlIoUtils.MoveToElement(xr, false, __ElemNetwork);
            int initialDepth = xr.Depth;

            // Read genome ID attribute if present. Otherwise default to zero; it's the caller's responsibility to
            // check IDs are unique and in-line with the genome factory's ID generators.
            string genomeIdStr = xr.GetAttribute(__AttrId);
            uint genomeId;
            uint.TryParse(genomeIdStr, out genomeId);

            // Read birthGeneration attribute if present. Otherwise default to zero.
            string birthGenStr = xr.GetAttribute(__AttrBirthGeneration);
            uint birthGen;
            uint.TryParse(birthGenStr, out birthGen);

            // Find <Nodes>.
            XmlIoUtils.MoveToElement(xr, true, __ElemNodes);

            // Create a reader over the <Nodes> sub-tree.
            int inputNodeCount = 0;
            int outputNodeCount = 0;
            NeuronGeneList nGeneList = new NeuronGeneList();
            using(XmlReader xrSubtree = xr.ReadSubtree())
            {
                // Re-scan for the root <Nodes> element.
                XmlIoUtils.MoveToElement(xrSubtree, false);

                // Move to first node elem.
                XmlIoUtils.MoveToElement(xrSubtree, true, __ElemNode);

                // Read node elements.
                do
                {
                    NodeType neuronType = NetworkXmlIO.ReadAttributeAsNodeType(xrSubtree, __AttrType);
                    uint id = XmlIoUtils.ReadAttributeAsUInt(xrSubtree, __AttrId);
                    int functionId = 0;
                    double[] auxState = null;
                    if(nodeFnIds)
                    {	// Read activation fn ID.
                        functionId = XmlIoUtils.ReadAttributeAsInt(xrSubtree, __AttrActivationFunctionId);

                        // Read aux state as comma seperated list of real values.
                        auxState = XmlIoUtils.ReadAttributeAsDoubleArray(xrSubtree, __AttrAuxState);
                    }

                    NeuronGene nGene = new NeuronGene(id, neuronType, functionId, auxState);
                    nGeneList.Add(nGene);

                    // Track the number of input and output nodes.
                    switch(neuronType)
                    {
                        case NodeType.Input:
                            inputNodeCount++;
                            break;
                        case NodeType.Output:
                            outputNodeCount++;
                            break;
                    }
                }
                while(xrSubtree.ReadToNextSibling(__ElemNode));
            }

            // Find <Connections>.
            XmlIoUtils.MoveToElement(xr, false, __ElemConnections);

            // Create a reader over the <Connections> sub-tree.
            ConnectionGeneList cGeneList = new ConnectionGeneList();
            using(XmlReader xrSubtree = xr.ReadSubtree())
            {
                // Re-scan for the root <Connections> element.
                XmlIoUtils.MoveToElement(xrSubtree, false);

                // Move to first connection elem.
                string localName = XmlIoUtils.MoveToElement(xrSubtree, true);
                if(localName == __ElemConnection)
                {   // We have at least one connection.
                    // Read connection elements.
                    do
                    {
                        uint id = XmlIoUtils.ReadAttributeAsUInt(xrSubtree, __AttrId);
                        uint srcId = XmlIoUtils.ReadAttributeAsUInt(xrSubtree, __AttrSourceId);
                        uint tgtId = XmlIoUtils.ReadAttributeAsUInt(xrSubtree, __AttrTargetId);
                        double weight = XmlIoUtils.ReadAttributeAsDouble(xrSubtree, __AttrWeight);
                        ConnectionGene cGene = new ConnectionGene(id, srcId, tgtId, weight);
                        cGeneList.Add(cGene);
                    }
                    while(xrSubtree.ReadToNextSibling(__ElemConnection));
                }
            }

            // Move the reader beyond the closing tags </Connections> and </Network>.
            do
            {
                if (xr.Depth <= initialDepth) {
                    break;
                }
            }
            while(xr.Read());

            // Construct and return loaded NeatGenome.
            return new NeatGenome(null, genomeId, birthGen, nGeneList, cGeneList, inputNodeCount, outputNodeCount, true, true);
        }
        /// <summary>
        ///     Creates a single randomly initialised genome.
        ///     A random set of connections are made form the input to the output neurons, the number of
        ///     connections made is based on the NeatGenomeParameters.InitialInterconnectionsProportion
        ///     which specifies the proportion of all posssible input-output connections to be made in
        ///     initial genomes.
        ///     The connections that are made are allocated innovation IDs in a consistent manner across
        ///     the initial population of genomes. To do this we allocate IDs sequentially to all possible
        ///     interconnections and then randomly select some proportion of connections for inclusion in the
        ///     genome. In addition, for this scheme to work the innovation ID generator must be reset to zero
        ///     prior to each call to CreateGenome(), and a test is made to ensure this is the case.
        ///     The consistent allocation of innovation IDs ensure that equivalent connections in different
        ///     genomes have the same innovation ID, and although this isn't strictly necessary it is
        ///     required for sexual reproduction to work effectively - like structures are detected by comparing
        ///     innovation IDs only.
        /// </summary>
        /// <param name="birthGeneration">
        ///     The current evolution algorithm generation.
        ///     Assigned to the new genome as its birth generation.
        /// </param>
        public override NeatGenome CreateGenome(uint birthGeneration)
        {
            NeuronGeneList neuronGeneList = new NeuronGeneList(_inputNeuronCount + _outputNeuronCount + _hiddenNeuronCount);
            NeuronGeneList inputNeuronGeneList = new NeuronGeneList(_inputNeuronCount); // includes single bias neuron.
            NeuronGeneList outputNeuronGeneList = new NeuronGeneList(_outputNeuronCount);
            NeuronGeneList hiddenNeuronGeneList = new NeuronGeneList(_hiddenNeuronCount);

            // Create a single bias neuron.
            uint biasNeuronId = _innovationIdGenerator.NextId;
            if (0 != biasNeuronId)
            {
                // The ID generator must be reset before calling this method so that all generated genomes use the
                // same innovation ID for matching neurons and structures.
                throw new SharpNeatException("IdGenerator must be reset before calling CreateGenome(uint)");
            }

            // Note. Genes within nGeneList must always be arranged according to the following layout plan.
            //   Bias - single neuron. Innovation ID = 0
            //   Input neurons.
            //   Output neurons.
            //   Hidden neurons.
            NeuronGene neuronGene = CreateNeuronGene(biasNeuronId, NodeType.Bias);
            inputNeuronGeneList.Add(neuronGene);
            neuronGeneList.Add(neuronGene);

            // Create input neuron genes.
            for (int i = 0; i < _inputNeuronCount; i++)
            {
                neuronGene = CreateNeuronGene(_innovationIdGenerator.NextId, NodeType.Input);
                inputNeuronGeneList.Add(neuronGene);
                neuronGeneList.Add(neuronGene);
            }

            // Create output neuron genes.
            for (int i = 0; i < _outputNeuronCount; i++)
            {
                neuronGene = CreateNeuronGene(_innovationIdGenerator.NextId, NodeType.Output);
                outputNeuronGeneList.Add(neuronGene);
                neuronGeneList.Add(neuronGene);
            }

            // Create hidden neuron genes.
            for (int i = 0; i < _hiddenNeuronCount; i++)
            {
                neuronGene = CreateNeuronGene(_innovationIdGenerator.NextId, NodeType.Hidden);
                hiddenNeuronGeneList.Add(neuronGene);
                neuronGeneList.Add(neuronGene);
            }

            // Define all possible connections between the input and hidden neurons and the hidden and output neurons
            // (fully interconnected with minimal hidden/feature layer).
            int srcCount = inputNeuronGeneList.Count;
            int tgtCount = outputNeuronGeneList.Count;
            int hdnCount = hiddenNeuronGeneList.Count;
            ConnectionDefinition[] srcHdnConnectionDefArr = new ConnectionDefinition[srcCount * hdnCount];
            ConnectionDefinition[] hdnTgtConnectionDefArr = new ConnectionDefinition[tgtCount * hdnCount];

            for (int hdnIdx = 0, i = 0; hdnIdx < hdnCount; hdnIdx++)
            {
                for (int srcIdx = 0; srcIdx < srcCount; srcIdx++)
                {
                    srcHdnConnectionDefArr[i++] = new ConnectionDefinition(_innovationIdGenerator.NextId, srcIdx, hdnIdx);
                }
            }

            for (int hdnIdx = 0, i = 0; hdnIdx < hdnCount; hdnIdx++)
            {
                for (int tgtIdx = 0; tgtIdx < tgtCount; tgtIdx++)
                {
                    hdnTgtConnectionDefArr[i++] = new ConnectionDefinition(_innovationIdGenerator.NextId, hdnIdx, tgtIdx);
                }
            }

            // Shuffle the array of possible connections.
            Utilities.Shuffle(srcHdnConnectionDefArr, _rng);
            Utilities.Shuffle(hdnTgtConnectionDefArr, _rng);

            // Select connection definitions from the head of the list and convert them to real connections.
            // We want some proportion of all possible connections but at least one (Connectionless genomes are not allowed).
            int srcConnectionCount = (int) Utilities.ProbabilisticRound(
                srcHdnConnectionDefArr.Length*_neatGenomeParamsComplexifying.InitialInterconnectionsProportion,
                _rng);
            srcConnectionCount = Math.Max(1, srcConnectionCount);

            int tgtConnectionCount = (int)Utilities.ProbabilisticRound(
                hdnTgtConnectionDefArr.Length * _neatGenomeParamsComplexifying.InitialInterconnectionsProportion,
                _rng);
            tgtConnectionCount = Math.Max(1, tgtConnectionCount);

            // Create the connection gene list and populate it.
            ConnectionGeneList connectionGeneList = new ConnectionGeneList(srcConnectionCount + tgtConnectionCount);

            for (int i = 0; i < srcConnectionCount; i++)
            {
                ConnectionDefinition def = srcHdnConnectionDefArr[i];
                NeuronGene srcNeuronGene = inputNeuronGeneList[def._sourceNeuronIdx];
                NeuronGene tgtNeuronGene = hiddenNeuronGeneList[def._targetNeuronIdx];

                ConnectionGene cGene = new ConnectionGene(def._innovationId,
                    srcNeuronGene.InnovationId,
                    tgtNeuronGene.InnovationId,
                    GenerateRandomConnectionWeight());
                connectionGeneList.Add(cGene);

                // Register connection with endpoint neurons.
                srcNeuronGene.TargetNeurons.Add(cGene.TargetNodeId);
                tgtNeuronGene.SourceNeurons.Add(cGene.SourceNodeId);
            }

            for (int i = 0; i < tgtConnectionCount; i++)
            {
                ConnectionDefinition def = hdnTgtConnectionDefArr[i];
                NeuronGene srcNeuronGene = hiddenNeuronGeneList[def._sourceNeuronIdx];
                NeuronGene tgtNeuronGene = outputNeuronGeneList[def._targetNeuronIdx];

                ConnectionGene cGene = new ConnectionGene(def._innovationId,
                    srcNeuronGene.InnovationId,
                    tgtNeuronGene.InnovationId,
                    GenerateRandomConnectionWeight());
                connectionGeneList.Add(cGene);

                // Register connection with endpoint neurons.
                srcNeuronGene.TargetNeurons.Add(cGene.TargetNodeId);
                tgtNeuronGene.SourceNeurons.Add(cGene.SourceNodeId);
            }

            // Ensure connections are sorted.
            connectionGeneList.SortByInnovationId();

            // Create and return the completed genome object.
            return CreateGenome(_genomeIdGenerator.NextId, birthGeneration,
                neuronGeneList, connectionGeneList,
                _inputNeuronCount, _outputNeuronCount, false);
        }
 /// <summary>
 /// Add a ConnectionGene to the builder, but only if the connection is
 /// not already present (as determined by it's neuron ID endpoints).
 /// </summary>
 /// <param name="connectionGene">The connection to add.</param>
 /// <param name="parentGenome">The conenction's parent genome. This is
 /// used to obtain NeuronGene(s) for the connection endpoints.</param>
 /// <param name="overwriteExisting">A flag that indicates if this
 /// connection should take precedence oevr an existing connection with
 /// the same endpoints.</param>
 public void TryAddGene(ConnectionGene connectionGene,
                        NeatGenome parentGenome, bool overwriteExisting)
 {
     TryAddGene(connectionGene, parentGenome, overwriteExisting, false);
 }