Bardo.PopulationManager.GenomeMutator (Bardo v0.1.0)

View Source

The genome_mutator is responsible for mutating genotypes. It uses various mutation operators to modify a genotype, and return a mutant of the genotype. Specifically, the mutation operators include both topological and parametric mutations. The topological mutations mutate the structure of a genotype by adding, or removing, neurons, connections, sensors, and actuators. The parametric mutations mutate the parameters of the genotype, such as the weights and the plasticity parameters. In a multi-objective optimization, bias mutation is performed on the bias parameters of the neural network, thus changing the biasing of the NN from one objective to another, while preserving overall proficiency.

Technically, we do not need every one of these mutation operators; the following list will be enough for a highly versatile complexifying topology and weight evolving artificial neural network (TWEANN) system: mutate_weights, add_bias, remove_bias, mutate_af, add_neuron, splice (just one of them), add_inlink, add_outlink, add_sensorlink, add_actuatorlink, add_sensor, and add_actuator. Note that this combination of MOs can convert any NN topology A into a NN topology B, given that A is contained (smaller, and simpler in a sense) within B.

Summary

Functions

The add_bias function is called with the AgentId parameter. The function first extracts the neuron_ids list from the cortex element and chooses a random neuron from the id list. After the neuron is read from the database, we check whether input_idps and input_idps_modulation lists already have bias, and we randomly generate a value 1 or 2. If the value 1 is generated and the input_idps list does not have a bias, it is added. If the value 2 is generated, and the input_idps_modulation does not have a bias, it is added. Otherwise an error is returned.

The link_from_element_to_element first calculates what type of link is going to be established (neuron to neuron, sensor to neuron, or neuron to actuator), and then calls the specific linking function based on that.

The link_from_neuron_to_neuron establishes a link from neuron with id FromNeuronId, to a neuron with id ToNeuronId. The function then calls link_from_neuron, which establishes the link on the FromNeuronId's side. The updated neuron associated with the FromNeuronId is then written to database.

The function link_from_sensor_to_neuron establishes a connection from the sensor with id FromSensorId, and the neuron with id ToNeuronId.

The function mutate first updates the generation of the agent to be mutated, then calculates the number of mutation operators to be applied to it by executing the tot_topological_mutations:TTMName/2 function, and then finally runs the apply_mutators/2 function, which mutates the agent. Once the agent is mutated, the function updates its fingerprint by executing genotype:update_finrgerprint/1.

The mutate_af function chooses a random neuron, and then changes its currently used activation function into another one available from the neural_afs list of the agent's constraint record.

The mutate_heredity_type function checks if there are any other heredity types in the agent's constraint record. If any other than the one currently used by the agent are present, the agent exchanges the heredity type it currently uses to a random one from the remaining list. If no other heredity types are available, the mutation operator exits with an error, and the neuroevolutionary system tries another mutation operator.

The mutate_tot_topological_mutations function checks if there are any other than the currently used tuning tot topological mutation functions available in the agent's constraint. If there is, then it chooses a random one from this list, and sets the agent's tot_topological_mutations_f to it. If there are no other functions that can calculate tot topological mutations, then it exits with an error.

The mutate_annealing_parameter function checks if there are any other than the currently used tuning annealing parameters available in the agent's constraint. If there is, then it chooses a random one from this list, and sets the agent's annealing_parameter to it. If there are no other tuning annealing parameters, then it exits with an error.

The mutate_tuning_selection function checks if there are any other than the currently used tuning selection functions available in the agent's constraint. If there is, then it chooses a random one from this list, and sets the agent's tuning_selection_f to it. If there are no other tuning selection functions, then it exits with an error.

The mutate_weights function accepts the AgentId parameter, extracts the NN's cortex, and then chooses a random neuron belonging to the NN with a uniform distribution probability. Then the neuron's input_idps list is extracted, and the function perturb_idps/1 is used to perturb/mutate the weights. Once the InputIdPs have been perturbed, the agent's evolutionary history, EvoHist is updated to include the successfully applied mutate_weights mutation operator. Then the updated Agent and the updated neuron are written to the database.

The remove_bias function is called with the AgentId parameter. The function first extracts the neuron_ids list from the cortex element and chooses a random neuron from the id list. After the neuron is read from the database, we check whether input_idps and input_idps_modulation lists already have bias, and we randomly generate a value 1 or 2. If the value 1 is generated and the input_idps list has a bias, it is removed. If the value 2 is generated, and the input_idps_modulation has a bias, it is removed. Otherwise an error is returned.

Applies mutation operators to a genotype based on probabilities.

Functions

add_bias(agent_id)

@spec add_bias(Bardo.Models.agent_id()) :: :ok | false

The add_bias function is called with the AgentId parameter. The function first extracts the neuron_ids list from the cortex element and chooses a random neuron from the id list. After the neuron is read from the database, we check whether input_idps and input_idps_modulation lists already have bias, and we randomly generate a value 1 or 2. If the value 1 is generated and the input_idps list does not have a bias, it is added. If the value 2 is generated, and the input_idps_modulation does not have a bias, it is added. Otherwise an error is returned.

mutate(agent_id)

@spec mutate(Bardo.Models.agent_id()) :: :ok

The function mutate first updates the generation of the agent to be mutated, then calculates the number of mutation operators to be applied to it by executing the tot_topological_mutations:TTMName/2 function, and then finally runs the apply_mutators/2 function, which mutates the agent. Once the agent is mutated, the function updates its fingerprint by executing genotype:update_finrgerprint/1.

mutate_af(agent_id)

@spec mutate_af(Bardo.Models.agent_id()) :: :ok | false

The mutate_af function chooses a random neuron, and then changes its currently used activation function into another one available from the neural_afs list of the agent's constraint record.

mutate_heredity_type(agent_id)

@spec mutate_heredity_type(Bardo.Models.agent_id()) :: :ok | false

The mutate_heredity_type function checks if there are any other heredity types in the agent's constraint record. If any other than the one currently used by the agent are present, the agent exchanges the heredity type it currently uses to a random one from the remaining list. If no other heredity types are available, the mutation operator exits with an error, and the neuroevolutionary system tries another mutation operator.

mutate_tot_topological_mutations(agent_id)

@spec mutate_tot_topological_mutations(Bardo.Models.agent_id()) :: :ok | false

The mutate_tot_topological_mutations function checks if there are any other than the currently used tuning tot topological mutation functions available in the agent's constraint. If there is, then it chooses a random one from this list, and sets the agent's tot_topological_mutations_f to it. If there are no other functions that can calculate tot topological mutations, then it exits with an error.

mutate_tuning_annealing(agent_id)

@spec mutate_tuning_annealing(Bardo.Models.agent_id()) :: :ok | false

The mutate_annealing_parameter function checks if there are any other than the currently used tuning annealing parameters available in the agent's constraint. If there is, then it chooses a random one from this list, and sets the agent's annealing_parameter to it. If there are no other tuning annealing parameters, then it exits with an error.

mutate_tuning_selection(agent_id)

@spec mutate_tuning_selection(Bardo.Models.agent_id()) :: :ok | false

The mutate_tuning_selection function checks if there are any other than the currently used tuning selection functions available in the agent's constraint. If there is, then it chooses a random one from this list, and sets the agent's tuning_selection_f to it. If there are no other tuning selection functions, then it exits with an error.

mutate_weights(agent_id)

@spec mutate_weights(Bardo.Models.agent_id()) :: :ok

The mutate_weights function accepts the AgentId parameter, extracts the NN's cortex, and then chooses a random neuron belonging to the NN with a uniform distribution probability. Then the neuron's input_idps list is extracted, and the function perturb_idps/1 is used to perturb/mutate the weights. Once the InputIdPs have been perturbed, the agent's evolutionary history, EvoHist is updated to include the successfully applied mutate_weights mutation operator. Then the updated Agent and the updated neuron are written to the database.

remove_bias(agent_id)

@spec remove_bias(Bardo.Models.agent_id()) :: :ok | false

The remove_bias function is called with the AgentId parameter. The function first extracts the neuron_ids list from the cortex element and chooses a random neuron from the id list. After the neuron is read from the database, we check whether input_idps and input_idps_modulation lists already have bias, and we randomly generate a value 1 or 2. If the value 1 is generated and the input_idps list has a bias, it is removed. If the value 2 is generated, and the input_idps_modulation has a bias, it is removed. Otherwise an error is returned.

simple_mutate(genotype, opts \\ %{})

Applies mutation operators to a genotype based on probabilities.

Parameters

  • genotype - The genotype to mutate
  • opts - Options controlling mutation probabilities

Options

  • :add_neuron_probability - Probability of adding a neuron (default: 0.1)
  • :add_link_probability - Probability of adding a connection (default: 0.2)
  • :mutate_weights_probability - Probability of mutating weights (default: 0.8)

Examples

iex> genotype = Bardo.PopulationManager.Genotype.new()
iex> mutated = Bardo.PopulationManager.GenomeMutator.simple_mutate(genotype)