Skip to main content

radiate_engines/
context.rs

1use crate::{Chromosome, ThreadSync, events::EngineStateChange};
2use crate::{builder::config::EngineConfig, events::EventStream};
3use radiate_core::ExprSet;
4use radiate_core::error::RadiateResult;
5use radiate_core::{
6    Ecosystem, EngineState, Front, MetricSet, Objective, Phenotype, Problem, Score, metric,
7    metric_names,
8};
9use std::sync::{Arc, Mutex, RwLock};
10
11pub struct EvolutionContext<C: Chromosome, T> {
12    pub(crate) ecosystem: Ecosystem<C>,
13    pub(crate) best: T,
14    pub(crate) index: usize,
15    pub(crate) metrics: MetricSet,
16    pub(crate) objective: Objective,
17    pub(crate) sync: ThreadSync,
18    pub(crate) score: Option<Score>,
19    pub(crate) front: Arc<RwLock<Front<Phenotype<C>>>>,
20    pub(crate) problem: Arc<dyn Problem<C, T>>,
21    pub(crate) exprs: Option<Arc<Mutex<ExprSet>>>,
22    pub(crate) events: EventStream,
23    pub(crate) state: EngineState,
24}
25
26impl<C: Chromosome, T> EvolutionContext<C, T> {
27    pub fn index(&self) -> usize {
28        self.index
29    }
30
31    pub fn metrics(&self) -> &MetricSet {
32        &self.metrics
33    }
34
35    pub fn score(&self) -> Option<&Score> {
36        self.score.as_ref()
37    }
38
39    pub fn ecosystem(&self) -> &Ecosystem<C> {
40        &self.ecosystem
41    }
42
43    pub fn front(&self) -> Arc<RwLock<Front<Phenotype<C>>>> {
44        Arc::clone(&self.front)
45    }
46
47    pub fn event_stream(&self) -> &EventStream {
48        &self.events
49    }
50
51    pub fn wait(&self) {
52        self.sync.wait()
53    }
54
55    pub fn get_or_create_sync(&mut self) -> ThreadSync {
56        self.sync.clone()
57    }
58
59    pub fn request_stop(&self) {
60        self.sync.stop();
61    }
62
63    pub fn stop_requested(&self) -> bool {
64        self.sync.is_stopped()
65    }
66
67    pub fn pause_requested(&self) -> bool {
68        self.sync.is_paused()
69    }
70
71    pub fn state(&self) -> EngineState {
72        self.state
73    }
74
75    pub(crate) fn set_running(&mut self) {
76        self.change_state(EngineState::Running);
77    }
78
79    pub(crate) fn set_paused(&mut self) {
80        self.change_state(EngineState::Paused);
81    }
82
83    pub(crate) fn set_stopped(&mut self) {
84        self.change_state(EngineState::Stopped);
85    }
86
87    pub(crate) fn try_advance_one(&mut self) -> RadiateResult<bool> {
88        self.index += 1;
89
90        let best = self.ecosystem.get_phenotype(0);
91        let best_improved = self
92            .metrics
93            .improvements()
94            .map(|m| m.last_value() > 0.0)
95            .unwrap_or(false);
96
97        if best_improved && let Some(best) = best {
98            self.score = best.score().cloned();
99            self.best = self.problem.decode(best.genotype());
100        }
101
102        self.metrics
103            .replace(metric!(metric_names::INDEX, self.index));
104        self.metrics.bump(self.index);
105
106        Ok(best_improved)
107    }
108
109    fn change_state(&mut self, state: EngineState) {
110        if self.state == state {
111            return;
112        }
113
114        self.events.publish(EngineStateChange {
115            from: self.state,
116            to: state,
117            index: self.index,
118        });
119
120        self.state = state;
121    }
122}
123
124impl<C, T> From<EngineConfig<C, T>> for EvolutionContext<C, T>
125where
126    C: Chromosome + Clone,
127    T: Clone,
128{
129    fn from(config: EngineConfig<C, T>) -> Self {
130        if let Some(generation) = config.generation() {
131            return EvolutionContext {
132                ecosystem: generation.ecosystem().clone(),
133                best: generation.value().clone(),
134                index: generation.index(),
135                metrics: generation.metrics().clone(),
136                score: Some(generation.score().clone()),
137                front: config.front(),
138                objective: config.objective().clone(),
139                problem: config.problem().clone(),
140                sync: config.sync(),
141                exprs: generation.exprs(),
142                events: config.event_stream(),
143                state: EngineState::PreStart,
144            };
145        }
146
147        let initial_genotype = config
148            .ecosystem()
149            .get_genotype(0)
150            .map(|geno| config.problem().decode(geno));
151
152        EvolutionContext {
153            ecosystem: config.ecosystem().clone(),
154            best: initial_genotype.unwrap(),
155            index: 0,
156            metrics: MetricSet::default(),
157            score: None,
158            front: config.front(),
159            objective: config.objective().clone(),
160            problem: config.problem().clone(),
161            sync: config.sync(),
162            exprs: config.exprs(),
163            events: config.event_stream(),
164            state: EngineState::PreStart,
165        }
166    }
167}