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,
}