Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do some renaming and refactors #158

Merged
merged 6 commits into from
Apr 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ version = "0.1.0"
anyhow = "1.0.51"
ciborium = "0.2.0"
coco-rs = "0.5"
derive_deref = "1.1.1"
derive_more = { version = "0.99.17", features = ["deref", "deref_mut"]}
embed-doc-image = "0.1.4"
erased-serde = "0.3.16"
float_eq = "0.7.0"
Expand Down
4 changes: 2 additions & 2 deletions docs/framework.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ Configuration::builder()
Every component has to implement the [Component](components::Component) trait, which looks like this:
```ignore
pub trait Component<P: Problem>: AnyComponent {
fn execute(&self, problem: &P, state: &mut State);
fn execute(&self, problem: &P, state: &mut State<P>);

fn initialize(&self, problem: &P, state: &mut State) { ... }
fn initialize(&self, problem: &P, state: &mut State<P>) { ... }
}
```

Expand Down
4 changes: 2 additions & 2 deletions docs/state.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ You would start by defining the state like this:

```rust
use mahf::framework::state::CustomState;
use mahf::derive_deref::{Deref, DerefMut};
use mahf::derive_more::{Deref, DerefMut};
use mahf::serde::Serialize;

#[derive(Default, Debug, Deref, DerefMut, Serialize)]
Expand All @@ -32,7 +32,7 @@ Now you can use it in your component:

The [CustomState] trait serves as a marker for custom state.
You can take a look at its documentation to get a list off all state types provided by MAHF.
If you have custom state representing a single value, it is recommended to also derive [Deref](derive_deref::Deref), [DerefMut](derive_deref::DerefMut) and [serde::Serialize].
If you have custom state representing a single value, it is recommended to also derive [Deref](derive_more::Deref), [DerefMut](derive_more::DerefMut) and [serde::Serialize].

## Mutable Access

Expand Down
35 changes: 16 additions & 19 deletions examples/bmf.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,29 @@
use mahf::framework::Random;
use mahf::prelude::*;
use problems::bmf::BenchmarkFunction;

type P = problems::bmf::BenchmarkFunction;

fn main() -> anyhow::Result<()> {
let problem = P::sphere(10);
let config = pso::real_pso(
fn main() {
// Specify the problem: Sphere function with 10 dimensions.
let problem: BenchmarkFunction = BenchmarkFunction::sphere(/*dim: */ 10);
// Specify the metaheuristic: Particle Swarm Optimization (pre-implemented in MAHF).
let config: Configuration<BenchmarkFunction> = pso::real_pso(
/*params: */
pso::RealProblemParameters {
num_particles: 100,
num_particles: 20,
weight: 1.0,
c_one: 1.0,
c_two: 1.0,
v_max: 1.0,
},
termination::FixedIterations::new(500),
/*termination: */
termination::FixedIterations::new(/*max_iterations: */ 500)
& termination::DistanceToOpt::new(0.01),
);

let state = config.optimize_with(&problem, |state| state.insert(Random::seeded(0)));
// Execute the metaheuristic on the problem with a random seed.
let state: State<BenchmarkFunction> = config.optimize(&problem);

println!(
"Found Fitness: {:?}",
state.best_objective_value::<P>().unwrap()
);
println!(
"Found Individual: {:?}",
state.best_individual::<P>().unwrap(),
);
// Print the results.
println!("Found Individual: {:?}", state.best_individual().unwrap());
println!("This took {} iterations.", state.iterations());
println!("Global Optimum: {}", problem.known_optimum());

Ok(())
}
2 changes: 1 addition & 1 deletion examples/coco.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ fn main() -> anyhow::Result<()> {
.with_common_extractors(trigger::Iteration::new(10))
.with(
trigger::Change::<common::Progress>::new(0.1),
functions::auto::<common::Progress>,
functions::auto::<common::Progress, _>,
)
.with(
trigger::Iteration::new(50),
Expand Down
57 changes: 37 additions & 20 deletions examples/tsp.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,43 @@
use aco::ant_ops;
use mahf::prelude::*;
use problems::tsp::{self, SymmetricTsp};
use tracking::{files, functions, trigger};

type P = problems::tsp::SymmetricTsp;

fn main() -> anyhow::Result<()> {
let problem = problems::tsp::Instances::BERLIN52.load();

let config = ils::permutation_iterated_local_search(
ils::PermutationProblemParameters {
local_search_params: ls::PermutationProblemParameters {
n_neighbors: 100,
n_swap: 10,
fn main() {
// Specify the problem: TSPLIB instance Berlin52.
let problem: SymmetricTsp = tsp::Instances::BERLIN52.load();
// Specify the metaheuristic: Ant System.
let config: Configuration<SymmetricTsp> = Configuration::builder()
.do_(initialization::Empty::new())
.while_(
termination::FixedEvaluations::new(/*max_evaluations: */ 10_000),
|builder| {
builder
.do_(ant_ops::AcoGeneration::new(
/*num_ants: */ 20, /*alpha: */ 2.0, /*beta: */ 1.0,
/*initial_pheromones: */ 0.0,
))
.evaluate()
.update_best_individual()
.do_(ant_ops::AsPheromoneUpdate::new(
/*evaporation: */ 0.2, /*decay_coefficient: */ 1.0,
))
.do_(tracking::Logger::new())
},
local_search_termination: termination::FixedIterations::new(100),
},
termination::FixedIterations::new(10),
)
.into_builder()
.assert(|state| state.population_stack::<P>().current().len() == 1)
.single_objective_summary()
.build();
)
.build();

config.optimize(&problem);
// Execute the metaheuristic on the problem.
let state: State<SymmetricTsp> = config.optimize_with(&problem, |state| {
// Set the seed to 42.
state.insert(Random::seeded(42));
// Log the best individual every 50 iterations.
state.insert(
tracking::LogSet::<SymmetricTsp>::new()
.with(trigger::Iteration::new(50), functions::best_individual),
);
});

Ok(())
// Save the log to file "aco_berlin52.log".
files::write_log_file("aco_berlin52.log", state.log()).unwrap();
}
18 changes: 8 additions & 10 deletions src/components/constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::{
///
/// Types implementing this trait can implement [Component] by wrapping the type in a [BoundaryConstrainer].
pub trait BoundaryConstraint<P: Problem> {
fn constrain(&self, solution: &mut P::Encoding, problem: &P, state: &mut State);
fn constrain(&self, solution: &mut P::Encoding, problem: &P, state: &mut State<P>);
}

#[derive(serde::Serialize, Clone)]
Expand All @@ -24,14 +24,12 @@ where
P: Problem,
T: AnyComponent + BoundaryConstraint<P> + Serialize + Clone,
{
fn execute(&self, problem: &P, state: &mut State) {
let mut population = state.population_stack_mut::<P>().pop();

fn execute(&self, problem: &P, state: &mut State<P>) {
let mut population = state.populations_mut().pop();
for individual in population.iter_mut() {
self.0.constrain(individual.solution_mut(), problem, state);
}

state.population_stack_mut().push(population);
state.populations_mut().push(population);
}
}

Expand All @@ -47,7 +45,7 @@ impl Saturation {
impl<P: Problem<Encoding = Vec<f64>> + VectorProblem<T = f64> + LimitedVectorProblem>
BoundaryConstraint<P> for Saturation
{
fn constrain(&self, solution: &mut Vec<f64>, problem: &P, _state: &mut State) {
fn constrain(&self, solution: &mut Vec<f64>, problem: &P, _state: &mut State<P>) {
for (d, x) in solution.iter_mut().enumerate() {
let range = problem.range(d);
*x = x.clamp(range.start, range.end);
Expand All @@ -68,7 +66,7 @@ impl Toroidal {
impl<P: Problem<Encoding = Vec<f64>> + VectorProblem<T = f64> + LimitedVectorProblem>
BoundaryConstraint<P> for Toroidal
{
fn constrain(&self, solution: &mut Vec<f64>, problem: &P, _state: &mut State) {
fn constrain(&self, solution: &mut Vec<f64>, problem: &P, _state: &mut State<P>) {
for (d, x) in solution.iter_mut().enumerate() {
let range = problem.range(d);
let a = range.start;
Expand Down Expand Up @@ -97,7 +95,7 @@ impl Mirror {
impl<P: Problem<Encoding = Vec<f64>> + VectorProblem<T = f64> + LimitedVectorProblem>
BoundaryConstraint<P> for Mirror
{
fn constrain(&self, solution: &mut Vec<f64>, problem: &P, _state: &mut State) {
fn constrain(&self, solution: &mut Vec<f64>, problem: &P, _state: &mut State<P>) {
for (d, x) in solution.iter_mut().enumerate() {
let range = problem.range(d);
let a = range.start;
Expand Down Expand Up @@ -133,7 +131,7 @@ impl CompleteOneTailedNormalCorrection {
impl<P: Problem<Encoding = Vec<f64>> + VectorProblem<T = f64> + LimitedVectorProblem>
BoundaryConstraint<P> for CompleteOneTailedNormalCorrection
{
fn constrain(&self, solution: &mut Vec<f64>, problem: &P, state: &mut State) {
fn constrain(&self, solution: &mut Vec<f64>, problem: &P, state: &mut State<P>) {
for (d, x) in solution.iter_mut().enumerate() {
let range = problem.range(d);
let a = range.start;
Expand Down
26 changes: 13 additions & 13 deletions src/components/evaluation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::{
///
/// This component should be inserted after every generating component.
///
/// Only the head of the [common::Population] will be evaluated.
/// Only the head of the [common::Populations] will be evaluated.
/// Requires either [common::EvaluatorInstance] to be present
/// in the [State] or [Problem::default_evaluator] to be implemented.
///
Expand All @@ -28,25 +28,25 @@ impl Evaluator {
}

impl<P: Problem> Component<P> for Evaluator {
fn initialize(&self, problem: &P, state: &mut State) {
state.require::<common::Population<P>>();
fn initialize(&self, problem: &P, state: &mut State<P>) {
state.require::<Self, common::Populations<P>>();
state.insert(common::Evaluations(0));

if !state.has::<common::EvaluatorInstance<P>>() {
state.insert(problem.default_evaluator());
}
}

fn execute(&self, problem: &P, state: &mut State) {
if let Some(mut population) = state.population_stack_mut().try_pop() {
fn execute(&self, problem: &P, state: &mut State<P>) {
if let Some(mut population) = state.populations_mut().try_pop() {
state.holding::<common::EvaluatorInstance<P>>(|evaluator_state, state| {
evaluator_state
.evaluator
.evaluate(problem, state, &mut population);
});

*state.get_value_mut::<common::Evaluations>() += population.len() as u32;
state.population_stack_mut().push(population);
state.populations_mut().push(population);
}
}
}
Expand All @@ -65,15 +65,15 @@ impl UpdateBestIndividual {
}

impl<P: SingleObjectiveProblem> Component<P> for UpdateBestIndividual {
fn initialize(&self, _problem: &P, state: &mut State) {
fn initialize(&self, _problem: &P, state: &mut State<P>) {
state.insert(common::BestIndividual::<P>(None));
}

fn execute(&self, _problem: &P, state: &mut State) {
fn execute(&self, _problem: &P, state: &mut State<P>) {
let mut mut_state = state.get_states_mut();

let best_individual = mut_state
.population_stack()
.populations()
.current()
.iter()
.min_by_key(|i| i.objective());
Expand All @@ -100,14 +100,14 @@ impl UpdateParetoFront {
}

impl<P: MultiObjectiveProblem> Component<P> for UpdateParetoFront {
fn initialize(&self, _problem: &P, state: &mut State) {
fn initialize(&self, _problem: &P, state: &mut State<P>) {
state.insert(common::ParetoFront::<P>::new());
}

fn execute(&self, _problem: &P, state: &mut State) {
fn execute(&self, _problem: &P, state: &mut State<P>) {
let mut mut_state = state.get_states_mut();

let front = mut_state.get_mut::<common::ParetoFront<P>>();
front.update_multiple(mut_state.population_stack().current());
let front = mut_state.pareto_front_mut();
front.update_multiple(mut_state.populations().current());
}
}
Loading