1use crate::error::Result;
7use crate::traits::{Search, Traversal};
8use core::hash::{BuildHasher, Hash};
9use hashbrown::{DefaultHashBuilder, HashSet};
10use rshyper::idx::{HashIndex, HyperIndex, VertexId, VertexSet};
11use rshyper::rel::RawLayout;
12use rshyper::{GraphProps, HyperGraph};
13
14pub struct DepthFirstTraversal<'a, N, E, A, H, S = DefaultHashBuilder>
16where
17 A: GraphProps,
18 H: HyperGraph<N, E, A>,
19{
20 pub(crate) graph: &'a H,
21 pub(crate) stack: Vec<VertexId<A::Ix>>,
22 pub(crate) visited: VertexSet<A::Ix, S>,
23 _marker: core::marker::PhantomData<(N, E)>,
24}
25
26impl<'a, N, E, H, A, S> DepthFirstTraversal<'a, N, E, A, H, S>
27where
28 A: GraphProps,
29 H: HyperGraph<N, E, A>,
30 S: BuildHasher,
31{
32 pub fn new(graph: &'a H) -> Self
34 where
35 S: Default,
36 {
37 Self {
38 graph,
39 stack: Vec::new(),
40 visited: VertexSet::default(),
41 _marker: core::marker::PhantomData::<(N, E)>,
42 }
43 }
44 pub const fn stack(&self) -> &Vec<VertexId<A::Ix>> {
46 &self.stack
47 }
48 pub const fn stack_mut(&mut self) -> &mut Vec<VertexId<A::Ix>> {
50 &mut self.stack
51 }
52 pub const fn visited(&self) -> &VertexSet<A::Ix, S> {
54 &self.visited
55 }
56 pub const fn visited_mut(&mut self) -> &mut VertexSet<A::Ix, S> {
58 &mut self.visited
59 }
60 pub fn has_visited<Q>(&self, vertex: &Q) -> bool
62 where
63 A::Ix: Eq + Hash,
64 Q: ?Sized + Eq + Hash,
65 VertexId<A::Ix>: core::borrow::Borrow<Q>,
66 {
67 self.visited().contains(vertex)
68 }
69 pub fn reset(&mut self) -> &mut Self {
71 #[cfg(feature = "tracing")]
72 tracing::debug!("resetting the depth-first traversal operator state...");
73 self.stack_mut().clear();
75 self.visited_mut().clear();
77 self
78 }
79 pub fn search(
81 &mut self,
82 start: VertexId<A::Ix>,
83 ) -> Result<<Self as Search<VertexId<A::Ix>>>::Output>
84 where
85 Self: Search<VertexId<A::Ix>>,
86 A::Ix: HyperIndex,
87 {
88 Search::search(self, start)
89 }
90 pub(crate) fn register_vertex(&mut self, index: VertexId<A::Ix>) -> &mut Self
92 where
93 A::Ix: Copy + Eq + Hash,
94 {
95 self.stack_mut().push(index);
96 self.visited_mut().insert(index);
97 self
98 }
99}
100
101impl<'a, N, E, A, H, S> Traversal<VertexId<A::Ix>> for DepthFirstTraversal<'a, N, E, A, H, S>
102where
103 A: GraphProps,
104 H: HyperGraph<N, E, A>,
105 S: BuildHasher,
106 A::Ix: HashIndex,
107{
108 type Store<I2> = HashSet<I2, S>;
109
110 fn has_visited(&self, vertex: &VertexId<A::Ix>) -> bool {
111 self.visited().contains(vertex)
112 }
113
114 fn visited(&self) -> &Self::Store<VertexId<A::Ix>> {
115 &self.visited
116 }
117}
118
119impl<'a, N, E, A, H, S> Search<VertexId<A::Ix>> for DepthFirstTraversal<'a, N, E, A, H, S>
120where
121 A: GraphProps,
122 H: HyperGraph<N, E, A>,
123 S: BuildHasher,
124 A::Ix: HyperIndex,
125 for<'b> &'b <H::Edge<E> as RawLayout>::Store: IntoIterator<Item = &'b VertexId<A::Ix>>,
126{
127 type Output = Vec<VertexId<A::Ix>>;
128
129 fn search(&mut self, start: VertexId<A::Ix>) -> Result<Self::Output> {
130 self.reset();
132
133 if !self.graph.contains_node(&start) {
135 return Err(rshyper::Error::NodeNotFound.into());
136 }
137
138 self.register_vertex(start);
140
141 let mut path = Vec::new();
143
144 while let Some(current) = self.stack.pop() {
146 path.push(current);
147
148 for edge_id in self.graph.find_edges_with_node(¤t) {
150 let vertices = self.graph.get_edge_domain(edge_id).expect("Edge is empty");
151
152 let mut new_vertices = vertices
154 .into_iter()
155 .filter(|&v| !self.has_visited(v))
156 .copied()
157 .collect::<Vec<_>>();
158
159 new_vertices.sort_by(|&a, &b| b.cmp(a));
161
162 for v in new_vertices {
163 self.register_vertex(v);
165 }
166 }
167 }
168
169 Ok(path)
170 }
171}