use crate::core::math::Scalar;
use crate::core::problem::EvalCounts;
use crate::core::rng::ChaCha8Rng;
use crate::core::state::{
CountsMirror, ExactResumeState, PopulationState, State,
};
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Debug)]
pub struct GlobalBestPsoState<V, F = f64, R = ChaCha8Rng> {
pub(crate) positions: Vec<V>,
pub(crate) costs: Vec<F>,
pub(crate) velocities: Vec<V>,
pub(crate) personal_best_positions: Vec<V>,
pub(crate) personal_best_costs: Vec<F>,
pub(crate) global_best_position: Option<V>,
pub(crate) global_best_cost: F,
pub(crate) rng: Option<R>,
pub(crate) initialized: bool,
pub(crate) iter: u64,
pub(crate) eval_counts: EvalCounts,
pub(crate) best_cost: F,
pub(crate) best_iter: u64,
pub(crate) best_cost_evals: u64,
}
impl<V, F: Scalar, R> GlobalBestPsoState<V, F, R> {
fn empty() -> Self {
Self {
positions: Vec::new(),
costs: Vec::new(),
velocities: Vec::new(),
personal_best_positions: Vec::new(),
personal_best_costs: Vec::new(),
global_best_position: None,
global_best_cost: F::infinity(),
rng: None,
initialized: false,
iter: 0,
eval_counts: EvalCounts::default(),
best_cost: F::infinity(),
best_iter: 0,
best_cost_evals: 0,
}
}
pub fn new() -> Self {
Self::empty()
}
pub fn from_positions(positions: Vec<V>) -> Self {
assert!(
!positions.is_empty(),
"GlobalBestPsoState requires at least one position"
);
let mut state = Self::empty();
state.positions = positions;
state
}
pub fn from_positions_and_velocities(
positions: Vec<V>,
velocities: Vec<V>,
) -> Self {
assert!(
!positions.is_empty(),
"GlobalBestPsoState requires at least one position"
);
assert_eq!(
positions.len(),
velocities.len(),
"GlobalBestPsoState requires one velocity per position"
);
let mut state = Self::empty();
state.positions = positions;
state.velocities = velocities;
state
}
pub fn velocities(&self) -> &[V] {
&self.velocities
}
pub fn personal_best_positions(&self) -> &[V] {
&self.personal_best_positions
}
pub fn personal_best_costs(&self) -> &[F] {
&self.personal_best_costs
}
pub fn global_best_position(&self) -> &V {
self.global_best_position.as_ref().expect(
"GlobalBestPsoState::global_best_position read before Solver::init",
)
}
pub fn global_best_cost(&self) -> F {
self.global_best_cost
}
}
impl<V, F: Scalar, R> Default for GlobalBestPsoState<V, F, R> {
fn default() -> Self {
Self::new()
}
}
impl<V: Clone, F: Scalar, R> State for GlobalBestPsoState<V, F, R> {
type Param = V;
type Float = F;
fn iter(&self) -> u64 {
self.iter
}
fn increment_iter(&mut self) {
self.iter += 1;
}
fn cost_evals(&self) -> u64 {
self.eval_counts.total_work()
}
fn param(&self) -> &V {
self.global_best_position()
}
fn cost(&self) -> F {
self.global_best_cost
}
fn best_param(&self) -> &V {
self.global_best_position()
}
fn best_cost(&self) -> F {
self.best_cost
}
fn best_iter(&self) -> u64 {
self.best_iter
}
fn best_cost_evals(&self) -> u64 {
self.best_cost_evals
}
fn update_best(&mut self) {
if self.global_best_cost < self.best_cost {
self.best_cost = self.global_best_cost;
self.best_iter = self.iter;
self.best_cost_evals = self.eval_counts.total_work();
}
}
fn reset_best(&mut self) {
self.best_cost = F::infinity();
self.best_iter = 0;
self.best_cost_evals = 0;
}
}
impl<V, F, R> CountsMirror for GlobalBestPsoState<V, F, R>
where
GlobalBestPsoState<V, F, R>: State,
{
fn mirror(&mut self, counts: &EvalCounts) {
self.eval_counts = *counts;
}
}
impl<V, F, R> ExactResumeState for GlobalBestPsoState<V, F, R>
where
GlobalBestPsoState<V, F, R>: State,
{
fn resume_counts(&self) -> EvalCounts {
self.eval_counts
}
}
impl<V, F: Scalar, R> PopulationState for GlobalBestPsoState<V, F, R>
where
V: Clone,
{
fn candidates(&self) -> &[V] {
&self.positions
}
fn costs(&self) -> &[F] {
&self.costs
}
}