Skip to content

Commit 2e2ef7e

Browse files
authored
Refactor algorithm macro to generate pub type aliases for algorithms (#262)
1 parent b48aac6 commit 2e2ef7e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+6823
-6654
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ fn main() -> Result<(), AlgorithmError> {
106106
.build()?;
107107

108108
algorithm.run()?;
109-
let population = algorithm.population()?;
109+
let population = algorithm.population?;
110110
println!("Done! Population size: {}", population.len());
111111

112112
Ok(())

moors/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ fn main() -> Result<(), AlgorithmError> {
7777
.build()?;
7878

7979
algorithm.run()?;
80-
let population = algorithm.population()?;
80+
let population = algorithm.population?;
8181
println!("Done! Population size: {}", population.len());
8282

8383
Ok(())

moors/benches/dtlz2.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use ndarray::{Array2, Axis, stack};
77

88
use moors::{
99
CloseDuplicatesCleaner, DanAndDenisReferencePoints, GaussianMutation, Nsga3Builder,
10-
Nsga3ReferencePoints, Nsga3ReferencePointsSurvival, RandomSamplingFloat,
11-
SimulatedBinaryCrossover, StructuredReferencePoints, impl_constraints_fn,
10+
Nsga3ReferencePointsSurvival, RandomSamplingFloat, SimulatedBinaryCrossover,
11+
StructuredReferencePoints, impl_constraints_fn,
1212
};
1313

1414
/// DTLZ2 for 3 objectives (m = 3) with k = 0 (so num_vars = m−1 = 2):
@@ -34,8 +34,7 @@ fn fitness_dtlz2_3obj(pop: &Array2<f64>) -> Array2<f64> {
3434

3535
fn bench_nsga3_dtlz2(c: &mut Criterion) {
3636
// 1) prepare 3-objective reference points once
37-
let base_rp = DanAndDenisReferencePoints::new(1000, 3).generate();
38-
let nsga3_rp = Nsga3ReferencePoints::new(base_rp, false);
37+
let rp = DanAndDenisReferencePoints::new(1000, 3).generate();
3938
impl_constraints_fn!(MyConstr, lower_bound = 0.0, upper_bound = 1.0);
4039

4140
c.bench_function("nsga3_dtlz2_3obj", |b| {
@@ -45,7 +44,8 @@ fn bench_nsga3_dtlz2(c: &mut Criterion) {
4544
.sampler(RandomSamplingFloat::new(0.0, 1.0))
4645
.crossover(SimulatedBinaryCrossover::new(20.0))
4746
.mutation(GaussianMutation::new(0.05, 0.1))
48-
.survivor(Nsga3ReferencePointsSurvival::new(nsga3_rp.clone()))
47+
.reference_points(rp.clone())
48+
.are_aspirational(false)
4949
.duplicates_cleaner(CloseDuplicatesCleaner::new(1e-6))
5050
.fitness_fn(fitness_dtlz2_3obj)
5151
.constraints_fn(MyConstr)
@@ -63,7 +63,7 @@ fn bench_nsga3_dtlz2(c: &mut Criterion) {
6363

6464
algorithm.run().expect("NSGA3 run failed");
6565
// prevent optimizer from eliding the result
66-
black_box(algorithm.population().expect("Population getter failed"));
66+
black_box(algorithm.population.expect("Population getter failed"));
6767
})
6868
});
6969
}

moors/benches/zdt1.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ fn bench_nsga2_zdt1(c: &mut Criterion) {
4848

4949
algorithm.run().expect("NSGA2 run failed");
5050
// prevent the optimizer from eliding the result
51-
black_box(algorithm.population().expect("Population getter failed"));
51+
black_box(algorithm.population.expect("Population getter failed"));
5252
})
5353
});
5454
}

moors/src/algorithms/builder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ pub struct GeneticAlgorithmParams<
8989
num_vars: usize,
9090
population_size: usize,
9191
num_offsprings: usize,
92+
#[builder(field(vis = "pub"))]
9293
num_iterations: usize,
9394
#[builder(default = "0.2")]
9495
mutation_rate: f64,

moors/src/algorithms/macros.rs

Lines changed: 200 additions & 110 deletions
Large diffs are not rendered by default.
Lines changed: 4 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use crate::{
2-
create_algorithm, selection::moo::RankAndScoringSelection, survival::moo::AgeMoeaSurvival,
2+
define_algorithm_and_builder, selection::moo::AgeMoeaRankCrowdingSelection,
3+
survival::moo::AgeMoeaSurvival,
34
};
45

5-
create_algorithm!(
6+
define_algorithm_and_builder!(
67
/// AGE-MOEA algorithm wrapper.
78
///
89
/// This struct is a thin facade over [`GeneticAlgorithm`] preset with
@@ -23,36 +24,6 @@ create_algorithm!(
2324
/// pp. 595–603, July 2019.
2425
/// DOI: 10.1145/3321707.3321839
2526
AgeMoea,
26-
RankAndScoringSelection,
27+
AgeMoeaRankCrowdingSelection,
2728
AgeMoeaSurvival
2829
);
29-
30-
impl<S, Cross, Mut, F, G, DC> Default for AgeMoeaBuilder<S, Cross, Mut, F, G, DC>
31-
where
32-
S: SamplingOperator,
33-
Cross: CrossoverOperator,
34-
Mut: MutationOperator,
35-
F: FitnessFn<Dim = ndarray::Ix2>,
36-
G: ConstraintsFn,
37-
DC: PopulationCleaner,
38-
AlgorithmBuilder<S, RankAndScoringSelection, AgeMoeaSurvival, Cross, Mut, F, G, DC>: Default,
39-
{
40-
fn default() -> Self {
41-
let mut inner: AlgorithmBuilder<
42-
S,
43-
RankAndScoringSelection,
44-
AgeMoeaSurvival,
45-
Cross,
46-
Mut,
47-
F,
48-
G,
49-
DC,
50-
> = Default::default();
51-
inner = inner
52-
.selector(RankAndScoringSelection::default())
53-
.survivor(AgeMoeaSurvival);
54-
AgeMoeaBuilder {
55-
inner_builder: inner,
56-
}
57-
}
58-
}

moors/src/algorithms/moo/ibea.rs

Lines changed: 10 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@
1717
//!
1818
//! The default configuration keeps a single population (no external archive).
1919
20+
use ndarray::Array1;
21+
2022
use crate::{
21-
create_algorithm,
22-
selection::moo::RankAndScoringSelection,
23-
survival::moo::{IbeaHyperVolumeSurvivalOperator, SurvivalScoringComparison},
23+
define_algorithm_and_builder,
24+
operators::{
25+
selection::moo::IbeaScoringSelection, survival::moo::IbeaHyperVolumeSurvivalOperator,
26+
},
2427
};
2528

26-
create_algorithm!(
29+
define_algorithm_and_builder!(
2730
/// IBEA algorithm wrapper.
2831
///
2932
/// Thin façade over [`GeneticAlgorithm`] preset with IBEA’s selection/survival strategy.
@@ -39,48 +42,7 @@ create_algorithm!(
3942
/// Zitzler & Künzli (2004), *Indicator-Based Evolutionary Algorithm for Multiobjective Optimization*,
4043
/// EMO 2004, LNCS 3248, Springer.
4144
Ibea,
42-
RankAndScoringSelection,
43-
IbeaHyperVolumeSurvivalOperator
45+
IbeaScoringSelection,
46+
IbeaHyperVolumeSurvivalOperator,
47+
survival_args = [reference: Array1<f64>, kappa: f64],
4448
);
45-
46-
impl<S, Cross, Mut, F, G, DC> Default for IbeaBuilder<S, Cross, Mut, F, G, DC>
47-
where
48-
S: SamplingOperator,
49-
Cross: CrossoverOperator,
50-
Mut: MutationOperator,
51-
F: FitnessFn<Dim = ndarray::Ix2>,
52-
G: ConstraintsFn,
53-
DC: PopulationCleaner,
54-
AlgorithmBuilder<
55-
S,
56-
RankAndScoringSelection,
57-
IbeaHyperVolumeSurvivalOperator,
58-
Cross,
59-
Mut,
60-
F,
61-
G,
62-
DC,
63-
>: Default,
64-
{
65-
fn default() -> Self {
66-
let mut inner: AlgorithmBuilder<
67-
S,
68-
RankAndScoringSelection,
69-
IbeaHyperVolumeSurvivalOperator,
70-
Cross,
71-
Mut,
72-
F,
73-
G,
74-
DC,
75-
> = Default::default();
76-
77-
// Selector operator uses scoring survival given by the raw fitness but it doesn't use rank
78-
let selector =
79-
RankAndScoringSelection::new(false, true, SurvivalScoringComparison::Maximize);
80-
81-
inner = inner.selector(selector);
82-
IbeaBuilder {
83-
inner_builder: inner,
84-
}
85-
}
86-
}

moors/src/algorithms/moo/mod.rs

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -54,36 +54,10 @@
5454
//! .build()?; // ← macro‑generated .build()
5555
//!
5656
//! algorithm.run()?;
57-
//! println!("Done – final pop: {}", algorithm.population()?.len());
57+
//! println!("Done – final pop: {}", algorithm.population?.len());
5858
//! Ok(())
5959
//! }
6060
//! ```
61-
//!
62-
//! ### Writing your **own** algorithm
63-
//!
64-
//! 1. **Pick / implement** a [`SelectionOperator`] and a [`SurvivalOperator`].
65-
//! 2. Use them with helper macro `create_algorithm!`:
66-
//!
67-
//! ```rust, ignore
68-
//! create_algorithm!(MyNewAlgorithm, NewSelector, NewSurvival);
69-
//! ```
70-
//!
71-
//! From there, a new algorithm struct will be created
72-
//! ```rust, ignore
73-
//! pub struct MyAlgo<S, Cross, Mut, F, G, DC> {
74-
//! inner: GeneticAlgorithm<S, NewSelector, NewSurvival, Cross, Mut, F, G, DC>
75-
//! }
76-
//! ```
77-
//! Also, the its respective builder is availble `MyAlgoBuilder`
78-
//!
79-
//! ## GeneticAlgorithm – generic core
80-
//!
81-
//! The struct [`GeneticAlgorithm`] is **not** intended to be used
82-
//! directly by most users; it’s the reusable engine that handles initial
83-
//! sampling, iterative evolution, evaluation and survivor selection. Concrete
84-
//! algorithms customise its behaviour exclusively through trait objects, so
85-
//! they stay **zero‑cost abstractions** once monomorphised.
86-
8761
//! ---
8862
//!
8963
//! *Evolution is a mystery* Feel free to open an issue or PR if you implement a new

moors/src/algorithms/moo/nsga2.rs

Lines changed: 6 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@
2121
//! you need custom behaviour.
2222
2323
use crate::{
24-
create_algorithm, selection::moo::RankAndScoringSelection,
25-
survival::moo::Nsga2RankCrowdingSurvival,
24+
define_algorithm_and_builder,
25+
operators::{
26+
selection::moo::Nsga2RankAndScoringSelection, survival::moo::Nsga2RankCrowdingSurvival,
27+
},
2628
};
2729

28-
create_algorithm!(
30+
define_algorithm_and_builder!(
2931
/// NSGA-II algorithm wrapper.
3032
///
3133
/// This struct is a thin facade over [`GeneticAlgorithm`] preset with
@@ -46,37 +48,6 @@ create_algorithm!(
4648
/// pp. 182–197, Apr. 2002.
4749
/// DOI: 10.1109/4235.996017
4850
Nsga2,
49-
RankAndScoringSelection,
51+
Nsga2RankAndScoringSelection,
5052
Nsga2RankCrowdingSurvival
5153
);
52-
53-
impl<S, Cross, Mut, F, G, DC> Default for Nsga2Builder<S, Cross, Mut, F, G, DC>
54-
where
55-
S: SamplingOperator,
56-
Cross: CrossoverOperator,
57-
Mut: MutationOperator,
58-
F: FitnessFn<Dim = ndarray::Ix2>,
59-
G: ConstraintsFn,
60-
DC: PopulationCleaner,
61-
AlgorithmBuilder<S, RankAndScoringSelection, Nsga2RankCrowdingSurvival, Cross, Mut, F, G, DC>:
62-
Default,
63-
{
64-
fn default() -> Self {
65-
let mut inner: AlgorithmBuilder<
66-
S,
67-
RankAndScoringSelection,
68-
Nsga2RankCrowdingSurvival,
69-
Cross,
70-
Mut,
71-
F,
72-
G,
73-
DC,
74-
> = Default::default();
75-
inner = inner
76-
.selector(RankAndScoringSelection::default())
77-
.survivor(Nsga2RankCrowdingSurvival);
78-
Nsga2Builder {
79-
inner_builder: inner,
80-
}
81-
}
82-
}

0 commit comments

Comments
 (0)