// returns an individual randomly selected from the best N% Genome Species::GetIndividual(Parameters& a_Parameters, RNG& a_RNG) const { ASSERT(m_Individuals.size() > 0); // Make a pool of only evaluated individuals! std::vector<Genome> t_Evaluated; for(unsigned int i=0; i<m_Individuals.size(); i++) { if (m_Individuals[i].IsEvaluated()) t_Evaluated.push_back( m_Individuals[i] ); } ASSERT(t_Evaluated.size() > 0); if (t_Evaluated.size() == 1) { return (t_Evaluated[0]); } else if (t_Evaluated.size() == 2) { return (t_Evaluated[ Rounded(a_RNG.RandFloat()) ]); } // Warning!!!! The individuals must be sorted by best fitness for this to work int t_chosen_one=0; // Here might be introduced better selection scheme, but this works OK for now if (!a_Parameters.RouletteWheelSelection) { //start with the last one just for comparison sake int temp_genome; int t_num_parents = static_cast<int>( floor((a_Parameters.SurvivalRate * (static_cast<double>(t_Evaluated.size())))+1.0)); ASSERT(t_num_parents>0); if (t_num_parents>=t_Evaluated.size()) t_num_parents = t_Evaluated.size()-1; t_chosen_one = a_RNG.RandInt(0, t_num_parents); for (unsigned int i = 0; i < a_Parameters.TournamentSize; i++) { temp_genome = a_RNG.RandInt(0, t_num_parents); if (m_Individuals[temp_genome].GetFitness() > m_Individuals[t_chosen_one].GetFitness()) { t_chosen_one = temp_genome; } } } else { // roulette wheel selection std::vector<double> t_probs; for(unsigned int i=0; i<t_Evaluated.size(); i++) t_probs.push_back( t_Evaluated[i].GetFitness() ); t_chosen_one = a_RNG.Roulette(t_probs); } return (t_Evaluated[t_chosen_one]); }
// Mutates a genome void Species::MutateGenome( bool t_baby_is_clone, Population &a_Pop, Genome &t_baby, Parameters& a_Parameters, RNG& a_RNG ) { #if 1 // NEW version: // All mutations are mutually exclusive - can't have 2 mutations at once // for example a weight mutation and time constants mutation // or add link and add node and then weight mutation // We will perform roulette wheel selection to choose the type of mutation and will mutate the baby // This method guarantees that the baby will be mutated at least with one mutation enum MutationTypes {ADD_NODE = 0, ADD_LINK, REMOVE_NODE, REMOVE_LINK, CHANGE_ACTIVATION_FUNCTION, MUTATE_WEIGHTS, MUTATE_ACTIVATION_A, MUTATE_ACTIVATION_B, MUTATE_TIMECONSTS, MUTATE_BIASES }; std::vector<int> t_muts; std::vector<double> t_mut_probs; // ADD_NODE; t_mut_probs.push_back( a_Parameters.MutateAddNeuronProb ); // ADD_LINK; t_mut_probs.push_back( a_Parameters.MutateAddLinkProb ); // REMOVE_NODE; t_mut_probs.push_back( a_Parameters.MutateRemSimpleNeuronProb ); // REMOVE_LINK; t_mut_probs.push_back( a_Parameters.MutateRemLinkProb ); // CHANGE_ACTIVATION_FUNCTION; t_mut_probs.push_back( a_Parameters.MutateNeuronActivationTypeProb ); // MUTATE_WEIGHTS; t_mut_probs.push_back( a_Parameters.MutateWeightsProb ); // MUTATE_ACTIVATION_A; t_mut_probs.push_back( a_Parameters.MutateActivationAProb ); // MUTATE_ACTIVATION_B; t_mut_probs.push_back( a_Parameters.MutateActivationBProb ); // MUTATE_TIMECONSTS; t_mut_probs.push_back( a_Parameters.MutateNeuronTimeConstantsProb ); // MUTATE_BIASES; t_mut_probs.push_back( a_Parameters.MutateNeuronBiasesProb ); // Special consideration for phased searching - do not allow certain mutations depending on the search mode // also don't use additive mutations if we just want to get rid of the clones if ((a_Pop.GetSearchMode() == SIMPLIFYING) || t_baby_is_clone) { t_mut_probs[ADD_NODE] = 0; // add node t_mut_probs[ADD_LINK] = 0; // add link } if ((a_Pop.GetSearchMode() == COMPLEXIFYING) || t_baby_is_clone) { t_mut_probs[REMOVE_NODE] = 0; // rem node t_mut_probs[REMOVE_LINK] = 0; // rem link } bool t_mutation_success = false; // repeat until successful while (t_mutation_success == false) { int ChosenMutation = a_RNG.Roulette(t_mut_probs); // Now mutate based on the choice switch(ChosenMutation) { case ADD_NODE: t_mutation_success = t_baby.Mutate_AddNeuron(a_Pop.AccessInnovationDatabase(), a_Parameters, a_RNG); break; case ADD_LINK: t_mutation_success = t_baby.Mutate_AddLink(a_Pop.AccessInnovationDatabase(), a_Parameters, a_RNG); break; case REMOVE_NODE: t_mutation_success = t_baby.Mutate_RemoveSimpleNeuron(a_Pop.AccessInnovationDatabase(), a_RNG); break; case REMOVE_LINK: { // Keep doing this mutation until it is sure that the baby will not // end up having dead ends or no links Genome t_saved_baby = t_baby; bool t_no_links = false, t_has_dead_ends = false; int t_tries = 128; do { t_tries--; if (t_tries <= 0) { t_saved_baby = t_baby; break; // give up } t_saved_baby = t_baby; t_mutation_success = t_saved_baby.Mutate_RemoveLink(a_RNG); t_no_links = t_has_dead_ends = false; if (t_saved_baby.NumLinks() == 0) t_no_links = true; t_has_dead_ends = t_saved_baby.HasDeadEnds(); } while(t_no_links || t_has_dead_ends); t_baby = t_saved_baby; // debugger trap if (t_baby.NumLinks() == 0) { std::cerr << "No links in baby after mutation" << std::endl; } if (t_baby.HasDeadEnds()) { std::cerr << "Dead ends in baby after mutation" << std::endl; } } break; case CHANGE_ACTIVATION_FUNCTION: t_baby.Mutate_NeuronActivation_Type(a_Parameters, a_RNG); t_mutation_success = true; break; case MUTATE_WEIGHTS: t_baby.Mutate_LinkWeights(a_Parameters, a_RNG); t_mutation_success = true; break; case MUTATE_ACTIVATION_A: t_baby.Mutate_NeuronActivations_A(a_Parameters, a_RNG); t_mutation_success = true; break; case MUTATE_ACTIVATION_B: t_baby.Mutate_NeuronActivations_B(a_Parameters, a_RNG); t_mutation_success = true; break; case MUTATE_TIMECONSTS: t_baby.Mutate_NeuronTimeConstants(a_Parameters, a_RNG); t_mutation_success = true; break; case MUTATE_BIASES: t_baby.Mutate_NeuronBiases(a_Parameters, a_RNG); t_mutation_success = true; break; default: t_mutation_success = false; break; } } #else // Old version of the function - added just to test various ways to do mutation bool t_mutation_success = false; // repeat until successful while (t_mutation_success == false) { if (a_RNG.RandFloat() < a_Parameters.MutateAddNeuronProb) t_mutation_success = t_baby.Mutate_AddNeuron(a_Pop.AccessInnovationDatabase(), a_Parameters, a_RNG); else if (a_RNG.RandFloat() < a_Parameters.MutateAddLinkProb) t_mutation_success = t_baby.Mutate_AddLink(a_Pop.AccessInnovationDatabase(), a_Parameters, a_RNG); else { /*if (a_RNG.RandFloat() < a_Parameters.MutateNeuronActivationTypeProb) { t_baby.Mutate_NeuronActivation_Type(a_Parameters, a_RNG); t_mutation_success = true; }*/ if (a_RNG.RandFloat() < a_Parameters.MutateWeightsProb) { t_baby.Mutate_LinkWeights(a_Parameters, a_RNG); t_mutation_success = true; break; } /*case MUTATE_ACTIVATION_A: t_baby.Mutate_NeuronActivations_A(a_Parameters, a_RNG); t_mutation_success = true; break; case MUTATE_ACTIVATION_B: t_baby.Mutate_NeuronActivations_B(a_Parameters, a_RNG); t_mutation_success = true; break; case MUTATE_TIMECONSTS: t_baby.Mutate_NeuronTimeConstants(a_Parameters, a_RNG); t_mutation_success = true; break; case MUTATE_BIASES: t_baby.Mutate_NeuronBiases(a_Parameters, a_RNG); t_mutation_success = true; break;*/ } } #endif }