Skip to main content

csp_solver/constraint/
not_equal.rs

1//! Binary not-equal constraint: `x != y`.
2//!
3//! Tests: `tests/solver.rs`.
4
5use crate::domain::Domain;
6use crate::variable::Variable;
7
8use super::traits::{Constraint, Revision, VarId};
9
10#[derive(Debug)]
11pub struct NotEqual {
12    pub(crate) scope: [VarId; 2],
13}
14
15impl NotEqual {
16    pub fn new(x: VarId, y: VarId) -> Self {
17        Self { scope: [x, y] }
18    }
19
20    pub(crate) fn check_impl<V: PartialEq>(&self, assignment: &[Option<V>]) -> bool {
21        let xi = self.scope[0] as usize;
22        let xj = self.scope[1] as usize;
23        match (&assignment[xi], &assignment[xj]) {
24            (Some(a), Some(b)) => a != b,
25            _ => true,
26        }
27    }
28
29    pub(crate) fn revise_impl<D: Domain>(&self, vars: &mut [Variable<D>], depth: usize) -> Revision
30    where
31        D::Value: PartialEq,
32    {
33        let xi = self.scope[0] as usize;
34        let xj = self.scope[1] as usize;
35        let mut changed = false;
36
37        if let Some(v) = vars[xi].domain.singleton_value()
38            && vars[xj].prune(&v, depth)
39        {
40            changed = true;
41        }
42        if let Some(v) = vars[xj].domain.singleton_value()
43            && vars[xi].prune(&v, depth)
44        {
45            changed = true;
46        }
47
48        if vars[xi].domain.is_empty() || vars[xj].domain.is_empty() {
49            return Revision::Unsatisfiable;
50        }
51
52        if changed {
53            Revision::Changed
54        } else {
55            Revision::Unchanged
56        }
57    }
58}
59
60impl<D: Domain> Constraint<D> for NotEqual
61where
62    D::Value: PartialEq,
63{
64    fn scope(&self) -> &[VarId] {
65        &self.scope
66    }
67    fn check(&self, assignment: &[Option<D::Value>]) -> bool {
68        self.check_impl(assignment)
69    }
70    fn revise(&self, vars: &mut [Variable<D>], depth: usize) -> Revision {
71        self.revise_impl(vars, depth)
72    }
73}