crossover (macula_tweann v0.18.1)

View Source

Genetic crossover (recombination) for neural networks.

This module implements sexual reproduction by combining genetic material from two parent agents to create offspring. Crossover enables exploration of the solution space by mixing successful traits from different individuals.

Crossover Strategies

Network-Level Crossover: - Select matching neurons from both parents - Randomly choose which parent contributes each neuron - Inherit connections and weights from selected neurons - Handles structural differences (different topologies)

Neuron-Level Crossover: - For matching neurons, can mix properties: * Activation function from parent A * Weights from parent B * Bias from parent A - Creates fine-grained genetic mixing

Weight-Level Crossover: - For matching connections, blend weights: * Averaging: W_child = (W_A + W_B) / 2 * Random selection: W_child = random choice of W_A or W_B * Weighted average based on fitness - Preserves promising weight configurations

Implementation Notes

Matching Strategy: - Neurons match by layer coordinate - Connections match by source/target pair - Unmatched elements inherited from fitter parent

Compatibility: - Parents must have compatible morphologies - Sensor/actuator counts must match - Layer structure should align (though not required)

Summary

Functions

Perform genetic crossover between two parent agents.

Perform neuron-level crossover.

Perform weight-level crossover.

Types

actuator_id/0

-type actuator_id() :: {unique_id(), actuator}.

cortex_id/0

-type cortex_id() :: {unique_id(), cortex}.

delta_weight/0

-type delta_weight() :: float().

element_id/0

-type element_id() :: neuron_id() | sensor_id() | actuator_id() | cortex_id().

learning_rate/0

-type learning_rate() :: float().

neuron_id/0

-type neuron_id() :: {unique_id(), neuron}.

parameter_list/0

-type parameter_list() :: [float()].

sensor_id/0

-type sensor_id() :: {unique_id(), sensor}.

unique_id/0

-type unique_id() :: {float(), float()}.

weight/0

-type weight() :: float().

weight_list/0

-type weight_list() :: [weight_spec()].

weight_spec/0

-type weight_spec() :: {weight(), delta_weight(), learning_rate(), parameter_list()}.

weighted_input/0

-type weighted_input() :: {element_id(), weight_list()}.

weighted_inputs/0

-type weighted_inputs() :: [weighted_input()].

Functions

crossover(Parent1Id, Parent2Id)

-spec crossover(term(), term()) -> {float(), agent}.

Perform genetic crossover between two parent agents.

Creates a new offspring agent by combining genetic material from two parents. The offspring inherits a mix of neurons, connections, and weights from both parents.

Algorithm: 1. Clone one parent as base structure 2. For each matching neuron, perform neuron-level crossover 3. For unmatched neurons, inherit from fitter parent 4. Return offspring agent ID

Example: Parent1 = {1.0, agent} Parent2 = {2.0, agent} Offspring = crossover(Parent1, Parent2) % Offspring inherits mix of traits from both parents

neuron_crossover(Neuron, Neuron, CrossoverRate)

-spec neuron_crossover(#neuron{id :: term(),
                               generation :: term(),
                               cx_id :: term(),
                               pre_processor :: term(),
                               signal_integrator :: term(),
                               af :: term(),
                               post_processor :: term(),
                               pf :: term(),
                               aggr_f :: term(),
                               input_idps :: term(),
                               input_idps_modulation :: term(),
                               output_ids :: term(),
                               ro_ids :: term(),
                               neuron_type :: term(),
                               time_constant :: term(),
                               state_bound :: term(),
                               ltc_backbone_weights :: term(),
                               ltc_head_weights :: term(),
                               internal_state :: term(),
                               innovation :: term()},
                       #neuron{id :: term(),
                               generation :: term(),
                               cx_id :: term(),
                               pre_processor :: term(),
                               signal_integrator :: term(),
                               af :: term(),
                               post_processor :: term(),
                               pf :: term(),
                               aggr_f :: term(),
                               input_idps :: term(),
                               input_idps_modulation :: term(),
                               output_ids :: term(),
                               ro_ids :: term(),
                               neuron_type :: term(),
                               time_constant :: term(),
                               state_bound :: term(),
                               ltc_backbone_weights :: term(),
                               ltc_head_weights :: term(),
                               internal_state :: term(),
                               innovation :: term()},
                       float()) ->
                          #neuron{id :: term(),
                                  generation :: term(),
                                  cx_id :: term(),
                                  pre_processor :: term(),
                                  signal_integrator :: term(),
                                  af :: term(),
                                  post_processor :: term(),
                                  pf :: term(),
                                  aggr_f :: term(),
                                  input_idps :: term(),
                                  input_idps_modulation :: term(),
                                  output_ids :: term(),
                                  ro_ids :: term(),
                                  neuron_type :: term(),
                                  time_constant :: term(),
                                  state_bound :: term(),
                                  ltc_backbone_weights :: term(),
                                  ltc_head_weights :: term(),
                                  internal_state :: term(),
                                  innovation :: term()}.

Perform neuron-level crossover.

Combines properties from matching neurons in both parents. Can mix activation function, weights, LTC parameters, etc.

Strategy: - Activation function: random choice from parents - Input weights: weight-level crossover - Aggregation function: random choice - Output connections: union of both parents - LTC parameters: random choice with averaging for continuous values

Example: Neuron1 = #neuron{af = tanh, ...} Neuron2 = #neuron{af = sigmoid, ...} Result = neuron_crossover(Neuron1, Neuron2, 0.5) % Result might have tanh from parent 1

weight_crossover(Weights1, Weights2, CrossoverRate)

-spec weight_crossover(weighted_inputs(), weighted_inputs(), float()) -> weighted_inputs().

Perform weight-level crossover.

Combines weight vectors from two parent neurons. For matching connections (same source), blends weights. For unmatched connections, includes from both parents.

Blending strategies: - Averaging: (W1 + W2) / 2 - Random selection: random choice - Crossover rate determines probability

Example: Weights1 = [{sensor1, [{0.5, 0.0, 0.01, []}]}] Weights2 = [{sensor1, [{-0.3, 0.0, 0.01, []}]}] Result = weight_crossover(Weights1, Weights2, 0.5) % Might average to [{sensor1, [{0.1, 0.0, 0.01, []}]}]