/// <inheritdoc/> public override void PerformOperation(EncogRandom rnd, IGenome[] parents, int parentIndex, IGenome[] offspring, int offspringIndex) { var target = ObtainGenome(parents, parentIndex, offspring, offspringIndex); if (target.LinksChromosome.Count < MinLink) { // don't remove from small genomes return; } // determine the target and remove var index = RangeRandomizer.RandomInt(0, target .LinksChromosome.Count - 1); NEATLinkGene targetGene = target.LinksChromosome[index]; target.LinksChromosome.Remove(targetGene); // if this orphaned any nodes, then kill them too! if (!IsNeuronNeeded(target, targetGene.FromNeuronId)) { RemoveNeuron(target, targetGene.FromNeuronId); } if (!IsNeuronNeeded(target, targetGene.ToNeuronId)) { RemoveNeuron(target, targetGene.ToNeuronId); } }
/// <summary> /// Choose a random neuron. /// </summary> /// <param name="includeInput">Should the input neurons be included.</param> /// <returns>The random neuron.</returns> private NEATNeuronGene ChooseRandomNeuron(bool includeInput) { int start; if (includeInput) { start = 0; } else { start = inputCount + 1; } int neuronPos = RangeRandomizer.RandomInt(start, Neurons .Genes.Count - 1); NEATNeuronGene neuronGene = (NEATNeuronGene)neuronsChromosome.Genes[neuronPos]; return(neuronGene); }
/// <summary> /// Get the next row from the underlying CSV file. /// </summary> /// <param name="csv">The underlying CSV file.</param> /// <returns>The loaded row.</returns> private LoadedRow GetNextRow(ReadCSV csv) { if (_remaining == 0) { LoadBuffer(csv); } while (_remaining > 0) { int index = RangeRandomizer.RandomInt(0, _bufferSize - 1); if (_buffer[index] != null) { LoadedRow result = _buffer[index]; _buffer[index] = null; _remaining--; return(result); } } return(null); }
/// <summary> /// Choose a random neuron. /// </summary> /// <param name="target">The target genome. Should the input and bias neurons be /// included.</param> /// <param name="choosingFrom">True if we are chosing from all neurons, false if we exclude /// the input and bias.</param> /// <returns>The random neuron.</returns> public NEATNeuronGene ChooseRandomNeuron(NEATGenome target, bool choosingFrom) { int start; if (choosingFrom) { start = 0; } else { start = target.InputCount + 1; } // if this network will not "cycle" then output neurons cannot be source // neurons if (!choosingFrom) { int ac = ((NEATPopulation)target.Population) .ActivationCycles; if (ac == 1) { start += target.OutputCount; } } int end = target.NeuronsChromosome.Count - 1; // no neurons to pick! if (start > end) { return(null); } int neuronPos = RangeRandomizer.RandomInt(start, end); NEATNeuronGene neuronGene = target.NeuronsChromosome[neuronPos]; return(neuronGene); }
/// <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> public void AddNeuron(double mutationRate, int numTrysToFindOldLink) { // should we add a neuron? if (ThreadSafeRandom.NextDouble() > mutationRate) { return; } // the link to split NEATLinkGene splitLink = null; int sizeThreshold = inputCount + outputCount + 10; // if there are not at least int upperLimit; if (linksChromosome.Genes.Count < sizeThreshold) { upperLimit = NumGenes - 1 - (int)Math.Sqrt(NumGenes); } else { upperLimit = NumGenes - 1; } while ((numTrysToFindOldLink--) > 0) { // choose a link, use the square root to prefer the older links int i = RangeRandomizer.RandomInt(0, upperLimit); NEATLinkGene link = (NEATLinkGene)linksChromosome.Genes[i]; // get the from neuron long fromNeuron = link.FromNeuronID; if ((link.Enabled) && (!link.IsRecurrent) && (((NEATNeuronGene)Neurons.Genes[ 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; NEATNeuronGene fromGene = (NEATNeuronGene)Neurons.Genes[ GetElementPos(from)]; NEATNeuronGene toGene = (NEATNeuronGene)Neurons.Genes[ 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.Genes.Add(new NEATNeuronGene(NEATNeuronType.Hidden, newNeuronID, newDepth, newWidth)); // add the first link long link1ID = ((NEATTraining)GA).Population.AssignInnovationID(); ((NEATTraining)GA).Innovations.CreateNewInnovation(from, newNeuronID, NEATInnovationType.NewLink); NEATLinkGene link1 = new NEATLinkGene(from, newNeuronID, true, link1ID, 1.0, false); linksChromosome.Genes.Add(link1); // add the second link long link2ID = ((NEATTraining)GA).Population.AssignInnovationID(); ((NEATTraining)GA).Innovations.CreateNewInnovation(newNeuronID, to, NEATInnovationType.NewLink); NEATLinkGene link2 = new NEATLinkGene(newNeuronID, to, true, link2ID, originalWeight, false); linksChromosome.Genes.Add(link2); } else { // existing innovation long newNeuronID = innovation.NeuronID; NEATInnovation innovationLink1 = ((NEATTraining)GA).Innovations .CheckInnovation(from, newNeuronID, NEATInnovationType.NewLink); NEATInnovation innovationLink2 = ((NEATTraining)GA).Innovations .CheckInnovation(newNeuronID, to, NEATInnovationType.NewLink); if ((innovationLink1 == null) || (innovationLink2 == null)) { throw new NeuralNetworkError("NEAT Error"); } NEATLinkGene link1 = new NEATLinkGene(from, newNeuronID, true, innovationLink1.InnovationID, 1.0, false); NEATLinkGene link2 = new NEATLinkGene(newNeuronID, to, true, innovationLink2.InnovationID, originalWeight, false); linksChromosome.Genes.Add(link1); linksChromosome.Genes.Add(link2); NEATNeuronGene newNeuron = new NEATNeuronGene( NEATNeuronType.Hidden, newNeuronID, newDepth, newWidth); neuronsChromosome.Genes.Add(newNeuron); } return; }
/// <inheritdoc/> public override void PerformOperation(EncogRandom rnd, IGenome[] parents, int parentIndex, IGenome[] offspring, int offspringIndex) { var target = ObtainGenome(parents, parentIndex, offspring, offspringIndex); var countTrysToFindOldLink = Owner.MaxTries; var pop = ((NEATPopulation)target.Population); // the link to split NEATLinkGene splitLink = null; int sizeBias = ((NEATGenome)parents[0]).InputCount + ((NEATGenome)parents[0]).OutputCount + 10; // if there are not at least int upperLimit; if (target.LinksChromosome.Count < sizeBias) { upperLimit = target.NumGenes - 1 - (int)Math.Sqrt(target.NumGenes); } else { upperLimit = target.NumGenes - 1; } while ((countTrysToFindOldLink--) > 0) { // choose a link, use the square root to prefer the older links int i = RangeRandomizer.RandomInt(0, upperLimit); NEATLinkGene link = target.LinksChromosome[i]; // get the from neuron long fromNeuron = link.FromNeuronId; if ((link.Enabled) && (target.NeuronsChromosome [GetElementPos(target, fromNeuron)] .NeuronType != NEATNeuronType.Bias)) { splitLink = link; break; } } if (splitLink == null) { return; } splitLink.Enabled = false; long from = splitLink.FromNeuronId; long to = splitLink.ToNeuronId; NEATInnovation innovation = ((NEATPopulation)Owner.Population).Innovations .FindInnovationSplit(from, to); // add the splitting neuron IActivationFunction af = ((NEATPopulation)Owner.Population).ActivationFunctions.Pick(new Random()); target.NeuronsChromosome.Add( new NEATNeuronGene(NEATNeuronType.Hidden, af, innovation .NeuronId, innovation.InnovationId)); // add the other two sides of the link CreateLink(target, from, innovation.NeuronId, splitLink.Weight); CreateLink(target, innovation.NeuronId, to, pop.WeightRange); target.SortGenes(); }