use eyre::WrapErr;
use crate::{
component::ExecResult,
components::{boundary, initialization, mapping, swarm},
conditions::Condition,
configuration::Configuration,
identifier::{Global, Identifier},
lens::ValueOf,
logging::Logger,
problems::{LimitedVectorProblem, SingleObjectiveProblem},
state::common,
Component,
};
pub struct RealProblemParameters {
pub num_particles: u32,
pub start_weight: f64,
pub end_weight: f64,
pub c_one: f64,
pub c_two: f64,
pub v_max: f64,
}
pub fn real_pso<P>(
params: RealProblemParameters,
condition: Box<dyn Condition<P>>,
) -> ExecResult<Configuration<P>>
where
P: SingleObjectiveProblem + LimitedVectorProblem<Element = f64>,
{
let RealProblemParameters {
num_particles,
start_weight,
end_weight,
c_one,
c_two,
v_max,
} = params;
Ok(Configuration::builder()
.do_(initialization::RandomSpread::new(num_particles))
.evaluate()
.update_best_individual()
.do_(pso::<P, Global>(
Parameters {
particle_init: swarm::ParticleSwarmInit::new(v_max)?,
particle_update: swarm::ParticleVelocitiesUpdate::new(
start_weight,
c_one,
c_two,
v_max,
)
.wrap_err("failed to construct particle velocities update")?,
constraints: boundary::Saturation::new(),
inertia_weight_update: Some(mapping::Linear::new(
start_weight,
end_weight,
ValueOf::<common::Progress<ValueOf<common::Iterations>>>::new(),
ValueOf::<swarm::InertiaWeight<swarm::ParticleVelocitiesUpdate>>::new(),
)),
state_update: swarm::ParticleSwarmUpdate::new(),
},
condition,
))
.build())
}
pub struct Parameters<P> {
pub particle_init: Box<dyn Component<P>>,
pub particle_update: Box<dyn Component<P>>,
pub constraints: Box<dyn Component<P>>,
pub inertia_weight_update: Option<Box<dyn Component<P>>>,
pub state_update: Box<dyn Component<P>>,
}
pub fn pso<P, I>(params: Parameters<P>, condition: Box<dyn Condition<P>>) -> Box<dyn Component<P>>
where
P: SingleObjectiveProblem,
I: Identifier,
{
let Parameters {
particle_init,
particle_update,
constraints,
inertia_weight_update,
state_update,
} = params;
Configuration::builder()
.do_(particle_init)
.while_(condition, |builder| {
builder
.do_(particle_update)
.do_(constraints)
.evaluate_with::<I>()
.update_best_individual()
.do_if_some_(inertia_weight_update)
.do_(state_update)
.do_(Logger::new())
})
.build_component()
}