radiate_engines/steps/
evaluate.rs

1use radiate_core::{
2    Chromosome, Ecosystem, MetricSet, Objective, Problem, engine::EngineStep, metric_names,
3    thread_pool::ThreadPool,
4};
5use std::sync::Arc;
6
7pub trait Evaluator<C: Chromosome, T>: Send + Sync {
8    fn eval(
9        &self,
10        ecosystem: &mut Ecosystem<C>,
11        thread_pool: Arc<ThreadPool>,
12        problem: Arc<dyn Problem<C, T>>,
13    ) -> usize;
14}
15
16pub struct SequentialEvaluator;
17
18impl<C: Chromosome, T> Evaluator<C, T> for SequentialEvaluator
19where
20    C: Chromosome + 'static,
21{
22    fn eval(
23        &self,
24        ecosystem: &mut Ecosystem<C>,
25        _thread_pool: Arc<ThreadPool>,
26        problem: Arc<dyn Problem<C, T>>,
27    ) -> usize {
28        let mut count = 0;
29        for individual in ecosystem.population.iter_mut() {
30            if individual.score().is_some() {
31                continue;
32            } else {
33                let geno = individual.take_genotype();
34                let score = problem.eval(&geno);
35                individual.set_score(Some(score));
36                individual.set_genotype(geno);
37                count += 1;
38            }
39        }
40
41        count
42    }
43}
44
45pub struct WorkerPoolEvaluator;
46
47impl<C: Chromosome, T> Evaluator<C, T> for WorkerPoolEvaluator
48where
49    C: Chromosome + 'static,
50    T: Send + Sync + 'static,
51{
52    fn eval(
53        &self,
54        ecosystem: &mut Ecosystem<C>,
55        thread_pool: Arc<ThreadPool>,
56        problem: Arc<dyn Problem<C, T>>,
57    ) -> usize {
58        let mut jobs = Vec::new();
59        let len = ecosystem.population.len();
60        for idx in 0..len {
61            if ecosystem.population[idx].score().is_none() {
62                let geno = ecosystem.population[idx].take_genotype();
63                jobs.push((idx, geno));
64            }
65        }
66
67        let work_results = jobs
68            .into_iter()
69            .map(|(idx, geno)| {
70                let problem = Arc::clone(&problem);
71                thread_pool.submit_with_result(move || {
72                    let score = problem.eval(&geno);
73                    (idx, score, geno)
74                })
75            })
76            .collect::<Vec<_>>();
77
78        let count = work_results.len();
79        for work_result in work_results {
80            let (idx, score, genotype) = work_result.result();
81            ecosystem.population[idx].set_score(Some(score));
82            ecosystem.population[idx].set_genotype(genotype);
83        }
84
85        count
86    }
87}
88
89pub struct EvaluateStep<C: Chromosome, T> {
90    pub(crate) objective: Objective,
91    pub(crate) evaluator: Arc<dyn Evaluator<C, T>>,
92    pub(crate) problem: Arc<dyn Problem<C, T>>,
93    pub(crate) thread_pool: Arc<ThreadPool>,
94}
95
96impl<C: Chromosome, T> EvaluateStep<C, T> {
97    pub fn new(
98        objective: Objective,
99        thread_pool: Arc<ThreadPool>,
100        problem: Arc<dyn Problem<C, T>>,
101        evaluator: Arc<dyn Evaluator<C, T>>,
102    ) -> Self {
103        EvaluateStep {
104            objective,
105            evaluator,
106            problem,
107            thread_pool,
108        }
109    }
110}
111
112impl<C, T> EngineStep<C> for EvaluateStep<C, T>
113where
114    C: Chromosome + 'static,
115{
116    fn execute(&mut self, _: usize, metrics: &mut MetricSet, ecosystem: &mut Ecosystem<C>) {
117        let timer = std::time::Instant::now();
118
119        let count = self.evaluator.eval(
120            ecosystem,
121            Arc::clone(&self.thread_pool),
122            Arc::clone(&self.problem),
123        ) as f32;
124
125        self.objective.sort(&mut ecosystem.population);
126
127        metrics.upsert_operations(metric_names::FITNESS, count, timer.elapsed());
128    }
129}