/rust/registry/src/index.crates.io-1949cf8c6b5b557f/petgraph-0.8.3/src/acyclic.rs
Line | Count | Source |
1 | | //! A wrapper around graph types that enforces an acyclicity invariant. |
2 | | |
3 | | use alloc::collections::{BTreeMap, BTreeSet}; |
4 | | use core::{ |
5 | | cell::RefCell, |
6 | | cmp::Ordering, |
7 | | convert::TryFrom, |
8 | | ops::{Deref, RangeBounds}, |
9 | | }; |
10 | | |
11 | | use crate::{ |
12 | | adj::IndexType, |
13 | | algo::Cycle, |
14 | | data::{Build, Create, DataMap, DataMapMut}, |
15 | | graph::NodeIndex, |
16 | | prelude::DiGraph, |
17 | | visit::{ |
18 | | dfs_visitor, Control, Data, DfsEvent, EdgeCount, EdgeIndexable, GetAdjacencyMatrix, |
19 | | GraphBase, GraphProp, IntoEdgeReferences, IntoEdges, IntoEdgesDirected, IntoNeighbors, |
20 | | IntoNeighborsDirected, IntoNodeIdentifiers, IntoNodeReferences, NodeCompactIndexable, |
21 | | NodeCount, NodeIndexable, Reversed, Time, Visitable, |
22 | | }, |
23 | | Direction, |
24 | | }; |
25 | | |
26 | | #[cfg(feature = "stable_graph")] |
27 | | use crate::stable_graph::StableDiGraph; |
28 | | |
29 | | mod order_map; |
30 | | use fixedbitset::FixedBitSet; |
31 | | use order_map::OrderMap; |
32 | | pub use order_map::TopologicalPosition; |
33 | | |
34 | | /// A directed acyclic graph. |
35 | | /// |
36 | | /// Wrap directed acyclic graphs and expose an API that ensures the invariant |
37 | | /// is maintained, i.e. no cycles can be created. This uses a topological order |
38 | | /// that is dynamically updated when edges are added. In the worst case, the |
39 | | /// runtime may be linear in the number of vertices, but it has been shown to |
40 | | /// be fast in practice, particularly on sparse graphs (Pierce and Kelly, 2004). |
41 | | /// |
42 | | /// To be modifiable (and hence to be useful), the graphs of generic type `G` |
43 | | /// should implement the [`Build`] trait. Good candidates for `G` are thus |
44 | | /// [`crate::graph::DiGraph`] and [`crate::stable_graph::StableDiGraph`]. |
45 | | /// |
46 | | /// ## Algorithm |
47 | | /// This implements the PK algorithm for dynamic topological sort described in |
48 | | /// "A Dynamic Topological Sort Algorithm for Directed Acyclic Graphs" by |
49 | | /// D. Pierce and P. Kelly, JEA, 2004. It maintains a topological order of the |
50 | | /// nodes that can be efficiently updated when edges are added. Achieves a good |
51 | | /// balance between simplicity and performance in practice, see the paper for |
52 | | /// discussions of the running time. |
53 | | /// |
54 | | /// ## Graph traits |
55 | | /// All graph traits are delegated to the inner graph, with the exception of |
56 | | /// the graph construction trait [`Build`]. The wrapped graph can thus only |
57 | | /// be modified through the wrapped API that ensures no cycles are created. |
58 | | /// |
59 | | /// ## Behaviour on cycles |
60 | | /// By design, edge additions to this datatype may fail. It is recommended to |
61 | | /// prefer the dedicated [`Acyclic::try_add_edge`] and |
62 | | /// [`Acyclic::try_update_edge`] methods whenever possible. The |
63 | | /// [`Build::update_edge`] methods will panic if it is attempted to add an edge |
64 | | /// that would create a cycle. The [`Build::add_edge`] on the other hand method |
65 | | /// will return `None` if the edge cannot be added (either it already exists on |
66 | | /// a graph type that does not support it or would create a cycle). |
67 | | #[derive(Clone, Debug)] |
68 | | pub struct Acyclic<G: Visitable> { |
69 | | /// The underlying graph, accessible through the `inner` method. |
70 | | graph: G, |
71 | | /// The current topological order of the nodes. |
72 | | order_map: OrderMap<G::NodeId>, |
73 | | |
74 | | // We fix the internal DFS maps to FixedBitSet instead of G::VisitMap to do |
75 | | // faster resets (by just setting bits to false) |
76 | | /// Helper map for DFS tracking discovered nodes. |
77 | | discovered: RefCell<FixedBitSet>, |
78 | | /// Helper map for DFS tracking finished nodes. |
79 | | finished: RefCell<FixedBitSet>, |
80 | | } |
81 | | |
82 | | /// An error that can occur during edge addition for acyclic graphs. |
83 | | #[derive(Clone, Debug, PartialEq)] |
84 | | pub enum AcyclicEdgeError<N> { |
85 | | /// The edge would create a cycle. |
86 | | Cycle(Cycle<N>), |
87 | | /// The edge would create a self-loop. |
88 | | SelfLoop, |
89 | | /// Could not successfully add the edge to the underlying graph. |
90 | | InvalidEdge, |
91 | | } |
92 | | |
93 | | impl<N> From<Cycle<N>> for AcyclicEdgeError<N> { |
94 | 0 | fn from(cycle: Cycle<N>) -> Self { |
95 | 0 | AcyclicEdgeError::Cycle(cycle) |
96 | 0 | } |
97 | | } |
98 | | |
99 | | impl<G: Visitable> Acyclic<G> { |
100 | | /// Create a new empty acyclic graph. |
101 | 0 | pub fn new() -> Self |
102 | 0 | where |
103 | 0 | G: Default, |
104 | | { |
105 | 0 | Default::default() |
106 | 0 | } |
107 | | |
108 | | /// Get an iterator over the nodes, ordered by their position. |
109 | 0 | pub fn nodes_iter(&self) -> impl Iterator<Item = G::NodeId> + '_ { |
110 | 0 | self.order_map.nodes_iter() |
111 | 0 | } |
112 | | |
113 | | /// Get an iterator over the nodes within the range of positions. |
114 | | /// |
115 | | /// The nodes are ordered by their position in the topological sort. |
116 | 0 | pub fn range<'r>( |
117 | 0 | &'r self, |
118 | 0 | range: impl RangeBounds<TopologicalPosition> + 'r, |
119 | 0 | ) -> impl Iterator<Item = G::NodeId> + 'r { |
120 | 0 | self.order_map.range(range) |
121 | 0 | } |
122 | | |
123 | | /// Get the underlying graph. |
124 | 0 | pub fn inner(&self) -> &G { |
125 | 0 | &self.graph |
126 | 0 | } |
127 | | |
128 | | /// Get the underlying graph mutably. |
129 | | /// |
130 | | /// This cannot be public because it might break the acyclicity invariant. |
131 | 0 | fn inner_mut(&mut self) -> &mut G { |
132 | 0 | &mut self.graph |
133 | 0 | } |
134 | | |
135 | | /// Consume the `Acyclic` wrapper and return the underlying graph. |
136 | 0 | pub fn into_inner(self) -> G { |
137 | 0 | self.graph |
138 | 0 | } |
139 | | } |
140 | | |
141 | | impl<G: Visitable + NodeIndexable> Acyclic<G> |
142 | | where |
143 | | for<'a> &'a G: IntoNeighborsDirected + IntoNodeIdentifiers + GraphBase<NodeId = G::NodeId>, |
144 | | { |
145 | | /// Wrap a graph into an acyclic graph. |
146 | | /// |
147 | | /// The graph types [`DiGraph`] and [`StableDiGraph`] also implement |
148 | | /// [`TryFrom`], which can be used instead of this method and have looser |
149 | | /// type bounds. |
150 | 0 | pub fn try_from_graph(graph: G) -> Result<Self, Cycle<G::NodeId>> { |
151 | 0 | let order_map = OrderMap::try_from_graph(&graph)?; |
152 | 0 | let discovered = RefCell::new(FixedBitSet::with_capacity(graph.node_bound())); |
153 | 0 | let finished = RefCell::new(FixedBitSet::with_capacity(graph.node_bound())); |
154 | 0 | Ok(Self { |
155 | 0 | graph, |
156 | 0 | order_map, |
157 | 0 | discovered, |
158 | 0 | finished, |
159 | 0 | }) |
160 | 0 | } |
161 | | |
162 | | /// Add an edge to the graph using [`Build::add_edge`]. |
163 | | /// |
164 | | /// Returns the id of the added edge, or an [`AcyclicEdgeError`] if the edge |
165 | | /// would create a cycle, a self-loop or if the edge addition failed in |
166 | | /// the underlying graph. |
167 | | /// |
168 | | /// In cases where edge addition using [`Build::add_edge`] cannot fail in |
169 | | /// the underlying graph (e.g. when multi-edges are allowed, as in |
170 | | /// [`DiGraph`] and [`StableDiGraph`]), this will return an error if and |
171 | | /// only if [`Self::is_valid_edge`] returns `false`. |
172 | | /// |
173 | | /// Note that for some graph types, the semantics of [`Build::add_edge`] may |
174 | | /// not coincide with the semantics of the `add_edge` method provided by the |
175 | | /// graph type. |
176 | | /// |
177 | | /// **Panics** if `a` or `b` are not found. |
178 | | #[track_caller] |
179 | 0 | pub fn try_add_edge( |
180 | 0 | &mut self, |
181 | 0 | a: G::NodeId, |
182 | 0 | b: G::NodeId, |
183 | 0 | weight: G::EdgeWeight, |
184 | 0 | ) -> Result<G::EdgeId, AcyclicEdgeError<G::NodeId>> |
185 | 0 | where |
186 | 0 | G: Build, |
187 | 0 | G::NodeId: IndexType, |
188 | | { |
189 | 0 | if a == b { |
190 | | // No self-loops allowed |
191 | 0 | return Err(AcyclicEdgeError::SelfLoop); |
192 | 0 | } |
193 | 0 | self.update_ordering(a, b)?; |
194 | 0 | self.graph |
195 | 0 | .add_edge(a, b, weight) |
196 | 0 | .ok_or(AcyclicEdgeError::InvalidEdge) |
197 | 0 | } |
198 | | |
199 | | /// Add or update an edge in a graph using [`Build::update_edge`]. |
200 | | /// |
201 | | /// Returns the id of the updated edge, or an [`AcyclicEdgeError`] if the edge |
202 | | /// would create a cycle or a self-loop. If the edge does not exist, the |
203 | | /// edge is created. |
204 | | /// |
205 | | /// This will return an error if and only if [`Self::is_valid_edge`] returns |
206 | | /// `false`. |
207 | | /// |
208 | | /// **Panics** if `a` or `b` are not found. |
209 | 0 | pub fn try_update_edge( |
210 | 0 | &mut self, |
211 | 0 | a: G::NodeId, |
212 | 0 | b: G::NodeId, |
213 | 0 | weight: G::EdgeWeight, |
214 | 0 | ) -> Result<G::EdgeId, AcyclicEdgeError<G::NodeId>> |
215 | 0 | where |
216 | 0 | G: Build, |
217 | 0 | G::NodeId: IndexType, |
218 | | { |
219 | 0 | if a == b { |
220 | | // No self-loops allowed |
221 | 0 | return Err(AcyclicEdgeError::SelfLoop); |
222 | 0 | } |
223 | 0 | self.update_ordering(a, b)?; |
224 | 0 | Ok(self.graph.update_edge(a, b, weight)) |
225 | 0 | } |
226 | | |
227 | | /// Check if an edge would be valid, i.e. adding it would not create a cycle. |
228 | | /// |
229 | | /// **Panics** if `a` or `b` are not found. |
230 | 0 | pub fn is_valid_edge(&self, a: G::NodeId, b: G::NodeId) -> bool |
231 | 0 | where |
232 | 0 | G::NodeId: IndexType, |
233 | | { |
234 | 0 | if a == b { |
235 | 0 | false // No self-loops |
236 | 0 | } else if self.get_position(a) < self.get_position(b) { |
237 | 0 | true // valid edge in the current topological order |
238 | | } else { |
239 | | // Check if the future of `b` is disjoint from the past of `a` |
240 | | // (in which case the topological order could be adjusted) |
241 | 0 | self.causal_cones(b, a).is_ok() |
242 | | } |
243 | 0 | } |
244 | | |
245 | | /// Update the ordering of the nodes in the order map resulting from adding an |
246 | | /// edge a -> b. |
247 | | /// |
248 | | /// If a cycle is detected, an error is returned and `self` remains unchanged. |
249 | | /// |
250 | | /// Implements the core update logic of the PK algorithm. |
251 | | #[track_caller] |
252 | 0 | fn update_ordering(&mut self, a: G::NodeId, b: G::NodeId) -> Result<(), Cycle<G::NodeId>> |
253 | 0 | where |
254 | 0 | G::NodeId: IndexType, |
255 | | { |
256 | 0 | let min_order = self.get_position(b); |
257 | 0 | let max_order = self.get_position(a); |
258 | 0 | if min_order >= max_order { |
259 | | // Order is already correct |
260 | 0 | return Ok(()); |
261 | 0 | } |
262 | | |
263 | | // Get the nodes reachable from `b` and the nodes that can reach `a` |
264 | | // between `min_order` and `max_order` |
265 | 0 | let (b_fut, a_past) = self.causal_cones(b, a)?; |
266 | | |
267 | | // Now reorder of nodes in a_past and b_fut such that |
268 | | // i) within each vec, the nodes are in topological order, |
269 | | // ii) all elements of b_fut come before all elements of a_past in the new order. |
270 | 0 | let all_positions: BTreeSet<_> = b_fut.keys().chain(a_past.keys()).copied().collect(); |
271 | 0 | let all_nodes = a_past.values().chain(b_fut.values()).copied(); |
272 | | |
273 | 0 | debug_assert_eq!(all_positions.len(), b_fut.len() + a_past.len()); |
274 | | |
275 | 0 | for (pos, node) in all_positions.into_iter().zip(all_nodes) { |
276 | 0 | self.order_map.set_position(node, pos, &self.graph); |
277 | 0 | } |
278 | 0 | Ok(()) |
279 | 0 | } |
280 | | |
281 | | /// Use DFS to find the future causal cone of `min_node` and the past causal |
282 | | /// cone of `max_node`. |
283 | | /// |
284 | | /// The cones are trimmed to the range `[min_order, max_order]`. The cones |
285 | | /// are returned if they are disjoint. Otherwise, a [`Cycle`] error is returned. |
286 | | /// |
287 | | /// If `return_result` is false, then the cones are not constructed and the |
288 | | /// method only checks for disjointedness. |
289 | | #[allow(clippy::type_complexity)] |
290 | 0 | fn causal_cones( |
291 | 0 | &self, |
292 | 0 | min_node: G::NodeId, |
293 | 0 | max_node: G::NodeId, |
294 | 0 | ) -> Result< |
295 | 0 | ( |
296 | 0 | BTreeMap<TopologicalPosition, G::NodeId>, |
297 | 0 | BTreeMap<TopologicalPosition, G::NodeId>, |
298 | 0 | ), |
299 | 0 | Cycle<G::NodeId>, |
300 | 0 | > |
301 | 0 | where |
302 | 0 | G::NodeId: IndexType, |
303 | | { |
304 | 0 | debug_assert!(self.discovered.borrow().is_clear()); |
305 | 0 | debug_assert!(self.finished.borrow().is_clear()); |
306 | | |
307 | 0 | let min_order = self.get_position(min_node); |
308 | 0 | let max_order = self.get_position(max_node); |
309 | | |
310 | | // Prepare DFS scratch space: make sure the maps have enough capacity |
311 | 0 | if self.discovered.borrow().len() < self.graph.node_bound() { |
312 | 0 | self.discovered.borrow_mut().grow(self.graph.node_bound()); |
313 | 0 | self.finished.borrow_mut().grow(self.graph.node_bound()); |
314 | 0 | } |
315 | | |
316 | | // Get all nodes reachable from b with min_order <= order < max_order |
317 | 0 | let mut forward_cone = BTreeMap::new(); |
318 | 0 | let mut backward_cone = BTreeMap::new(); |
319 | | |
320 | | // The main logic: run DFS twice. We run this in a closure to catch |
321 | | // errors and reset the maps properly at the end. |
322 | 0 | let mut run_dfs = || { |
323 | | // Get all nodes reachable from min_node with min_order < order <= max_order |
324 | 0 | self.future_cone(min_node, min_order, max_order, &mut forward_cone)?; |
325 | | |
326 | | // Get all nodes that can reach a with min_order < order <= max_order |
327 | | // These are disjoint from the nodes in the forward cone, otherwise |
328 | | // we would have a cycle. |
329 | 0 | self.past_cone(max_node, min_order, max_order, &mut backward_cone) |
330 | 0 | .expect("cycles already checked in future_cone"); |
331 | | |
332 | 0 | Ok(()) |
333 | 0 | }; |
334 | | |
335 | 0 | let success = run_dfs(); |
336 | | |
337 | | // Cleanup: reset map to 0. This is faster than a full reset, especially |
338 | | // on large sparse graphs. |
339 | 0 | for &v in forward_cone.values().chain(backward_cone.values()) { |
340 | 0 | self.discovered.borrow_mut().set(v.index(), false); |
341 | 0 | self.finished.borrow_mut().set(v.index(), false); |
342 | 0 | } |
343 | 0 | debug_assert!(self.discovered.borrow().is_clear()); |
344 | 0 | debug_assert!(self.finished.borrow().is_clear()); |
345 | | |
346 | 0 | match success { |
347 | 0 | Ok(()) => Ok((forward_cone, backward_cone)), |
348 | 0 | Err(cycle) => Err(cycle), |
349 | | } |
350 | 0 | } |
351 | | |
352 | 0 | fn future_cone( |
353 | 0 | &self, |
354 | 0 | start: G::NodeId, |
355 | 0 | min_position: TopologicalPosition, |
356 | 0 | max_position: TopologicalPosition, |
357 | 0 | res: &mut BTreeMap<TopologicalPosition, G::NodeId>, |
358 | 0 | ) -> Result<(), Cycle<G::NodeId>> |
359 | 0 | where |
360 | 0 | G::NodeId: IndexType, |
361 | | { |
362 | 0 | dfs( |
363 | 0 | &self.graph, |
364 | 0 | start, |
365 | 0 | &self.order_map, |
366 | 0 | |order| { |
367 | 0 | debug_assert!(order >= min_position, "invalid topological order"); |
368 | 0 | match order.cmp(&max_position) { |
369 | 0 | Ordering::Less => Ok(true), // node within [min_node, max_node] |
370 | 0 | Ordering::Equal => Err(Cycle(start)), // cycle! |
371 | 0 | Ordering::Greater => Ok(false), // node beyond [min_node, max_node] |
372 | | } |
373 | 0 | }, |
374 | 0 | res, |
375 | 0 | &mut self.discovered.borrow_mut(), |
376 | 0 | &mut self.finished.borrow_mut(), |
377 | | ) |
378 | 0 | } |
379 | | |
380 | 0 | fn past_cone( |
381 | 0 | &self, |
382 | 0 | start: G::NodeId, |
383 | 0 | min_position: TopologicalPosition, |
384 | 0 | max_position: TopologicalPosition, |
385 | 0 | res: &mut BTreeMap<TopologicalPosition, G::NodeId>, |
386 | 0 | ) -> Result<(), Cycle<G::NodeId>> |
387 | 0 | where |
388 | 0 | G::NodeId: IndexType, |
389 | | { |
390 | 0 | dfs( |
391 | 0 | Reversed(&self.graph), |
392 | 0 | start, |
393 | 0 | &self.order_map, |
394 | 0 | |order| { |
395 | 0 | debug_assert!(order <= max_position, "invalid topological order"); |
396 | 0 | match order.cmp(&min_position) { |
397 | 0 | Ordering::Less => Ok(false), // node beyond [min_node, max_node] |
398 | 0 | Ordering::Equal => unreachable!("checked by future_cone"), // cycle! |
399 | 0 | Ordering::Greater => Ok(true), // node within [min_node, max_node] |
400 | | } |
401 | 0 | }, |
402 | 0 | res, |
403 | 0 | &mut self.discovered.borrow_mut(), |
404 | 0 | &mut self.finished.borrow_mut(), |
405 | | ) |
406 | 0 | } |
407 | | } |
408 | | |
409 | | impl<G: Visitable> GraphBase for Acyclic<G> { |
410 | | type NodeId = G::NodeId; |
411 | | type EdgeId = G::EdgeId; |
412 | | } |
413 | | |
414 | | impl<G: Default + Visitable> Default for Acyclic<G> { |
415 | 0 | fn default() -> Self { |
416 | 0 | let graph: G = Default::default(); |
417 | 0 | let order_map = Default::default(); |
418 | 0 | let discovered = RefCell::new(FixedBitSet::default()); |
419 | 0 | let finished = RefCell::new(FixedBitSet::default()); |
420 | 0 | Self { |
421 | 0 | graph, |
422 | 0 | order_map, |
423 | 0 | discovered, |
424 | 0 | finished, |
425 | 0 | } |
426 | 0 | } |
427 | | } |
428 | | |
429 | | impl<G: Build + Visitable + NodeIndexable> Build for Acyclic<G> |
430 | | where |
431 | | for<'a> &'a G: IntoNeighborsDirected |
432 | | + IntoNodeIdentifiers |
433 | | + Visitable<Map = G::Map> |
434 | | + GraphBase<NodeId = G::NodeId>, |
435 | | G::NodeId: IndexType, |
436 | | { |
437 | 0 | fn add_node(&mut self, weight: Self::NodeWeight) -> Self::NodeId { |
438 | 0 | let n = self.graph.add_node(weight); |
439 | 0 | self.order_map.add_node(n, &self.graph); |
440 | 0 | n |
441 | 0 | } |
442 | | |
443 | 0 | fn add_edge( |
444 | 0 | &mut self, |
445 | 0 | a: Self::NodeId, |
446 | 0 | b: Self::NodeId, |
447 | 0 | weight: Self::EdgeWeight, |
448 | 0 | ) -> Option<Self::EdgeId> { |
449 | 0 | self.try_add_edge(a, b, weight).ok() |
450 | 0 | } |
451 | | |
452 | 0 | fn update_edge( |
453 | 0 | &mut self, |
454 | 0 | a: Self::NodeId, |
455 | 0 | b: Self::NodeId, |
456 | 0 | weight: Self::EdgeWeight, |
457 | 0 | ) -> Self::EdgeId { |
458 | 0 | self.try_update_edge(a, b, weight).unwrap() |
459 | 0 | } |
460 | | } |
461 | | |
462 | | impl<G: Create + Visitable + NodeIndexable> Create for Acyclic<G> |
463 | | where |
464 | | for<'a> &'a G: IntoNeighborsDirected |
465 | | + IntoNodeIdentifiers |
466 | | + Visitable<Map = G::Map> |
467 | | + GraphBase<NodeId = G::NodeId>, |
468 | | G::NodeId: IndexType, |
469 | | { |
470 | 0 | fn with_capacity(nodes: usize, edges: usize) -> Self { |
471 | 0 | let graph = G::with_capacity(nodes, edges); |
472 | 0 | let order_map = OrderMap::with_capacity(nodes); |
473 | 0 | let discovered = FixedBitSet::with_capacity(nodes); |
474 | 0 | let finished = FixedBitSet::with_capacity(nodes); |
475 | 0 | Self { |
476 | 0 | graph, |
477 | 0 | order_map, |
478 | 0 | discovered: RefCell::new(discovered), |
479 | 0 | finished: RefCell::new(finished), |
480 | 0 | } |
481 | 0 | } |
482 | | } |
483 | | |
484 | | impl<G: Visitable> Deref for Acyclic<G> { |
485 | | type Target = G; |
486 | | |
487 | 0 | fn deref(&self) -> &Self::Target { |
488 | 0 | &self.graph |
489 | 0 | } |
490 | | } |
491 | | |
492 | | /// Traverse nodes in `graph` in DFS order, starting from `start`, for as long |
493 | | /// as the predicate `valid_order` returns `true` on the current node's order. |
494 | 0 | fn dfs<G: NodeIndexable + IntoNeighborsDirected + IntoNodeIdentifiers + Visitable>( |
495 | 0 | graph: G, |
496 | 0 | start: G::NodeId, |
497 | 0 | order_map: &OrderMap<G::NodeId>, |
498 | 0 | // A predicate that returns whether to continue the search from a node, |
499 | 0 | // or an error to stop and shortcircuit the search. |
500 | 0 | mut valid_order: impl FnMut(TopologicalPosition) -> Result<bool, Cycle<G::NodeId>>, |
501 | 0 | res: &mut BTreeMap<TopologicalPosition, G::NodeId>, |
502 | 0 | discovered: &mut FixedBitSet, |
503 | 0 | finished: &mut FixedBitSet, |
504 | 0 | ) -> Result<(), Cycle<G::NodeId>> |
505 | 0 | where |
506 | 0 | G::NodeId: IndexType, |
507 | | { |
508 | 0 | dfs_visitor( |
509 | 0 | graph, |
510 | 0 | start, |
511 | 0 | &mut |ev| -> Result<Control<()>, Cycle<G::NodeId>> { |
512 | 0 | match ev { |
513 | 0 | DfsEvent::Discover(u, _) => { |
514 | | // We are visiting u |
515 | 0 | let order = order_map.get_position(u, &graph); |
516 | 0 | res.insert(order, u); |
517 | 0 | Ok(Control::Continue) |
518 | | } |
519 | 0 | DfsEvent::TreeEdge(_, u) => { |
520 | | // Should we visit u? |
521 | 0 | let order = order_map.get_position(u, &graph); |
522 | 0 | match valid_order(order) { |
523 | 0 | Ok(true) => Ok(Control::Continue), |
524 | 0 | Ok(false) => Ok(Control::Prune), |
525 | 0 | Err(cycle) => Err(cycle), |
526 | | } |
527 | | } |
528 | 0 | _ => Ok(Control::Continue), |
529 | | } |
530 | 0 | }, |
531 | 0 | discovered, |
532 | 0 | finished, |
533 | 0 | &mut Time::default(), |
534 | 0 | )?; |
535 | | |
536 | 0 | Ok(()) |
537 | 0 | } |
538 | | |
539 | | /////////////////////// Pass-through graph traits /////////////////////// |
540 | | // We implement all the following traits by delegating to the inner graph: |
541 | | // - Data |
542 | | // - DataMap |
543 | | // - DataMapMut |
544 | | // - EdgeCount |
545 | | // - EdgeIndexable |
546 | | // - GetAdjacencyMatrix |
547 | | // - GraphProp |
548 | | // - NodeCompactIndexable |
549 | | // - NodeCount |
550 | | // - NodeIndexable |
551 | | // - Visitable |
552 | | // |
553 | | // Furthermore, we also implement the `remove_node` and `remove_edge` methods, |
554 | | // as well as the following traits for `DiGraph` and `StableDiGraph` (these |
555 | | // are hard/impossible to implement generically): |
556 | | // - TryFrom |
557 | | // - IntoEdgeReferences |
558 | | // - IntoEdges |
559 | | // - IntoEdgesDirected |
560 | | // - IntoNeighbors |
561 | | // - IntoNeighborsDirected |
562 | | // - IntoNodeIdentifiers |
563 | | // - IntoNodeReferences |
564 | | |
565 | | impl<G: Visitable + Data> Data for Acyclic<G> { |
566 | | type NodeWeight = G::NodeWeight; |
567 | | type EdgeWeight = G::EdgeWeight; |
568 | | } |
569 | | |
570 | | impl<G: Visitable + DataMap> DataMap for Acyclic<G> { |
571 | 0 | fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight> { |
572 | 0 | self.inner().node_weight(id) |
573 | 0 | } |
574 | | |
575 | 0 | fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight> { |
576 | 0 | self.inner().edge_weight(id) |
577 | 0 | } |
578 | | } |
579 | | |
580 | | impl<G: Visitable + DataMapMut> DataMapMut for Acyclic<G> { |
581 | 0 | fn node_weight_mut(&mut self, id: Self::NodeId) -> Option<&mut Self::NodeWeight> { |
582 | 0 | self.inner_mut().node_weight_mut(id) |
583 | 0 | } |
584 | | |
585 | 0 | fn edge_weight_mut(&mut self, id: Self::EdgeId) -> Option<&mut Self::EdgeWeight> { |
586 | 0 | self.inner_mut().edge_weight_mut(id) |
587 | 0 | } |
588 | | } |
589 | | |
590 | | impl<G: Visitable + EdgeCount> EdgeCount for Acyclic<G> { |
591 | 0 | fn edge_count(&self) -> usize { |
592 | 0 | self.inner().edge_count() |
593 | 0 | } |
594 | | } |
595 | | |
596 | | impl<G: Visitable + EdgeIndexable> EdgeIndexable for Acyclic<G> { |
597 | 0 | fn edge_bound(&self) -> usize { |
598 | 0 | self.inner().edge_bound() |
599 | 0 | } |
600 | | |
601 | 0 | fn to_index(&self, a: Self::EdgeId) -> usize { |
602 | 0 | self.inner().to_index(a) |
603 | 0 | } |
604 | | |
605 | 0 | fn from_index(&self, i: usize) -> Self::EdgeId { |
606 | 0 | self.inner().from_index(i) |
607 | 0 | } |
608 | | } |
609 | | |
610 | | impl<G: Visitable + GetAdjacencyMatrix> GetAdjacencyMatrix for Acyclic<G> { |
611 | | type AdjMatrix = G::AdjMatrix; |
612 | | |
613 | 0 | fn adjacency_matrix(&self) -> Self::AdjMatrix { |
614 | 0 | self.inner().adjacency_matrix() |
615 | 0 | } |
616 | | |
617 | 0 | fn is_adjacent(&self, matrix: &Self::AdjMatrix, a: Self::NodeId, b: Self::NodeId) -> bool { |
618 | 0 | self.inner().is_adjacent(matrix, a, b) |
619 | 0 | } |
620 | | } |
621 | | |
622 | | impl<G: Visitable + GraphProp> GraphProp for Acyclic<G> { |
623 | | type EdgeType = G::EdgeType; |
624 | | } |
625 | | |
626 | | impl<G: Visitable + NodeCompactIndexable> NodeCompactIndexable for Acyclic<G> {} |
627 | | |
628 | | impl<G: Visitable + NodeCount> NodeCount for Acyclic<G> { |
629 | 0 | fn node_count(&self) -> usize { |
630 | 0 | self.inner().node_count() |
631 | 0 | } |
632 | | } |
633 | | |
634 | | impl<G: Visitable + NodeIndexable> NodeIndexable for Acyclic<G> { |
635 | 0 | fn node_bound(&self) -> usize { |
636 | 0 | self.inner().node_bound() |
637 | 0 | } |
638 | | |
639 | 0 | fn to_index(&self, a: Self::NodeId) -> usize { |
640 | 0 | self.inner().to_index(a) |
641 | 0 | } |
642 | | |
643 | 0 | fn from_index(&self, i: usize) -> Self::NodeId { |
644 | 0 | self.inner().from_index(i) |
645 | 0 | } |
646 | | } |
647 | | |
648 | | impl<G: Visitable> Visitable for Acyclic<G> { |
649 | | type Map = G::Map; |
650 | | |
651 | 0 | fn visit_map(&self) -> Self::Map { |
652 | 0 | self.inner().visit_map() |
653 | 0 | } |
654 | | |
655 | 0 | fn reset_map(&self, map: &mut Self::Map) { |
656 | 0 | self.inner().reset_map(map) |
657 | 0 | } |
658 | | } |
659 | | |
660 | | macro_rules! impl_graph_traits { |
661 | | ($graph_type:ident) => { |
662 | | // Remove edge and node methods (not available through traits) |
663 | | impl<N, E, Ix: IndexType> Acyclic<$graph_type<N, E, Ix>> { |
664 | | /// Remove an edge and return its edge weight, or None if it didn't exist. |
665 | | /// |
666 | | /// Pass through to underlying graph. |
667 | 0 | pub fn remove_edge( |
668 | 0 | &mut self, |
669 | 0 | e: <$graph_type<N, E, Ix> as GraphBase>::EdgeId, |
670 | 0 | ) -> Option<E> { |
671 | 0 | self.graph.remove_edge(e) |
672 | 0 | } |
673 | | |
674 | | /// Remove a node from the graph if it exists, and return its |
675 | | /// weight. If it doesn't exist in the graph, return None. |
676 | | /// |
677 | | /// This updates the order in O(v) runtime and removes the node in |
678 | | /// the underlying graph. |
679 | 0 | pub fn remove_node( |
680 | 0 | &mut self, |
681 | 0 | n: <$graph_type<N, E, Ix> as GraphBase>::NodeId, |
682 | 0 | ) -> Option<N> { |
683 | 0 | self.order_map.remove_node(n, &self.graph); |
684 | 0 | self.graph.remove_node(n) |
685 | 0 | } |
686 | | } |
687 | | |
688 | | impl<N, E, Ix: IndexType> TryFrom<$graph_type<N, E, Ix>> |
689 | | for Acyclic<$graph_type<N, E, Ix>> |
690 | | { |
691 | | type Error = Cycle<NodeIndex<Ix>>; |
692 | | |
693 | 0 | fn try_from(graph: $graph_type<N, E, Ix>) -> Result<Self, Self::Error> { |
694 | 0 | let order_map = OrderMap::try_from_graph(&graph)?; |
695 | 0 | let discovered = RefCell::new(FixedBitSet::with_capacity(graph.node_bound())); |
696 | 0 | let finished = RefCell::new(FixedBitSet::with_capacity(graph.node_bound())); |
697 | 0 | Ok(Self { |
698 | 0 | graph, |
699 | 0 | order_map, |
700 | 0 | discovered, |
701 | 0 | finished, |
702 | 0 | }) |
703 | 0 | } |
704 | | } |
705 | | |
706 | | impl<'a, N, E, Ix: IndexType> IntoEdgeReferences for &'a Acyclic<$graph_type<N, E, Ix>> { |
707 | | type EdgeRef = <&'a $graph_type<N, E, Ix> as IntoEdgeReferences>::EdgeRef; |
708 | | type EdgeReferences = <&'a $graph_type<N, E, Ix> as IntoEdgeReferences>::EdgeReferences; |
709 | | |
710 | 0 | fn edge_references(self) -> Self::EdgeReferences { |
711 | 0 | self.inner().edge_references() |
712 | 0 | } |
713 | | } |
714 | | |
715 | | impl<'a, N, E, Ix: IndexType> IntoEdges for &'a Acyclic<$graph_type<N, E, Ix>> { |
716 | | type Edges = <&'a $graph_type<N, E, Ix> as IntoEdges>::Edges; |
717 | | |
718 | 0 | fn edges(self, a: Self::NodeId) -> Self::Edges { |
719 | 0 | self.inner().edges(a) |
720 | 0 | } |
721 | | } |
722 | | |
723 | | impl<'a, N, E, Ix: IndexType> IntoEdgesDirected for &'a Acyclic<$graph_type<N, E, Ix>> { |
724 | | type EdgesDirected = <&'a $graph_type<N, E, Ix> as IntoEdgesDirected>::EdgesDirected; |
725 | | |
726 | 0 | fn edges_directed(self, a: Self::NodeId, dir: Direction) -> Self::EdgesDirected { |
727 | 0 | self.inner().edges_directed(a, dir) |
728 | 0 | } |
729 | | } |
730 | | |
731 | | impl<'a, N, E, Ix: IndexType> IntoNeighbors for &'a Acyclic<$graph_type<N, E, Ix>> { |
732 | | type Neighbors = <&'a $graph_type<N, E, Ix> as IntoNeighbors>::Neighbors; |
733 | | |
734 | 0 | fn neighbors(self, a: Self::NodeId) -> Self::Neighbors { |
735 | 0 | self.inner().neighbors(a) |
736 | 0 | } |
737 | | } |
738 | | |
739 | | impl<'a, N, E, Ix: IndexType> IntoNeighborsDirected for &'a Acyclic<$graph_type<N, E, Ix>> { |
740 | | type NeighborsDirected = |
741 | | <&'a $graph_type<N, E, Ix> as IntoNeighborsDirected>::NeighborsDirected; |
742 | | |
743 | 0 | fn neighbors_directed(self, n: Self::NodeId, d: Direction) -> Self::NeighborsDirected { |
744 | 0 | self.inner().neighbors_directed(n, d) |
745 | 0 | } |
746 | | } |
747 | | |
748 | | impl<'a, N, E, Ix: IndexType> IntoNodeIdentifiers for &'a Acyclic<$graph_type<N, E, Ix>> { |
749 | | type NodeIdentifiers = |
750 | | <&'a $graph_type<N, E, Ix> as IntoNodeIdentifiers>::NodeIdentifiers; |
751 | | |
752 | 0 | fn node_identifiers(self) -> Self::NodeIdentifiers { |
753 | 0 | self.inner().node_identifiers() |
754 | 0 | } |
755 | | } |
756 | | |
757 | | impl<'a, N, E, Ix: IndexType> IntoNodeReferences for &'a Acyclic<$graph_type<N, E, Ix>> { |
758 | | type NodeRef = <&'a $graph_type<N, E, Ix> as IntoNodeReferences>::NodeRef; |
759 | | type NodeReferences = <&'a $graph_type<N, E, Ix> as IntoNodeReferences>::NodeReferences; |
760 | | |
761 | 0 | fn node_references(self) -> Self::NodeReferences { |
762 | 0 | self.inner().node_references() |
763 | 0 | } |
764 | | } |
765 | | }; |
766 | | } |
767 | | |
768 | | impl_graph_traits!(DiGraph); |
769 | | #[cfg(feature = "stable_graph")] |
770 | | impl_graph_traits!(StableDiGraph); |
771 | | |
772 | | #[cfg(test)] |
773 | | mod tests { |
774 | | use alloc::vec::Vec; |
775 | | |
776 | | use super::*; |
777 | | use crate::prelude::DiGraph; |
778 | | use crate::visit::IntoNodeReferences; |
779 | | |
780 | | #[cfg(feature = "stable_graph")] |
781 | | use crate::prelude::StableDiGraph; |
782 | | |
783 | | #[test] |
784 | | fn test_acyclic_graph() { |
785 | | // Create an acyclic DiGraph |
786 | | let mut graph = DiGraph::<(), ()>::new(); |
787 | | let a = graph.add_node(()); |
788 | | let c = graph.add_node(()); |
789 | | let b = graph.add_node(()); |
790 | | graph.add_edge(a, b, ()); |
791 | | graph.add_edge(b, c, ()); |
792 | | |
793 | | // Create an Acyclic object |
794 | | let mut acyclic = Acyclic::try_from_graph(graph).unwrap(); |
795 | | |
796 | | // Test initial topological order |
797 | | assert_valid_topological_order(&acyclic); |
798 | | |
799 | | // Add a valid edge |
800 | | assert!(acyclic.try_add_edge(a, c, ()).is_ok()); |
801 | | assert_valid_topological_order(&acyclic); |
802 | | |
803 | | // Try to add an edge that would create a cycle |
804 | | assert!(acyclic.try_add_edge(c, a, ()).is_err()); |
805 | | |
806 | | // Add another valid edge |
807 | | let d = acyclic.add_node(()); |
808 | | assert!(acyclic.try_add_edge(c, d, ()).is_ok()); |
809 | | assert_valid_topological_order(&acyclic); |
810 | | |
811 | | // Try to add an edge that would create a cycle (using the Build trait) |
812 | | assert!(acyclic.add_edge(d, a, ()).is_none()); |
813 | | } |
814 | | |
815 | | #[cfg(feature = "stable_graph")] |
816 | | #[test] |
817 | | fn test_acyclic_graph_add_remove() { |
818 | | // Create an initial Acyclic graph with two nodes and one edge |
819 | | let mut acyclic = Acyclic::<StableDiGraph<(), ()>>::new(); |
820 | | let a = acyclic.add_node(()); |
821 | | let b = acyclic.add_node(()); |
822 | | assert!(acyclic.try_add_edge(a, b, ()).is_ok()); |
823 | | |
824 | | // Check initial topological order |
825 | | assert_valid_topological_order(&acyclic); |
826 | | |
827 | | // Add a new node and an edge |
828 | | let c = acyclic.add_node(()); |
829 | | assert!(acyclic.try_add_edge(b, c, ()).is_ok()); |
830 | | |
831 | | // Check topological order after addition |
832 | | assert_valid_topological_order(&acyclic); |
833 | | |
834 | | // Remove the node connected to two edges (node b) |
835 | | acyclic.remove_node(b); |
836 | | |
837 | | // Check topological order after removal |
838 | | assert_valid_topological_order(&acyclic); |
839 | | |
840 | | // Verify the remaining structure |
841 | | let remaining_nodes: Vec<_> = acyclic |
842 | | .inner() |
843 | | .node_references() |
844 | | .map(|(id, _)| id) |
845 | | .collect(); |
846 | | assert_eq!(remaining_nodes.len(), 2); |
847 | | assert!(remaining_nodes.contains(&a)); |
848 | | assert!(remaining_nodes.contains(&c)); |
849 | | assert!(!acyclic.inner().contains_edge(a, c)); |
850 | | } |
851 | | |
852 | | fn assert_valid_topological_order<'a, G>(acyclic: &'a Acyclic<G>) |
853 | | where |
854 | | G: Visitable + NodeCount + NodeIndexable, |
855 | | &'a G: NodeIndexable |
856 | | + IntoNodeReferences |
857 | | + IntoNeighborsDirected |
858 | | + GraphBase<NodeId = G::NodeId>, |
859 | | G::NodeId: core::fmt::Debug, |
860 | | { |
861 | | let ordered_nodes: Vec<_> = acyclic.nodes_iter().collect(); |
862 | | assert_eq!(ordered_nodes.len(), acyclic.node_count()); |
863 | | let nodes: Vec<_> = acyclic.inner().node_identifiers().collect(); |
864 | | |
865 | | // Check that the nodes are in topological order |
866 | | let mut last_position = None; |
867 | | for (idx, &node) in ordered_nodes.iter().enumerate() { |
868 | | assert!(nodes.contains(&node)); |
869 | | |
870 | | // Check that the node positions are monotonically increasing |
871 | | let pos = acyclic.get_position(node); |
872 | | assert!(Some(pos) > last_position); |
873 | | last_position = Some(pos); |
874 | | |
875 | | // Check that the neighbors are in the future of the current node |
876 | | for neighbor in acyclic.inner().neighbors(node) { |
877 | | let neighbour_idx = ordered_nodes.iter().position(|&n| n == neighbor).unwrap(); |
878 | | assert!(neighbour_idx > idx); |
879 | | } |
880 | | } |
881 | | } |
882 | | |
883 | | #[cfg(feature = "graphmap")] |
884 | | #[test] |
885 | | fn test_multiedge_allowed() { |
886 | | use crate::prelude::GraphMap; |
887 | | use crate::Directed; |
888 | | |
889 | | let mut graph = Acyclic::<GraphMap<usize, (), Directed>>::new(); |
890 | | graph.add_node(0); |
891 | | graph.add_node(1); |
892 | | graph.try_update_edge(0, 1, ()).unwrap(); |
893 | | graph.try_update_edge(0, 1, ()).unwrap(); // `Result::unwrap()` on an `Err` value: InvalidEdge |
894 | | } |
895 | | } |