//-----------------------------------Epoch()----------------------------- // // takes a population of chromosones and runs the algorithm through one // cycle. // Returns a new population of chromosones. //----------------------------------------------------------------------- vector<SGenome> CGenAlg::Epoch(vector<SGenome> &old_pop) { //assign the given population to the classes population m_vecPop = old_pop; //reset the appropriate variables Reset(); //create a temporary vector to store new chromosones vector <SGenome> vecNewPop; CalculateBestWorstAvTot(); //sort the population (for scaling and elitism) sort(m_vecPop.begin(), m_vecPop.end()); //Now to add a little elitism we shall add in some copies of the //fittest genomes. Make sure we add an EVEN number or the roulette //wheel sampling will crash if (!(CParams::iNumCopiesElite * CParams::iNumElite % 2)) { GrabNBest(CParams::iNumElite, CParams::iNumCopiesElite, vecNewPop); } //--------------now to enter the GA loop //repeat until a new population is generated while (vecNewPop.size() < m_iPopSize) { //select using tournament selection for a change SGenome mum = TournamentSelection(CParams::iTournamentCompetitors); SGenome dad = TournamentSelection(CParams::iTournamentCompetitors); //create some offspring via crossover vector<double> baby1, baby2; CrossoverAtSplits(mum.vecWeights, dad.vecWeights, baby1, baby2); //now we mutate Mutate(baby1); Mutate(baby2); //now copy into vecNewPop population vecNewPop.push_back( SGenome(baby1, 0) ); vecNewPop.push_back( SGenome(baby2, 0) ); } //finished so assign new pop back into m_vecPop m_vecPop = vecNewPop; return m_vecPop; }
/////////////////////////////// INTERFACE //////////////////////////////// void GeneticClass::Interface(){ lc = 10000; int algorithmIteration = 30; float crossoverRatio = 0.9; int mutationIteration = 1000; int score = 0, parent1, parent2; DrawingPopulation(); Rating(); cout << "Rodzice: " << bestScoreInAll << endl; checksRepeatsInSet(); ////////////// SELEKCJA I KRZYZOWANIE I MUTACJA/////////////////////////////// for (int z = 0; z<algorithmIteration; z++){ int P = -1; // licznik nowej populacji vector<bool> crossed(lc,false); int crossoverIterations = (lc - 2) * crossoverRatio; #pragma omp parallel for for (P = -1; P < crossoverIterations; P += 2) { parent1 = TournamentSelection(10); do parent2 = TournamentSelection(10); while (parent1 == parent2); crossed[parent1] = true; crossed[parent2] = true; Crossover(parent1, parent2, children[P + 1], children[P + 2]); } for (int i = 0 ; i < lc; i++) { //Dopisuje do children osobniki ktore nie braly udzialu w krzyzowaniu if (crossoverIterations != lc) { if (crossed[i] == false) { children[crossoverIterations++] = chromosom[i]; } } else { break; } } chromosom.swap(children); for (int i = 0; i<mutationIteration; i++){ int target = TournamentSelection(100); Mutation(chromosom[target]); // przy zakomentowanym krzyzowaniu wpisalem tu chromosom zamiast children } checksRepeatsInSet(); score = Rating(); cout << "Populacja_" << z << " = " << score << endl; } showBest(); }
//------------------------Epoch------------------------------- // // creates a new population of genomes using the selection, // mutation and crossover operators //------------------------------------------------------------ void CgaTSP::Epoch() { //first we reset variables and calculate the fitness of each genome Reset(); CalculatePopulationsFitness(); //if we have found a solution exit if ((m_dShortestRoute <= m_pMap->BestPossibleRoute())) { m_bStarted = false; return; } //perform the appropriate fitness scaling FitnessScaleSwitch(); //if sigma is zero (either set in sigma scaling or in CalculateBestWorstAv //then the population are identical and we should stop the run if (m_dSigma == 0) { m_bStarted = false; return; } //create a temporary vector for the new population vector<SGenome> vecNewPop; if (m_bElitism) { //Now to add a little elitism we shall add in some copies of the //fittest genomes const int CopiesToAdd = 2; const int NBest = 4; //make sure we add an EVEN number or the roulette wheel //sampling will crash if (!(CopiesToAdd * NBest % 2)) { GrabNBest(NBest, CopiesToAdd, vecNewPop); } } //SUS selection selects the entire population all at once so we have to //handle the epoch slightly differently if SUS is chosen if(m_SelectionType != SUS) { //now create the remainder of the population while (vecNewPop.size() != m_iPopSize) { SGenome mum, dad; //switch on selection method switch(m_SelectionType) { case ROULETTE: //grab two parents dependent on the selection method mum = RouletteWheelSelection(); dad = RouletteWheelSelection(); break; case TOURNAMENT: mum = TournamentSelection(NUM_TO_COMPARE); dad = TournamentSelection(NUM_TO_COMPARE); break; case ALT_TOURNAMENT: mum = AlternativeTournamentSelection(); dad = AlternativeTournamentSelection(); break; } //create 2 children SGenome baby1, baby2; //Breed them Crossover(mum.vecCities, dad.vecCities, baby1.vecCities, baby2.vecCities, m_CrossoverType); //and mutate them Mutate(baby1.vecCities, m_MutationType); Mutate(baby2.vecCities, m_MutationType); //add them to new population vecNewPop.push_back(baby1); vecNewPop.push_back(baby2); } } //SUS selection else { //select all the individuals vector<SGenome> vecSampledPop; SUSSelection(vecSampledPop); //step through the newly sampled population and apply crossover //and mutation operators for (int gen=0; gen<vecSampledPop.size(); gen+=2) { SGenome baby1, baby2; Crossover(vecSampledPop[gen].vecCities, vecSampledPop[gen+1].vecCities, baby1.vecCities, baby2.vecCities, m_CrossoverType); Mutate(baby1.vecCities, m_MutationType); Mutate(baby2.vecCities, m_MutationType); vecNewPop.push_back(baby1); vecNewPop.push_back(baby2); } } //copy into next generation m_vecPopulation = vecNewPop; //increment generation counter ++m_iGeneration; }
int main() { // Declare GA parameters - pop. size, variables, etc const int populationSize = 30; const int numberOfGenerations = 100; const int tournamentSize = 2; const double tournamentSelectionParameter = 0.75; const float crossOverProbability = 0.7; const float creepRateMutation = 0.1; const double mutationProbability = 0.05; // Vehicle related parameters for chromosome construction int numberOfUnits = 4; // Including Tractor std::vector<int> numberOfAxlesOnEachUnit{3,3,2,3}; // Can be made inputs later int numberOfEngines = 3; // D11, D13, D16 int numberOfElectricMotors = 3; int numberOfElectricBuffers = 3; std::vector<int> machineParameters{numberOfEngines, numberOfElectricMotors, numberOfElectricBuffers}; std::vector<std::vector<int>> vehicleConfigurationParameters{machineParameters, numberOfAxlesOnEachUnit}; // Initialise the population Population population = InitialisePopulation(populationSize, vehicleConfigurationParameters); // Check if population is correctly initialised std::cout<<"Population initialised"<<std::endl; PrintMembersOfPopulation(population); // Create files for storing population of each generation & fitnesses of each individual in each generation std::fstream populationEachGeneration; std::fstream fitnessEachGeneration; //Delete any existing instances of the files to be created remove("PopulationEachGeneration.txt"); remove("FitnessEachGeneration.txt"); std::vector<double> bestFitnessOverGenerations; std::vector<std::vector<double>> missionData; LoadMission(missionData); // Loop begins - generation evolution start for(int generationIndex=0;generationIndex<numberOfGenerations;generationIndex++) { std::cout<<"GENERATION NUMBER : "<<generationIndex<<std::endl; // Store current population in file PopulationEachGeneration.txt //StoreCurrentPopulationInFile(population, populationEachGeneration, rangeAllVariables); // Declare variables required for fitness evaluation Fitnesses fitness; // Keep inside scope of each generation double tempFitness; // Keep inside scope of each generation // Evaluate the fitness of each member in the population and assign to 'fitness' vector fitness = EvaluatePopulationFitness(population, missionData); StoreCurrentFitnessInPopulation(fitness, fitnessEachGeneration); // Declare variables required for best individual search long double maximumFitness; int bestIndividualIndex; Individual bestIndividual; // Find best individual in the current population bestIndividualIndex = GetBestIndividualIndex(fitness); //, population, rangeAllVariables); bestIndividual = population[bestIndividualIndex]; maximumFitness = fitness[bestIndividualIndex]; bestFitnessOverGenerations.push_back(maximumFitness); //PrintFitness(fitness); //std::cout<<"The best Individual is "<<bestIndividualIndex<<std::endl; std::cout<<"The optimal function value is "<<maximumFitness<<std::endl; // Based on fitness, perform selection & crossover without replacement Population tempPopulation; tempPopulation = population; for(int i=0;i<populationSize;i=i+2) { // i=i+2 since 2 individuals are crossed over // Select two random individuals using tournament selection std::vector<Individual> individualsToCrossover; // Both individuals to be crossed over placed in a vector for(int j=0;j<tournamentSize;j++) { int temporaryIndex=TournamentSelection(fitness, tournamentSelectionParameter, tournamentSize); //std::cout<<"Chosen Individual :"<<temporaryIndex<<std::endl; individualsToCrossover.push_back(population[temporaryIndex]); } // end of Tournament Selection // Perform crossover // ALGORITHM ONE - INDIVIDUAL UNIT GENE CONSIDERATION FOR CROSSOVER std::vector<Individual> crossedOverIndividuals = CrossOver(individualsToCrossover, crossOverProbability); tempPopulation[i]=crossedOverIndividuals[0]; tempPopulation[i+1]=crossedOverIndividuals[1]; // ALGORITHM TWO - CROSSOVER AT UNIT GENE BOUNDARIES FOR WHOLE INDIVIDUALS /*double randomDouble = GetRandomDouble(); if(randomDouble < crossOverProbability) { //std::cout<<"CrossOver Initiated"<<std::endl; std::vector<Individual> crossedOverIndividuals = CrossOver(individualsToCrossover); tempPopulation[i]=crossedOverIndividuals[0]; tempPopulation[i+1]=crossedOverIndividuals[1]; } else { // Place original pair of individuals in corresponding (consecutive) locations in tempPopulation //std::cout<<"No Crossover"<<std::endl; tempPopulation[i]=individualsToCrossover[0]; tempPopulation[i+1]=individualsToCrossover[1]; } // end of Crossover*/ } // End of Selection and Crossover //std::cout<<std::endl<<"After Crossover"<<std::endl; //PrintMembersOfPopulation(tempPopulation); // Mutate each individual MutatePopulation(tempPopulation, mutationProbability); // Population mutated //std::cout<<std::endl<<"After Mutation"<<std::endl; //PrintMembersOfPopulation(tempPopulation); // Elitism tempPopulation[0]=population[bestIndividualIndex]; for(int i=0;i<tempPopulation.size();i++) population[i]=tempPopulation[i]; } // end of generation loop // Declare variables required for final fitness evaluation Fitnesses finalFitness; // Keep inside scope of each generation double tempFitness; // Keep inside scope of each generation // Evaluate the fitness of each member in the population and assign to 'fitness' vector finalFitness = EvaluatePopulationFitness(population, missionData); //PrintFitness(finalFitness); // Declare variables required for best individual search long double finalMaximumFitness; int finalBestIndividualIndex; Individual finalBestIndividual; // Find best individual in the current population finalBestIndividualIndex = GetBestIndividualIndex(finalFitness); //, population, rangeAllVariables); finalBestIndividual = population[finalBestIndividualIndex]; finalMaximumFitness = finalFitness[finalBestIndividualIndex]; PrintMembersOfPopulation(population); // Check if the best individual is being correctly calculated std::cout<<"The best Individual is "<<finalBestIndividualIndex<<std::endl; PrintIndividual(population[finalBestIndividualIndex]); std::cout<<"The optimal function value is "<<finalMaximumFitness<<std::endl; //std::cout<<std::endl; std::ofstream fileOperation; remove("fitness_vs_generation.txt"); fileOperation.open("fitness_vs_generation.txt"); if (fileOperation.is_open()) { for(int i=0;i<bestFitnessOverGenerations.size();i++) { fileOperation << bestFitnessOverGenerations[i] << '\n'; } fileOperation.close(); } }// end of main()
//------------------------------------- Epoch ---------------------------- // // This function performs one epoch of the genetic algorithm and returns // a vector of pointers to the new phenotypes //------------------------------------------------------------------------ vector<CNeuralNet*> Cga::Epoch(const vector<double> &FitnessScores) { //first check to make sure we have the correct amount of fitness scores if (FitnessScores.size() != m_vecGenomes.size()) { MessageBox(NULL,"Cga::Epoch(scores/ genomes mismatch)!","Error", MB_OK); } //reset appropriate values and kill off the existing phenotypes and //any poorly performing species ResetAndKill(); //update the genomes with the fitnesses scored in the last run for (int gen=0; gen<m_vecGenomes.size(); ++gen) { m_vecGenomes[gen].SetFitness(FitnessScores[gen]); } //sort genomes and keep a record of the best performers SortAndRecord(); //separate the population into species of similar topology, adjust //fitnesses and calculate spawn levels SpeciateAndCalculateSpawnLevels(); //this will hold the new population of genomes vector<CGenome> NewPop; //request the offspring from each species. The number of children to //spawn is a double which we need to convert to an int. int NumSpawnedSoFar = 0; CGenome baby; //now to iterate through each species selecting offspring to be mated and //mutated for (int spc=0; spc<m_vecSpecies.size(); ++spc) { //because of the number to spawn from each species is a double //rounded up or down to an integer it is possible to get an overflow //of genomes spawned. This statement just makes sure that doesn't //happen if (NumSpawnedSoFar < CParams::iNumSweepers) { //this is the amount of offspring this species is required to // spawn. Rounded simply rounds the double up or down. int NumToSpawn = Rounded(m_vecSpecies[spc].NumToSpawn()); bool bChosenBestYet = false; while (NumToSpawn--) { //first grab the best performing genome from this species and transfer //to the new population without mutation. This provides per species //elitism if (!bChosenBestYet) { baby = m_vecSpecies[spc].Leader(); bChosenBestYet = true; } else { //if the number of individuals in this species is only one //then we can only perform mutation if (m_vecSpecies[spc].NumMembers() == 1) { //spawn a child baby = m_vecSpecies[spc].Spawn(); } //if greater than one we can use the crossover operator else { //spawn1 CGenome g1 = m_vecSpecies[spc].Spawn(); if (RandFloat() < CParams::dCrossoverRate) { //spawn2, make sure it's not the same as g1 CGenome g2 = m_vecSpecies[spc].Spawn(); //number of attempts at finding a different genome int NumAttempts = 5; while ( (g1.ID() == g2.ID()) && (NumAttempts--) ) { g2 = m_vecSpecies[spc].Spawn(); } if (g1.ID() != g2.ID()) { baby = Crossover(g1, g2); } } else { baby = g1; } } ++m_iNextGenomeID; baby.SetID(m_iNextGenomeID); //now we have a spawned child lets mutate it! First there is the //chance a neuron may be added if (baby.NumNeurons() < CParams::iMaxPermittedNeurons) { baby.AddNeuron(CParams::dChanceAddNode, *m_pInnovation, CParams::iNumTrysToFindOldLink); } //now there's the chance a link may be added baby.AddLink(CParams::dChanceAddLink, CParams::dChanceAddRecurrentLink, *m_pInnovation, CParams::iNumTrysToFindLoopedLink, CParams::iNumAddLinkAttempts); //mutate the weights baby.MutateWeights(CParams::dMutationRate, CParams::dProbabilityWeightReplaced, CParams::dMaxWeightPerturbation); baby.MutateActivationResponse(CParams::dActivationMutationRate, CParams::dMaxActivationPerturbation); } //sort the babies genes by their innovation numbers baby.SortGenes(); //add to new pop NewPop.push_back(baby); ++NumSpawnedSoFar; if (NumSpawnedSoFar == CParams::iNumSweepers) { NumToSpawn = 0; } }//end while }//end if }//next species //if there is an underflow due to the rounding error and the amount //of offspring falls short of the population size additional children //need to be created and added to the new population. This is achieved //simply, by using tournament selection over the entire population. if (NumSpawnedSoFar < CParams::iNumSweepers) { //calculate amount of additional children required int Rqd = CParams::iNumSweepers - NumSpawnedSoFar; //grab them while (Rqd--) { NewPop.push_back(TournamentSelection(m_iPopSize/5)); } } //replace the current population with the new one m_vecGenomes = NewPop; //create the new phenotypes vector<CNeuralNet*> new_phenotypes; for (gen=0; gen<m_vecGenomes.size(); ++gen) { //calculate max network depth int depth = CalculateNetDepth(m_vecGenomes[gen]); CNeuralNet* phenotype = m_vecGenomes[gen].CreatePhenotype(depth); new_phenotypes.push_back(phenotype); } //increase generation counter ++m_iGeneration; return new_phenotypes; }