First revision of search stack.

This commit is contained in:
Stu Black 2016-03-20 14:54:51 -04:00
parent 2a90dce9e2
commit ed9b4001ce
4 changed files with 209 additions and 0 deletions

View File

@ -1,3 +1,4 @@
pub mod base;
pub mod nav;
pub mod mutators;

View File

@ -7,6 +7,8 @@ use ::hidden::base::*;
use ::hidden::nav::{ChildList, ChildListIter, Edge, Node, ParentList, ParentListIter};
use ::hidden::nav::{make_child_list, make_edge, make_node, make_parent_list};
pub mod stack;
/// Mutable handle to a graph vertex ("node handle").
///
/// This zipper-like type enables traversal of a graph along the vertex's

View File

@ -0,0 +1,205 @@
use std::clone::Clone;
use std::cmp::Eq;
use std::error::Error;
use std::fmt;
use std::hash::Hash;
use std::iter::Iterator;
use ::{Graph, Target};
use ::hidden::base::*;
use ::hidden::mutators::MutNode;
use ::hidden::nav::{Edge, Node, make_edge, make_node};
enum Head {
Vertex(StateId),
Unexpanded(ArcId),
}
#[derive(Debug)]
pub enum SearchError<E> where E: Error {
Unexpanded,
ChildBounds(usize, usize),
ParentBounds(usize, usize),
PredicateError(E),
}
impl<E> fmt::Display for SearchError<E> where E: Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
SearchError::Unexpanded => write!(f, "Stack head is unexpanded"),
SearchError::ChildBounds(i, len) => write!(f, "Search chose child {}/{}", i, len),
SearchError::ParentBounds(i, len) => write!(f, "Search chose parent {}/{}", i, len),
SearchError::PredicateError(ref e) => write!(f, "Error in search predicate: {}", e),
}
}
}
impl<E> Error for SearchError<E> where E: Error {
fn description(&self) -> &str {
match *self {
SearchError::Unexpanded => "unexpanded",
SearchError::ChildBounds(_, _) => "child out of bounds",
SearchError::ParentBounds(_, _) => "parent out of bounds",
SearchError::PredicateError(ref e) => e.description(),
}
}
fn cause(&self) -> Option<&Error> {
match *self {
SearchError::PredicateError(ref e) => Some(e),
_ => None,
}
}
}
pub struct SearchStack<'a, T, S, A> where T: 'a + Hash + Eq + Clone, S: 'a, A: 'a {
graph: &'a mut Graph<T, S, A>,
stack: Vec<(StateId, ArcId)>,
head: Head,
}
pub struct SearchStackIter<'a, 's, T, S, A> where T: 'a + Hash + Eq + Clone, S: 'a, A: 'a, 'a: 's {
stack: &'s SearchStack<'a, T, S, A>,
position: usize,
exhausted: bool,
}
pub enum StackItem<'a, T, S, A> where T: 'a + Hash + Eq + Clone, S: 'a, A: 'a {
Item(Node<'a, T, S, A>, Edge<'a, T, S, A>),
Head(Target<Node<'a, T, S, A>, Edge<'a, T, S, A>>),
}
impl<'a, T, S, A> SearchStack<'a, T, S, A> where T: 'a + Hash + Eq + Clone, S: 'a, A: 'a {
pub fn new(node: MutNode<'a, T, S, A>) -> Self {
SearchStack {
graph: node.graph,
stack: Vec::new(),
head: Head::Vertex(node.id),
}
}
pub fn len(&self) -> usize {
self.stack.len() + 1
}
pub fn pop(&mut self) -> bool {
match self.stack.pop() {
Some((new_head, _)) => {
self.head = Head::Vertex(new_head);
true
},
None => false,
}
}
pub fn head<'s>(&'s self) -> Target<Node<'s, T, S, A>, Edge<'s, T, S, A>> {
match self.head {
Head::Vertex(id) => Target::Expanded(make_node(self.graph, id)),
Head::Unexpanded(id) => Target::Unexpanded(make_edge(self.graph, id)),
}
}
pub fn is_head_expanded(&self) -> bool {
match self.head {
Head::Vertex(_) => true,
Head::Unexpanded(_) => false,
}
}
pub fn push_child<'s, F, E>(&'s mut self, f: F)
-> Result<Option<Edge<'s, T, S, A>>, SearchError<E>>
where F: Fn(Node<'s, T, S, A>) -> Result<Option<usize>, E>, E: Error {
match self.head {
Head::Vertex(head_id) => {
let node = make_node(self.graph, head_id);
let children = node.get_child_list();
match f(node) {
Ok(Some(i)) if i >= children.len() =>
Err(SearchError::ChildBounds(i, children.len())),
Ok(Some(i)) => {
let child = children.get_edge(i);
self.stack.push((head_id, ArcId(child.get_id())));
self.head = match child.get_target() {
Target::Expanded(n) => Head::Vertex(StateId(n.get_id())),
Target::Unexpanded(()) => Head::Unexpanded(ArcId(child.get_id())),
};
Ok(Some(child))
},
Ok(None) => Ok(None),
Err(e) => Err(SearchError::PredicateError(e)),
}
},
Head::Unexpanded(_) => Err(SearchError::Unexpanded),
}
}
pub fn push_parent<'s, F, E>(&'s mut self, f: F)
-> Result<Option<Edge<'s, T, S, A>>, SearchError<E>>
where F: Fn(Node<'s, T, S, A>) -> Result<Option<usize>, E>, E: Error {
match self.head {
Head::Vertex(head_id) => {
let node = make_node(self.graph, head_id);
let parents = node.get_parent_list();
match f(node) {
Ok(Some(i)) if i >= parents.len() =>
Err(SearchError::ParentBounds(i, parents.len())),
Ok(Some(i)) => {
let parent = parents.get_edge(i);
self.stack.push((head_id, ArcId(parent.get_id())));
self.head = match parent.get_target() {
Target::Expanded(n) => Head::Vertex(StateId(n.get_id())),
Target::Unexpanded(()) => Head::Unexpanded(ArcId(parent.get_id())),
};
Ok(Some(parent))
},
Ok(None) => Ok(None),
Err(e) => Err(SearchError::PredicateError(e)),
}
},
Head::Unexpanded(_) => Err(SearchError::Unexpanded),
}
}
pub fn iter<'s>(&'s self) -> SearchStackIter<'a, 's, T, S, A> {
SearchStackIter::new(self)
}
}
impl<'a, 's, T, S, A> SearchStackIter<'a, 's, T, S, A> where T: 'a + Hash + Eq + Clone, S: 'a, A: 'a, 'a: 's {
fn new(stack: &'s SearchStack<'a, T, S, A>) -> Self {
SearchStackIter {
stack: stack,
position: 0,
exhausted: false,
}
}
}
impl<'a, 's, T, S, A> Iterator for SearchStackIter<'a, 's, T, S, A>
where T: 'a + Hash + Eq + Clone, S: 'a, A: 'a, 'a: 's {
type Item = StackItem<'s, T, S, A>;
fn next(&mut self) -> Option<StackItem<'s, T, S, A>> {
if self.position >= self.stack.stack.len() {
if self.exhausted {
None
} else {
self.exhausted = true;
Some(StackItem::Head(match self.stack.head {
Head::Vertex(id) => Target::Expanded(make_node(self.stack.graph, id)),
Head::Unexpanded(id) => Target::Unexpanded(make_edge(self.stack.graph, id)),
}))
}
} else {
let (state_id, edge_id) = self.stack.stack[self.position];
self.position += 1;
Some(StackItem::Item(make_node(self.stack.graph, state_id),
make_edge(self.stack.graph, edge_id)))
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.stack.len() - self.position - (if self.exhausted { 1 } else { 0 });
(len, Some(len))
}
}

View File

@ -8,6 +8,7 @@ use self::hidden::mutators::make_mut_node;
pub use self::hidden::nav::{ChildList, ChildListIter, Edge, Node, ParentList, ParentListIter};
pub use self::hidden::mutators::{EdgeExpander, MutChildList, MutEdge, MutNode, MutParentList};
pub use self::hidden::mutators::stack::{SearchError, SearchStack, SearchStackIter};
/// A search graph.
///