evolution_strategy behaviour (faber_neuroevolution v1.2.4)
View SourceBehaviour definition for pluggable evolution strategies.
This behaviour allows different evolution paradigms to be implemented as interchangeable modules. Each strategy controls:
- When individuals are created and removed - How selection and reproduction work - What events are emitted - What inputs are provided to meta-controllers
Implementing a Strategy
A strategy module must implement these callbacks:
- init/1 - Initialize strategy state from configuration - handle_evaluation_result/3 - Process a single evaluation result - tick/1 - Periodic callback for time-based actions - get_population_snapshot/1 - Return current population state for UI - get_meta_inputs/1 - Return inputs for meta-controller - apply_meta_params/2 - Apply meta-controller parameter adjustments
Built-in Strategies
- generational_strategy - Traditional (mu,lambda) batch evolution - steady_state_strategy - Continuous replacement, no generations - island_strategy - Parallel populations with migration - novelty_strategy - Behavioral novelty search - map_elites_strategy - Quality-diversity with niche grid
Actions and Events
Strategies return {Actions, Events, NewState} tuples:
Actions are requests for the server to perform: - {create_individual, ParentIds, Metadata} - {remove_individual, Id, Reason} - {evaluate_individual, Id} - {evaluate_batch, [Id]}
Events are lifecycle notifications: - #individual_born{} - #individual_died{} - #generation_advanced{} - etc.
Summary
Functions
Apply meta-controller parameters to strategy.
Get meta-controller inputs from strategy.
Get population snapshot from strategy.
Dispatch evaluation result to strategy.
Check if a strategy module exports an optional callback.
Initialize a strategy.
Dispatch tick to strategy.
Types
-type birth_origin() :: initial | crossover | mutation | migration | insertion.
-type death_reason() ::
selection_pressure | stagnation | age_limit | niche_competition | migration |
population_limit | extinction.
-type fitness() :: float() | undefined.
-type individual_id() :: term().
-type individual_summary() :: #{id := individual_id(), fitness := fitness(), is_survivor => boolean(), is_offspring => boolean(), species_id => species_id(), age => non_neg_integer()}.
-type island_id() :: pos_integer() | atom().
-type lifecycle_event() :: #individual_born{id :: individual_id(), parent_ids :: [individual_id()], timestamp :: timestamp(), origin :: birth_origin(), metadata :: map()} | #individual_died{id :: individual_id(), reason :: death_reason(), final_fitness :: float() | undefined, timestamp :: timestamp(), metadata :: map()} | #individual_evaluated{id :: individual_id(), fitness :: float(), metrics :: map(), timestamp :: timestamp(), metadata :: map()} | #species_emerged{species_id :: species_id(), founder_id :: individual_id(), parent_species_id :: species_id() | undefined, timestamp :: timestamp(), metadata :: map()} | #species_extinct{species_id :: species_id(), reason :: stagnation | empty | merged | eliminated, final_stats :: map(), timestamp :: timestamp()} | #cohort_evaluated{generation :: pos_integer(), best_fitness :: float(), avg_fitness :: float(), worst_fitness :: float(), population_size :: pos_integer(), timestamp :: timestamp()} | #breeding_complete{generation :: pos_integer(), survivor_count :: non_neg_integer(), eliminated_count :: non_neg_integer(), offspring_count :: non_neg_integer(), timestamp :: timestamp()} | #generation_advanced{generation :: pos_integer(), previous_best_fitness :: float(), previous_avg_fitness :: float(), population_size :: pos_integer(), species_count :: non_neg_integer(), timestamp :: timestamp()} | #steady_state_replacement{replaced_ids :: [individual_id()], offspring_ids :: [individual_id()], best_fitness :: float() | undefined, avg_fitness :: float() | undefined, timestamp :: timestamp()} | #island_migration{individual_id :: individual_id(), from_island :: island_id(), to_island :: island_id(), fitness :: float(), timestamp :: timestamp()} | #island_topology_changed{islands :: [island_id()], connections :: [{island_id(), island_id()}], change_type :: island_added | island_removed | connection_changed, timestamp :: timestamp()} | #niche_discovered{niche_id :: niche_id(), behavior_descriptor :: [float()], individual_id :: individual_id(), fitness :: float(), timestamp :: timestamp()} | #niche_updated{niche_id :: niche_id(), old_individual_id :: individual_id(), new_individual_id :: individual_id(), old_fitness :: float(), new_fitness :: float(), improvement :: float(), timestamp :: timestamp()} | #archive_updated{size :: non_neg_integer(), coverage :: float(), qd_score :: float(), updates_since_last :: non_neg_integer(), timestamp :: timestamp()} | #competitor_updated{competitor_id :: term(), change_type :: generation_advanced | champion_changed | strategy_shift, champion_fitness :: float() | undefined, timestamp :: timestamp()} | #arms_race_event{event_type :: fitness_surge | counter_adaptation | stalemate | breakthrough, populations :: [term()], metrics :: map(), timestamp :: timestamp()} | #competition_result{competitors :: [individual_id()], scores :: [{individual_id(), float()}], winner_id :: individual_id() | draw, competition_type :: tournament | round_robin | elimination | ranked_match | team_vs_team, metadata :: map(), timestamp :: timestamp()} | #capability_emerged{capability_id :: term(), description :: binary(), exhibitors :: [individual_id()], timestamp :: timestamp()} | #complexity_increased{metric :: genome_size | network_depth | behavior_repertoire | term(), old_value :: number(), new_value :: number(), increase_pct :: float(), timestamp :: timestamp()} | #progress_checkpoint{total_evaluations :: non_neg_integer(), evaluations_since_last :: non_neg_integer(), cohort :: non_neg_integer(), best_fitness :: float(), avg_fitness :: float(), worst_fitness :: float(), population_size :: non_neg_integer(), species_count :: pos_integer(), improvement :: float(), elapsed_ms :: non_neg_integer(), evals_per_second :: float(), checkpoint_interval :: non_neg_integer(), timestamp :: timestamp()} | #environment_changed{environment_id :: term(), change_type :: difficulty_increased | difficulty_decreased | task_shifted | condition_changed | curriculum_advanced, description :: binary(), metrics :: map(), timestamp :: timestamp()} | #individual_aged_out{id :: individual_id(), final_age :: pos_integer(), final_fitness :: float(), lifetime_stats :: #{total_evaluations := non_neg_integer(), avg_fitness := float(), best_fitness := float(), offspring_count := non_neg_integer()}, timestamp :: timestamp()}.
-type meta_inputs() :: [float()].
-type niche_id() :: term().
-type population_snapshot() :: #{size := non_neg_integer(), individuals := [individual_summary()], best_fitness := fitness(), avg_fitness := fitness(), worst_fitness := fitness(), species_count => non_neg_integer(), generation => pos_integer(), extra => map()}.
-type species_id() :: pos_integer().
-type strategy_action() :: {create_individual, ParentIds :: [individual_id()], Metadata :: map()} | {remove_individual, individual_id(), Reason :: death_reason()} | {evaluate_individual, individual_id()} | {evaluate_batch, [individual_id()]} | {update_config, ConfigUpdates :: map()} | {migrate_individual, individual_id(), ToIsland :: island_id()} | {update_archive, ArchiveUpdate :: term()} | {emit_event, lifecycle_event()} | noop.
-type strategy_module() :: module().
-type strategy_result() :: {Actions :: [strategy_action()], Events :: [lifecycle_event()], NewState :: strategy_state()}.
-type strategy_state() :: term().
-type timestamp() :: erlang:timestamp().
Callbacks
-callback apply_meta_params(Params :: meta_params(), State :: strategy_state()) -> strategy_state().
-callback get_archive_state(State :: strategy_state()) -> {ok, ArchiveState :: map()} | {error, not_supported}.
-callback get_island_state(IslandId :: island_id(), State :: strategy_state()) -> {ok, IslandState :: map()} | {error, not_found}.
-callback get_meta_inputs(State :: strategy_state()) -> meta_inputs().
-callback get_population_snapshot(State :: strategy_state()) -> population_snapshot().
-callback handle_archive_update(IndividualId :: individual_id(), Novelty :: float(), State :: strategy_state()) -> strategy_result().
-callback handle_evaluation_result(IndividualId :: individual_id(), FitnessResult :: #{fitness := fitness(), metrics => map()}, State :: strategy_state()) -> strategy_result().
-callback handle_migration(IndividualId :: individual_id(), FromIsland :: island_id(), ToIsland :: island_id(), State :: strategy_state()) -> strategy_result().
-callback handle_niche_update(NicheId :: niche_id(), NewIndividualId :: individual_id(), State :: strategy_state()) -> strategy_result().
-callback init(Config :: map()) -> {ok, State :: strategy_state()} | {error, Reason :: term()}.
-callback tick(State :: strategy_state()) -> strategy_result().
Functions
-spec apply_meta_params(Module, Params, State) -> strategy_state() when Module :: strategy_module(), Params :: meta_params(), State :: strategy_state().
Apply meta-controller parameters to strategy.
-spec get_meta_inputs(Module, State) -> meta_inputs() when Module :: strategy_module(), State :: strategy_state().
Get meta-controller inputs from strategy.
-spec get_population_snapshot(Module, State) -> population_snapshot() when Module :: strategy_module(), State :: strategy_state().
Get population snapshot from strategy.
-spec handle_evaluation_result(Module, IndividualId, FitnessResult, State) -> Result when Module :: strategy_module(), IndividualId :: individual_id(), FitnessResult :: map(), State :: strategy_state(), Result :: strategy_result().
Dispatch evaluation result to strategy.
-spec has_callback(Module, Function, Arity) -> boolean() when Module :: strategy_module(), Function :: atom(), Arity :: non_neg_integer().
Check if a strategy module exports an optional callback.
-spec init(Module, Config) -> Result when Module :: strategy_module(), Config :: map(), Result :: {ok, strategy_state()} | {error, term()}.
Initialize a strategy.
-spec tick(Module, State) -> Result when Module :: strategy_module(), State :: strategy_state(), Result :: strategy_result().
Dispatch tick to strategy.