csp_solver/constraint/
all_different.rs1use crate::domain::Domain;
7use crate::variable::Variable;
8
9use super::traits::{Constraint, Revision, VarId};
10
11#[derive(Debug)]
12pub struct AllDifferent {
13 pub(crate) scope: Vec<VarId>,
14 gac_id: u32,
16}
17
18impl AllDifferent {
19 pub fn new(vars: Vec<VarId>) -> Self {
20 Self {
21 scope: vars,
22 gac_id: crate::solver::gac::next_gac_id(),
23 }
24 }
25
26 pub(crate) fn check_impl<V: PartialEq>(&self, assignment: &[Option<V>]) -> bool {
27 let assigned: Vec<&V> = self
28 .scope
29 .iter()
30 .filter_map(|&v| assignment[v as usize].as_ref())
31 .collect();
32 for i in 0..assigned.len() {
33 for j in (i + 1)..assigned.len() {
34 if assigned[i] == assigned[j] {
35 return false;
36 }
37 }
38 }
39 true
40 }
41
42 pub(crate) fn revise_impl<D: Domain>(&self, vars: &mut [Variable<D>], depth: usize) -> Revision
51 where
52 D::Value: PartialEq + 'static,
53 {
54 let mut changed = false;
55 let unsat = super::scratch::with_singleton_buf::<D::Value, _>(|singletons| {
61 for &v in &self.scope {
62 if let Some(val) = vars[v as usize].domain.singleton_value() {
63 singletons.push((v, val));
64 }
65 }
66 for (sv, sval) in singletons.iter() {
67 for &other in &self.scope {
68 if other == *sv {
69 continue;
70 }
71 if vars[other as usize].prune(sval, depth) {
72 changed = true;
73 }
74 if vars[other as usize].domain.is_empty() {
75 return true;
76 }
77 }
78 }
79 false
80 });
81 if unsat {
82 return Revision::Unsatisfiable;
83 }
84
85 let live = self
87 .scope
88 .iter()
89 .filter(|&&v| {
90 let d = &vars[v as usize].domain;
91 !d.is_singleton() && !d.is_empty()
92 })
93 .count();
94
95 if live >= crate::solver::gac::GAC_MIN_PARTICIPANTS
96 && crate::solver::gac::GAC_IN_ALLDIFF_ENABLED.load(std::sync::atomic::Ordering::Relaxed)
97 {
98 match crate::solver::gac::propagate_gac_core(
99 &self.scope,
100 None,
101 vars,
102 depth,
103 Some(self.gac_id),
104 ) {
105 Revision::Unsatisfiable => return Revision::Unsatisfiable,
106 Revision::Changed => changed = true,
107 Revision::Unchanged => {}
108 }
109 }
110
111 if changed {
112 Revision::Changed
113 } else {
114 Revision::Unchanged
115 }
116 }
117}
118
119impl<D: Domain> Constraint<D> for AllDifferent
120where
121 D::Value: PartialEq + 'static,
122{
123 fn scope(&self) -> &[VarId] {
124 &self.scope
125 }
126 fn check(&self, assignment: &[Option<D::Value>]) -> bool {
127 self.check_impl(assignment)
128 }
129 fn revise(&self, vars: &mut [Variable<D>], depth: usize) -> Revision {
130 self.revise_impl(vars, depth)
131 }
132}