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

Make heuristics usable as components #107

Merged
merged 10 commits into from
Sep 1, 2022
Merged
23 changes: 17 additions & 6 deletions examples/bmf.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
use mahf::heuristics::pso;
use mahf::{framework, problems::bmf::BenchmarkFunction};
use mahf::prelude::*;

type P = problems::bmf::BenchmarkFunction;

fn main() -> anyhow::Result<()> {
let problem = BenchmarkFunction::sphere(30);
let config = pso::pso(100, 1., 1., 1., 1., 500);
let problem = P::sphere(30);
let config = pso::real_pso(
pso::RealProblemParameters {
num_particles: 100,
a: 1.0,
b: 1.0,
c: 1.0,
v_max: 1.0,
},
termination::FixedIterations::new(500),
tracking::Logger::default(),
);

let state = framework::run(&problem, &config, None);

println!(
"Found Fitness: {:?}",
state.best_objective_value::<BenchmarkFunction>().unwrap(),
state.best_objective_value::<P>().unwrap()
);
println!(
"Found Individual: {:?}",
state.best_individual::<BenchmarkFunction>().unwrap(),
state.best_individual::<P>().unwrap(),
);
println!("Global Optimum: {}", problem.known_optimum());

Expand Down
17 changes: 7 additions & 10 deletions examples/coco.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
use mahf::{
heuristics::iwo,
operators::termination,
problems::coco_bound::{suits, CocoInstance},
tracking::{self, trigger, LogSet},
};
use mahf::prelude::*;
use problems::coco_bound::{suits, CocoInstance};
use tracking::{functions, trigger};

fn main() -> anyhow::Result<()> {
let output = "data/coco/iwo";
let config = iwo::iwo(
iwo::Parameters {
let config = iwo::real_iwo(
iwo::RealProblemParameters {
initial_population_size: 5,
max_population_size: 20,
min_number_of_seeds: 0,
Expand All @@ -21,9 +18,9 @@ fn main() -> anyhow::Result<()> {
tracking::Logger::builder()
.log_common_sets()
.log_set(
LogSet::new()
tracking::LogSet::new()
.with_trigger(trigger::Iteration::new(50))
.with_logger(tracking::functions::best_individual::<CocoInstance>),
.with_logger(functions::best_individual::<CocoInstance>),
)
.build(),
);
Expand Down
31 changes: 20 additions & 11 deletions examples/tsp.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
use mahf::heuristics::aco;
use mahf::{framework, problems};
use mahf::prelude::*;

type P = problems::tsp::SymmetricTsp;

fn main() -> anyhow::Result<()> {
let problem = problems::tsp::Instances::BERLIN52.load();
let tau0 = 1. / problem.best_fitness().unwrap();
let config = aco::min_max_ant_system(20, 1., 1., tau0, 0.1, 1., 0.1, 500);

let state = framework::run(&problem, &config, None);
let config = ils::permutation_iterated_local_search(
ils::PermutationProblemParameters {
local_search_params: ls::PermutationProblemParameters {
n_neighbors: 100,
pm: 0.9,
n_swap: 10,
},
local_search_termination: termination::FixedIterations::new(100),
},
termination::FixedIterations::new(10),
tracking::Logger::default(),
)
.into_builder()
.assert(|state| state.population_stack::<P>().current().len() == 1)
.single_objective_summary()
.build();

println!(
"Found Solution: {:?}",
state
.best_objective_value::<problems::tsp::SymmetricTsp>()
.unwrap()
);
framework::run(&problem, &config, None);

Ok(())
}
4 changes: 2 additions & 2 deletions param-study/src/instances/iwo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ pub fn run(setup: &Setup, args: &mut ArgsIter) {

let problem = BenchmarkFunction::try_from(setup.instance.as_str()).unwrap();

let config = iwo::iwo(
iwo::Parameters {
let config = iwo::real_iwo(
iwo::RealProblemParameters {
initial_population_size: params.initial_population_size,
max_population_size: params.max_population_size,
min_number_of_seeds: params.min_number_of_seeds,
Expand Down
19 changes: 12 additions & 7 deletions param-study/src/instances/pso.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ use mahf::{
float_eq::float_eq,
framework::{self, Random},
heuristics::pso,
operators::termination,
problems::bmf::BenchmarkFunction,
tracking,
};

use crate::{
Expand All @@ -25,13 +27,16 @@ pub fn run(setup: &Setup, args: &mut ArgsIter) {

let problem = BenchmarkFunction::try_from(setup.instance.as_str()).unwrap();

let config = pso::pso(
params.population_size,
params.a,
params.b,
params.c,
params.v_max,
setup.cutoff_length,
let config = pso::real_pso(
pso::RealProblemParameters {
num_particles: params.population_size,
a: params.a,
b: params.b,
c: params.c,
v_max: params.v_max,
},
termination::FixedIterations::new(setup.cutoff_length),
tracking::Logger::default(),
);

let rng = Random::seeded(setup.seed);
Expand Down
66 changes: 65 additions & 1 deletion src/framework/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ use crate::{
framework::{
components::{Block, Branch, Component, Loop, Scope},
conditions::Condition,
state,
},
problems::Problem,
operators,
problems::{MultiObjectiveProblem, Problem, SingleObjectiveProblem},
};

pub struct Configuration<P: Problem>(Box<dyn Component<P>>);
Expand All @@ -20,6 +22,14 @@ impl<P: Problem> Configuration<P> {
pub fn heuristic(&self) -> &dyn Component<P> {
self.0.as_ref()
}

pub fn into_inner(self) -> Box<dyn Component<P>> {
self.0
}

pub fn into_builder(self) -> ConfigurationBuilder<P> {
ConfigurationBuilder::new().do_(self.0)
}
Comment on lines +30 to +32
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this useful? I can't really come up with a good use case because you could only append to the end, but not within the loop.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that this method might only be used in rather obscure cases, but I figured that an elegant way to append to existing configurations could not hurt.

}

impl<P: Problem> From<Configuration<P>> for Box<dyn Component<P>> {
Expand All @@ -32,6 +42,7 @@ pub struct ConfigurationBuilder<P: Problem> {
components: Vec<Box<dyn Component<P>>>,
}

// Basic functionality
impl<P: Problem> ConfigurationBuilder<P> {
fn new() -> Self {
Self {
Expand All @@ -44,6 +55,14 @@ impl<P: Problem> ConfigurationBuilder<P> {
self
}

pub fn do_optional_(self, component: Option<Box<dyn Component<P>>>) -> Self {
if let Some(component) = component {
self.do_(component)
} else {
self
}
}

pub fn while_(
self,
condition: Box<dyn Condition<P>>,
Expand Down Expand Up @@ -88,4 +107,49 @@ impl<P: Problem> ConfigurationBuilder<P> {
pub fn build(self) -> Configuration<P> {
Configuration::new(Block::new(self.components))
}

pub fn build_component(self) -> Box<dyn Component<P>> {
Block::new(self.components)
}
}

// Convenience methods
impl<P: Problem> ConfigurationBuilder<P> {
/// Asserts the condition on [State][state::State].
///
/// Uses the [Debug][operators::misc::Debug] component internally.
#[track_caller]
pub fn assert(self, assert: impl Fn(&state::State) -> bool + Send + Sync + 'static) -> Self {
self.debug(move |_problem, state| assert!(assert(state)))
}
Saethox marked this conversation as resolved.
Show resolved Hide resolved

/// Constructs a [Debug][operators::misc::Debug] component with the given behaviour.
pub fn debug(self, behaviour: impl Fn(&P, &mut state::State) + Send + Sync + 'static) -> Self {
self.do_(operators::misc::Debug::new(behaviour))
}

pub fn evaluate_sequential(self) -> Self {
self.do_(operators::evaluation::SequentialEvaluator::new())
}
}

impl<P: SingleObjectiveProblem> ConfigurationBuilder<P> {
pub fn update_best_individual(self) -> Self {
self.do_(operators::evaluation::UpdateBestIndividual::new())
}
}

impl<P: SingleObjectiveProblem> ConfigurationBuilder<P>
where
P::Encoding: std::fmt::Debug,
{
pub fn single_objective_summary(self) -> Self {
self.do_(operators::misc::PrintSingleObjectiveSummary::new())
}
}

impl<P: MultiObjectiveProblem> ConfigurationBuilder<P> {
pub fn update_pareto_front(self) -> Self {
self.do_(operators::evaluation::UpdateParetoFront::new())
}
}
Loading