/// <summary> /// Construct a genome, do not provide links and neurons. /// </summary> /// /// <param name="id">The genome id.</param> /// <param name="inputCount_0">The input count.</param> /// <param name="outputCount_1">The output count.</param> public NEATGenome(long id, int inputCount_0, int outputCount_1) { GenomeID = id; AdjustedScore = 0; inputCount = inputCount_0; outputCount = outputCount_1; AmountToSpawn = 0; speciesID = 0; double inputRowSlice = 0.8d / (inputCount_0); neuronsChromosome = new Chromosome(); linksChromosome = new Chromosome(); Chromosomes.Add(neuronsChromosome); Chromosomes.Add(linksChromosome); for (int i = 0; i < inputCount_0; i++) { neuronsChromosome.Add(new NEATNeuronGene(NEATNeuronType.Input, i, 0, 0.1d + i * inputRowSlice)); } neuronsChromosome.Add(new NEATNeuronGene(NEATNeuronType.Bias, inputCount_0, 0, 0.9d)); double outputRowSlice = 1 / (double)(outputCount_1 + 1); for (int i_2 = 0; i_2 < outputCount_1; i_2++) { neuronsChromosome.Add(new NEATNeuronGene( NEATNeuronType.Output, i_2 + inputCount_0 + 1, 1, (i_2 + 1) * outputRowSlice)); } for (int i_3 = 0; i_3 < inputCount_0 + 1; i_3++) { for (int j = 0; j < outputCount_1; j++) { linksChromosome.Add(new NEATLinkGene( ((NEATNeuronGene)neuronsChromosome.Get(i_3)).Id, ((NEATNeuronGene)Neurons.Get( inputCount_0 + j + 1)).Id, true, inputCount_0 + outputCount_1 + 1 + NumGenes, RangeRandomizer.Randomize(-1, 1), false)); } } }
/// <summary> /// Mutate the genome by adding a neuron. /// </summary> /// /// <param name="mutationRate">The mutation rate.</param> /// <param name="numTrysToFindOldLink">The number of tries to find a link to split.</param> internal void AddNeuron(double mutationRate, int numTrysToFindOldLink) { // should we add a neuron? if (ThreadSafeRandom.NextDouble() > mutationRate) { return; } int countTrysToFindOldLink = numTrysToFindOldLink; // the link to split NEATLinkGene splitLink = null; int sizeBias = inputCount + outputCount + 10; // if there are not at least int upperLimit; if (linksChromosome.Size() < sizeBias) { upperLimit = NumGenes - 1 - (int)Math.Sqrt(NumGenes); } else { upperLimit = NumGenes - 1; } while ((countTrysToFindOldLink--) > 0) { // choose a link, use the square root to prefer the older links int i = RangeRandomizer.RandomInt(0, upperLimit); var link = (NEATLinkGene)linksChromosome .Get(i); // get the from neuron long fromNeuron = link.FromNeuronID; if ((link.Enabled) && (!link.Recurrent) && (((NEATNeuronGene)Neurons.Get( GetElementPos(fromNeuron))).NeuronType != NEATNeuronType.Bias)) { splitLink = link; break; } } if (splitLink == null) { return; } splitLink.Enabled = false; double originalWeight = splitLink.Weight; long from = splitLink.FromNeuronID; long to = splitLink.ToNeuronID; var fromGene = (NEATNeuronGene)Neurons.Get( GetElementPos(from)); var toGene = (NEATNeuronGene)Neurons.Get( GetElementPos(to)); double newDepth = (fromGene.SplitY + toGene.SplitY) / 2; double newWidth = (fromGene.SplitX + toGene.SplitX) / 2; // has this innovation already been tried? NEATInnovation innovation = ((NEATTraining)GA).Innovations.CheckInnovation(from, to, NEATInnovationType .NewNeuron); // prevent chaining if (innovation != null) { long neuronID = innovation.NeuronID; if (AlreadyHaveThisNeuronID(neuronID)) { innovation = null; } } if (innovation == null) { // this innovation has not been tried, create it long newNeuronID = ((NEATTraining)GA).Innovations.CreateNewInnovation(from, to, NEATInnovationType. NewNeuron, NEATNeuronType. Hidden, newWidth, newDepth); neuronsChromosome.Add(new NEATNeuronGene( NEATNeuronType.Hidden, newNeuronID, newDepth, newWidth)); // add the first link long link1ID = (GA).Population.AssignInnovationID(); ((NEATTraining)GA).Innovations .CreateNewInnovation(from, newNeuronID, NEATInnovationType.NewLink); var link1 = new NEATLinkGene(from, newNeuronID, true, link1ID, 1.0d, false); linksChromosome.Add(link1); // add the second link long link2ID = (GA).Population.AssignInnovationID(); ((NEATTraining)GA).Innovations .CreateNewInnovation(newNeuronID, to, NEATInnovationType.NewLink); var link2 = new NEATLinkGene(newNeuronID, to, true, link2ID, originalWeight, false); linksChromosome.Add(link2); } else { // existing innovation long newNeuronID_0 = innovation.NeuronID; NEATInnovation innovationLink1 = ((NEATTraining)GA).Innovations.CheckInnovation(from, newNeuronID_0, NEATInnovationType . NewLink); NEATInnovation innovationLink2 = ((NEATTraining)GA).Innovations.CheckInnovation(newNeuronID_0, to, NEATInnovationType.NewLink); if ((innovationLink1 == null) || (innovationLink2 == null)) { throw new NeuralNetworkError("NEAT Error"); } var link1_1 = new NEATLinkGene(from, newNeuronID_0, true, innovationLink1.InnovationID, 1.0d, false); var link2_2 = new NEATLinkGene(newNeuronID_0, to, true, innovationLink2.InnovationID, originalWeight, false); linksChromosome.Add(link1_1); linksChromosome.Add(link2_2); var newNeuron = new NEATNeuronGene( NEATNeuronType.Hidden, newNeuronID_0, newDepth, newWidth); neuronsChromosome.Add(newNeuron); } return; }