/// <summary> /// Creates the next generation of programs. This method also keeps tabs on memory /// as it creates the new Population. If we run out of physical memory then the /// new Population size is changed to wherever we ran out of memory. /// </summary> /// <param name="nGeneration">Which generation is currently being processed</param> /// <param name="Population">Reference to the Population just computed for fitness</param> /// <param name="Fitness">Fitness object with the fitness computation results</param> /// <param name="AutoReproduce">List of programs to automatically reproduce into the next generation</param> /// <returns>Reference to the new Population to use</returns> public GPPopulation ComputeNext(int nGeneration, GPPopulation Population, GPFitness Fitness, List <GPProgram> AutoReproduce) { m_PopCurrent = Population; m_Fitness = Fitness; // // Setup the program selection delegate switch (m_ModelerConfig.Profile.Reproduction) { case GPEnums.Reproduction.Tournament: ExecProgramSelection = new DELProgramSelection(Fitness.FitnessSelection.SelectProgramTournament); break; case GPEnums.Reproduction.OverSelection: ExecProgramSelection = new DELProgramSelection(Fitness.FitnessSelection.SelectProgramOverSelection); break; } // // Create a Tree Factory object - It helps in support of the mutation and // crossover operations m_TreeFactory = new GPProgramTreeFactory(m_ModelerConfig, m_InputDimension); return(ComputeNext(Population, Fitness, AutoReproduce)); }
/// <summary> /// Use the SPEA2 algorithm to compute fitness, with RawFitness and Program /// Complexity the two objectives to minimize. /// </summary> /// <param name="RawFitness"></param> /// <param name="Population"></param> public override void PrepareFitness(double[] RawFitness, GPPopulation Population) { m_RawFitness = RawFitness; // // --- Run The SPEA2 Algorithm --- m_Archive = UpdateArchive(Population); // // Create a new RawFitness based upon the Archive SPEA2 fitness values double[] SPEA2Fitness = new double[m_Archive.Count]; for (int Program = 0; Program < m_Archive.Count; Program++) { SPEA2Fitness[Program] = m_Archive[Program].SPEA2Fitness; } // // In case the archive size changes, let the base class know so it can resize // its storage to match the new size. base.PopulationSize = m_Archive.Count; // // Use the base class to get the final program selection stats computed. base.PrepareFitness(SPEA2Fitness, Population); }
/// <summary> /// Create the next generation of programs. /// </summary> public void ComputeNextGeneration(int Generation) { if (m_PopulatonFactory == null) { m_PopulatonFactory = new GPPopulationFactory(this, this.Training.Columns); } // // Create the next generation of programs GPPopulation popNew = m_PopulatonFactory.ComputeNext(Generation, m_Population, m_Fitness, m_SeedPrograms); // // If the Population size changed, update the configuration if (popNew.Count != m_Population.Count) { this.Profile.PopulationSize = popNew.Count; Console.WriteLine("GPServer: Memory is low, Population size reduced to ({0})", popNew.Count); // // Reset the Fitness object m_Fitness.TerminateProcessingThreads(); m_Fitness = null; } m_Population = popNew; // // Clear out any seed programs we just used ResetSeedPrograms(); }
/// <summary> /// Select two parents, based upon fitness, for a crossover operation. /// Place the two children into the new Population. /// </summary> /// <param name="PopNew">Population to add the newly created program to</param> private void Crossover(GPPopulation PopNew, GPFitnessObjectiveBase FitnessSelection) { GPProgram Child1 = (GPProgram)FitnessSelection.Programs(ExecProgramSelection()).Clone(); GPProgram Child2 = (GPProgram)FitnessSelection.Programs(ExecProgramSelection()).Clone(); // // Convert to trees Child1.ConvertToTree(m_ModelerConfig.FunctionSet, false); Child2.ConvertToTree(m_ModelerConfig.FunctionSet, false); // // Perform the crossover m_TreeFactory.Attach(Child1); Child2 = m_TreeFactory.Crossover(Child2); // // Convert to arrays Child1.ConvertToArray(m_ModelerConfig.FunctionSet); Child2.ConvertToArray(m_ModelerConfig.FunctionSet); // // Add them to the new Population PopNew.Programs.Add(Child1); if (PopNew.Count < m_PopCurrent.Count) { PopNew.Programs.Add(Child2); } }
/// <summary> /// This method instructs the server object to clean up as much memory /// as possible. /// </summary> public void ForceCleanup() { m_Population = null; m_Fitness.TerminateProcessingThreads(); m_Fitness = null; m_Training = null; System.GC.Collect(); }
/// <summary> /// Select a program based upon fitness to reproduce into the next generation. /// </summary> /// <param name="PopNew">Population to add the reproduced program into</param> private void Reproduce(GPPopulation PopNew, GPFitnessObjectiveBase FitnessSelection) { GPProgram Copy = (GPProgram)FitnessSelection.Programs(ExecProgramSelection()).Clone(); // // Add this copied child into the new Population PopNew.Programs.Add(Copy); }
/// <summary> /// Assign the Population complexity values for use in the MOO domination calculation /// </summary> /// <param name="Population"></param> private int[] PrepareComplexity(GPPopulation Population) { int[] Complexity = new int[Population.Count]; for (int Program = 0; Program < Population.Count; Program++) { Complexity[Program] = Population.Programs[Program].CountNodes; } return(Complexity); }
/// <summary> /// Creates the initial Population on this server. The Population size /// is sent as a parameter, rather than relying upon the profile, because /// this might be one of many remote objects and it is only working with /// some subset of the Population. /// </summary> /// <param name="PopulationSize">How many individuals to create initially</param> public void InitializePopulation(int PopulationSize) { // // Go ahead and replace, there is no need to have any knowledge of the // original Population size; m_Profile.PopulationSize = PopulationSize; m_Population = new GPPopulation(this); m_Population.Build(this.Profile.PopulationBuild, (short)Training.Columns); // // Need to get this initialized somewhere, so this seems like a good time ResetSeedPrograms(); }
/// <summary> /// Works through the Population to compute the fitness for each program, keeping /// track of a few statistics, such as best program, worst fitness and /// average fitness. Makes a call to the abstract method "ComputeFitness" that /// must be implemented by all GPFitness derived classes. /// </summary> /// <param name="Generation">Current modeling generation</param> /// <param name="Population">Current generation Population of programs</param> /// <returns></returns> private int EvaluatePopulation(int Generation, GPPopulation Population) { // // Check to see if the Population size changed, if so, reallocate the array // that holds the fitness values if (Population.Count != m_PrevPopulationSize) { if (m_Config.Profile.SPEA2MultiObjective) { m_FitnessSelection = new GPFitnessSPEA2(Population.Count); } else { m_FitnessSelection = new GPFitnessSingle(Population.Count); } } FitnessMaximum = 0.0; FitnessAverage = 0.0; // // Go through each program in the Population. First, compute the raw // fitness result of the program. Once that is done, a call to the // abstract ComputeFitness function is made where the User Defined Fitness // function is called. m_BestProgramGeneration = 0; m_WorstProgramGeneration = 0; m_CurrentProgram = 0; m_CompletedPrograms = 0; m_Population = Population; // // Create the event to be signed when the last program is done processing wh_LastProgramDone = new EventWaitHandle(false, EventResetMode.ManualReset); // // Signal the suspend event wh_Suspend.Set(); // // Wait for the last program to be computed wh_LastProgramDone.WaitOne(); // // Finish up the average Population fitness FitnessAverage /= Population.Count; return(m_BestProgramGeneration); }
/// <summary> /// Performs the fitness computation over the Population /// </summary> /// <param name="Generation"></param> /// <param name="Population"></param> /// <returns></returns> public GPProgram Compute(int Generation, GPPopulation Population) { m_Abort = false; // // Go through the Population and compute the fitness of each // program, returning the best program index. BestProgram = EvaluatePopulation(Generation, Population); m_BestProgramRef = Population.Programs[BestProgram]; if (!m_Abort) { m_FitnessSelection.PrepareFitness(this.FitnessMeasure, Population); } // // return the best program return(m_BestProgramRef); }
/// <summary> /// Select a program, based on fitness, for mutation. Place // the mutated program into the new Population. /// </summary> /// <param name="PopNew">Population to add the newly created program to</param> private void Mutate(GPPopulation PopNew, GPFitnessObjectiveBase FitnessSelection) { GPProgram Copy = (GPProgram)FitnessSelection.Programs(ExecProgramSelection()).Clone(); // // Convert it to a tree Copy.ConvertToTree(m_ModelerConfig.FunctionSet, false); // // Perform the mutation m_TreeFactory.Attach(Copy); m_TreeFactory.Mutate(); // // Return it back to an array Copy.ConvertToArray(m_ModelerConfig.FunctionSet); // // Add this mutated individual to the new Population PopNew.Programs.Add(Copy); }
/// <summary> /// Copys all nondominated programs from ArchivePopulation and PopCurrent into /// the next archive...which is returned from the method /// </summary> /// <param name="ArchivePopulation"></param> /// <param name="Population"></param> private List <SPEA2ProgramStats> UpdateArchive(GPPopulation Population) { SPEA2ProgramStats[] SPEA2Population = new SPEA2ProgramStats[Population.Count]; // // Grab the complexity of each program. We do this here, rather than getting it // from the Population object because it saves some computation time due to the // complexity values being reused several times. int[] Complexity = PrepareComplexity(Population); // // Init the min/max objective values - arbitrarily choose the first program's complexity value m_MinObjectiveFitness = m_MaxObjectiveFitness = m_RawFitness[0]; m_MinObjectiveComplexity = m_MaxObjectiveComplexity = Complexity[0]; // // Compute how many solutions each program in the current Population is dominated by for (int ProgramA = 0; ProgramA < Population.Count; ProgramA++) { SPEA2Population[ProgramA] = new SPEA2ProgramStats(); SPEA2Population[ProgramA].Program = Population.Programs[ProgramA]; SPEA2Population[ProgramA].RawFitness = m_RawFitness[ProgramA]; SPEA2Population[ProgramA].Complexity = Complexity[ProgramA]; SPEA2Population[ProgramA].Strength = 0; // // Test ProgramA against all programs in the current Population for (int ProgramB = 0; ProgramB < Population.Count; ProgramB++) { if ((m_RawFitness[ProgramB] > SPEA2Population[ProgramA].RawFitness) && (Complexity[ProgramB] > SPEA2Population[ProgramA].Complexity)) { SPEA2Population[ProgramA].Strength++; } } // // Test ProgramA against all programs in the current archive for (int ProgramB = 0; ProgramB < Archive.Count; ProgramB++) { if (Archive[ProgramB].RawFitness > SPEA2Population[ProgramA].RawFitness && Archive[ProgramB].Complexity > SPEA2Population[ProgramA].Complexity) { SPEA2Population[ProgramA].Strength++; } } // // Maintain the min/max objective values from the current Population m_MinObjectiveFitness = Math.Min(SPEA2Population[ProgramA].RawFitness, m_MinObjectiveFitness); m_MinObjectiveComplexity = Math.Min(SPEA2Population[ProgramA].Complexity, m_MinObjectiveComplexity); m_MaxObjectiveFitness = Math.Max(SPEA2Population[ProgramA].RawFitness, m_MaxObjectiveFitness); m_MaxObjectiveComplexity = Math.Max(SPEA2Population[ProgramA].Complexity, m_MaxObjectiveComplexity); } // // Count how many solutions each program in the archive is dominated by for (int ProgramA = 0; ProgramA < Archive.Count; ProgramA++) { SPEA2ProgramStats ProgramAStats = Archive[ProgramA]; ProgramAStats.Strength = 0; // // Test ProgramA against all programs in the current Population for (int ProgramB = 0; ProgramB < Population.Count; ProgramB++) { if (m_RawFitness[ProgramB] > ProgramAStats.RawFitness && Complexity[ProgramB] > ProgramAStats.Complexity) { ProgramAStats.Strength++; } } // // Test ProgramA against all programs in the current archive for (int ProgramB = 0; ProgramB < Archive.Count; ProgramB++) { if (Archive[ProgramB].RawFitness > ProgramAStats.RawFitness && Archive[ProgramB].Complexity > ProgramAStats.Complexity) { ProgramAStats.Strength++; } } Archive[ProgramA] = ProgramAStats; // // Maintain the min/max objective values from the current archive m_MinObjectiveFitness = Math.Min(ProgramAStats.RawFitness, m_MinObjectiveFitness); m_MinObjectiveComplexity = Math.Min(ProgramAStats.Complexity, m_MinObjectiveComplexity); m_MaxObjectiveFitness = Math.Max(ProgramAStats.RawFitness, m_MaxObjectiveFitness); m_MaxObjectiveComplexity = Math.Max(ProgramAStats.Complexity, m_MaxObjectiveComplexity); } if (m_MinObjectiveComplexity == m_MaxObjectiveComplexity) { m_MaxObjectiveComplexity += 1.0; } // // Now, we can compute the SPEA2 fitness for each individual by summing // the strenth values for each program it is dominated by. for (int ProgramA = 0; ProgramA < Population.Count; ProgramA++) { SPEA2Population[ProgramA].SPEA2Fitness = 0.0; // // Test ProgramA against all programs in the current Population for (int ProgramB = 0; ProgramB < Population.Count; ProgramB++) { if (m_RawFitness[ProgramB] < SPEA2Population[ProgramA].RawFitness && Complexity[ProgramB] < SPEA2Population[ProgramA].Complexity) { SPEA2Population[ProgramA].SPEA2Fitness += SPEA2Population[ProgramB].Strength; } } // // Test ProgramA against all programs in the current archive for (int ProgramB = 0; ProgramB < Archive.Count; ProgramB++) { if (Archive[ProgramB].RawFitness < SPEA2Population[ProgramA].RawFitness && Archive[ProgramB].Complexity < SPEA2Population[ProgramA].Complexity) { SPEA2Population[ProgramA].SPEA2Fitness += Archive[ProgramB].Strength; } } } // // Now, do it for the current archive for (int ProgramA = 0; ProgramA < Archive.Count; ProgramA++) { SPEA2ProgramStats ProgramAStats = Archive[ProgramA]; ProgramAStats.SPEA2Fitness = 0.0; // // Test ProgramA against all programs in the current Population for (int ProgramB = 0; ProgramB < Population.Count; ProgramB++) { if (SPEA2Population[ProgramB].RawFitness < ProgramAStats.RawFitness && SPEA2Population[ProgramB].Complexity < ProgramAStats.Complexity) { ProgramAStats.SPEA2Fitness += SPEA2Population[ProgramB].Strength; } } // // Test ProgramA against all programs in the current archive for (int ProgramB = 0; ProgramB < Archive.Count; ProgramB++) { if (Archive[ProgramB].RawFitness < ProgramAStats.RawFitness && Archive[ProgramB].Complexity < ProgramAStats.Complexity) { ProgramAStats.SPEA2Fitness += Archive[ProgramB].Strength; } } Archive[ProgramA] = ProgramAStats; } // // Compute the Density estimate for each program in the current Population for (int ProgramA = 0; ProgramA < Population.Count; ProgramA++) { SPEA2Population[ProgramA].Density = ComputeDensity(ref SPEA2Population[ProgramA], SPEA2Population, Archive); } // // Compute the Density estimate for each program in the current archive for (int ProgramA = 0; ProgramA < Archive.Count; ProgramA++) { SPEA2ProgramStats ProgramAStats = Archive[ProgramA]; ProgramAStats.Density = ComputeDensity(ref ProgramAStats, SPEA2Population, Archive); Archive[ProgramA] = ProgramAStats; } // // Final SPEA2 fitness calculation: F(i)=R(i)+D(i) for (int ProgramA = 0; ProgramA < Population.Count; ProgramA++) { SPEA2Population[ProgramA].SPEA2Fitness = SPEA2Population[ProgramA].SPEA2Fitness + SPEA2Population[ProgramA].Density; } for (int ProgramA = 0; ProgramA < Archive.Count; ProgramA++) { SPEA2ProgramStats ProgramAStats = Archive[ProgramA]; ProgramAStats.SPEA2Fitness = ProgramAStats.SPEA2Fitness + ProgramAStats.Density; Archive[ProgramA] = ProgramAStats; } // // Add all nondominated programs from the current Population into the new archive // The max complexity program allowed in the archive is 10,000. There are two reasons for this... // *The List container has an "short" sized counter, so programs bigger than 16 bits can't be stored // in the compressed array representation. Setting a value of 10,000 keeps programs from // getting too out of hand. // *A program size of 10,000 is ridiculous in size, so don't allow it. List <SPEA2ProgramStats> New_Archive = new List <SPEA2ProgramStats>(); SortedDictionary <int, int> New_ArchivePrograms = new SortedDictionary <int, int>(); for (int Program = 0; Program < Population.Programs.Count; Program++) { if (SPEA2Population[Program].SPEA2Fitness < 1.0 && SPEA2Population[Program].Complexity > 2 && SPEA2Population[Program].Complexity < 10000) { New_Archive.Add(SPEA2Population[Program]); New_ArchivePrograms.Add(Program, Program); } } // // Add all nondominated programs for the current archive into the new archive for (int Program = 0; Program < Archive.Count; Program++) { if (Archive[Program].SPEA2Fitness < 1.0 && Archive[Program].Complexity > 2) { New_Archive.Add(Archive[Program]); } } #if GPLOG GPLog.ReportLine("Archive Size: " + New_Archive.Count, true); #endif // // Get the archive to the right size int ArchiveSize = Population.Count / ARCHIVESCALE; if (New_Archive.Count < ArchiveSize) { ExpandArchive(New_Archive, ArchiveSize, SPEA2Population, New_ArchivePrograms); } else if (New_Archive.Count > ArchiveSize) { ShrinkArchive(New_Archive, ArchiveSize); } return(New_Archive); }
public virtual void PrepareFitness(double[] RawFitness, GPPopulation Population) { m_Population = Population; this.RawFitness = RawFitness; }
public GPPopulation ComputeNext(GPPopulation PopCurrent, GPFitness Fitness, List <GPProgram> AutoReproduce) { GPPopulation PopNew = new GPPopulation(m_ModelerConfig); // // Add the new programs into the next generation automatically foreach (GPProgram Seed in AutoReproduce) { PopNew.Programs.Add(Seed); } // // Automatically reproduce the best program into the next generation PopNew.Programs.Add((GPProgram)Fitness.BestProgramRef.Clone()); // // Now, go ahead and fill out the rest of the Population while (PopNew.Count < m_ModelerConfig.Profile.PopulationSize) { // // Make a probabilistic selection between... // Reproduction // Mutation // Crossover double Choice = GPUtilities.rngNextDouble(); double Cumulative = m_ModelerConfig.Profile.ProbabilityReproductionD; bool bSelected = false; if (Choice <= Cumulative) { Reproduce(PopNew, Fitness.FitnessSelection); bSelected = true; } Cumulative += m_ModelerConfig.Profile.ProbabilityMutationD; if (!bSelected && (Choice <= Cumulative)) { Mutate(PopNew, Fitness.FitnessSelection); bSelected = true; } Cumulative += m_ModelerConfig.Profile.ProbabilityCrossoverD; if (!bSelected && (Choice <= Cumulative)) { Crossover(PopNew, Fitness.FitnessSelection); bSelected = true; } // // Only check every 100 times to save a little time on doing this // check. if (PopNew.Count % 100 == 0) { if (!CheckMemory()) { // // Do a garbage collect just to be sure and check again System.GC.Collect(); if (!CheckMemory()) { break; } } } } return(PopNew); }