/// <summary> /// Construct an innovation list. /// </summary> /// <param name="population">The population.</param> /// <param name="links">The links.</param> /// <param name="neurons">The neurons.</param> public NEATInnovationList(IPopulation population, Chromosome links, Chromosome neurons) { this.population = population; foreach (IGene gene in neurons.Genes) { NEATNeuronGene neuronGene = (NEATNeuronGene)gene; NEATInnovation innovation = new NEATInnovation(neuronGene, population.AssignInnovationID(), AssignNeuronID()); Innovations.Add(innovation); } foreach (IGene gene in links.Genes) { NEATLinkGene linkGene = (NEATLinkGene)gene; NEATInnovation innovation = new NEATInnovation(linkGene .FromNeuronID, linkGene.ToNeuronID, NEATInnovationType.NewLink, this.population.AssignInnovationID()); Innovations.Add(innovation); } }
/// <summary> /// Create a new innovation. /// </summary> /// <param name="input">The input neuron.</param> /// <param name="output">The output neuron.</param> /// <param name="type">The type.</param> public void CreateNewInnovation(long input, long output, NEATInnovationType type) { NEATInnovation newInnovation = new NEATInnovation(input, output, type, this.population.AssignInnovationID()); if (type == NEATInnovationType.NewNeuron) { newInnovation.NeuronID = AssignNeuronID(); } Innovations.Add(newInnovation); }
/// <summary> /// Create a new innovation. /// </summary> /// <param name="from">The from neuron.</param> /// <param name="to">The to neuron.</param> /// <param name="innovationType">The innovation type.</param> /// <param name="neuronType">The neuron type.</param> /// <param name="x">The x-coordinate.</param> /// <param name="y">The y-coordinate.</param> /// <returns>The new innovation.</returns> public long CreateNewInnovation(long from, long to, NEATInnovationType innovationType, NEATNeuronType neuronType, double x, double y) { NEATInnovation newInnovation = new NEATInnovation(from, to, innovationType, population.AssignInnovationID(), neuronType, x, y); if (innovationType == NEATInnovationType.NewNeuron) { newInnovation.NeuronID = AssignNeuronID(); } Innovations.Add(newInnovation); return(this.nextNeuronID - 1); // ??????? should it be innov? }
/// <summary> /// Check to see if we already have an innovation. /// </summary> /// <param name="input">The input neuron.</param> /// <param name="output">The output neuron.</param> /// <param name="type">The type.</param> /// <returns>The innovation, either new or existing if found.</returns> public NEATInnovation CheckInnovation(long input, long output, NEATInnovationType type) { foreach (IInnovation i in Innovations) { NEATInnovation innovation = (NEATInnovation)i; if ((innovation.FromNeuronID == input) && (innovation.ToNeuronID == output) && (innovation.InnovationType == type)) { return(innovation); } } return(null); }
/// <summary> /// Create a new neuron gene from an id. /// </summary> /// <param name="neuronID">The neuron id.</param> /// <returns>The neuron gene.</returns> public NEATNeuronGene CreateNeuronFromID(long neuronID) { NEATNeuronGene result = new NEATNeuronGene(NEATNeuronType.Hidden, 0, 0, 0); foreach (IInnovation i in Innovations) { NEATInnovation innovation = (NEATInnovation)i; if (innovation.NeuronID == neuronID) { result.NeuronType = innovation.NeuronType; result.Id = innovation.NeuronID; result.SplitY = innovation.SplitY; result.SplitX = innovation.SplitX; return(result); } } return(result); }
/// <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; }
/// <summary> /// Mutate the genome by adding a link to this genome. /// </summary> /// <param name="mutationRate">The mutation rate.</param> /// <param name="chanceOfLooped">The chance of a self-connected neuron.</param> /// <param name="numTrysToFindLoop">The number of tries to find a loop.</param> /// <param name="numTrysToAddLink">The number of tries to add a link.</param> public void AddLink(double mutationRate, double chanceOfLooped, int numTrysToFindLoop, int numTrysToAddLink) { // should we even add the link if (ThreadSafeRandom.NextDouble() > mutationRate) { return; } // the link will be between these two neurons long neuron1ID = -1; long neuron2ID = -1; bool recurrent = false; // a self-connected loop? if (ThreadSafeRandom.NextDouble() < chanceOfLooped) { // try to find(randomly) a neuron to add a self-connected link to while ((numTrysToFindLoop--) > 0) { NEATNeuronGene neuronGene = ChooseRandomNeuron(false); // no self-links on input or bias neurons if (!neuronGene.Recurrent && (neuronGene.NeuronType != NEATNeuronType.Bias) && (neuronGene.NeuronType != NEATNeuronType.Input)) { neuron1ID = neuron2ID = neuronGene.Id; neuronGene.Recurrent = true; recurrent = true; numTrysToFindLoop = 0; } } } else { // try to add a regular link while ((numTrysToAddLink--) > 0) { NEATNeuronGene neuron1 = ChooseRandomNeuron(true); NEATNeuronGene neuron2 = ChooseRandomNeuron(false); if (!IsDuplicateLink(neuron1ID, neuron2ID) && (neuron1.Id != neuron2.Id) && (neuron2.NeuronType != NEATNeuronType.Bias)) { neuron1ID = -1; neuron2ID = -1; break; } } } // did we fail to find a link if ((neuron1ID < 0) || (neuron2ID < 0)) { return; } // check to see if this innovation has already been tried NEATInnovation innovation = ((NEATTraining)GA).Innovations .CheckInnovation(neuron1ID, neuron1ID, NEATInnovationType.NewLink); // see if this is a recurrent(backwards) link NEATNeuronGene neuronGene2 = (NEATNeuronGene)neuronsChromosome.Genes [GetElementPos(neuron1ID)]; if (neuronGene2.SplitY > neuronGene2.SplitY) { recurrent = true; } // is this a new innovation? if (innovation == null) { // new innovation ((NEATTraining)GA).Innovations.CreateNewInnovation(neuron1ID, neuron2ID, NEATInnovationType.NewLink); long id2 = ((NEATTraining)GA).Population.AssignInnovationID(); NEATLinkGene linkGene = new NEATLinkGene(neuron1ID, neuron2ID, true, id2, RangeRandomizer.Randomize(-1, 1), recurrent); linksChromosome.Genes.Add(linkGene); } else { // existing innovation NEATLinkGene linkGene = new NEATLinkGene(neuron1ID, neuron2ID, true, innovation.InnovationID, RangeRandomizer.Randomize(-1, 1), recurrent); linksChromosome.Genes.Add(linkGene); } }
/// <summary> /// Create a new innovation. /// </summary> /// <param name="from">The from neuron.</param> /// <param name="to">The to neuron.</param> /// <param name="innovationType">The innovation type.</param> /// <param name="neuronType">The neuron type.</param> /// <param name="x">The x-coordinate.</param> /// <param name="y">The y-coordinate.</param> /// <returns>The new innovation.</returns> public long CreateNewInnovation(long from, long to, NEATInnovationType innovationType, NEATNeuronType neuronType, double x, double y) { NEATInnovation newInnovation = new NEATInnovation(from, to, innovationType, population.AssignInnovationID(), neuronType, x, y); if (innovationType == NEATInnovationType.NewNeuron) { newInnovation.NeuronID = AssignNeuronID(); } Innovations.Add(newInnovation); return (this.nextNeuronID - 1); // ??????? should it be innov? }