public void addPending(bool suppressThresholdUpdate = false) { int length = pending_addition.Count; if (usingProbabilisticArchive) { // Do something different for probabilistic archive. No thresholds involved. Just add everyone that is pending. if (!probTournament) { for (int i = 0; i < length; i++) { archive.Add(pending_addition[i]); } pending_addition.Clear(); Console.WriteLine("Added " + length + " to the archive. Current size: " + archive.Count); } else { // Hold a diversity tournament to decide to gets added to the archive int countThem = 0; double averageAdd = 0; for (int i = 0; i + 1 < length; i = i + 2) { double first = valueAgainstArchive(pending_addition[i]); double second = valueAgainstArchive(pending_addition[i + 1]); if (first > second) { archive.Add(pending_addition[i]); averageAdd += first; } else { archive.Add(pending_addition[i + 1]); averageAdd += second; } countThem++; } // The straggler is almost never added... need a more fair method of adding stragglers. Maybe give them an early tournament against someone random? /*if (length % 2 == 1) // The last one was not considered if there was an odd number in the list. We should consider it against the average. * { * if (countThem != 0) * { * averageAdd /= countThem; * if (valueAgainstArchive(pending_addition[length - 1]) > averageAdd) * { * Console.WriteLine("Straggler added! " + valueAgainstArchive(pending_addition[length - 1]) + " beats avg " + averageAdd); * archive.Add(pending_addition[length - 1]); * } * else * { * Console.WriteLine("Straggler not added. " + valueAgainstArchive(pending_addition[length - 1]) + " loses to avg " + averageAdd); * } * } * }//*/ pending_addition.Clear(); Console.WriteLine("Added " + countThem + " (" + length + ") to the archive. Current size: " + archive.Count); } } else { if (!suppressThresholdUpdate) { if (length == 0) { archive_threshold *= 0.95; Console.WriteLine("Decreasing threshold. New: " + archive_threshold + ", adding " + length + " to archive. (" + archive.Count + ")"); } if (length > 5) { archive_threshold *= 1.3; Console.WriteLine("Increasing threshold. New: " + archive_threshold + ", adding " + length + " to archive. (" + archive.Count + ")"); } } for (int i = 0; i < length; i++) { if (measureAgainstArchive((NeatGenome.NeatGenome)pending_addition[i], false)) { archive.Add(pending_addition[i]); } } pending_addition.Clear(); } if (enforceArchiveLimit) { if (probDeletionTournament) { // Check the archive against the size limit and if it exceeds the limit, run a tournament to delete members while (archive.Count > archiveSizeLimit) { int firstIdx = archiveAddingRNG.Next(archive.Count); int secondIdx = firstIdx; while (firstIdx == secondIdx) // Make sure the indexes are unique { secondIdx = archiveAddingRNG.Next(archive.Count); } // Evaluate the candidate victims against the archive double first = valueAgainstArchive(archive[firstIdx]); double second = valueAgainstArchive(archive[secondIdx]); // Remove the one with the lower novelty score if (first < second) { archive.RemoveAt(firstIdx); //Console.WriteLine(first + " vs " + second + " : removing first."); } else { archive.RemoveAt(secondIdx); //Console.WriteLine(first + " vs " + second + " : removing second."); } } } else // No tournament, just delete randomly { while (archive.Count > archiveSizeLimit) { int firstIdx = archiveAddingRNG.Next(archive.Count); // Evaluate the candidate victims against the archive double first = valueAgainstArchive(archive[firstIdx]); archive.RemoveAt(firstIdx); } } } }
public void PerformOneGeneration() { // JUSTIN: IF WE ARE DOING MAPELITES, BAIL AND DO THE MAPELITES CHAIN INSTEAD! if (neatParameters.mapelites) { mePerformOneGeneration(); return; } // JUSTIN: IF WE ARE DOING NOVELTY SEARCH 2.0, BAIL AND DO THE NS2 CHAIN INSTEAD! if (neatParameters.NS2) { ns2PerformOneGeneration(); return; } // JUSTIN: IF WE ARE DOING SS-NSLC, BAIL AND DO THE SS-NSLC CHAIN INSTEAD! if (neatParameters.NSLC) { nslcPerformOneGeneration(); // TODO: JUSTIN: IMPLEMENT THIS, OKAY. return; } // If we are tracking a ME-style grid, we have to insert the freshly-evaluated population ("batch") here, before any further processing. // Note: This takes negligible time. if (neatParameters.track_me_grid) { // Insert population into ME Grid foreach (IGenome g in pop.GenomeList) { (g as AbstractGenome).GridCoords = bcToBinCoordinates(g.Behavior.behaviorList).ToArray(); UInt64 coord = cantorPairing(bcToBinCoordinates(g.Behavior.behaviorList)); if (!meGrid.ContainsKey(coord)) { // If this grid slot is empty, just go ahead and add the genome meGrid[coord] = g; } else { // If it's not empty, replace only if g has higher fitness if (g.RealFitness > meGrid[coord].RealFitness) { // It's higher fitness, good. Replace with the higher fit individual. meGrid[coord] = g; } else { // So sad } } } } //----- Elmininate any poor species before we do anything else. These are species with a zero target // size for this generation and will therefore not have generate any offspring. Here we have to // explicitly eliminate these species, otherwise the species would persist because of elitism. // Also, the species object would persist without any genomes within it, so we have to clean it up. // This code could be executed at the end of this method instead of the start, it doesn't really // matter. Except that If we do it here then the population size will be relatively constant // between generations. /*if(pop.EliminateSpeciesWithZeroTargetSize()) { // If species were removed then we should recalculate population stats. UpdateFitnessStats(); DetermineSpeciesTargetSize(); }*/ //----- Stage 1. Create offspring / cull old genomes / add offspring to population. bool regenerate = false; if(neatParameters.noveltySearch && neatParameters.noveltyFixed) { if((generation+1)%20==0) { this.noveltyFixed.add_most_novel(pop); this.noveltyFixed.update_measure(pop); pop.ResetPopulation(noveltyFixed.measure_against,this); pop.RedetermineSpeciation(this); regenerate=true; } } /*for (int i = 0; i < pop.GenomeList.Count; i++) { Console.Write("!BehaviorList! "); foreach (double argh in pop.GenomeList[i].objectives) { Console.Write(argh + " "); } Console.WriteLine(); }//*/ // For some reason this crashes.. maybe there is no objectives list??? /*Console.Write("localGenomeNovelty: "); foreach (IGenome g in pop.GenomeList) Console.Write(g.localGenomeNovelty + " "); Console.WriteLine(); Console.Write("competition: "); foreach (IGenome g in pop.GenomeList) Console.Write(g.competition + " "); Console.WriteLine(); Console.Write("nearestNeighbors: "); foreach (IGenome g in pop.GenomeList) Console.Write(g.nearestNeighbors + " "); Console.WriteLine();//*/ if(neatParameters.multiobjective) { // JUSTIN: I hope this fixes it.. if (neatParameters.noveltySearch) { // We are doing multiobjective novelty search, presumably NS+LC. //Console.WriteLine("Adding in the NS+LC objectives"); // Add in the extra objectives (see comments below) foreach (IGenome g in pop.GenomeList) { g.objectives = new double[6]; int len = g.objectives.Length; //g.objectives[len - 5] = g.geneticDiversity; g.objectives[len - 4] = g.RealFitness; //g.objectives[len - 3] = g.competition / g.nearestNeighbors; // Local competition objective (based on real fitness) g.objectives[len - 2] = g.Fitness + 0.001; // Novelty objective //g.objectives[len - 1] = g.localGenomeNovelty / g.nearestNeighbors; // Local genetic diversity objective (does this work?) //foreach (double d in g.objectives) Console.Write(d + " "); Console.WriteLine(); } //Console.WriteLine("Completed adding NS+LC objectives with no problems. (" + pop.GenomeList.Count + " members)"); } //Console.WriteLine("pop=" + pop.GenomeList.Count + "popMO=" + multiobjective.population.Count); /*foreach (IGenome g in multiobjective.population) { Console.Write("MO_OldPop: "); Console.Write(g.Fitness + " : [" + g.RealFitness + "] : "); foreach (double d in g.objectives) Console.Write(d + " "); Console.WriteLine(); }//*/ multiobjective.addPopulation(pop); //Console.WriteLine("pop2=" + pop.GenomeList.Count + "pop2MO=" + multiobjective.population.Count); /*foreach (IGenome g in multiobjective.population) { Console.Write("MO_NewPop: "); Console.Write(g.Fitness + " : [" + g.RealFitness + "] : "); foreach (double d in g.objectives) Console.Write(d + " "); Console.WriteLine(); }//*/ multiobjective.rankGenomes(); //Console.WriteLine("pop3=" + pop.GenomeList.Count + "pop3MO=" + multiobjective.population.Count); /*foreach (IGenome g in multiobjective.population) { Console.Write("MO_AfterRankingPop: "); Console.Write(g.Fitness + " : [" + g.RealFitness + "] : "); foreach (double d in g.objectives) Console.Write(d + " "); Console.WriteLine(); }//*/ /*foreach (IGenome aye in pop.GenomeList) { Console.Write("Before:"+ aye.Fitness + " : [" + aye.RealFitness + "] : "); foreach (double d in aye.objectives) Console.Write(d + " "); Console.WriteLine(); }//*/ pop.ResetPopulation(multiobjective.truncatePopulation(pop.GenomeList.Count),this); /*foreach (IGenome aye in pop.GenomeList) { Console.Write("After:" + aye.Fitness + " : [" + aye.RealFitness + "] : "); foreach (double d in aye.objectives) Console.Write(d + " "); Console.WriteLine(); }//*/ //Console.WriteLine("pop4=" + pop.GenomeList.Count + "pop4MO=" + multiobjective.population.Count); /*foreach (IGenome g in multiobjective.population) { Console.Write("MO_AfterTruncatePop: "); Console.Write(g.Fitness + " : [" + g.RealFitness + "] : "); foreach (double d in g.objectives) Console.Write(d + " "); Console.WriteLine(); }//*/ /*foreach (IGenome g in pop.GenomeList) { Console.Write("FinalPop: "); foreach (double d in g.objectives) Console.Write(d + " "); Console.WriteLine(); }//*/ pop.RedetermineSpeciation(this); UpdateFitnessStats(); DetermineSpeciesTargetSize(); //Console.WriteLine("DOES IT DO THIS? WHEN? SHOW ME!!"); } if(!regenerate) { CreateOffSpring(); pop.TrimAllSpeciesBackToElite(); // JUSTIN: DEBUG /*Console.WriteLine("These are the newly created children. Are they zeroed out?"); foreach (IGenome g in offspringList) { Console.Write("RF:" + g.RealFitness + ", fit:" + g.Fitness + "misc:" + g.locality + " " + g.nearestNeighbors + " " + g.localGenomeNovelty + " " + g.geneticDiversity + " " + g.competition + ", objectives:"); foreach (double d in g.objectives) Console.Write(" " + d); Console.WriteLine(); }//*/ // They are. // Add offspring to the population. int genomeBound = offspringList.Count; for(int genomeIdx=0; genomeIdx<genomeBound; genomeIdx++) pop.AddGenomeToPopulation(this, offspringList[genomeIdx]); /*foreach (IGenome g in pop.GenomeList) { Console.Write("RF:" + g.RealFitness + ", fit:" + g.Fitness + "misc:" + g.locality + " " + g.nearestNeighbors + " " + g.localGenomeNovelty + " " + g.geneticDiversity + " " + g.competition + ", objectives:"); //foreach (double d in g.objectives) Console.Write(" " + d); Console.WriteLine(); }//*/ } // Adjust the speciation threshold to try and keep the number of species within defined limits. if (!neatParameters.multiobjective) { AdjustSpeciationThreshold(); } //Console.WriteLine("pop5=" + pop.GenomeList.Count + "pop5MO=" + multiobjective.population.Count); //----- Stage 2. Evaluate genomes / Update stats. //Console.WriteLine("Before pop eval"); populationEvaluator.EvaluatePopulation(pop, this); //Console.WriteLine("After pop eval"); // JUSTIN: DEBUG /*Console.WriteLine("Here is the population rightafter being evaluated. Whats it look like?"); foreach (IGenome g in pop.GenomeList) { Console.Write("RF:" + g.RealFitness + ", fit:" + g.Fitness + "misc:" + g.locality + " " + g.nearestNeighbors + " " + g.localGenomeNovelty + " " + g.geneticDiversity + " " + g.competition + ", objectives:"); foreach (double d in g.objectives) Console.Write(" " + d); Console.WriteLine(); }//*/ // It looked good. Objectives were all 0 0 0 0 0 0, everything else was defined. if (neatParameters.multiobjective && neatParameters.noveltySearch) { // Redefine all objectives in case they haven't been defined yet (new genomes) or the aux data changed (it probably did). This is especially important for genomes being added to the archive or the measure_against population. foreach (IGenome g in pop.GenomeList) { g.objectives = new double[6]; int len = g.objectives.Length; //g.objectives[len - 5] = g.geneticDiversity; // Global genetic diversity objective g.objectives[len - 4] = g.RealFitness; // Global competition objective //g.objectives[len - 3] = g.competition / g.nearestNeighbors; // Local competition objective g.objectives[len - 2] = g.Fitness + 0.001; // Novelty objective //g.objectives[len - 1] = g.localGenomeNovelty / g.nearestNeighbors; // Local genetic diversity objective //foreach (double d in g.objectives) Console.Write(d + " "); Console.WriteLine(); } } UpdateFitnessStats(); DetermineSpeciesTargetSize(); pop.IncrementGenomeAges(); pop.IncrementSpeciesAges(); generation++; // ------------------------------------------------------------------------------------------------------------------------ // JUSTIN: // The following code saves some high fitness genomes at random, as long as they exceed a specified fitness threshold // To use this functionality, edit the following parameters: // // SAVED_PER_GENERATION FITNESS_SAVE_THRESHOLD EMPTY_HOPPER_AT // if (SAVETHINGS) { saveTicker += SAVED_PER_GENERATION; GenomeList tempOverThreshold = new GenomeList(); foreach (IGenome g in pop.GenomeList) { if (g.RealFitness > FITNESS_SAVE_THRESHOLD) { tempOverThreshold.Add(g); } } totalOverFitnessThreshold += tempOverThreshold.Count; while (saveTicker >= 1) { // Choose a random genome from tempOverThreshold to save... if possible. if (tempOverThreshold.Count != 0) { //(int)Math.Floor(Utilities.NextDouble()*championSpecies.Count) int pickMe = (int)(Math.Floor(Utilities.NextDouble() * tempOverThreshold.Count)); savedGenomeHopper.Add(tempOverThreshold[pickMe]); tempOverThreshold.RemoveAt(pickMe); } saveTicker -= 1; } //NOTE: If no genomes are over the threshold, then no genomes are saved this tick. they are NOT made up later. // Potentially dump genomes to file (if there are enough) /* if (savedGenomeHopper.Count >= EMPTY_HOPPER_AT) { Console.WriteLine("Dumping high-fitness genomes. Total over threshold: " + totalOverFitnessThreshold); dumpGoodGenomes(); } * */ } // --------- Done dumping HF genomes. -------------------------------------------------- Done dumping HF genomes. --------- if(neatParameters.noveltySearch) { //Console.WriteLine("Archive size: " + this.noveltyFixed.archive.Count.ToString()); //Console.WriteLine("MO Archive size: " + multiobjective.nov.archive.Count.ToString()); //JUSTIN: The MO archive doesn't grow... maybe call it below... or just don't use it at all... } if(neatParameters.noveltySearch && neatParameters.noveltyFloat) { //Console.WriteLine("I BET THIS HAPPENS: OPTION A."); this.noveltyFixed.initialize(pop); this.noveltyFixed.addPending(); } if(neatParameters.noveltySearch && neatParameters.noveltyFixed) { //Console.WriteLine("DOES THIS HAPPEN??????????????? NAH PROLLY NOT"); this.noveltyFixed.addPending(); } /*Console.WriteLine("Here's the measure_against. " + noveltyFixed.measure_against.Count); foreach (IGenome g in noveltyFixed.measure_against) { Console.Write("RF:" + g.RealFitness + ", fit:" + g.Fitness + "misc:" + g.locality + " " + g.nearestNeighbors + " " + g.localGenomeNovelty + " " + g.geneticDiversity + " " + g.competition + ", objectives:"); foreach (double d in g.objectives) Console.Write(" " + d); Console.WriteLine(); } Console.WriteLine("=================================== End measure_against"); Console.WriteLine("Here's the archive. " + noveltyFixed.archive.Count); foreach (IGenome g in noveltyFixed.archive) { Console.Write("RF:" + g.RealFitness + ", fit:" + g.Fitness + "misc:" + g.locality + " " + g.nearestNeighbors + " " + g.localGenomeNovelty + " " + g.geneticDiversity + " " + g.competition + ", objectives:"); foreach (double d in g.objectives) Console.Write(" " + d); Console.WriteLine(); } Console.WriteLine("=================================== End archive");//*/ //JUSTIN: I THINK IT'S WORKING! FUUUUUUUUUUUU-N! //----- Stage 3. Pruning phase tracking / Pruning phase entry & exit. if(pruningModeEnabled) { if(pruningMode) { // Track the falling population complexity. if(pop.AvgComplexity < prunePhase_MinimumStructuresPerGenome) { prunePhase_MinimumStructuresPerGenome = pop.AvgComplexity; prunePhase_generationAtLastSimplification = generation; } if(TestForPruningPhaseEnd()) EndPruningPhase(); } else { if(TestForPruningPhaseBegin()) BeginPruningPhase(); } } }