Population::Population(const char *a_FileName) { m_BestFitnessEver = 0.0; m_Generation = 0; m_NumEvaluations = 0; m_NextSpeciesID = 1; m_GensSinceBestFitnessLastChanged = 0; m_GensSinceMPCLastChanged = 0; std::ifstream t_DataFile(a_FileName); if (!t_DataFile.is_open()) throw std::exception(); std::string t_str; // Load the parameters m_Parameters.Load(t_DataFile); // Load the innovation database m_InnovationDatabase.Init(t_DataFile); // Load all genomes for(unsigned int i=0; i<m_Parameters.PopulationSize; i++) { Genome t_genome(t_DataFile); m_Genomes.push_back( t_genome ); } t_DataFile.close(); m_NextGenomeID = 0; for(unsigned int i=0; i<m_Genomes.size(); i++) { if (m_Genomes[i].GetID() > m_NextGenomeID) { m_NextGenomeID = m_Genomes[i].GetID(); } } m_NextGenomeID++; // Initialize Speciate(); m_BestGenome = m_Species[0].GetLeader(); Sort(); // Set up the phased search variables CalculateMPC(); m_BaseMPC = m_CurrentMPC; m_OldMPC = m_BaseMPC; if (m_Parameters.PhasedSearching) { m_SearchMode = COMPLEXIFYING; } else { m_SearchMode = BLENDED; } }
// The constructor Population::Population(const Genome& a_Seed, const Parameters& a_Parameters, bool a_RandomizeWeights, double a_RandomizationRange) { m_RNG.TimeSeed(); //m_RNG.Seed(0); m_BestFitnessEver = 0.0; m_Parameters = a_Parameters; m_Generation = 0; m_NumEvaluations = 0; m_NextGenomeID = m_Parameters.PopulationSize; m_NextSpeciesID = 1; m_GensSinceBestFitnessLastChanged = 0; m_GensSinceMPCLastChanged = 0; // Spawn the population for(unsigned int i=0; i<m_Parameters.PopulationSize; i++) { Genome t_clone = a_Seed; t_clone.SetID(i); m_Genomes.push_back( t_clone ); } // Now now initialize each genome's weights for(unsigned int i=0; i<m_Genomes.size(); i++) { if (a_RandomizeWeights) m_Genomes[i].Randomize_LinkWeights(a_RandomizationRange, m_RNG); //m_Genomes[i].CalculateDepth(); } // Initialize the innovation database m_InnovationDatabase.Init(a_Seed); // Speciate Speciate(); m_BestGenome = m_Species[0].GetLeader(); Sort(); // Set up the phased search variables CalculateMPC(); m_BaseMPC = m_CurrentMPC; m_OldMPC = m_BaseMPC; if (m_Parameters.PhasedSearching) { m_SearchMode = COMPLEXIFYING; } else { m_SearchMode = BLENDED; } }
// the epoch method - the heart of the GA void Population::Epoch() { // So, all genomes are evaluated.. for(unsigned int i=0; i<m_Species.size(); i++) { for(unsigned int j=0; j<m_Species[i].m_Individuals.size(); j++) { m_Species[i].m_Individuals[j].SetEvaluated(); } } // Sort each species's members by fitness and the species by fitness Sort(); // Update species stagnation info & stuff UpdateSpecies(); /////////////////// // Preparation /////////////////// // Adjust the species's fitness AdjustFitness(); // Count the offspring of each individual and species CountOffspring(); // Incrementing the global stagnation counter, we can check later for global stagnation m_GensSinceBestFitnessLastChanged++; // Find and save the best genome and fitness for(unsigned int i=0; i<m_Species.size(); i++) { // Update best genome info m_Species[i].m_BestGenome = m_Species[i].GetLeader(); for(unsigned int j=0; j<m_Species[i].m_Individuals.size(); j++) { // Make sure all are evaluated as we don't run in realtime m_Species[i].m_Individuals[j].SetEvaluated(); const double t_Fitness = m_Species[i].m_Individuals[j].GetFitness(); if (m_BestFitnessEver < t_Fitness) { // Reset the stagnation counter only if the fitness jump is greater or equal to the delta. if (fabs(t_Fitness - m_BestFitnessEver) >= m_Parameters.StagnationDelta) { m_GensSinceBestFitnessLastChanged = 0; } m_BestFitnessEver = t_Fitness; m_BestGenomeEver = m_Species[i].m_Individuals[j]; } } } // Find and save the current best genome double t_bestf = std::numeric_limits<double>::min(); for(unsigned int i=0; i<m_Species.size(); i++) { for(unsigned int j=0; j<m_Species[i].m_Individuals.size(); j++) { if (m_Species[i].m_Individuals[j].GetFitness() > t_bestf) { t_bestf = m_Species[i].m_Individuals[j].GetFitness(); m_BestGenome = m_Species[i].m_Individuals[j]; } } } // adjust the compatibility threshold if (m_Parameters.DynamicCompatibility == true) { if ((m_Generation % m_Parameters.CompatTreshChangeInterval_Generations) == 0) { if (m_Species.size() > m_Parameters.MaxSpecies) { m_Parameters.CompatTreshold += m_Parameters.CompatTresholdModifier; } else if (m_Species.size() < m_Parameters.MinSpecies) { m_Parameters.CompatTreshold -= m_Parameters.CompatTresholdModifier; } } if (m_Parameters.CompatTreshold < m_Parameters.MinCompatTreshold) m_Parameters.CompatTreshold = m_Parameters.MinCompatTreshold; } // A special case for global stagnation. // Delta coding - if there is a global stagnation // for dropoff age + 10 generations, focus the search on the top 2 species, // in case there are more than 2, of course if (m_Parameters.DeltaCoding) { if (m_GensSinceBestFitnessLastChanged > (m_Parameters.SpeciesMaxStagnation + 10)) { // make the top 2 reproduce by 50% individuals // and the rest - no offspring if (m_Species.size() > 2) { // The first two will reproduce m_Species[0].SetOffspringRqd( m_Parameters.PopulationSize/2 ); m_Species[1].SetOffspringRqd( m_Parameters.PopulationSize/2 ); // The rest will not for (unsigned int i=2; i<m_Species.size(); i++) { m_Species[i].SetOffspringRqd( 0 ); } // Now reset the stagnation counter and species age m_Species[0].ResetAge(); m_Species[1].ResetAge(); m_GensSinceBestFitnessLastChanged = 0; } } } ////////////////////////////////// // Phased searching core logic ////////////////////////////////// // Update the current MPC CalculateMPC(); if (m_Parameters.PhasedSearching) { // Keep track of complexity when in simplifying phase if (m_SearchMode == SIMPLIFYING) { // The MPC has lowered? if (m_CurrentMPC < m_OldMPC) { // reset that m_GensSinceMPCLastChanged = 0; m_OldMPC = m_CurrentMPC; } else { m_GensSinceMPCLastChanged++; } } // At complexifying phase? if (m_SearchMode == COMPLEXIFYING) { // Need to begin simplification? if (m_CurrentMPC > (m_BaseMPC + m_Parameters.SimplifyingPhaseMPCTreshold)) { // Do this only if the whole population is stagnating if (m_GensSinceBestFitnessLastChanged > m_Parameters.SimplifyingPhaseStagnationTreshold) { // Change the current search mode m_SearchMode = SIMPLIFYING; // Reset variables for simplifying mode m_GensSinceMPCLastChanged = 0; m_OldMPC = std::numeric_limits<double>::max(); // Really big one // reset the age of species for(unsigned int i=0; i<m_Species.size(); i++) { m_Species[i].ResetAge(); } } } } else if (m_SearchMode == SIMPLIFYING) // At simplifying phase? { // The MPC reached its floor level? if (m_GensSinceMPCLastChanged > m_Parameters.ComplexityFloorGenerations) { // Re-enter complexifying phase m_SearchMode = COMPLEXIFYING; // Set the base MPC with the current MPC m_BaseMPC = m_CurrentMPC; // reset the age of species for(unsigned int i=0; i<m_Species.size(); i++) { m_Species[i].ResetAge(); } } } } ///////////////////////////// // Reproduction ///////////////////////////// // Kill all bad performing individuals // Todo: this baby/adult/killworst scheme is complicated and basically sucks, // I should remove it completely. // for(unsigned int i=0; i<m_Species.size(); i++) m_Species[i].KillWorst(m_Parameters); // Perform reproduction for each species m_TempSpecies.clear(); m_TempSpecies = m_Species; for(unsigned int i=0; i<m_TempSpecies.size(); i++) { m_TempSpecies[i].Clear(); } for(unsigned int i=0; i<m_Species.size(); i++) { m_Species[i].Reproduce(*this, m_Parameters, m_RNG); } m_Species = m_TempSpecies; // Now we kill off the old parents // Todo: this baby/adult scheme is complicated and basically sucks, // I should remove it completely. // for(unsigned int i=0; i<m_Species.size(); i++) m_Species[i].KillOldParents(); // Here we kill off any empty species too // Remove all empty species (cleanup routine for every case..) for(unsigned int i=0; i<m_Species.size(); i++) { if (m_Species[i].m_Individuals.size() == 0) { m_Species.erase(m_Species.begin() + i); i--; } } // Now reassign the representatives for each species for(unsigned int i=0; i<m_Species.size(); i++) { m_Species[i].SetRepresentative( m_Species[i].m_Individuals[0] ); } // If the total amount of genomes reproduced is less than the population size, // due to some floating point rounding error, // we will add some bonus clones of the first species's leader to it unsigned int t_total_genomes = 0; for(unsigned int i=0; i<m_Species.size(); i++) t_total_genomes += static_cast<unsigned int>(m_Species[i].m_Individuals.size()); if (t_total_genomes < m_Parameters.PopulationSize) { int t_nts = m_Parameters.PopulationSize - t_total_genomes; while(t_nts--) { ASSERT(m_Species.size() > 0); Genome t_tg = m_Species[0].m_Individuals[0]; m_Species[0].AddIndividual(t_tg); } } // Increase generation number m_Generation++; // At this point we may also empty our innovation database // This is the place where we control whether we want to // keep innovation numbers forever or not. if (!m_Parameters.InnovationsForever) { m_InnovationDatabase.Flush(); } }
Population::Population(const char *a_FileName) { m_BestFitnessEver = 0.0; m_Generation = 0; m_NumEvaluations = 0; m_NextSpeciesID = 1; m_GensSinceBestFitnessLastChanged = 0; m_GensSinceMPCLastChanged = 0; std::ifstream t_DataFile(a_FileName); if (!t_DataFile.is_open()) throw std::exception(); std::string t_str; // Load the parameters m_Parameters.Load(t_DataFile); // Load the innovation database m_InnovationDatabase.Init(t_DataFile); // Load all genomes /*for(unsigned int i=0; i<m_Parameters.PopulationSize; i++) { Genome t_genome(t_DataFile); m_Genomes.push_back( t_genome ); }*/ // Fix a bug where populations with more than PopulationSize genomes wouldn't get parsed correctly while(t_DataFile.peek() != EOF) { streampos sp = t_DataFile.tellg(); string line; t_DataFile >> line; if (line == "GenomeStart") { t_DataFile.seekg(sp); Genome t_genome(t_DataFile); m_Genomes.push_back( t_genome ); } } t_DataFile.close(); m_NextGenomeID = 0; for(unsigned int i=0; i<m_Genomes.size(); i++) { if (m_Genomes[i].GetID() > m_NextGenomeID) { m_NextGenomeID = m_Genomes[i].GetID(); } } m_NextGenomeID++; // Initialize Speciate(); m_BestGenome = m_Species[0].GetLeader(); Sort(); // Set up the phased search variables CalculateMPC(); m_BaseMPC = m_CurrentMPC; m_OldMPC = m_BaseMPC; if (m_Parameters.PhasedSearching) { m_SearchMode = COMPLEXIFYING; } else { m_SearchMode = BLENDED; } }