use crate::constraint::PropagationResult;
use crate::model::domain::TrailedDomains;
use crate::propagation::graph::{ConstraintGraph, ConstraintId};
use std::collections::{HashMap, VecDeque};
#[derive(Debug, Default)]
pub struct PropagationEngine;
impl PropagationEngine {
pub fn new() -> Self {
Self
}
pub fn propagate(
&self,
graph: &ConstraintGraph,
domains: &mut TrailedDomains,
mut weights: Option<&mut HashMap<ConstraintId, u32>>,
) -> PropagationResult {
let mut queue: VecDeque<ConstraintId> = (0..graph.constraints().len())
.map(|i| ConstraintId(i as u32))
.collect();
let mut in_queue: HashMap<ConstraintId, bool> =
queue.iter().map(|&cid| (cid, true)).collect();
let mut global_changed = false;
while let Some(cid) = queue.pop_front() {
in_queue.insert(cid, false);
if let Some(constraint) = graph.get_constraint(cid) {
let trail_checkpoint = domains.checkpoint();
match constraint.propagate(domains) {
PropagationResult::Conflict => {
if let Some(w) = weights.as_deref_mut() {
*w.entry(cid).or_insert(1) += 1;
}
return PropagationResult::Conflict;
}
PropagationResult::Success { changed } => {
if changed {
global_changed = true;
for var_id in domains.changed_since(trail_checkpoint) {
for &dep_cid in graph.constraints_for_variable(var_id) {
if dep_cid != cid && !*in_queue.get(&dep_cid).unwrap_or(&false)
{
queue.push_back(dep_cid);
in_queue.insert(dep_cid, true);
}
}
}
}
}
}
}
}
PropagationResult::Success {
changed: global_changed,
}
}
}