use std::fmt::Debug;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::Score;
use super::Acceptor;
pub struct DiversifiedLateAcceptanceAcceptor<S: PlanningSolution> {
late_acceptance_size: usize,
score_history: Vec<Option<S::Score>>,
current_index: usize,
best_score: Option<S::Score>,
tolerance: f64,
}
impl<S: PlanningSolution> Debug for DiversifiedLateAcceptanceAcceptor<S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DiversifiedLateAcceptanceAcceptor")
.field("late_acceptance_size", &self.late_acceptance_size)
.field("current_index", &self.current_index)
.field("tolerance", &self.tolerance)
.finish()
}
}
impl<S: PlanningSolution> Clone for DiversifiedLateAcceptanceAcceptor<S> {
fn clone(&self) -> Self {
Self {
late_acceptance_size: self.late_acceptance_size,
score_history: self.score_history.clone(),
current_index: self.current_index,
best_score: self.best_score,
tolerance: self.tolerance,
}
}
}
impl<S: PlanningSolution> DiversifiedLateAcceptanceAcceptor<S> {
pub fn new(late_acceptance_size: usize, tolerance: f64) -> Self {
assert!(
late_acceptance_size > 0,
"late_acceptance_size must be > 0, got 0"
);
Self {
late_acceptance_size,
score_history: vec![None; late_acceptance_size],
current_index: 0,
best_score: None,
tolerance,
}
}
pub fn with_default_tolerance(late_acceptance_size: usize) -> Self {
Self::new(late_acceptance_size, 0.01)
}
}
impl<S: PlanningSolution> Default for DiversifiedLateAcceptanceAcceptor<S> {
fn default() -> Self {
Self::new(400, 0.01)
}
}
impl<S: PlanningSolution> Acceptor<S> for DiversifiedLateAcceptanceAcceptor<S> {
fn is_accepted(&mut self, last_step_score: &S::Score, move_score: &S::Score) -> bool {
if move_score >= last_step_score {
return true;
}
if let Some(late_score) = &self.score_history[self.current_index] {
if move_score >= late_score {
return true;
}
} else {
return true;
}
if let Some(best) = &self.best_score {
let abs_best = best.abs();
let threshold = *best - abs_best.multiply(self.tolerance);
if move_score >= &threshold {
return true;
}
}
false
}
fn phase_started(&mut self, initial_score: &S::Score) {
for slot in &mut self.score_history {
*slot = Some(*initial_score);
}
self.current_index = 0;
self.best_score = Some(*initial_score);
}
fn step_ended(&mut self, step_score: &S::Score) {
if let Some(best) = &self.best_score {
if step_score > best {
self.best_score = Some(*step_score);
}
} else {
self.best_score = Some(*step_score);
}
self.score_history[self.current_index] = Some(*step_score);
self.current_index = (self.current_index + 1) % self.late_acceptance_size;
}
}
#[cfg(test)]
#[path = "diversified_late_acceptance_tests.rs"]
mod tests;