// 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 }