use crate::ga::TerminationCause;
use crate::observer::{
ExtensionEvent, GaObserver, IbeaObserver, IslandGaObserver, MoeaDObserver, Nsga2Observer,
Nsga3Observer, SmsEmoaObserver, Spea2Observer,
};
use crate::stats::GenerationStats;
use crate::traits::ChromosomeT;
use std::time::Duration;
pub struct LogObserver;
impl<U: ChromosomeT> GaObserver<U> for LogObserver {
fn on_run_start(&self) {
log::info!("Initialization started");
}
fn on_generation_start(&self, generation: usize) {
log::info!(target="ga_events", method="run"; "Generation number: {}", generation + 1);
}
fn on_selection_complete(
&self,
_generation: usize,
_duration: Duration,
_population_size: usize,
) {
log::debug!(target="ga_events", method="run"; "Parents selected for reproduction");
}
fn on_crossover_complete(
&self,
_generation: usize,
_duration: Duration,
_offspring_count: usize,
) {
log::debug!(target="ga_events", method="parent_crossover"; "Started the parent crossover");
log::debug!(target="ga_events", method="run"; "Offspring created");
log::debug!(target="ga_events", method="parent_crossover"; "Parent crossover finished");
}
fn on_mutation_complete(
&self,
_generation: usize,
_duration: Duration,
_population_size: usize,
) {
}
fn on_fitness_evaluation_complete(
&self,
_generation: usize,
_duration: Duration,
_population_size: usize,
) {
}
fn on_survivor_selection_complete(
&self,
_generation: usize,
_duration: Duration,
_population_size: usize,
) {
log::debug!(target="ga_events", method="run"; "Survivors selected");
}
fn on_new_best(&self, _generation: usize, _best: &U) {
}
fn on_stagnation(&self, _generation: usize, _stagnation_count: usize) {
}
fn on_extension_triggered(&self, event: ExtensionEvent) {
log::info!(
target="extension_events",
method="run";
"Extension triggered: diversity={:.6} < threshold={:.6}",
event.diversity,
event.threshold
);
}
fn on_generation_end(&self, stats: &GenerationStats) {
log::debug!(target="ga_events", method="run"; "Best chromosome calculated - generation {}", stats.generation + 1);
if let Some(prob) = stats.dynamic_mutation_probability {
log::debug!(
target="ga_events",
method="run";
"Dynamic mutation: diversity={:.4}, probability={:.4}",
stats.diversity,
prob
);
}
}
fn on_run_end(&self, cause: TerminationCause, _all_stats: &[GenerationStats]) {
log::debug!(target="ga_events", method="limit_reached"; "Started limit reached method");
if matches!(cause, TerminationCause::FitnessTargetReached) {
log::trace!(target="ga_events", method="limit_reached"; "limit reached for fixed fitness");
}
log::debug!(target="ga_events", method="limit_reached"; "Limit reached method finished");
}
}
impl<U: ChromosomeT> IslandGaObserver<U> for LogObserver {
fn on_island_run_start(&self, _island_id: usize) {
log::info!(target: "island_events", "Island model GA started");
}
fn on_island_run_end(&self, _island_id: usize) {
log::info!(target: "island_events", "Island model GA ended");
}
fn on_island_generation_end(
&self,
_island_id: usize,
generation: usize,
stats: &GenerationStats,
) {
log::debug!(target: "island_events", "Best chromosome calculated - generation {}", generation + 1);
if let Some(prob) = stats.dynamic_mutation_probability {
log::debug!(
target: "island_events",
"Dynamic mutation: diversity={:.4}, probability={:.4}",
stats.diversity,
prob
);
}
}
fn on_migration_triggered(&self, generation: usize, migration_count: usize) {
log::debug!(target: "island_events", "Migration performed at generation {} (count={})", generation, migration_count);
}
}
impl<U: ChromosomeT> Nsga2Observer<U> for LogObserver {
fn on_pareto_front_assigned(
&self,
generation: usize,
front_count: usize,
population_size: usize,
) {
log::debug!(target: "nsga2_events", "Generation {} complete, population size = {}, fronts = {}", generation, population_size, front_count);
}
fn on_non_dominated_sort_complete(&self, generation: usize, duration_ms: f64) {
log::debug!(target: "nsga2_events", "Non-dominated sort complete at generation {} ({:.2}ms)", generation, duration_ms);
}
fn on_crowding_distance_calculated(&self, generation: usize, duration_ms: f64) {
log::debug!(target: "nsga2_events", "Crowding distance calculated at generation {} ({:.2}ms)", generation, duration_ms);
}
}
impl<U: ChromosomeT> Nsga3Observer<U> for LogObserver {
fn on_pareto_front_assigned(
&self,
generation: usize,
front_count: usize,
population_size: usize,
) {
log::debug!(target: "nsga3_events", "Generation {} complete, population size = {}, fronts = {}", generation, population_size, front_count);
}
fn on_non_dominated_sort_complete(&self, generation: usize, duration_ms: f64) {
log::debug!(target: "nsga3_events", "Non-dominated sort complete at generation {} ({:.2}ms)", generation, duration_ms);
}
}
impl<U: ChromosomeT> MoeaDObserver<U> for LogObserver {
fn on_pareto_front_assigned(
&self,
generation: usize,
front_count: usize,
population_size: usize,
) {
log::debug!(target: "moead_events",
"Generation {} complete, population size = {}, fronts = {}",
generation, population_size, front_count);
}
fn on_non_dominated_sort_complete(&self, generation: usize, duration_ms: f64) {
log::debug!(target: "moead_events",
"Non-dominated sort complete at generation {} ({:.2}ms)",
generation, duration_ms);
}
}
impl<U: ChromosomeT> Spea2Observer<U> for LogObserver {
fn on_fitness_assigned(
&self,
generation: usize,
duration_ms: f64,
pop_size: usize,
archive_size: usize,
) {
log::debug!(target: "spea2_events",
"Strength+density fitness assigned at generation {} ({:.2}ms) — pop={}, archive={}",
generation, duration_ms, pop_size, archive_size);
}
fn on_archive_updated(
&self,
generation: usize,
archive_size: usize,
non_dominated_count: usize,
) {
log::debug!(target: "spea2_events",
"Archive updated at generation {} — size={}, non-dominated={}",
generation, archive_size, non_dominated_count);
}
}
impl<U: ChromosomeT> SmsEmoaObserver<U> for LogObserver {
fn on_hypervolume_contribution_assigned(
&self,
generation: usize,
duration_ms: f64,
population_size: usize,
) {
log::debug!(target: "sms_emoa_events",
"Hypervolume contribution assigned at generation {} ({:.2}ms) — pop={}",
generation, duration_ms, population_size);
}
fn on_steady_state_removal(&self, generation: usize, population_size: usize) {
log::debug!(target: "sms_emoa_events",
"Steady-state removal at generation {} — pop={}",
generation, population_size);
}
}
impl<U: ChromosomeT> IbeaObserver<U> for LogObserver {
fn on_indicator_fitness_assigned(
&self,
generation: usize,
duration_ms: f64,
population_size: usize,
) {
log::debug!(target: "ibea_events",
"Indicator fitness assigned at generation {} ({:.2}ms) — pop={}",
generation, duration_ms, population_size);
}
fn on_environmental_selection(
&self,
generation: usize,
population_size: usize,
_removed_index: usize,
) {
log::debug!(target: "ibea_events",
"Environmental selection at generation {} — pop={}",
generation, population_size);
}
}