/// <summary> /// Constructs a connection gene with the given weight and enabled. /// </summary> /// <param name="connectionGenePattern">The connection gene pattern that this connection gene implements.</param> /// <param name="weight">The weight of the connection.</param> /// <param name="enabled">Whether or not this connection is enabled.</param> /// <exception cref="ArgumentNullException">When the connection gene pattern is null.</exception> protected internal ConnectionGene(ConnectionGenePattern connectionGenePattern, double weight, bool enabled) { Helpers.ThrowOnNull(connectionGenePattern, "connectionGenePattern"); ConnectionGenePattern = connectionGenePattern; Weight = weight; Enabled = enabled; }
/// <summary> /// Gets the hash code of this connection gene. Is the ConnectionGenePattern hash code as well. /// </summary> /// <returns>The hash code.</returns> public override int GetHashCode() { return(ConnectionGenePattern.GetHashCode()); }
/// <summary> /// Constructs a connection gene with and enabled (true), and the given weight. /// </summary> /// <param name="connectionGenePattern">The connection gene pattern that this connection gene implements.</param> /// <param name="weight">The weight of the connection.</param> /// <exception cref="ArgumentNullException">When the connection gene pattern is null.</exception> protected internal ConnectionGene(ConnectionGenePattern connectionGenePattern, double weight) : this(connectionGenePattern, weight, true) { }
/// <summary> /// String representation of this connection gene. /// </summary> /// <returns>String representation of this connection gene.</returns> public override string ToString() { return(ConnectionGenePattern.ToString() + ", Weight: " + Weight.ToString() + ", Enabled: " + Enabled.ToString()); }
/// <summary> /// Crosses over this genome with the given genome. /// </summary> /// <param name="my_score">Score of this genome. See remarks.</param> /// <param name="genome">The genome to cross over with.</param> /// <param name="their_score">Score of the given genome. See remarks.</param> /// <param name="random">The random object for the created genome.</param> /// <returns>The crossed-over genome.</returns> /// <remarks> /// When the given scores are equal, use the following rules: /// <list type="bullet"> /// <item>On similar connection genes: See <see cref="NEAT.Genetic.Tracker.Pedigree.UniformCrossover"/>.</item> /// <item>On disjoint connection genes: Adds all to the created genome.</item> /// <item>On excess connection genes: Adds all to the created genome.</item> /// </list> /// /// When the given scores are not equal, use the following rules: /// <list type="bullet"> /// <item>On similar connection genes: See <see cref="NEAT.Genetic.Tracker.Pedigree.UniformCrossover"/>.</item> /// <item>On disjoint connection genes: Adds genes from parent with higher score.</item> /// <item>On excess connection genes: Adds genes from parent with higher score.</item> /// </list> /// </remarks> /// <exception cref="ArgumentNullException">When the genome or random is null.</exception> public Genome Crossover(double my_score, Genome genome, double their_score, Random random) { Helpers.ThrowOnNull(genome, "genome"); Helpers.ThrowOnNull(random, "random"); Genome created_genome = new Genome(Pedigree, random); #region ConnectionGenes SortedDictionary <int, ConnectionGene> .ValueCollection.Enumerator enumerator_me = ConnectionGenes.Values.GetEnumerator(); SortedDictionary <int, ConnectionGene> .ValueCollection.Enumerator enumerator_them = genome.ConnectionGenes.Values.GetEnumerator(); enumerator_me.MoveNext(); //Preps for first current. enumerator_them.MoveNext(); //Step through both genomes and cross them over randomly. while (enumerator_me.Current != null && enumerator_them.Current != null) { ConnectionGene connectionGene_me = enumerator_me.Current; ConnectionGene connectionGene_them = enumerator_them.Current; int inNum_me = connectionGene_me.ConnectionGenePattern.InnovationNumber; int inNum_them = connectionGene_them.ConnectionGenePattern.InnovationNumber; if (inNum_me == inNum_them) //Similar genes, choose either side at random. { enumerator_me.MoveNext(); enumerator_them.MoveNext(); if (Pedigree.UniformCrossover) { if (random.NextDouble() < .5) { created_genome.ConnectionGenes.Add(inNum_me, Pedigree.Copy_ConnectionGene(connectionGene_me)); } else { created_genome.ConnectionGenes.Add(inNum_them, Pedigree.Copy_ConnectionGene(connectionGene_them)); } } else { created_genome.ConnectionGenes.Add(inNum_me, Pedigree.Create_ConnectionGene(connectionGene_me.ConnectionGenePattern, (connectionGene_me.Weight + connectionGene_them.Weight) / 2, (random.NextDouble() < .5) ? connectionGene_me.Enabled : connectionGene_them.Enabled)); } } else if (inNum_me > inNum_them) //Disjoint gene at them, add this gene if allowed. { enumerator_them.MoveNext(); if (Math.Abs(my_score - their_score) < Pedigree.Crossover_ScoreDelta || their_score > my_score) { created_genome.ConnectionGenes.Add(inNum_them, Pedigree.Copy_ConnectionGene(connectionGene_them)); } } else //Disjoint gene at me, add this gene if allowed. { enumerator_me.MoveNext(); if (Math.Abs(my_score - their_score) < Pedigree.Crossover_ScoreDelta || my_score > their_score) { created_genome.ConnectionGenes.Add(inNum_me, Pedigree.Copy_ConnectionGene(connectionGene_me)); } } } //Run through the excess connections and add them all if allowed. if (enumerator_me.Current != null) //We have leftover genes, add ours if allowed. { if (Math.Abs(my_score - their_score) < Pedigree.Crossover_ScoreDelta || my_score > their_score) //Check legality. { do { created_genome.ConnectionGenes.Add(enumerator_me.Current.ConnectionGenePattern.InnovationNumber, Pedigree.Copy_ConnectionGene(enumerator_me.Current)); }while (enumerator_me.MoveNext()); } } else if (enumerator_them.Current != null) //They have leftover genes, add theirs if allowed. { if (Math.Abs(my_score - their_score) < Pedigree.Crossover_ScoreDelta || their_score > my_score) //Check legality. { do { created_genome.ConnectionGenes.Add(enumerator_them.Current.ConnectionGenePattern.InnovationNumber, Pedigree.Copy_ConnectionGene(enumerator_them.Current)); }while (enumerator_them.MoveNext()); } } //There is no else because if they have the same number of genes, there is no excess, so don't do anything. #endregion ConnectionGenes #region NodeGenes //Input/Output nodes and bias node. for (int i = 1; i <= Pedigree.Num_InputNodes + Pedigree.Num_OutputNodes + 1; ++i) //The +1 handles the bias node. { created_genome.NodeGenes.Add(i, NodeGenes[i]); } //Every other relavent node. foreach (ConnectionGene connectionGene in created_genome.ConnectionGenes.Values) { ConnectionGenePattern pattern = connectionGene.ConnectionGenePattern; if (!created_genome.NodeGenes.ContainsKey(pattern.From.InnovationNumber)) { NodeGene nodeGene_toCopy; try { nodeGene_toCopy = NodeGenes[pattern.From.InnovationNumber]; } catch (KeyNotFoundException) { nodeGene_toCopy = genome.NodeGenes[pattern.From.InnovationNumber]; } created_genome.NodeGenes.Add(pattern.From.InnovationNumber, Pedigree.Copy_NodeGene(nodeGene_toCopy)); } if (!created_genome.NodeGenes.ContainsKey(pattern.To.InnovationNumber)) { NodeGene nodeGene_toCopy; try { nodeGene_toCopy = NodeGenes[pattern.To.InnovationNumber]; } catch (KeyNotFoundException) { nodeGene_toCopy = genome.NodeGenes[pattern.To.InnovationNumber]; } created_genome.NodeGenes.Add(pattern.To.InnovationNumber, Pedigree.Copy_NodeGene(nodeGene_toCopy)); } } #endregion NodeGenes return(created_genome); }