/// <summary> /// Performs crossover breeding between two GeneticSequences. /// </summary> /// <param name="sequence1">The first sequence.</param> /// <param name="sequence2">The second sequence.</param> /// <param name="random">The random to be used for the random crossover.</param> /// <returns>Returns the two new genetic sequences.</returns> public static GeneticSequence[] Crossover(GeneticSequence sequence1, GeneticSequence sequence2, Random random) { if (sequence1.CanBreedWith(sequence2)) { int crossoverPoint = random.Next(0, sequence1.binarySequence.Length - 1); GeneticSequence[] parents = { sequence1, sequence2 }; bool[][] newSequences = new bool[2][]; for (int i = 0; i < newSequences.Length; i++) { newSequences[i] = new bool[sequence1.binarySequence.Length]; for (int j = 0; j <= crossoverPoint; j++) { newSequences[i][j] = parents[i].binarySequence[j]; } for (int j = crossoverPoint + 1; j < sequence1.binarySequence.Length; j++) { newSequences[i][j] = parents[(i + 1) % parents.Length].binarySequence[j]; } } return(new GeneticSequence[] { new GeneticSequence(newSequences[0]), new GeneticSequence(newSequences[1]) }); } else { throw new Exception("Supplied sequences are not compatible."); } }
/// <summary> /// Breeds two ModularMembers and produces two children. /// </summary> /// <param name="parent1">The first parent.</param> /// <param name="parent2">The second parent.</param> /// <param name="mutationRate">The mutation rate during breeding.</param> /// <param name="random">The random to be used while breeding.</param> /// <returns>Returns the two children.</returns> public static ModularMember[] BreedMembers(ModularMember parent1, ModularMember parent2, double mutationRate, Random random) { //Ensure breedable if (parent1.CanBreedWith(parent2)) { GeneticSequence[] child1Genome = new GeneticSequence[parent1.genome.Length]; GeneticSequence[] child2Genome = new GeneticSequence[parent1.genome.Length]; for (int i = 0; i < parent1.genome.Length; i++) { GeneticSequence[] crossoverSequences = GeneticSequence.Crossover(parent1.genome[i], parent2.genome[i], random); child1Genome[i] = crossoverSequences[0]; child2Genome[i] = crossoverSequences[1]; } //Mutate each genome for (int i = 0; i < child1Genome.Length; i++) { child1Genome[i] = child1Genome[i].BitwiseMutate(mutationRate, random); } for (int i = 0; i < child2Genome.Length; i++) { child2Genome[i] = child2Genome[i].BitwiseMutate(mutationRate, random); } ModularMember[] parents = new ModularMember[] { parent1, parent2 }; GeneticSequence[][] childSequences = new GeneticSequence[][] { child1Genome, child2Genome }; ModularMember[] children = new ModularMember[2]; for (int i = 0; i < children.Length; i++) { Phenotype[] phenotypes = new Phenotype[parents[i].phenotypes.Length]; for (int j = 0; j < phenotypes.Length; j++) { phenotypes[j] = parents[i].phenotypes[j].Clone(parents[(i + 1) % parents.Length].phenotypes[j]); } children[i] = new ModularMember(phenotypes); children[i].AssignGenome(childSequences[i]); } return(children); } else { throw new Exception("Provided parents are not breedable."); } }
/// <summary> /// Creates a random genome for a set of phenotypes. /// </summary> /// <param name="phenotypes">The set of phenotypes.</param> /// <param name="random">The random to be used for the random generation of genetic sequences.</param> /// <param name="sequenceBitLength">The bit length of the random genetic sequences.</param> /// <returns>Returns the randomly-generated genome.</returns> private static GeneticSequence[] GetRandomGenome(Phenotype[] phenotypes, Random random, int sequenceBitLength) { int sequenceLength = 0; for (int i = 0; i < phenotypes.Length; i++) { sequenceLength += phenotypes[i].GenomeLengthRequirement; } GeneticSequence[] genome = new GeneticSequence[sequenceLength]; for (int i = 0; i < genome.Length; i++) { genome[i] = new GeneticSequence(sequenceBitLength, random); } return(genome); }
/// <summary> /// Assigns a genome to the ModularMember. /// </summary> /// <param name="genome">The genome to be assigned.</param> /// <returns>Returns whether the assignment was successful.</returns> public bool AssignGenome(GeneticSequence[] genome) { int sequenceLength = 0; for (int i = 0; i < phenotypes.Length; i++) { sequenceLength += phenotypes[i].GenomeLengthRequirement; } //Ensure correct length and not already assigned if (isGenomeAssigned || genome.Length != sequenceLength) { return(false); } else { int sequenceIndex = 0; //Assign to phenotypes for (int i = 0; i < phenotypes.Length; i++) { GeneticSequence[] individualSequences = new GeneticSequence[phenotypes[i].GenomeLengthRequirement]; for (int j = 0; j < individualSequences.Length; j++) { individualSequences[j] = genome[sequenceIndex + j]; } phenotypes[i].SetGenome(individualSequences); sequenceIndex += phenotypes[i].GenomeLengthRequirement; } this.genome = genome; isGenomeAssigned = true; return(true); } }
/// <summary> /// Determines if this GeneticSequence can be bred with another sequence. /// </summary> /// <param name="partner">The other GeneticSequence.</param> /// <returns>Returns whether the sequences are breedable.</returns> public bool CanBreedWith(GeneticSequence partner) { return(binarySequence.Length == partner.binarySequence.Length); }