pso 0.2.0

Particle Swarm Optimizer
Documentation
use std::cmp::Ordering;
use std::fmt;
use std::sync::{Arc, RwLock};

const SAME_REC_EPS: f64 = std::f64::EPSILON * 2.0;

#[derive(Clone, Debug)]
pub struct OwnedRecord {
    pos: Vec<f64>,
    pub cost: f64,
}

impl OwnedRecord {
    pub fn new(num_variables: usize) -> Self {
        OwnedRecord {
            pos: vec![0.0; num_variables],
            cost: std::f64::MAX,
        }
    }

    pub fn build(pos: Vec<f64>, cost: f64) -> Self {
        OwnedRecord { pos, cost }
    }

    pub fn pos(&self) -> &Vec<f64> {
        &self.pos
    }

    pub fn to_tuple(&self) -> (f64, Vec<f64>) {
        (self.cost, self.pos.clone())
    }
}

impl PartialOrd for OwnedRecord {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.cost.partial_cmp(&other.cost)
    }
}

impl PartialEq for OwnedRecord {
    fn eq(&self, other: &Self) -> bool {
        self.cost == other.cost
    }
}

impl fmt::Display for OwnedRecord {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:.10} @ [", self.cost)?;
        for i in 0..self.pos.len() - 1 {
            write!(f, "{:.6}, ", self.pos[i])?;
        }
        write!(f, "{:.6}]", self.pos[self.pos.len() - 1])
    }
}

#[derive(Debug)]
pub struct GlobalRecord {
    rec: Arc<RwLock<OwnedRecord>>,
}

impl GlobalRecord {
    pub fn new(num_variables: usize) -> Self {
        Self {
            rec: Arc::new(RwLock::new(OwnedRecord::new(num_variables))),
        }
    }

    pub fn to_tuple(&self) -> Result<(f64, Vec<f64>), &str> {
        match self.rec.read() {
            Ok(rec_value) => Ok(rec_value.to_tuple()),
            Err(_) => Err("Unable to read GLobal Record!"),
        }
    }

    pub fn beats_global(&self, other_rec: &OwnedRecord) -> RecordBeatResult {
        match self.rec.try_read() {
            Ok(ref record) => {
                if (other_rec.cost - record.cost).abs() < SAME_REC_EPS {
                    return RecordBeatResult::Same;
                } else if other_rec.cost < record.cost {
                    return RecordBeatResult::Won;
                } else {
                    return RecordBeatResult::Lost((*record).clone());
                }
            }
            Err(_) => return RecordBeatResult::Retry,
        };
    }

    pub fn update_global(&self, other_rec: &OwnedRecord) -> RecordBeatResult {
        match self.rec.try_write() {
            Ok(mut record) => {
                if other_rec.cost < record.cost {
                    *record = other_rec.clone();
                    return RecordBeatResult::Won;
                } else {
                    return RecordBeatResult::Same;
                }
            }
            Err(_) => return RecordBeatResult::Retry,
        }
    }
}

impl Clone for GlobalRecord {
    fn clone(&self) -> Self {
        let rec_ref = self.rec.clone();
        Self { rec: rec_ref }
    }
}

pub enum RecordBeatResult {
    Won,
    Same,
    Lost(OwnedRecord),
    Retry,
}