Skip to main content

csp_solver/constraint/
not_equal.rs

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