Permalink
Browse files

[Search] Add a stop criterion on the number of nodes explored.

  • Loading branch information...
ptal committed Dec 1, 2017
1 parent 1237824 commit 8ac2566e163512a00f0068cf251305e3f3f5f5fa
@@ -52,48 +52,49 @@ impl<C, Space> SearchTreeVisitor<Space> for AllSolution<C> where
}
}
// #[cfg(test)]
// mod test {
// use super::*;
// use search::test::*;
// use search::monitor::*;
// use search::statistics::*;
// use search::engine::one_solution::*;
// use search::propagation::*;
// use search::branching::binary_split::*;
// use search::branching::brancher::*;
// use search::branching::first_smallest_var::*;
// use search::branching::middle_val::*;
// use gcollections::VectorStack;
// use gcollections::ops::*;
#[cfg(test)]
mod test {
use super::*;
use search::test::*;
use search::FDSpace;
use search::monitor::*;
use search::statistics::*;
use search::engine::one_solution::*;
use search::propagation::*;
use search::branching::binary_split::*;
use search::branching::brancher::*;
use search::branching::first_smallest_var::*;
use search::branching::middle_val::*;
use gcollections::VectorStack;
use gcollections::ops::*;
// #[test]
// fn example_nqueens() {
// // Data from Wikipedia.
// let nqueens_solution = vec![
// 1, 0, 0, 2, 10, 4, 40, 92, 352
// ];
#[test]
fn example_nqueens() {
// Data from Wikipedia.
let nqueens_solution = vec![
1, 0, 0, 2, 10, 4, 40, 92, 352
];
// for (n, sol) in nqueens_solution.into_iter().enumerate() {
// test_nqueens(n+1, sol, EndOfSearch);
// }
// }
for (n, sol) in nqueens_solution.into_iter().enumerate() {
test_nqueens(n+1, sol, EndOfSearch);
}
}
// fn test_nqueens(n: usize, sol_expected: usize, expect: Status<FDSpace>) {
// let mut space = FDSpace::empty();
// nqueens(n, &mut space);
fn test_nqueens(n: usize, sol_expected: usize, expect: Status<FDSpace>) {
let mut space = FDSpace::empty();
nqueens(n, &mut space);
// let mut statistics = Statistics::new();
// {
// let mut search: AllSolution<Monitor<Statistics,
// OneSolution<_, VectorStack<_>, FDSpace>>>
// =
// AllSolution::new(Monitor::new(&mut statistics,
// OneSolution::new(Propagation::new(Brancher::new(FirstSmallestVar, MiddleVal, BinarySplit)))));
// search.start(&space);
// let (_, status) = search.enter(space);
// assert_eq!(status, expect);
// }
// assert_eq!(statistics.num_solution, sol_expected);
// }
// }
let mut statistics = Statistics::new();
{
let mut search: AllSolution<Monitor<Statistics,
OneSolution<_, VectorStack<_>, FDSpace>>>
=
AllSolution::new(Monitor::new(&mut statistics,
OneSolution::new(Propagation::new(Brancher::new(FirstSmallestVar, MiddleVal, BinarySplit)))));
search.start(&space);
let (_, status) = search.enter(space);
assert_eq!(status, expect);
}
assert_eq!(statistics.num_solution, sol_expected);
}
}
@@ -108,44 +108,44 @@ impl<C, Q, Space> SearchTreeVisitor<Space> for OneSolution<C, Q, Space> where
}
}
// #[cfg(test)]
// mod test {
// use super::*;
// use search::test::*;
// use search::propagation::*;
// use search::branching::binary_split::*;
// use search::branching::brancher::*;
// use search::branching::first_smallest_var::*;
// use search::branching::middle_val::*;
// use gcollections::VectorStack;
// use gcollections::ops::*;
// use test::Bencher;
// #[test]
// fn example_nqueens() {
// test_nqueens(1, Satisfiable);
// test_nqueens(2, Unsatisfiable);
// test_nqueens(3, Unsatisfiable);
// for i in 4..12 {
// test_nqueens(i, Satisfiable);
// }
// }
// #[bench]
// fn bench_nqueens10(b: &mut Bencher) {
// b.iter(|| {
// test_nqueens(10, Satisfiable)
// });
// }
// fn test_nqueens(n: usize, expect: Status<FDSpace>) {
// let mut space = FDSpace::empty();
// nqueens(n, &mut space);
// let mut search: OneSolution<_, VectorStack<_>, FDSpace> =
// OneSolution::new(Propagation::new(Brancher::new(FirstSmallestVar, MiddleVal, BinarySplit)));
// search.start(&space);
// let (_, status) = search.enter(space);
// assert_eq!(status, expect);
// }
// }
#[cfg(test)]
mod test {
use super::*;
use search::test::*;
use search::propagation::*;
use search::branching::binary_split::*;
use search::branching::brancher::*;
use search::branching::first_smallest_var::*;
use search::branching::middle_val::*;
use gcollections::VectorStack;
use gcollections::ops::*;
use test::Bencher;
#[test]
fn example_nqueens() {
test_nqueens(1, Satisfiable);
test_nqueens(2, Unsatisfiable);
test_nqueens(3, Unsatisfiable);
for i in 4..12 {
test_nqueens(i, Satisfiable);
}
}
#[bench]
fn bench_nqueens10(b: &mut Bencher) {
b.iter(|| {
test_nqueens(10, Satisfiable)
});
}
fn test_nqueens(n: usize, expect: Status<FDSpace>) {
let mut space = FDSpace::empty();
nqueens(n, &mut space);
let mut search: OneSolution<_, VectorStack<_>, FDSpace> =
OneSolution::new(Propagation::new(Brancher::new(FirstSmallestVar, MiddleVal, BinarySplit)));
search.start(&space);
let (_, status) = search.enter(space);
assert_eq!(status, expect);
}
}
View
@@ -26,6 +26,7 @@ pub mod monitor;
pub mod statistics;
pub mod branch_and_bound;
pub mod debugger;
pub mod stop_node;
pub use search::space::*;
pub use search::search_tree_visitor::*;
@@ -49,33 +50,34 @@ pub fn one_solution_engine() -> Box<SearchTreeVisitor<FDSpace>> {
Box::new(search)
}
// #[cfg(test)]
// mod test {
// pub use super::*;
// use propagators::cmp::*;
// use propagators::distinct::*;
// use term::*;
// use gcollections::ops::*;
// use interval::interval_set::*;
#[cfg(test)]
mod test {
pub use super::*;
use propagators::cmp::*;
use propagators::distinct::*;
use term::*;
use gcollections::ops::*;
use interval::interval_set::*;
use concept::*;
// pub fn nqueens(n: usize, space: &mut FDSpace) {
// let mut queens = vec![];
// // 2 queens can't share the same line.
// for _ in 0..n {
// queens.push(space.vstore.alloc((1, n as i32).to_interval_set()));
// }
// for i in 0..n-1 {
// for j in i + 1..n {
// // 2 queens can't share the same diagonal.
// let q1 = (i + 1) as i32;
// let q2 = (j + 1) as i32;
// // Xi + i != Xj + j
// space.cstore.alloc(box XNeqY::new(queens[i].clone(), Addition::new(queens[j].clone(), q2 - q1)));
// // Xi - i != Xj - j
// space.cstore.alloc(box XNeqY::new(queens[i].clone(), Addition::new(queens[j].clone(), -q2 + q1)));
// }
// }
// // 2 queens can't share the same column.
// space.cstore.alloc(box Distinct::new(queens));
// }
// }
pub fn nqueens(n: usize, space: &mut FDSpace) {
let mut queens: Vec<Var<VStore>> = vec![];
// 2 queens can't share the same line.
for _ in 0..n {
queens.push(box space.vstore.alloc((1, n as i32).to_interval_set()));
}
for i in 0..n-1 {
for j in i + 1..n {
// 2 queens can't share the same diagonal.
let q1 = (i + 1) as i32;
let q2 = (j + 1) as i32;
// Xi + i != Xj + j
space.cstore.alloc(box XNeqY::new(queens[i].bclone(), box Addition::new(queens[j].bclone(), q2 - q1)));
// Xi - i != Xj - j
space.cstore.alloc(box XNeqY::new(queens[i].bclone(), box Addition::new(queens[j].bclone(), -q2 + q1)));
}
}
// 2 queens can't share the same column.
space.cstore.alloc(box Distinct::new(queens));
}
}
@@ -18,6 +18,11 @@ use search::search_tree_visitor::Status::*;
pub trait SearchMonitor<Space: Freeze> {
fn on_node(&mut self, space: &Space, status: &Status<Space>) {
self.dispatch_node(space, status)
}
fn dispatch_node(&mut self, space: &Space, status: &Status<Space>)
{
match status {
&Satisfiable => self.on_solution(space),
&Unsatisfiable => self.on_failure(space),
@@ -14,24 +14,33 @@
use kernel::*;
use search::monitor::*;
use search::search_tree_visitor::Status;
pub struct Statistics {
pub num_solution: usize,
pub num_failed_node: usize,
pub num_prune: usize
pub num_prune: usize,
pub num_nodes: usize
}
impl Statistics {
pub fn new() -> Self {
Statistics {
num_solution: 0,
num_failed_node: 0,
num_prune: 0
num_prune: 0,
num_nodes: 0
}
}
}
impl<Space:Freeze> SearchMonitor<Space> for Statistics {
fn on_node(&mut self, space: &Space, status: &Status<Space>) {
println!("\n\nLLLL\n\n");
self.num_nodes += 1;
self.dispatch_node(space, status)
}
fn on_solution(&mut self, _space: &Space) {
self.num_solution += 1;
}
@@ -0,0 +1,98 @@
// Copyright 2017 Pierre Talbot (IRCAM)
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use kernel::*;
use search::space::*;
use search::search_tree_visitor::*;
use concept::*;
pub struct StopNode<C> {
child: C,
limit: usize,
nodes_explored: usize
}
impl<C> StopNode<C> {
pub fn new(limit: usize, child: C) -> StopNode<C> {
StopNode {
child: child,
limit: limit,
nodes_explored: 0
}
}
}
impl<VStore, CStore, R, C> SearchTreeVisitor<Space<VStore, CStore, R>> for StopNode<C> where
VStore: VStoreConcept,
CStore: IntCStore<VStore>,
C: SearchTreeVisitor<Space<VStore, CStore, R>>,
R: FreezeSpace<VStore, CStore> + Snapshot<State=Space<VStore, CStore, R>>
{
fn start(&mut self, root: &Space<VStore, CStore, R>) {
self.child.start(root);
}
fn enter(&mut self, current: Space<VStore, CStore, R>)
-> (<Space<VStore, CStore, R> as Freeze>::FrozenState, Status<Space<VStore, CStore, R>>)
{
let (space, status) = self.child.enter(current);
self.nodes_explored += 1;
// If we reached the limit, we stop the search by changing the status.
if self.nodes_explored >= self.limit {
(space, Status::EndOfSearch)
}
else {
(space, status)
}
}
}
#[cfg(test)]
mod test {
use super::*;
use search::test::*;
use search::FDSpace;
use search::monitor::*;
use search::statistics::*;
use search::engine::one_solution::*;
use search::engine::all_solution::*;
use search::propagation::*;
use search::branching::binary_split::*;
use search::branching::brancher::*;
use search::branching::first_smallest_var::*;
use search::branching::middle_val::*;
use gcollections::VectorStack;
use gcollections::ops::*;
#[test]
fn test_stop() {
let n = 6;
let mut space = FDSpace::empty();
nqueens(n, &mut space);
let nodes_limit = 10;
let mut statistics = Statistics::new();
{
let mut search: AllSolution<OneSolution<_, VectorStack<_>, FDSpace>>
=
AllSolution::new(OneSolution::new(
Monitor::new(&mut statistics, StopNode::new(nodes_limit,
Propagation::new(Brancher::new(FirstSmallestVar, MiddleVal, BinarySplit))))));
search.start(&space);
let (_, status) = search.enter(space);
assert_eq!(status, Status::EndOfSearch);
}
assert_eq!(statistics.num_nodes, nodes_limit);
}
}

0 comments on commit 8ac2566

Please sign in to comment.