Skip to content

Commit 31cabfe

Browse files
committed
Feedback arc set
1 parent b72643c commit 31cabfe

File tree

3 files changed

+44
-1
lines changed

3 files changed

+44
-1
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "safety-net"
3-
version = "0.5.1"
3+
version = "0.5.2"
44
edition = "2024"
55
license = "MIT OR Apache-2.0"
66

src/graph.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,16 @@ where
327327
pub fn get_graph(&self) -> &DiGraph<Node<I, String>, Edge<I, Net>> {
328328
&self.graph
329329
}
330+
331+
/// Iterates through a [greedy feedback arc set](https://doi.org/10.1016/0020-0190(93)90079-O) for the graph.
332+
pub fn greedy_feedback_arcs(&self) -> impl Iterator<Item = Connection<I>> {
333+
petgraph::algo::feedback_arc_set::greedy_feedback_arc_set(&self.graph)
334+
.map(|e| match e.weight() {
335+
Edge::Connection(c) => c,
336+
_ => unreachable!("Outputs should be sinks"),
337+
})
338+
.cloned()
339+
}
330340
}
331341

332342
#[cfg(feature = "graph")]

tests/analysis.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,39 @@ fn test_petgraph() {
142142
// Outputs are a pseudo node
143143
assert_eq!(graph.node_count(), 4);
144144
assert_eq!(graph.edge_count(), 3);
145+
146+
// Ayclic graph should have no feedback arcs.
147+
let mut arcs = petgraph.greedy_feedback_arcs();
148+
assert!(arcs.next().is_none());
149+
}
150+
151+
#[cfg(feature = "graph")]
152+
#[test]
153+
fn test_feedback_arcs() {
154+
use safety_net::MultiDiGraph;
155+
156+
let netlist = divider_netlist();
157+
158+
let petgraph = netlist.get_analysis::<MultiDiGraph<_>>();
159+
assert!(petgraph.is_ok());
160+
let petgraph = petgraph.unwrap();
161+
162+
// Has exactly one arc
163+
let mut arcs = petgraph.greedy_feedback_arcs();
164+
let arc = arcs.next();
165+
assert!(arc.is_some());
166+
assert!(arcs.next().is_none());
167+
168+
// Disconnect the arc
169+
let arc = arc.unwrap();
170+
arc.target().disconnect();
171+
172+
// Should be acyclic now
173+
let petgraph = netlist.get_analysis::<MultiDiGraph<_>>();
174+
assert!(petgraph.is_ok());
175+
let petgraph = petgraph.unwrap();
176+
let mut arcs = petgraph.greedy_feedback_arcs();
177+
assert!(arcs.next().is_none());
145178
}
146179

147180
#[test]

0 commit comments

Comments
 (0)