pcp/search/
branch_and_bound.rs1use kernel::*;
16use search::space::*;
17use search::search_tree_visitor::*;
18use search::search_tree_visitor::Status::*;
19use term::*;
20use propagators::cmp::*;
21use gcollections::*;
22use concept::*;
23
24pub enum Mode {
25 Minimize,
26 Maximize
27}
28
29pub struct BranchAndBound<VStore, C> where
30 VStore: VStoreConcept,
31 VStore::Item: Collection
32{
33 pub mode: Mode,
34 pub var: Var<VStore>,
35 pub value: Option<<VStore::Item as Collection>::Item>,
36 pub child: C
37}
38
39impl<VStore, C> BranchAndBound<VStore, C> where
40 VStore: VStoreConcept,
41 VStore::Item: Collection
42{
43 pub fn new(mode: Mode, var: Var<VStore>, child: C) -> Self {
44 BranchAndBound {
45 mode: mode,
46 var: var,
47 value: None,
48 child: child,
49 }
50 }
51}
52
53impl<C, Bound, Dom, VStore, CStore, R> SearchTreeVisitor<Space<VStore, CStore, R>> for
54 BranchAndBound<VStore, C> where
55 VStore: VStoreConcept<Item=Dom> + 'static,
56 CStore: IntCStore<VStore>,
57 Dom: IntDomain<Item=Bound> + 'static,
58 Bound: IntBound + 'static,
59 C: SearchTreeVisitor<Space<VStore, CStore, R>>,
60 R: FreezeSpace<VStore, CStore> + Snapshot<State=Space<VStore, CStore, R>>
61{
62 fn start(&mut self, root: &Space<VStore, CStore, R>) {
63 self.child.start(root);
64 }
65
66 fn enter(&mut self, mut current: Space<VStore, CStore, R>)
67 -> (<Space<VStore, CStore, R> as Freeze>::FrozenState, Status<Space<VStore, CStore, R>>)
68 {
69 if let Some(bound) = self.value.clone() {
70 let bound = Box::new(Constant::new(bound)) as Var<VStore>;
71 match self.mode {
72 Mode::Minimize => current.cstore.alloc(Box::new(XLessY::new(self.var.bclone(), bound.bclone()))),
73 Mode::Maximize => current.cstore.alloc(Box::new(x_greater_y(self.var.bclone(), bound.bclone()))),
74 };
75 }
76 let (mut immutable_state, status) = self.child.enter(current);
77 if status == Satisfiable {
78 let space = immutable_state.unfreeze();
79 self.value = Some(self.var.read(&space.vstore).lower());
80 immutable_state = space.freeze();
81 }
82 (immutable_state, status)
83 }
84}
85
86#[cfg(test)]
87mod test {
88 use super::*;
89 use search::test::*;
90 use search::engine::all_solution::*;
91 use search::engine::one_solution::*;
92 use search::propagation::*;
93 use search::branching::binary_split::*;
94 use search::branching::brancher::*;
95 use search::branching::first_smallest_var::*;
96 use search::branching::middle_val::*;
97 use interval::interval_set::*;
98 use gcollections::VectorStack;
99 use gcollections::ops::*;
100
101 #[test]
102 fn simple_maximize_test() {
103 simple_optimization_test(Mode::Maximize, 9);
104 }
105
106 #[test]
107 fn simple_minimize_test() {
108 simple_optimization_test(Mode::Minimize, 0);
109 }
110
111 fn simple_optimization_test(mode: Mode, expect: i32) {
112 let mut space = FDSpace::empty();
113 let x = Box::new(space.vstore.alloc((0,10).to_interval_set())) as Var<VStore>;
114 let y = Box::new(space.vstore.alloc((0,10).to_interval_set())) as Var<VStore>;
115 space.cstore.alloc(Box::new(XLessY::new(x.bclone(), y)));
116
117 let mut search: AllSolution<OneSolution<_, VectorStack<_>, FDSpace>>
118 = AllSolution::new(
119 OneSolution::new(
120 BranchAndBound::new(mode, x.bclone(),
121 Propagation::new(Brancher::new(FirstSmallestVar, MiddleVal, BinarySplit)))));
122 search.start(&space);
123 let (_, status) = search.enter(space);
124 assert_eq!(status, EndOfSearch);
125 assert_eq!(search.child.child.value, Some(expect));
126 }
127}
128