Skip to content

Commit 946c81d

Browse files
committed
'Dfs' and 'TarjanSCC' now take 'Ensure + GraphDeref' as input graphs.
'TarjanSCC::new' now only requires 'HasVertex'.
1 parent 310abff commit 946c81d

File tree

5 files changed

+139
-78
lines changed

5 files changed

+139
-78
lines changed

src/algo/dfs.rs

+61-34
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::core::{property::VertexIn, Graph};
1+
use crate::core::{property::VertexIn, Ensure, Graph, GraphDeref};
22
use std::borrow::Borrow;
33

44
/// Performs [depth-first traversal](https://mathworld.wolfram.com/Depth-FirstTraversal.html)
@@ -90,59 +90,71 @@ use std::borrow::Borrow;
9090
///
9191
/// [`next`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next
9292
/// [`get_vertex`]: ../core/property/trait.HasVertex.html#method.get_vertex
93-
pub struct Dfs<'a, G, F>
93+
pub struct Dfs<G, F>
9494
where
95-
G: 'a + Graph,
95+
G: Ensure + GraphDeref,
9696
{
9797
/// A reference to the graph being traversed.
9898
///
9999
/// This is use by `Dfs` when doing the traversal. Mutating
100100
/// this reference between calls to
101101
/// [`next`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next)
102102
/// is undefined behaviour.
103-
pub graph: &'a G,
103+
pub graph: G,
104104

105105
/// A custom payload, available to the function called upon a vertex exit.
106106
/// See [`new`](#method.new).
107107
pub payload: F,
108-
visited: Vec<G::Vertex>,
108+
visited: Vec<<G::Graph as Graph>::Vertex>,
109109

110110
/// The vertex on the stack, and whether on_exit should be called upon
111111
/// popping.
112-
stack: Vec<(G::Vertex, bool)>,
112+
stack: Vec<(<G::Graph as Graph>::Vertex, bool)>,
113113

114114
/// Function to call when visiting a vertex
115-
on_visit: fn(&mut Self, G::Vertex),
115+
on_visit: fn(&G::Graph, <G::Graph as Graph>::Vertex, &mut F),
116116

117117
/// Function to call when exiting a vertex.
118118
///
119119
/// Provides a reference to the graph, the vertex that is exiting,
120120
/// and a mutable reference to the payload given to the Dfs.
121-
on_exit: fn(&G, G::Vertex, &mut F),
121+
on_exit: fn(&G::Graph, <G::Graph as Graph>::Vertex, &mut F),
122122

123123
/// Function to call when exploring an edge.
124124
///
125125
/// When a vertex is being visited, this function is called for
126126
/// every outgoing edge, regardless of whether the sinked vertex
127127
/// (second vertex argument) has already been visited.
128-
on_explore: fn(&mut Self, G::Vertex, G::Vertex, &G::EdgeWeight),
128+
on_explore: fn(
129+
&G::Graph,
130+
<G::Graph as Graph>::Vertex,
131+
<G::Graph as Graph>::Vertex,
132+
&<G::Graph as Graph>::EdgeWeight,
133+
&mut F,
134+
),
129135
}
130136

131-
impl<'a, G, F> Dfs<'a, G, F>
137+
impl<G, F> Dfs<G, F>
132138
where
133-
G: 'a + Graph,
139+
G: Ensure + GraphDeref,
134140
{
135141
pub fn new(
136-
g: &'a G,
137-
on_visit: fn(&mut Self, G::Vertex),
138-
on_exit: fn(&G, G::Vertex, &mut F),
139-
on_explore: fn(&mut Self, G::Vertex, G::Vertex, &G::EdgeWeight),
142+
g: G,
143+
on_visit: fn(&G::Graph, <G::Graph as Graph>::Vertex, &mut F),
144+
on_exit: fn(&G::Graph, <G::Graph as Graph>::Vertex, &mut F),
145+
on_explore: fn(
146+
&G::Graph,
147+
<G::Graph as Graph>::Vertex,
148+
<G::Graph as Graph>::Vertex,
149+
&<G::Graph as Graph>::EdgeWeight,
150+
&mut F,
151+
),
140152
payload: F,
141153
) -> Self
142154
where
143-
G: VertexIn<1>,
155+
G::Graph: VertexIn<1>,
144156
{
145-
let v = g.vertex_at::<0>();
157+
let v = g.graph().vertex_at::<0>();
146158
let mut result = Self {
147159
graph: g,
148160
visited: Vec::new(),
@@ -157,16 +169,22 @@ where
157169
result
158170
}
159171

160-
fn visit(&mut self, to_return: G::Vertex)
172+
fn visit(&mut self, to_return: <G::Graph as Graph>::Vertex)
161173
{
162-
(self.on_visit)(self, to_return);
174+
(self.on_visit)(self.graph.graph(), to_return, &mut self.payload);
163175
// Mark visited
164176
self.visited.push(to_return);
165177

166178
// Explore children
167-
for (child, weight) in self.graph.edges_sourced_in(to_return.clone())
179+
for (child, weight) in self.graph.graph().edges_sourced_in(to_return.clone())
168180
{
169-
(self.on_explore)(self, to_return, child, weight.borrow());
181+
(self.on_explore)(
182+
self.graph.graph(),
183+
to_return,
184+
child,
185+
weight.borrow(),
186+
&mut self.payload,
187+
);
170188
if !self.visited(child.clone())
171189
{
172190
// Push to stack without exit mark
@@ -175,7 +193,7 @@ where
175193
}
176194
}
177195

178-
pub fn visited(&self, v: G::Vertex) -> bool
196+
pub fn visited(&self, v: <G::Graph as Graph>::Vertex) -> bool
179197
{
180198
self.visited.contains(&v)
181199
}
@@ -185,7 +203,7 @@ where
185203
///
186204
/// If there was nothing to pop and call `on_exit` on, return false,
187205
/// otherwise returns true.
188-
pub fn advance_next_exit(&mut self) -> Option<G::Vertex>
206+
pub fn advance_next_exit(&mut self) -> Option<<G::Graph as Graph>::Vertex>
189207
{
190208
while let Some(last) = self.stack.last()
191209
{
@@ -196,7 +214,7 @@ where
196214
// If its exit marked, call the closure on it.
197215
if last.1
198216
{
199-
(self.on_exit)(self.graph, last.0, &mut self.payload);
217+
(self.on_exit)(self.graph.graph(), last.0, &mut self.payload);
200218
return Some(last.0);
201219
}
202220
}
@@ -208,7 +226,7 @@ where
208226
None
209227
}
210228

211-
pub fn continue_from(&mut self, v: G::Vertex) -> bool
229+
pub fn continue_from(&mut self, v: <G::Graph as Graph>::Vertex) -> bool
212230
{
213231
if !self.visited(v.clone())
214232
{
@@ -221,16 +239,25 @@ where
221239
}
222240
}
223241

224-
pub fn do_nothing_on_visit(_: &mut Self, _: G::Vertex) {}
242+
pub fn do_nothing_on_visit(_: &G::Graph, _: <G::Graph as Graph>::Vertex, _: &mut F) {}
225243

226-
pub fn do_nothing_on_exit(_: &G, _: G::Vertex, _: &mut F) {}
244+
pub fn do_nothing_on_exit(_: &G::Graph, _: <G::Graph as Graph>::Vertex, _: &mut F) {}
227245

228-
pub fn do_nothing_on_explore(_: &mut Self, _: G::Vertex, _: G::Vertex, _: &G::EdgeWeight) {}
246+
pub fn do_nothing_on_explore(
247+
_: &G::Graph,
248+
_: <G::Graph as Graph>::Vertex,
249+
_: <G::Graph as Graph>::Vertex,
250+
_: &<G::Graph as Graph>::EdgeWeight,
251+
_: &mut F,
252+
)
253+
{
254+
}
229255
}
230256

231-
impl<'a, G> Dfs<'a, G, ()>
257+
impl<G> Dfs<G, ()>
232258
where
233-
G: 'a + VertexIn<1>,
259+
G: Ensure + GraphDeref,
260+
G::Graph: VertexIn<1>,
234261
{
235262
/// Constructs a new `Dfs` to traverse the specified graph.
236263
///
@@ -247,7 +274,7 @@ where
247274
///
248275
/// [`next`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next
249276
/// [`get_vertex`]: ../core/property/trait.HasVertex.html#method.get_vertex
250-
pub fn new_simple(g: &'a G) -> Self
277+
pub fn new_simple(g: G) -> Self
251278
{
252279
Self::new(
253280
g,
@@ -259,11 +286,11 @@ where
259286
}
260287
}
261288

262-
impl<'a, G, F> Iterator for Dfs<'a, G, F>
289+
impl<'a, G, F> Iterator for Dfs<G, F>
263290
where
264-
G: 'a + Graph,
291+
G: 'a + Ensure + GraphDeref,
265292
{
266-
type Item = G::Vertex;
293+
type Item = <G::Graph as Graph>::Vertex;
267294

268295
fn next(&mut self) -> Option<Self::Item>
269296
{

src/algo/tarjan_scc.rs

+64-30
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
//! reachable from this vertex. The lowlink value should be seen as the lowest
1212
//! index reachable.
1313
//!
14-
//! When a vertex is pushed in the stack, it is assigned an index. It is also
14+
//! When a vertex is pushed on the stack, it is assigned an index. It is also
1515
//! given a lowlink value equal to its index (since we know it can at least
1616
//! reach itself). When you are finished visiting the children of a vertex,
1717
//! check all vertices that are reachable from the current one. If they are on
@@ -51,9 +51,9 @@
5151
use crate::{
5252
algo::Dfs,
5353
core::{
54-
property::{ConnectedGraph, VertexIn},
54+
property::{ConnectedGraph, HasVertex, VertexInGraph},
5555
proxy::SubgraphProxy,
56-
Directed, Graph, Guard,
56+
Directed, Ensure, Graph, GraphDeref, Guard,
5757
},
5858
};
5959
use std::cmp::min;
@@ -105,7 +105,7 @@ use std::cmp::min;
105105
/// // Connect first SCC to second
106106
/// graph.add_edge(&v0,&v2).unwrap();
107107
///
108-
/// let graph = VertexInGraph::ensure(graph, [v0]).unwrap();
108+
/// let graph = VertexInGraph::<_>::ensure(graph, [v0]).unwrap();
109109
///
110110
/// // Initialize algorithm
111111
/// let mut tarj = TarjanScc::new(&graph);
@@ -146,20 +146,22 @@ use std::cmp::min;
146146
/// [`subgraphs`]: ../core/property/trait.Subgraph.html
147147
/// [`Subgraph`]: ../core/property/trait.Subgraph.html
148148
/// [`Subgraph::reaches`]: ../core/property/trait.Subgraph.html#method.reaches
149-
pub struct TarjanScc<'a, G>
149+
pub struct TarjanScc<G>
150150
where
151-
G: 'a + Graph<Directedness = Directed>,
151+
G: Ensure + GraphDeref,
152+
G::Graph: Graph<Directedness = Directed>,
152153
{
153-
dfs: Dfs<'a, G, Vec<(G::Vertex, usize)>>,
154+
dfs: Dfs<VertexInGraph<G>, Vec<(<G::Graph as Graph>::Vertex, usize)>>,
154155

155-
/// We use this to keep track of which vertices we have check for
156+
/// We use this to keep track of which vertices we have to check for
156157
/// whether they have been visited.
157-
unchecked: Box<dyn 'a + Iterator<Item = G::Vertex>>,
158+
unchecked: std::vec::IntoIter<<G::Graph as Graph>::Vertex>,
158159
}
159160

160-
impl<'a, G> TarjanScc<'a, G>
161+
impl<G> TarjanScc<G>
161162
where
162-
G: 'a + Graph<Directedness = Directed> + VertexIn<1>,
163+
G: Ensure + GraphDeref,
164+
G::Graph: Graph<Directedness = Directed> + HasVertex,
163165
{
164166
/// Constructs a new `TarjanScc` to find the [strongly connected components](https://mathworld.wolfram.com/StronglyConnectedComponent.html)
165167
/// of the specified graph.
@@ -177,7 +179,7 @@ where
177179
/// [`next`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next
178180
/// [`get_vertex`]:
179181
/// ../core/property/trait.HasVertex.html#tymethod.get_vertex
180-
pub fn new(graph: &'a G) -> Self
182+
pub fn new(graph: G) -> Self
181183
{
182184
/// Implements part of Tarjan's algorithm, namely what happens when we
183185
/// are finished visiting a vertex.
@@ -207,36 +209,37 @@ where
207209
}
208210
}
209211

212+
let v = graph.graph().any_vertex();
213+
let graph = VertexInGraph::ensure_unchecked(graph, [v]);
214+
let vs = graph.all_vertices().collect::<Vec<_>>();
215+
210216
// Push the start vertex on the stack with low-link = 0
211217
let dfs = Dfs::new(
212218
graph,
213-
Dfs::do_nothing_on_visit,
219+
Dfs::<VertexInGraph<_>, _>::do_nothing_on_visit,
214220
on_exit,
215-
Dfs::do_nothing_on_explore,
216-
vec![(graph.vertex_at::<0>(), 0)],
221+
Dfs::<VertexInGraph<_>, _>::do_nothing_on_explore,
222+
vec![(v, 0)],
217223
);
218224
Self {
219225
dfs,
220-
unchecked: Box::new(graph.all_vertices()),
226+
unchecked: vs.into_iter(),
221227
}
222228
}
223229
}
224230

225-
impl<'a, G> Iterator for TarjanScc<'a, G>
226-
where
227-
G: 'a + Graph<Directedness = Directed>,
228-
{
229-
type Item = ConnectedGraph<SubgraphProxy<&'a G>>;
230-
231-
fn next(&mut self) -> Option<Self::Item>
231+
macro_rules! next_scc_impl {
232232
{
233+
$self_tt:ident,
234+
$($return_code:tt)*
235+
} => {
233236
// Repeat until either an SCC is found or all vertices have been visited.
234237
loop
235238
{
236239
// For each vertex we are finished visiting, check if its the root of a SCC.
237-
while let Some(v) = self.dfs.advance_next_exit()
240+
while let Some(v) = $self_tt.dfs.advance_next_exit()
238241
{
239-
let stack = &mut self.dfs.payload;
242+
let stack = &mut $self_tt.dfs.payload;
240243

241244
// Find the index of the vertex
242245
let index = stack.iter().position(|(v2, _)| *v2 == v).unwrap();
@@ -245,7 +248,7 @@ where
245248
{
246249
// Vertex is root of SCC, pop stack for all before it
247250

248-
let mut scc = SubgraphProxy::new(self.dfs.graph);
251+
let mut scc = SubgraphProxy::new($self_tt.dfs.graph.0 $($return_code)*);
249252
while stack.len() > index
250253
{
251254
scc.expand(stack.pop().unwrap().0).unwrap();
@@ -261,20 +264,51 @@ where
261264
}
262265

263266
// No SCCs found, let the Dfs run once
264-
if let Some(v) = self.dfs.next()
267+
if let Some(v) = $self_tt.dfs.next()
265268
{
266269
// First push vertex onto stack, with lowlink value equal to its index
267-
let stack = &mut self.dfs.payload;
270+
let stack = &mut $self_tt.dfs.payload;
268271
stack.push((v.clone(), stack.len()));
269272
}
270273
else
271274
{
272-
let dfs = &mut self.dfs;
273-
if !self.unchecked.any(|v| dfs.continue_from(v))
275+
let dfs = &mut $self_tt.dfs;
276+
if !$self_tt.unchecked.any(|v| dfs.continue_from(v))
274277
{
275278
return None;
276279
}
277280
}
278281
}
279282
}
280283
}
284+
285+
impl<G> TarjanScc<G>
286+
where
287+
G: Ensure + GraphDeref,
288+
G::Graph: Graph<Directedness = Directed>,
289+
{
290+
/// Returns the next strongly connected component `TarjanScc` has found, if
291+
/// any.
292+
///
293+
/// This is similar to `next`, however can be used when `TarjanScc` receives
294+
/// a non-copy ensure.
295+
///
296+
///
297+
pub fn next_scc(&mut self) -> Option<ConnectedGraph<SubgraphProxy<&G::Graph>>>
298+
{
299+
next_scc_impl!(self, .graph())
300+
}
301+
}
302+
303+
impl<G> Iterator for TarjanScc<G>
304+
where
305+
G: Ensure + GraphDeref + Copy,
306+
G::Graph: Graph<Directedness = Directed>,
307+
{
308+
type Item = ConnectedGraph<SubgraphProxy<G>>;
309+
310+
fn next(&mut self) -> Option<Self::Item>
311+
{
312+
next_scc_impl!(self,)
313+
}
314+
}

0 commit comments

Comments
 (0)