puzzle_solver/constraint/
unify.rs

1//! Unify implementation.
2
3use std::iter;
4use std::rc::Rc;
5
6use ::{Constraint,PsResult,PuzzleSearch,VarToken};
7
8pub struct Unify {
9    var1: VarToken,
10    var2: VarToken,
11}
12
13impl Unify {
14    /// Allocate a new Unify constraint.
15    ///
16    /// # Examples
17    ///
18    /// ```
19    /// let mut send_more_money = puzzle_solver::Puzzle::new();
20    /// let carry = send_more_money.new_vars_with_candidates_1d(4, &[0,1]);
21    /// let vars = send_more_money.new_vars_with_candidates_1d(8,
22    ///         &[0,1,2,3,4,5,6,7,8,9]);
23    ///
24    /// let m = vars[4];
25    /// puzzle_solver::constraint::Unify::new(m, carry[3]);
26    /// ```
27    pub fn new(var1: VarToken, var2: VarToken) -> Self {
28        Unify {
29            var1: var1,
30            var2: var2,
31        }
32    }
33}
34
35impl Constraint for Unify {
36    fn vars<'a>(&'a self) -> Box<Iterator<Item=&'a VarToken> + 'a> {
37        if self.var1 != self.var2 {
38            Box::new(iter::once(&self.var1).chain(iter::once(&self.var2)))
39        } else {
40            Box::new(iter::empty())
41        }
42    }
43
44    fn on_updated(&self, search: &mut PuzzleSearch) -> PsResult<()> {
45        if self.var1 != self.var2 {
46            search.unify(self.var1, self.var2)
47        } else {
48            Ok(())
49        }
50    }
51
52    fn substitute(&self, from: VarToken, to: VarToken)
53            -> PsResult<Rc<Constraint>> {
54        let var1 = if self.var1 == from { to } else { self.var1 };
55        let var2 = if self.var2 == from { to } else { self.var2 };
56        Ok(Rc::new(Unify{ var1: var1, var2: var2 }))
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use ::Puzzle;
63
64    #[test]
65    fn test_unify_alldifferent() {
66        let mut puzzle = Puzzle::new();
67        let v0 = puzzle.new_var_with_candidates(&[1,2]);
68        let v1 = puzzle.new_var_with_candidates(&[1,2]);
69
70        puzzle.all_different(&[v0, v1]);
71        puzzle.unify(v0, v1);
72
73        let search = puzzle.step();
74        assert!(search.is_none());
75    }
76
77    #[test]
78    fn test_unify_equality() {
79        let mut puzzle = Puzzle::new();
80        let v0 = puzzle.new_var_with_candidates(&[1,2,3,4]);
81        let v1 = puzzle.new_var_with_candidates(&[1,2,3,4]);
82        let v2 = puzzle.new_var_with_candidates(&[1,2,3,4]);
83
84        puzzle.equals(v0 + 2 * v1 + v2, 6);
85        puzzle.unify(v0, v1);
86
87        let search = puzzle.step().expect("contradiction");
88        assert_eq!(search[v0], 1);
89        assert_eq!(search[v1], 1);
90        assert_eq!(search[v2], 3);
91    }
92
93    #[test]
94    fn test_unify_unify() {
95        let mut puzzle = Puzzle::new();
96        let v0 = puzzle.new_var_with_candidates(&[1]);
97        let v1 = puzzle.new_var_with_candidates(&[1,2,3,4]);
98        let v2 = puzzle.new_var_with_candidates(&[1,2,3,4]);
99
100        puzzle.unify(v0, v1);
101        puzzle.unify(v1, v2);
102
103        let search = puzzle.step().expect("contradiction");
104        assert_eq!(search[v0], 1);
105        assert_eq!(search[v1], 1);
106        assert_eq!(search[v2], 1);
107    }
108}