public static void EvaluateSample(GameObject body, DragonScript scr, float wingSurface, float[] performanceOfChromosomes) { EvaluatedPhenotype evaluationData = new EvaluatedPhenotype(scr.wingSet.phenotype, body.transform.position.y, wingSurface, performanceOfChromosomes); evaluationData.AddToList(evaluatedPhenotypesGood, evaluatedPhenotypesBad); RemoveSample(body, scr); }
// Create a new phenotype based each half on a base phenotype public static Phenotype operator /(EvaluatedPhenotype P1, EvaluatedPhenotype P2) { Chromosome rootL, rootR; if (Random.value > 0.5f) { EvaluatedPhenotype P3 = P1; P1 = P2; P2 = P3; } rootL = P1.phenotype.rootChromL; rootR = P1.phenotype.rootChromR; List <Chromosome> newChromosomes = new List <Chromosome>(); int half = P1.phenotype.TypeChromosomes.Count; int ind = 1; foreach (Chromosome chrom in P1.phenotype.TypeChromosomes) { if (ind > half) { newChromosomes.Add(chrom); } else { newChromosomes.Add(P2.phenotype.TypeChromosomes[ind - 1]); } ind++; } float strengthDistr = P2.phenotype.muscleStrengthDistribution; int maxFlapSteps = P1.phenotype.maxFlapSteps; return(new Phenotype(rootL, rootR, newChromosomes, strengthDistr, maxFlapSteps)); }
// Initialize the ruels to the list public void LoadRules() { crossRule rule; int probability; int numOfPhenotypes; bool posOrNeg; CrossingRules.Clear(); ////// Crossing-Rules (Generation rules) ////// posOrNeg = true; // Rules using only positive fitness // Random crossing (Phenotypes are chosed randomly from P0 and P1) rule = (EvaluatedPhenotype[] P) => { return(P[0] * P[1]); }; numOfPhenotypes = 2; probability = 12; CrossingRules.Add(new CrossingRule(rule, probability, numOfPhenotypes, posOrNeg)); // Maximizing cross (The Chromosome with better fitness is chosen) rule = (EvaluatedPhenotype[] P) => { return(P[0] + P[1]); }; numOfPhenotypes = 2; probability = 24; CrossingRules.Add(new CrossingRule(rule, probability, numOfPhenotypes, posOrNeg)); // Split Cross (Chosing half of the chromosomes from P0 and half from P1) rule = (EvaluatedPhenotype[] P) => { return(P[0] / P[1]); }; numOfPhenotypes = 2; probability = 8; CrossingRules.Add(new CrossingRule(rule, probability, numOfPhenotypes, posOrNeg)); // Maximum from a range of Phenotypes (Chosing best chromosome-fitness from all rule = (EvaluatedPhenotype[] P) => { return(EvaluatedPhenotype.MAX_PHENOTYPE(P)); }; numOfPhenotypes = -1; probability = 20; CrossingRules.Add(new CrossingRule(rule, probability, numOfPhenotypes, posOrNeg)); posOrNeg = false; // Rules using negative/minimum fitness // Minimizing cross (The Chromosome with lower fitness is chosen) rule = (EvaluatedPhenotype[] P) => { return(P[0] - P[1]); }; numOfPhenotypes = 2; probability = 1; CrossingRules.Add(new CrossingRule(rule, probability, numOfPhenotypes, posOrNeg)); // Minimum from a range of Phenotypes (Chosing best chromosome-fitness from all rule = (EvaluatedPhenotype[] P) => { return(EvaluatedPhenotype.MIN_PHENOTYPE(P)); }; numOfPhenotypes = -1; probability = 1; CrossingRules.Add(new CrossingRule(rule, probability, numOfPhenotypes, posOrNeg)); // Minimizing cross (The Chromosome with lower fitness is chosen) with Inversion rule = (EvaluatedPhenotype[] P) => { return(EvaluatedPhenotype.INVERT_FLAPSTEPS(P[0] - P[1])); }; numOfPhenotypes = 2; probability = 2; CrossingRules.Add(new CrossingRule(rule, probability, numOfPhenotypes, posOrNeg)); totalCrossRuleProbability = 0; foreach (CrossingRule aRule in CrossingRules) { if (aRule.posOrNeg || GlobalSettings.UseNegativeRules) { totalCrossRuleProbability += aRule.probabilityCount; } } ////// Mutation Rules ////// mutateRule mRule; int probabilityCount; MutationRules.Clear(); // Mutate timesteps with 30% chance mRule = (Phenotype P) => { return(EvaluatedPhenotype.MUTATE_FLAPSTEPS(P, 0.3f)); }; probabilityCount = 3; MutationRules.Add(new MutationRule(mRule, probabilityCount)); // Mutate Limits with 20% chance mRule = (Phenotype P) => { return(EvaluatedPhenotype.MUTATE_LIMITS(P, 0.2f)); }; probabilityCount = 2; MutationRules.Add(new MutationRule(mRule, probabilityCount)); // Invert all timesteps mRule = (Phenotype P) => { return(EvaluatedPhenotype.INVERT_FLAPSTEPS(P)); }; probabilityCount = 1; MutationRules.Add(new MutationRule(mRule, probabilityCount)); // Invert timesteps with 30% chance mRule = (Phenotype P) => { return(EvaluatedPhenotype.INVERT_FLAPSTEPS(P, 0.3f)); }; probabilityCount = 2; MutationRules.Add(new MutationRule(mRule, probabilityCount)); // Invert timesteps with 30% chance mRule = (Phenotype P) => { return(EvaluatedPhenotype.INVERT_FLAPSTEPS(P, 0.3f)); }; probabilityCount = 2; MutationRules.Add(new MutationRule(mRule, probabilityCount)); // Randomize length of a full wing flap mRule = (Phenotype P) => { return(EvaluatedPhenotype.MUTATE_FLAPLENGTH(P)); }; probabilityCount = 4; MutationRules.Add(new MutationRule(mRule, probabilityCount)); // Randomize strength distribution mRule = (Phenotype P) => { return(EvaluatedPhenotype.MUTATE_STRENGTHDISTRIBUTION(P)); }; probabilityCount = 3; MutationRules.Add(new MutationRule(mRule, probabilityCount)); // Mutate length of wings egments with 10% probability mRule = (Phenotype P) => { return(EvaluatedPhenotype.MUTATE_BONELENGTH(P, 0.1f)); }; probabilityCount = 3; MutationRules.Add(new MutationRule(mRule, probabilityCount)); // Mutate length of wings egments with 40% probability mRule = (Phenotype P) => { return(EvaluatedPhenotype.MUTATE_BONELENGTH(P, 0.4f)); }; probabilityCount = 1; MutationRules.Add(new MutationRule(mRule, probabilityCount)); // Randomizes everything with 50% probability mRule = (Phenotype P) => { return(EvaluatedPhenotype.MUTATE_FULL(P, 0.5f)); }; probabilityCount = 1; MutationRules.Add(new MutationRule(mRule, probabilityCount)); // Randomizes everything with 5% probability mRule = (Phenotype P) => { return(EvaluatedPhenotype.MUTATE_FULL(P, 0.05f)); }; probabilityCount = 5; MutationRules.Add(new MutationRule(mRule, probabilityCount)); totalMutateRuleProbability = 0; foreach (MutationRule aRule in MutationRules) { totalMutateRuleProbability += aRule.probabilityCount; } }
// This function is where the core of the genetic algorithm happens. // Like described, it choses random rules for generation and for mutationa nd applies them. // So it basically performs the typical patterns of genetic algorithms called "crossing", "combination" and "mutation". public int GeneratePhenotypes(List <Phenotype> readyPhenotypes, List <int> freeIndices) { int repeat; for (repeat = 0; repeat < Random.value * 3; repeat++) { float chosenRuleVal = Mathf.Floor(Random.value * (totalCrossRuleProbability)); int pos = 0; CrossingRule chosenRule = null; foreach (CrossingRule aRule in CrossingRules) { pos += aRule.probabilityCount; if (pos >= chosenRuleVal) { chosenRule = aRule; break; } } if (chosenRule == null) { Debug.LogError("No rule has been chosen!"); } bool choseBad = (Random.value <= GlobalSettings.UseBadSampleProbability); if (choseBad && (PopulationControler.evaluatedPhenotypesBad.Count == 0)) { choseBad = false; } List <EvaluatedPhenotype> phenList; if (choseBad) { phenList = PopulationControler.evaluatedPhenotypesBad; } else { phenList = PopulationControler.evaluatedPhenotypesGood; } int phenLimit = phenList.Count; int phensToChose; if (chosenRule.numOfPhenotypes >= 0) // Rule with fixed number of phenotypes as a base { phensToChose = chosenRule.numOfPhenotypes; } else { phensToChose = Mathf.Max(2, Mathf.CeilToInt(Random.value * (phenLimit / 2))); // Rule with unlimited phenotypes } EvaluatedPhenotype[] phenotypesParam = new EvaluatedPhenotype[phensToChose]; int el = Mathf.FloorToInt(Random.value * Random.value * (phenLimit - 1)); if (phenLimit == 0) { Debug.LogError("Trying to generate new phenotype with empty lists."); } if (phenLimit < 2) { phenotypesParam[0] = phenList[0]; phenotypesParam[1] = phenList[0]; if (phenList[0].ReduceLife()) { phenList.Remove(phenList[0]); } } else { for (int i = 0; i < phensToChose; i++) { phenotypesParam[i] = phenList[Mathf.Min(phenLimit - 1, el + i)]; } foreach (EvaluatedPhenotype ph in phenotypesParam) { if (phenList[0].ReduceLife()) { phenList.Remove(ph); } } } // Execute the rule and generate the new phenotype Phenotype newPhenotype = chosenRule.rule(phenotypesParam); // Find mutation(s) while (Random.value < GlobalSettings.MutationRate) { chosenRuleVal = Mathf.Floor(Random.value * (totalMutateRuleProbability)); pos = 0; MutationRule mutChosenRule = null; foreach (MutationRule aRule in MutationRules) { pos += aRule.probabilityCount; if (pos >= chosenRuleVal) { mutChosenRule = aRule; break; } } if (mutChosenRule == null) { Debug.Log(pos); Debug.Log(totalMutateRuleProbability); Debug.Log(chosenRuleVal); Debug.LogError("No mutation rule has been chosen!"); } // Apply mutation newPhenotype = mutChosenRule.rule(newPhenotype); } readyPhenotypes.Add(newPhenotype); } // The variance is being reduced every time a bit until reaching a limit GlobalSettings.RandomVariance -= 0.0005f; if (GlobalSettings.RandomVariance <= 0.1f) { GlobalSettings.RandomVariance = 0.1f; } return(repeat); }