1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//! Population-wide evaluation helper used by the population-based algorithms.
//!
//! Two cfg-gated implementations:
//!
//! - With the `parallel` feature: rayon's `into_par_iter` evaluates decisions
//! on the global thread pool. The result preserves input order so any
//! downstream sort/dominance/crowding decisions remain reproducible.
//! - Without the feature: plain serial `into_iter`.
//!
//! Both implementations require `P: Problem + Sync` and `P::Decision: Send`,
//! so each algorithm's `Optimizer<P>` impl carries the same bounds regardless
//! of feature state. This keeps the public `Problem` trait itself unchanged.
use crate::core::candidate::Candidate;
use crate::core::problem::Problem;
/// Evaluate every decision in `decisions` against `problem` and return the
/// resulting candidates in the same order.
#[cfg(feature = "parallel")]
pub(crate) fn evaluate_batch<P>(
problem: &P,
decisions: Vec<P::Decision>,
) -> Vec<Candidate<P::Decision>>
where
P: Problem + Sync,
P::Decision: Send,
{
use rayon::prelude::*;
decisions
.into_par_iter()
.map(|d| {
let e = problem.evaluate(&d);
Candidate::new(d, e)
})
.collect()
}
/// Serial fallback used when the `parallel` feature is disabled.
#[cfg(not(feature = "parallel"))]
pub(crate) fn evaluate_batch<P>(
problem: &P,
decisions: Vec<P::Decision>,
) -> Vec<Candidate<P::Decision>>
where
P: Problem + Sync,
P::Decision: Send,
{
decisions
.into_iter()
.map(|d| {
let e = problem.evaluate(&d);
Candidate::new(d, e)
})
.collect()
}