1use std::{
2 collections::{HashMap, VecDeque},
3 ops::{Index, IndexMut},
4};
5
6use crate::{
7 graph::{GraphIndex, NodeIndex},
8 visit::{EdgeRef, GraphProp, IntoEdgeReferences},
9 Directed,
10};
11
12use self::linked_list::{LinkedList, LinkedListEntry};
13
14pub fn greedy_feedback_arc_set<G>(g: G) -> impl Iterator<Item = G::EdgeRef>
63where
64 G: IntoEdgeReferences + GraphProp<EdgeType = Directed>,
65 G::NodeId: GraphIndex,
66 G: crate::visit::NodeCount,
67{
68 let node_seq = good_node_sequence(g.edge_references().map(|e| {
69 (
70 NodeIndex::new(e.source().index()),
71 NodeIndex::new(e.target().index()),
72 )
73 }));
74
75 g.edge_references()
76 .filter(move |e| node_seq[&e.source().index()] >= node_seq[&e.target().index()])
77}
78
79fn good_node_sequence(
80 edge_refs: impl Iterator<Item = (NodeIndex<usize>, NodeIndex<usize>)>,
81) -> HashMap<usize, usize> {
82 let mut nodes = FasNodeContainer { nodes: Vec::new() };
83 let mut buckets = Buckets {
84 sinks_or_isolated: NodeLinkedList::new(),
85 sources: NodeLinkedList::new(),
86 bidirectional_pve_dd: Vec::new(),
87 bidirectional_nve_dd: Vec::new(),
88 };
89 let mut graph_ix_lookup = HashMap::new();
91
92 for (from_g_ix, to_g_ix) in edge_refs {
94 let mut fas_node_entry = |g_ix: NodeIndex<usize>| -> FasNodeIndex {
95 match graph_ix_lookup.get(&g_ix) {
96 Some(fas_ix) => *fas_ix,
97 None => {
98 let fas_ix = FasNodeIndex(nodes.nodes.len());
99
100 nodes.nodes.push(LinkedListEntry::new(FasNode {
101 graph_ix: g_ix,
102 out_edges: Vec::new(),
103 in_edges: Vec::new(),
104 out_degree: 0,
105 in_degree: 0,
106 }));
107
108 graph_ix_lookup.insert(g_ix, fas_ix);
109
110 fas_ix
111 }
112 }
113 };
114
115 let from_fas_ix = fas_node_entry(from_g_ix);
116 let to_fas_ix = fas_node_entry(to_g_ix);
117
118 nodes[from_fas_ix].data().out_edges.push(to_fas_ix);
119 nodes[to_fas_ix].data().in_edges.push(from_fas_ix);
120 }
121
122 for entry in nodes.nodes.iter_mut() {
124 let node = entry.data();
125 node.out_degree = node.out_edges.len();
126 node.in_degree = node.in_edges.len();
127 }
128
129 for i in 0..nodes.nodes.len() {
131 let fas_ix = FasNodeIndex(i);
132 buckets
133 .suitable_bucket(fas_ix, &mut nodes)
134 .push_front(fas_ix, &mut nodes);
135 }
136
137 let mut s_1 = VecDeque::new();
138 let mut s_2 = VecDeque::new();
139
140 loop {
141 let mut some_moved = false;
142
143 while let Some(sink_fas_ix) = buckets.sinks_or_isolated.pop(&mut nodes) {
144 some_moved = true;
145 buckets.update_neighbour_node_buckets(sink_fas_ix, &mut nodes);
146 s_2.push_front(nodes[sink_fas_ix].data().graph_ix);
147 }
148
149 while let Some(source_fas_ix) = buckets.sources.pop(&mut nodes) {
150 some_moved = true;
151 buckets.update_neighbour_node_buckets(source_fas_ix, &mut nodes);
152 s_1.push_back(nodes[source_fas_ix].data().graph_ix);
153 }
154
155 if let Some(list) = buckets
156 .bidirectional_pve_dd
157 .iter_mut()
158 .rev()
159 .chain(buckets.bidirectional_nve_dd.iter_mut())
160 .find(|b| b.start.is_some())
161 {
162 let highest_dd_fas_ix = list.pop(&mut nodes).unwrap();
163 some_moved = true;
164 buckets.update_neighbour_node_buckets(highest_dd_fas_ix, &mut nodes);
165 s_1.push_back(nodes[highest_dd_fas_ix].data().graph_ix);
166
167 Buckets::trim_bucket_list(&mut buckets.bidirectional_pve_dd);
168 Buckets::trim_bucket_list(&mut buckets.bidirectional_nve_dd);
169 }
170
171 if !some_moved {
172 break;
173 }
174 }
175
176 s_1.into_iter()
177 .chain(s_2)
178 .enumerate()
179 .map(|(seq_order, node_index)| (node_index.index(), seq_order))
180 .collect()
181}
182
183type NodeLinkedList = LinkedList<FasNode, FasNodeContainer, FasNodeIndex>;
184
185#[derive(Debug)]
186struct FasNodeContainer {
187 nodes: Vec<LinkedListEntry<FasNode, FasNodeIndex>>,
188}
189
190impl Index<FasNodeIndex> for FasNodeContainer {
191 type Output = LinkedListEntry<FasNode, FasNodeIndex>;
192
193 fn index(&self, index: FasNodeIndex) -> &Self::Output {
194 &self.nodes[index.0]
195 }
196}
197
198impl IndexMut<FasNodeIndex> for FasNodeContainer {
199 fn index_mut(&mut self, index: FasNodeIndex) -> &mut Self::Output {
200 &mut self.nodes[index.0]
201 }
202}
203
204#[derive(Debug)]
205struct Buckets {
206 sinks_or_isolated: NodeLinkedList,
207 sources: NodeLinkedList,
208 bidirectional_pve_dd: Vec<NodeLinkedList>,
210 bidirectional_nve_dd: Vec<NodeLinkedList>,
212}
213
214#[derive(Clone, Copy, PartialEq, Debug)]
215struct FasNodeIndex(usize);
216
217#[derive(Debug)]
219struct FasNode {
220 graph_ix: NodeIndex<usize>,
222
223 out_edges: Vec<FasNodeIndex>,
225
226 in_edges: Vec<FasNodeIndex>,
228
229 out_degree: usize,
232
233 in_degree: usize,
236}
237
238impl Buckets {
239 fn suitable_bucket(
240 &mut self,
241 ix: FasNodeIndex,
242 nodes: &mut FasNodeContainer,
243 ) -> &mut NodeLinkedList {
244 let node = nodes[ix].data();
245
246 if node.out_degree == 0 {
247 &mut self.sinks_or_isolated
248 } else if node.in_degree == 0 {
249 &mut self.sources
250 } else {
251 let delta_degree = node.out_degree as isize - node.in_degree as isize;
252
253 if delta_degree >= 0 {
254 let bucket_ix = delta_degree as usize;
255
256 if self.bidirectional_pve_dd.len() <= bucket_ix {
257 self.bidirectional_pve_dd
258 .resize_with(bucket_ix + 1, NodeLinkedList::new);
259 }
260
261 &mut self.bidirectional_pve_dd[bucket_ix]
262 } else {
263 let bucket_ix = (-delta_degree - 1) as usize;
264
265 if self.bidirectional_nve_dd.len() <= bucket_ix {
266 self.bidirectional_nve_dd
267 .resize_with(bucket_ix + 1, NodeLinkedList::new);
268 }
269
270 &mut self.bidirectional_nve_dd[bucket_ix]
271 }
272 }
273 }
274
275 fn update_neighbour_node_buckets(&mut self, ix: FasNodeIndex, nodes: &mut FasNodeContainer) {
276 for i in 0..nodes[ix].data().out_edges.len() {
277 let out_ix = nodes[ix].data().out_edges[i];
278
279 if out_ix == ix {
280 continue;
281 }
282
283 if !nodes[out_ix].is_in_list() {
285 continue;
286 }
287
288 self.suitable_bucket(out_ix, nodes).remove(out_ix, nodes);
289
290 nodes[out_ix].data().in_degree -= 1;
292
293 self.suitable_bucket(out_ix, nodes)
294 .push_front(out_ix, nodes);
295 }
296
297 for i in 0..nodes[ix].data().in_edges.len() {
298 let in_ix = nodes[ix].data().in_edges[i];
299
300 if in_ix == ix {
301 continue;
302 }
303
304 if !nodes[in_ix].is_in_list() {
306 continue;
307 }
308
309 self.suitable_bucket(in_ix, nodes).remove(in_ix, nodes);
310
311 nodes[in_ix].data().out_degree -= 1;
313
314 self.suitable_bucket(in_ix, nodes).push_front(in_ix, nodes);
315 }
316 }
317
318 fn trim_bucket_list(list: &mut Vec<NodeLinkedList>) {
319 let trunc_len = if let Some(highest_populated_index) =
320 (0..list.len()).rev().find(|i| list[*i].start.is_some())
321 {
322 highest_populated_index + 1
323 } else {
324 0
325 };
326
327 list.truncate(trunc_len);
328 }
329}
330
331mod linked_list {
332 use std::{marker::PhantomData, ops::IndexMut};
333
334 #[derive(PartialEq, Debug)]
335 pub struct LinkedList<Data, Container, Ix> {
336 pub start: Option<Ix>,
337 marker: PhantomData<(Data, Container)>,
338 }
339
340 #[derive(Debug)]
341 pub struct LinkedListEntry<Data, Ix> {
342 pos: Option<LinkedListPosition<Ix>>,
343 data: Data,
344 }
345
346 #[derive(Debug)]
347 struct LinkedListPosition<Ix> {
348 prev: Option<Ix>,
349 next: Option<Ix>,
350 }
351
352 impl<Data, Ix> LinkedListEntry<Data, Ix> {
353 pub fn new(data: Data) -> Self {
354 LinkedListEntry { pos: None, data }
355 }
356
357 pub fn data(&mut self) -> &mut Data {
358 &mut self.data
359 }
360
361 pub fn is_in_list(&mut self) -> bool {
362 self.pos.is_some()
363 }
364
365 fn pos_mut(&mut self) -> &mut LinkedListPosition<Ix> {
366 self.pos
367 .as_mut()
368 .expect("expected linked list entry to have populated position")
369 }
370 }
371
372 impl<Data, Container, Ix> LinkedList<Data, Container, Ix>
373 where
374 Container: IndexMut<Ix, Output = LinkedListEntry<Data, Ix>>,
375 Ix: PartialEq + Copy,
376 {
377 pub fn new() -> Self {
378 LinkedList {
379 start: None,
380 marker: PhantomData,
381 }
382 }
383
384 pub fn push_front(&mut self, push_ix: Ix, container: &mut Container) {
385 if let Some(start_ix) = self.start {
386 let entry = &mut container[start_ix];
387 entry.pos_mut().prev = Some(push_ix);
388 }
389
390 let push_entry = &mut container[push_ix];
391 push_entry.pos = Some(LinkedListPosition {
392 next: self.start,
393 prev: None,
394 });
395
396 self.start = Some(push_ix);
397 }
398
399 pub fn pop(&mut self, container: &mut Container) -> Option<Ix> {
400 if let Some(remove_ix) = self.start {
401 self.remove(remove_ix, container);
402 Some(remove_ix)
403 } else {
404 None
405 }
406 }
407
408 pub fn remove(&mut self, remove_ix: Ix, container: &mut Container) {
410 debug_assert!(
411 self.to_vec(container).contains(&remove_ix),
412 "node to remove should be member of current linked list"
413 );
414
415 let remove_entry = &mut container[remove_ix];
416 let ll_entry = remove_entry.pos.take().unwrap();
417
418 if let Some(prev_ix) = ll_entry.prev {
419 let prev_node = &mut container[prev_ix];
420 prev_node.pos_mut().next = ll_entry.next;
421 }
422
423 if let Some(next_ix) = ll_entry.next {
424 let next_node = &mut container[next_ix];
425 next_node.pos_mut().prev = ll_entry.prev;
426 }
427
428 if self.start == Some(remove_ix) {
430 self.start = ll_entry.next;
431 }
432 }
433
434 fn to_vec(&self, container: &mut Container) -> Vec<Ix> {
436 let mut ixs = Vec::new();
437
438 let mut node_ix = self.start;
439
440 while let Some(n_ix) = node_ix {
441 ixs.push(n_ix);
442
443 node_ix = container[n_ix].pos_mut().next;
444 }
445
446 ixs
447 }
448 }
449}