use crate::adjacency::Adjacency;
use crate::constraint::{ConstraintEnum, VarId};
use crate::domain::Domain;
use crate::variable::Variable;
struct Rng(u64);
impl Rng {
fn new() -> Self {
let seed = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos() as u64;
Self(seed)
}
fn next(&mut self) -> u64 {
self.0 = self
.0
.wrapping_mul(6364136223846793005)
.wrapping_add(1442695040888963407);
self.0
}
fn usize(&mut self, bound: usize) -> usize {
(self.next() % bound as u64) as usize
}
}
fn num_conflicts<D: Domain>(
var: VarId,
val: &D::Value,
assignment: &mut [Option<D::Value>],
constraints: &[ConstraintEnum<D>],
adjacency: &Adjacency,
) -> usize
where
D::Value: PartialEq + Clone,
{
let original = assignment[var as usize].take();
assignment[var as usize] = Some(val.clone());
let mut count = 0;
for &ci in adjacency.constraints_for(var) {
if !constraints[ci as usize].check(assignment) {
count += 1;
}
}
assignment[var as usize] = original;
count
}
fn conflicting_variables<D: Domain>(
assignment: &[Option<D::Value>],
constraints: &[ConstraintEnum<D>],
_adjacency: &Adjacency,
) -> Vec<VarId>
where
D::Value: PartialEq + Clone,
{
let num_vars = assignment.len();
let mut in_conflict = vec![false; num_vars];
for constraint in constraints {
if !constraint.check(assignment) {
for &v in constraint.scope() {
in_conflict[v as usize] = true;
}
}
}
(0..num_vars as VarId)
.filter(|&v| in_conflict[v as usize])
.collect()
}
pub fn min_conflicts<D: Domain>(
variables: &mut [Variable<D>],
constraints: &[ConstraintEnum<D>],
adjacency: &Adjacency,
max_iterations: usize,
) -> Option<Vec<D::Value>>
where
D::Value: PartialEq + Clone,
{
let n = variables.len();
if n == 0 {
return Some(Vec::new());
}
let mut rng = Rng::new();
let mut assignment: Vec<Option<D::Value>> = Vec::with_capacity(n);
for var in variables.iter() {
let vals = var.domain.values();
if vals.is_empty() {
return None; }
let idx = rng.usize(vals.len());
assignment.push(Some(vals[idx].clone()));
}
for _ in 0..max_iterations {
let conflicts = conflicting_variables(&assignment, constraints, adjacency);
if conflicts.is_empty() {
return Some(
assignment
.into_iter()
.map(|v| v.unwrap())
.collect(),
);
}
let var = conflicts[rng.usize(conflicts.len())];
let domain_vals = variables[var as usize].domain.values();
if domain_vals.is_empty() {
return None;
}
let mut best_val = domain_vals[0].clone();
let mut best_count = usize::MAX;
for val in &domain_vals {
let c = num_conflicts::<D>(var, val, &mut assignment, constraints, adjacency);
if c < best_count {
best_count = c;
best_val = val.clone();
if best_count == 0 {
break; }
}
}
assignment[var as usize] = Some(best_val);
}
None
}