Skip to content

Commit 09928b8

Browse files
WIP: Commit progress on rosomaxa crate
1 parent 379dfaa commit 09928b8

File tree

14 files changed

+289
-155
lines changed

14 files changed

+289
-155
lines changed

rosomaxa/src/evolution/config.rs

Lines changed: 57 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
use crate::evolution::*;
22
use crate::hyper::*;
3-
use crate::population::*;
43
use crate::termination::*;
5-
use crate::utils::TimeQuota;
64
use std::hash::Hash;
75
use std::sync::Arc;
86

@@ -19,12 +17,12 @@ where
1917
/// A pre/post processing config.
2018
pub processing: ProcessingConfig<C, O, S>,
2119

20+
/// A heuristic context.
21+
pub context: C,
22+
2223
/// A hyper heuristic.
2324
pub heuristic: Box<dyn HyperHeuristic<Context = C, Objective = O, Solution = S>>,
2425

25-
/// Population algorithm.
26-
pub population: Box<dyn HeuristicPopulation<Objective = O, Individual = S>>,
27-
2826
/// An evolution strategy.
2927
pub strategy: Box<dyn EvolutionStrategy<Context = C, Objective = O, Solution = S>>,
3028

@@ -33,9 +31,6 @@ where
3331

3432
/// A telemetry to be used.
3533
pub telemetry: Telemetry<C, O, S>,
36-
37-
/// An environmental context.
38-
pub environment: Arc<Environment>,
3934
}
4035

4136
/// Specifies an operator which builds initial solution.
@@ -97,7 +92,7 @@ where
9792
max_time: Option<usize>,
9893
min_cv: Option<(String, usize, f64, bool, K)>,
9994
heuristic: Option<Box<dyn HyperHeuristic<Context = C, Objective = O, Solution = S>>>,
100-
population: Option<Box<dyn HeuristicPopulation<Objective = O, Individual = S>>>,
95+
context: Option<C>,
10196
termination: Option<Box<dyn Termination<Context = C, Objective = O>>>,
10297
strategy: Option<Box<dyn EvolutionStrategy<Context = C, Objective = O, Solution = S>>>,
10398

@@ -107,7 +102,6 @@ where
107102
objective: Option<Arc<dyn HeuristicObjective<Solution = S>>>,
108103

109104
telemetry: Option<Telemetry<C, O, S>>,
110-
environment: Option<Arc<Environment>>,
111105

112106
initial: InitialConfig<C, O, S>,
113107
processing: ProcessingConfig<C, O, S>,
@@ -126,14 +120,13 @@ where
126120
max_time: None,
127121
min_cv: None,
128122
heuristic: None,
129-
population: None,
123+
context: None,
130124
termination: None,
131125
strategy: None,
132126
heuristic_operators: None,
133127
heuristic_group: None,
134128
objective: None,
135129
telemetry: None,
136-
environment: None,
137130
initial: InitialConfig { operators: vec![], max_size: 4, quota: 0.05, individuals: vec![] },
138131
processing: ProcessingConfig { context: vec![], solution: vec![] },
139132
}
@@ -147,12 +140,6 @@ where
147140
S: HeuristicSolution + 'static,
148141
K: Hash + Eq + Clone + Send + Sync + 'static,
149142
{
150-
/// Sets environment.
151-
pub fn with_environment(mut self, environment: Arc<Environment>) -> Self {
152-
self.environment = Some(environment);
153-
self
154-
}
155-
156143
/// Sets max generations to be run by evolution. Default is 3000.
157144
pub fn with_max_generations(mut self, limit: Option<usize>) -> Self {
158145
self.max_generations = limit;
@@ -202,9 +189,9 @@ where
202189
self
203190
}
204191

205-
/// Sets population algorithm. Default is rosomaxa.
206-
pub fn with_population(mut self, population: Box<dyn HeuristicPopulation<Objective = O, Individual = S>>) -> Self {
207-
self.population = Some(population);
192+
/// Sets heuristic context.
193+
pub fn with_context(mut self, context: C) -> Self {
194+
self.context = Some(context);
208195
self
209196
}
210197

@@ -252,78 +239,65 @@ where
252239

253240
/// Gets termination criterias.
254241
#[allow(clippy::type_complexity)]
255-
fn get_termination(
256-
&self,
257-
) -> Result<
258-
(Box<dyn Termination<Context = C, Objective = O> + Send + Sync>, Option<Arc<dyn Quota + Send + Sync>>),
259-
String,
260-
> {
242+
fn get_termination(&self) -> Result<Box<dyn Termination<Context = C, Objective = O> + Send + Sync>, String> {
261243
let telemetry = Telemetry::new(TelemetryMode::None);
262244
let telemetry = self.telemetry.as_ref().unwrap_or(&telemetry);
263245

264-
let (terminations, quota): (
265-
Vec<Box<dyn Termination<Context = C, Objective = O> + Send + Sync>>,
266-
Option<Arc<dyn Quota + Send + Sync>>,
267-
) = match (self.max_generations, self.max_time, &self.min_cv) {
268-
(None, None, None) => {
269-
telemetry.log("configured to use default max-generations (3000) and max-time (300secs)");
270-
(
271-
vec![Box::new(MaxGeneration::new(3000)), Box::new(MaxTime::new(300.))],
272-
Some(Arc::new(TimeQuota::new(300.))),
273-
)
274-
}
275-
_ => {
276-
let mut terminations: Vec<Box<dyn Termination<Context = C, Objective = O> + Send + Sync>> = vec![];
277-
278-
if let Some(limit) = self.max_generations {
279-
telemetry.log(format!("configured to use max-generations: {}", limit).as_str());
280-
terminations.push(Box::new(MaxGeneration::new(limit)))
246+
let terminations: Vec<Box<dyn Termination<Context = C, Objective = O> + Send + Sync>> =
247+
match (self.max_generations, self.max_time, &self.min_cv) {
248+
(None, None, None) => {
249+
telemetry.log("configured to use default max-generations (3000) and max-time (300secs)");
250+
vec![Box::new(MaxGeneration::new(3000)), Box::new(MaxTime::new(300.))]
281251
}
282-
283-
let quota: Option<Arc<dyn Quota + Send + Sync>> = if let Some(limit) = self.max_time {
284-
telemetry.log(format!("configured to use max-time: {}s", limit).as_str());
285-
terminations.push(Box::new(MaxTime::new(limit as f64)));
286-
Some(Arc::new(TimeQuota::new(limit as f64)))
287-
} else {
288-
None
289-
};
290-
291-
if let Some((interval_type, value, threshold, is_global, key)) = self.min_cv.clone() {
292-
telemetry.log(
293-
format!(
294-
"configured to use variation coefficient {} with sample: {}, threshold: {}",
295-
interval_type, value, threshold
296-
)
297-
.as_str(),
298-
);
299-
300-
let variation: Box<dyn Termination<Context = C, Objective = O> + Send + Sync> =
301-
match interval_type.as_str() {
302-
"sample" => {
303-
Box::new(MinVariation::<C, O, S, K>::new_with_sample(value, threshold, is_global, key))
304-
}
305-
"period" => {
306-
Box::new(MinVariation::<C, O, S, K>::new_with_period(value, threshold, is_global, key))
307-
}
308-
_ => return Err(format!("unknown variation interval type: {}", interval_type)),
309-
};
310-
311-
terminations.push(variation)
252+
_ => {
253+
let mut terminations: Vec<Box<dyn Termination<Context = C, Objective = O> + Send + Sync>> = vec![];
254+
255+
if let Some(limit) = self.max_generations {
256+
telemetry.log(format!("configured to use max-generations: {}", limit).as_str());
257+
terminations.push(Box::new(MaxGeneration::new(limit)))
258+
}
259+
260+
if let Some(limit) = self.max_time {
261+
telemetry.log(format!("configured to use max-time: {}s", limit).as_str());
262+
terminations.push(Box::new(MaxTime::new(limit as f64)));
263+
}
264+
265+
if let Some((interval_type, value, threshold, is_global, key)) = self.min_cv.clone() {
266+
telemetry.log(
267+
format!(
268+
"configured to use variation coefficient {} with sample: {}, threshold: {}",
269+
interval_type, value, threshold
270+
)
271+
.as_str(),
272+
);
273+
274+
let variation: Box<dyn Termination<Context = C, Objective = O> + Send + Sync> =
275+
match interval_type.as_str() {
276+
"sample" => Box::new(MinVariation::<C, O, S, K>::new_with_sample(
277+
value, threshold, is_global, key,
278+
)),
279+
"period" => Box::new(MinVariation::<C, O, S, K>::new_with_period(
280+
value, threshold, is_global, key,
281+
)),
282+
_ => return Err(format!("unknown variation interval type: {}", interval_type)),
283+
};
284+
285+
terminations.push(variation)
286+
}
287+
288+
terminations
312289
}
290+
};
313291

314-
(terminations, quota)
315-
}
316-
};
317-
318-
Ok((Box::new(CompositeTermination::new(terminations)), quota))
292+
Ok(Box::new(CompositeTermination::new(terminations)))
319293
}
320294

321295
/// Builds the evolution config.
322296
pub fn build(self) -> Result<EvolutionConfig<C, O, S>, String> {
323-
let (termination, quota) = self.get_termination()?;
297+
let termination = self.get_termination()?;
324298

299+
let context = self.context.ok_or_else(|| "missing heuristic context".to_string())?;
325300
let telemetry = self.telemetry.unwrap_or_else(|| Telemetry::new(TelemetryMode::None));
326-
let environment = self.environment.unwrap_or_else(|| Arc::new(Environment { quota, ..Environment::default() }));
327301

328302
Ok(EvolutionConfig {
329303
initial: self.initial,
@@ -335,19 +309,14 @@ where
335309
Box::new(DynamicSelective::new(
336310
self.heuristic_operators
337311
.ok_or_else(|| "missing heuristic operators or heuristic".to_string())?,
338-
environment.random.clone(),
312+
context.environment().random.clone(),
339313
)),
340314
Box::new(StaticSelective::new(
341315
self.heuristic_group.ok_or_else(|| "missing heuristic group or heuristic".to_string())?,
342316
)),
343317
))
344318
},
345-
population: if let Some(population) = self.population {
346-
telemetry.log("configured to use custom population");
347-
population
348-
} else {
349-
return Err("missing heuristic population".to_string());
350-
},
319+
context,
351320
strategy: if let Some(strategy) = self.strategy {
352321
telemetry.log("configured to use custom strategy");
353322
strategy
@@ -357,7 +326,6 @@ where
357326
termination,
358327
processing: self.processing,
359328
telemetry,
360-
environment,
361329
})
362330
}
363331
}

rosomaxa/src/evolution/simulator.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,28 @@ use std::marker::PhantomData;
55
use std::sync::Arc;
66

77
/// An entity which simulates evolution process.
8-
pub struct EvolutionSimulator<C, O, S, F>
8+
pub struct EvolutionSimulator<C, O, S>
99
where
1010
C: HeuristicContext<Objective = O, Solution = S>,
1111
O: HeuristicObjective<Solution = S>,
1212
S: HeuristicSolution,
13-
F: FnOnce(Box<dyn HeuristicPopulation<Objective = O, Individual = S>>) -> C,
1413
{
1514
config: EvolutionConfig<C, O, S>,
16-
context_factory: F,
1715
}
1816

19-
impl<C, O, S, F> EvolutionSimulator<C, O, S, F>
17+
impl<C, O, S> EvolutionSimulator<C, O, S>
2018
where
2119
C: HeuristicContext<Objective = O, Solution = S>,
2220
O: HeuristicObjective<Solution = S>,
2321
S: HeuristicSolution,
24-
F: FnOnce(Box<dyn HeuristicPopulation<Objective = O, Individual = S>>) -> C,
2522
{
2623
/// Creates a new instance of `EvolutionSimulator`.
27-
pub fn new(config: EvolutionConfig<C, O, S>, context_factory: F) -> Result<Self, String> {
24+
pub fn new(config: EvolutionConfig<C, O, S>) -> Result<Self, String> {
2825
if config.initial.operators.is_empty() {
2926
return Err("at least one initial method has to be specified".to_string());
3027
}
3128

32-
Ok(Self { config, context_factory })
29+
Ok(Self { config })
3330
}
3431

3532
/// Runs evolution for given `problem` using evolution `config`.
@@ -44,17 +41,18 @@ where
4441
.zip(0_usize..)
4542
.take(config.initial.max_size)
4643
.for_each(|(solution, idx)| {
47-
if should_add_solution(&config.environment.quota, config.population.as_ref()) {
44+
if should_add_solution(&config.context.environment().quota, config.context.population()) {
4845
config.telemetry.on_initial(&solution, idx, config.initial.max_size, Timer::start());
49-
config.population.add(solution);
46+
config.context.population_mut().add(solution);
5047
} else {
5148
config.telemetry.log(format!("skipping provided initial solution {}", idx).as_str())
5249
}
5350
});
5451

5552
let hooks = config.processing;
53+
let random = config.context.environment().random.clone();
5654

57-
let heuristic_ctx = (self.context_factory)(config.population);
55+
let heuristic_ctx = config.context;
5856
let mut heuristic_ctx = hooks.context.iter().fold(heuristic_ctx, |ctx, hook| hook.pre_process(ctx));
5957

6058
let weights = config.initial.operators.iter().map(|(_, weight)| *weight).collect::<Vec<_>>();
@@ -80,7 +78,7 @@ where
8078
let operator_idx = if idx < config.initial.operators.len() {
8179
idx
8280
} else {
83-
config.environment.random.weighted(weights.as_slice())
81+
random.weighted(weights.as_slice())
8482
};
8583

8684
// TODO consider initial quota limit

0 commit comments

Comments
 (0)