use std::cell::Cell;
use super::finite::FiniteDomain;
use super::traits::{CostDomain, Domain};
#[derive(Debug, Clone)]
pub struct CostFiniteDomain {
inner: FiniteDomain<i32>,
costs: Vec<(i32, f64)>,
min_cost_cache: Cell<Option<f64>>,
}
impl PartialEq for CostFiniteDomain {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner && self.costs == other.costs
}
}
impl CostFiniteDomain {
pub fn new(values: Vec<i32>, costs: Vec<f64>) -> Self {
assert_eq!(
values.len(),
costs.len(),
"CostFiniteDomain::new: values and costs length mismatch ({} vs {})",
values.len(),
costs.len(),
);
let mut pairs: Vec<(i32, f64)> = values.into_iter().zip(costs).collect();
pairs.sort_by_key(|(v, _)| *v);
let sorted_values: Vec<i32> = pairs.iter().map(|(v, _)| *v).collect();
Self {
inner: FiniteDomain::new(sorted_values),
costs: pairs,
min_cost_cache: Cell::new(None),
}
}
}
impl Domain for CostFiniteDomain {
type Value = i32;
fn size(&self) -> usize {
self.inner.size()
}
fn contains(&self, val: &i32) -> bool {
self.inner.contains(val)
}
fn remove(&mut self, val: &i32) -> bool {
let changed = self.inner.remove(val);
if changed {
self.min_cost_cache.set(None);
}
changed
}
fn add(&mut self, val: &i32) {
self.inner.add(val);
self.min_cost_cache.set(None);
}
fn values(&self) -> Vec<i32> {
self.inner.values()
}
fn iter(&self) -> impl Iterator<Item = i32> {
self.inner.iter()
}
}
impl CostDomain for CostFiniteDomain {
fn cost(&self, val: &i32) -> f64 {
match self.costs.binary_search_by(|(v, _)| v.cmp(val)) {
Ok(idx) => self.costs[idx].1,
Err(_) => f64::INFINITY,
}
}
fn min_cost(&self) -> f64 {
if let Some(cached) = self.min_cost_cache.get() {
return cached;
}
let min = self
.inner
.iter()
.map(|v| self.cost(&v))
.fold(f64::INFINITY, f64::min);
self.min_cost_cache.set(Some(min));
min
}
}