pub trait Schedule: Send + Sync {
fn initial_temp(&self) -> f64;
fn next_temp(&self, current_temp: f64, iteration: usize) -> f64;
}
#[derive(Clone, Debug)]
pub struct GeometricSchedule {
initial_temperature: f64,
alpha: f64,
}
impl GeometricSchedule {
pub fn new(initial_temperature: f64, alpha: f64) -> Self {
assert!(
initial_temperature > 0.0,
"Initial temperature must be positive"
);
assert!(
alpha > 0.0 && alpha < 1.0,
"Alpha must be between 0 and 1 (exclusive)"
);
Self {
initial_temperature,
alpha,
}
}
}
impl Schedule for GeometricSchedule {
fn initial_temp(&self) -> f64 {
self.initial_temperature
}
fn next_temp(&self, current_temp: f64, _iteration: usize) -> f64 {
current_temp * self.alpha
}
}
#[derive(Clone, Debug)]
pub struct LogarithmicSchedule {
initial_temperature: f64,
}
impl LogarithmicSchedule {
pub fn new(initial_temperature: f64) -> Self {
assert!(
initial_temperature > 0.0,
"Initial temperature must be positive"
);
Self {
initial_temperature,
}
}
}
impl Schedule for LogarithmicSchedule {
fn initial_temp(&self) -> f64 {
self.initial_temperature
}
fn next_temp(&self, _current_temp: f64, iteration: usize) -> f64 {
if iteration == 0 {
return self.initial_temperature;
}
self.initial_temperature / (1.0 + iteration as f64).ln()
}
}
#[derive(Clone, Debug)]
pub struct AdaptiveSchedule {
initial_temperature: f64,
target_acceptance_ratio: f64,
min_alpha: f64,
max_alpha: f64,
acceptance_history: Vec<bool>,
window_size: usize,
}
impl AdaptiveSchedule {
pub fn new(initial_temperature: f64) -> Self {
Self::with_params(initial_temperature, 0.44, 0.9, 0.99)
}
pub fn with_params(
initial_temperature: f64,
target_acceptance_ratio: f64,
min_alpha: f64,
max_alpha: f64,
) -> Self {
assert!(
initial_temperature > 0.0,
"Initial temperature must be positive"
);
assert!(
target_acceptance_ratio > 0.0 && target_acceptance_ratio < 1.0,
"Target acceptance ratio must be between 0 and 1"
);
assert!(
min_alpha > 0.0 && min_alpha < 1.0,
"Min alpha must be between 0 and 1"
);
assert!(
max_alpha > min_alpha && max_alpha < 1.0,
"Max alpha must be between min_alpha and 1"
);
Self {
initial_temperature,
target_acceptance_ratio,
min_alpha,
max_alpha,
acceptance_history: Vec::new(),
window_size: 100, }
}
pub fn record_acceptance(&mut self, accepted: bool) {
self.acceptance_history.push(accepted);
if self.acceptance_history.len() > self.window_size {
self.acceptance_history.remove(0);
}
}
fn acceptance_ratio(&self) -> f64 {
if self.acceptance_history.is_empty() {
return 0.5; }
self.acceptance_history.iter().filter(|&&x| x).count() as f64
/ self.acceptance_history.len() as f64
}
}
impl Schedule for AdaptiveSchedule {
fn initial_temp(&self) -> f64 {
self.initial_temperature
}
fn next_temp(&self, current_temp: f64, _iteration: usize) -> f64 {
let current_ratio = self.acceptance_ratio();
let ratio_diff = current_ratio - self.target_acceptance_ratio;
let alpha = if ratio_diff > 0.0 {
self.max_alpha
- (self.max_alpha - self.min_alpha) * (ratio_diff / self.target_acceptance_ratio)
} else {
self.max_alpha
};
let alpha = alpha.max(self.min_alpha).min(self.max_alpha);
current_temp * alpha
}
}