1use std::collections::{HashMap, HashSet};
2
3use petgraph::{
4 stable_graph::{EdgeIndex, NodeIndex, StableDiGraph},
5 visit::EdgeRef,
6 Direction,
7};
8
9use crate::core::{Accessability, EdgeId, NodeId};
10
11use super::{TopoEdge, TopoNode};
12
13#[derive(Debug, Clone)]
43pub struct TopologyGraph {
44 pub graph: StableDiGraph<TopoNode, TopoEdge, u32>,
46 id_to_index: HashMap<NodeId, (NodeIndex, NodeIndex)>,
47 index_to_id: HashMap<NodeIndex, NodeId>,
48}
49
50impl TopologyGraph {
51 pub fn new() -> Self {
53 TopologyGraph {
54 graph: StableDiGraph::<TopoNode, TopoEdge, u32>::new(),
55 id_to_index: HashMap::new(),
56 index_to_id: HashMap::new(),
57 }
58 }
59
60 pub fn index_to_id(&self, index: NodeIndex) -> Option<&NodeId> {
76 self.index_to_id.get(&index)
77 }
78
79 pub fn id_to_index(&self, id: NodeId) -> Option<&(NodeIndex, NodeIndex)> {
96 self.id_to_index.get(&id)
97 }
98
99 pub fn add_node(&mut self, node_id: NodeId) -> (NodeIndex, NodeIndex) {
109 let topo_node1 = TopoNode {
110 id: NodeIndex::default(), node_id,
112 };
113 let topo_node1_id = self.graph.add_node(topo_node1);
114 self.graph.node_weight_mut(topo_node1_id).unwrap().id = topo_node1_id;
115
116 let topo_node2 = TopoNode {
117 id: NodeIndex::default(), node_id,
119 };
120 let topo_node2_id = self.graph.add_node(topo_node2);
121 self.graph.node_weight_mut(topo_node2_id).unwrap().id = topo_node2_id;
122
123 self.id_to_index
124 .insert(node_id, (topo_node1_id, topo_node2_id));
125
126 self.index_to_id.insert(topo_node1_id, node_id);
127 self.index_to_id.insert(topo_node2_id, node_id);
128 (topo_node1_id, topo_node2_id)
129 }
130
131 pub fn add_edge(
143 &mut self,
144 edge_id: EdgeId,
145 from_node_id: NodeId,
146 to_node_id: NodeId,
147 ) -> (EdgeIndex, EdgeIndex) {
148 let (from_topo_node_id1, from_topo_node_id2) =
149 *self.id_to_index.get(&from_node_id).unwrap();
150 let (to_topo_node_id1, to_topo_node_id2) = *self.id_to_index.get(&to_node_id).unwrap();
151
152 let from_topo_node_id = if self.has_incoming(from_topo_node_id1) {
153 from_topo_node_id2
154 } else {
155 from_topo_node_id1
156 };
157
158 let to_topo_node_id = if self.has_incoming(to_topo_node_id1) {
159 to_topo_node_id2
160 } else {
161 to_topo_node_id1
162 };
163
164 let from_node_id: NodeId = *self.index_to_id.get(&from_topo_node_id).unwrap();
165 let to_node_id: NodeId = *self.index_to_id.get(&to_topo_node_id).unwrap();
166
167 let topo_edge1 = TopoEdge {
168 id: EdgeIndex::new(0), from: from_node_id,
170 to: to_node_id,
171 edge_id,
172 };
173 let topo_edge1_id = self
174 .graph
175 .add_edge(from_topo_node_id, to_topo_node_id, topo_edge1);
176 self.graph.edge_weight_mut(topo_edge1_id).unwrap().id = topo_edge1_id;
177
178 let from_topo_node_id = self.get_other_toponode(from_topo_node_id).unwrap();
179 let to_topo_node_id = self.get_other_toponode(to_topo_node_id).unwrap();
180
181 let topo_edge2 = TopoEdge {
182 id: EdgeIndex::new(0), from: to_node_id,
184 to: from_node_id,
185 edge_id,
186 };
187 let topo_edge2_id = self
188 .graph
189 .add_edge(to_topo_node_id, from_topo_node_id, topo_edge2);
190 self.graph.edge_weight_mut(topo_edge2_id).unwrap().id = topo_edge2_id;
191
192 (topo_edge1_id, topo_edge2_id)
193 }
194
195 pub fn no_edges_in_direction(
207 &self,
208 topo_node_id: NodeIndex,
209 neighbors: Vec<NodeId>,
210 dir: Direction,
211 ) -> bool {
212 let neighbors_set: HashSet<_> = neighbors.into_iter().collect();
214
215 for edge in self.graph.edges_directed(topo_node_id, dir) {
217 if neighbors_set.contains(&self.graph[edge.target()].node_id) {
218 return false;
220 }
221 }
222
223 true
225 }
226
227 pub fn find_node_index_with_edges(
239 &self,
240 node_id: NodeId,
241 neighbors: Vec<NodeId>,
242 dir: Direction,
243 ) -> Option<NodeIndex> {
244 let topo_node_ids = self.id_to_index.get(&node_id)?;
245 if self.no_edges_in_direction(topo_node_ids.0, neighbors.clone(), dir.opposite()) {
246 return Some(topo_node_ids.0);
247 }
248 if self.no_edges_in_direction(topo_node_ids.1, neighbors, dir.opposite()) {
249 return Some(topo_node_ids.1);
250 }
251 None
252 }
253
254 pub fn get_other_toponode(&self, topo_node_id: NodeIndex) -> Option<NodeIndex> {
264 let node_id = self.index_to_id.get(&topo_node_id)?;
265 let topo_node_ids = self.id_to_index.get(node_id)?;
266 if topo_node_ids.0 == topo_node_id {
267 Some(topo_node_ids.1)
268 } else if topo_node_ids.1 == topo_node_id {
269 Some(topo_node_ids.0)
270 } else {
271 None
272 }
273 }
274 pub fn add_edge_with_accessibility(
291 &mut self,
292 edge_id: EdgeId,
293 from_node_id: NodeId,
294 to_node_id: NodeId,
295 accessability: Accessability,
296 ) -> (EdgeIndex, EdgeIndex) {
297 let direction = match &accessability {
298 Accessability::ReachableNodes(_) => (Direction::Incoming, Direction::Outgoing),
299 Accessability::UnreachableNodes(_) => (Direction::Outgoing, Direction::Incoming),
300 };
301
302 let nodes = match &accessability {
303 Accessability::ReachableNodes(nodes) => nodes,
304 Accessability::UnreachableNodes(nodes) => nodes,
305 };
306
307 let u1 = self.find_node_index_with_edges(from_node_id, nodes.clone(), direction.0);
308 let v1 = self.find_node_index_with_edges(to_node_id, nodes.clone(), direction.1);
309
310 if let (Some(u1), Some(v1)) = (u1, v1) {
311 let u2 = self.get_other_toponode(u1);
312 let v2 = self.get_other_toponode(v1);
313
314 if let (Some(u2), Some(v2)) = (u2, v2) {
315 let from_node_id = *self.index_to_id.get(&u1).unwrap();
316 let to_node_id = *self.index_to_id.get(&v1).unwrap();
317
318 let topo_edge1 = TopoEdge {
319 id: EdgeIndex::new(0), from: from_node_id,
321 to: to_node_id,
322 edge_id,
323 };
324 let topo_edge1_id = self.graph.add_edge(u1, v1, topo_edge1);
325 self.graph.edge_weight_mut(topo_edge1_id).unwrap().id = topo_edge1_id;
326
327 let topo_edge2 = TopoEdge {
328 id: EdgeIndex::new(0), from: to_node_id,
330 to: from_node_id,
331 edge_id,
332 };
333 let topo_edge2_id = self.graph.add_edge(v2, u2, topo_edge2);
334 self.graph.edge_weight_mut(topo_edge2_id).unwrap().id = topo_edge2_id;
335 return (topo_edge1_id, topo_edge2_id);
336 }
337 }
338
339 unreachable!("Could not add edge with accessibility");
340 }
341
342 pub fn has_incoming(&self, node: NodeIndex) -> bool {
352 self.graph
353 .neighbors_directed(node, petgraph::Incoming)
354 .next()
355 .is_some()
356 }
357
358 pub fn reverse_edge(&mut self, edge_index: EdgeIndex) {
368 let (source, target) = self.graph.edge_endpoints(edge_index).unwrap();
369 let weight = self.graph.edge_weight(edge_index).unwrap().clone();
370 self.graph.remove_edge(edge_index);
371 self.graph.add_edge(target, source, weight);
372 }
373
374 pub fn find_edge_indices(
389 &self,
390 node1_id: NodeId,
391 node2_id: NodeId,
392 ) -> Option<(EdgeIndex, EdgeIndex)> {
393 let (node1_index1, node1_index2) = self.id_to_index(node1_id).unwrap();
394 let (node2_index1, node2_index2) = self.id_to_index(node2_id).unwrap();
395
396 let mut edges = Vec::new();
397
398 for &source_index in &[node1_index1, node1_index2] {
399 for &target_index in &[node2_index1, node2_index2] {
400 if let Some(edge) = self.graph.find_edge(*source_index, *target_index) {
401 edges.push(edge);
402 }
403 if let Some(edge) = self.graph.find_edge(*target_index, *source_index) {
404 edges.push(edge);
405 }
406 }
407 }
408
409 if edges.len() == 2 {
410 Some((edges[0], edges[1]))
411 } else {
412 None
413 }
414 }
415
416 pub fn edge_is_in_neighbors_direction(&self, edge_index: EdgeIndex) -> bool {
430 let (source, target) = self.graph.edge_endpoints(edge_index).unwrap();
431
432 let source_has_same_direction = self
434 .graph
435 .neighbors_directed(source, petgraph::Direction::Incoming)
436 .any(|neighbor| neighbor != target);
437
438 let target_has_same_direction = self
439 .graph
440 .neighbors_directed(target, petgraph::Direction::Outgoing)
441 .any(|neighbor| neighbor != source);
442
443 source_has_same_direction && target_has_same_direction
444 }
445}
446
447impl Default for TopologyGraph {
448 fn default() -> Self {
449 Self::new()
450 }
451}
452
453#[cfg(test)]
454mod tests {
455 use petgraph::dot::Dot;
456
457 use super::*;
458
459 #[test]
460 fn test_topology_graph() {
461 let mut topo_graph = TopologyGraph::new();
462
463 let node_id1 = 1;
464 let node_id2 = 2;
465
466 let (added_node_id1_1, added_node_id1_2) = topo_graph.add_node(node_id1);
467 let (added_node_id2_1, added_node_id2_2) = topo_graph.add_node(node_id2);
468
469 assert_eq!(topo_graph.graph.node_count(), 4);
471
472 let edge_id1 = 1;
473
474 let topo_edge = TopoEdge {
475 id: EdgeIndex::new(0),
476 from: node_id1,
477 to: node_id2,
478 edge_id: edge_id1,
479 };
480
481 topo_graph
482 .graph
483 .add_edge(added_node_id1_1, added_node_id2_1, topo_edge.clone());
484 topo_graph
485 .graph
486 .add_edge(added_node_id2_2, added_node_id1_2, topo_edge);
487
488 assert_eq!(topo_graph.graph.edge_count(), 2);
489
490 assert!(topo_graph.has_incoming(added_node_id2_1));
492 assert!(!topo_graph.has_incoming(added_node_id1_1));
493
494 assert!(topo_graph.has_incoming(added_node_id1_2));
495 assert!(!topo_graph.has_incoming(added_node_id2_2));
496 }
497
498 #[test]
499 fn test_no_edges_in_direction() {
500 let mut graph = TopologyGraph::new();
502
503 let node1 = 1;
505 let node2 = 2;
506 let node3 = 3;
507
508 let node1_id = graph.add_node(node1);
510 let node2_id = graph.add_node(node2);
511 let _node3_id = graph.add_node(node3);
512
513 let edge_id1 = 1;
515 let edge_id2 = 2;
516 graph.add_edge(edge_id1, node1, node2);
517 graph.add_edge(edge_id2, node1, node3);
518
519 assert!(!graph.no_edges_in_direction(node1_id.0, vec![node2], Direction::Outgoing));
521
522 assert!(!graph.no_edges_in_direction(node1_id.0, vec![node2, node3], Direction::Outgoing));
524
525 assert!(graph.no_edges_in_direction(node2_id.0, vec![node1], Direction::Outgoing));
527 }
528
529 #[test]
530 fn test_find_node_index_with_edges() {
531 let mut graph = TopologyGraph::new();
533
534 let node1 = 1;
536 let node2 = 2;
537 let node3 = 3;
538 let node4 = 4;
539
540 let topo_node1 = graph.add_node(node1);
542 let topo_node2 = graph.add_node(node2);
543 let topo_node3 = graph.add_node(node3);
544 let topo_node4 = graph.add_node(node4);
545
546 graph.add_edge(1, node1, node2);
547 graph.add_edge(2, node1, node3);
548 graph.add_edge(3, node2, node3);
549 graph.add_edge(4, node3, node4);
550
551 assert_eq!(
553 graph.find_node_index_with_edges(node1, vec![node2, node3], Direction::Outgoing),
554 Some(topo_node1.0)
555 );
556 assert_eq!(
557 graph.find_node_index_with_edges(node2, vec![node1, node3], Direction::Incoming),
558 Some(topo_node2.0)
559 );
560 assert_eq!(
561 graph.find_node_index_with_edges(node3, vec![node2, node4], Direction::Outgoing),
562 Some(topo_node3.0)
563 );
564 assert_eq!(
565 graph.find_node_index_with_edges(node4, vec![node3], Direction::Incoming),
566 Some(topo_node4.0)
567 );
568 }
569
570 #[test]
571 fn test_get_other_toponode() {
572 let mut topo_graph = TopologyGraph::new();
573
574 let node_id1: NodeId = 1;
576 let node_id2: NodeId = 2;
577
578 let (topo_node_id1_1, topo_node_id1_2) = topo_graph.add_node(node_id1);
579 let (topo_node_id2_1, topo_node_id2_2) = topo_graph.add_node(node_id2);
580
581 assert_eq!(
583 topo_graph.get_other_toponode(topo_node_id1_1),
584 Some(topo_node_id1_2)
585 );
586 assert_eq!(
587 topo_graph.get_other_toponode(topo_node_id1_2),
588 Some(topo_node_id1_1)
589 );
590
591 assert_eq!(
592 topo_graph.get_other_toponode(topo_node_id2_1),
593 Some(topo_node_id2_2)
594 );
595 assert_eq!(
596 topo_graph.get_other_toponode(topo_node_id2_2),
597 Some(topo_node_id2_1)
598 );
599
600 assert_eq!(topo_graph.get_other_toponode(NodeIndex::new(100)), None);
602 }
603
604 #[test]
605 fn test_add_edge_with_accessibility() {
606 let mut topo_graph = TopologyGraph::new();
607
608 let node_id1 = 1;
610 let node_id2 = 2;
611 topo_graph.add_node(node_id1);
612 topo_graph.add_node(node_id2);
613
614 let edge_id = 1;
616 let accessability = Accessability::ReachableNodes(vec![node_id1, node_id2]);
617 let (edge_index1, edge_index2) =
618 topo_graph.add_edge_with_accessibility(edge_id, node_id1, node_id2, accessability);
619
620 assert!(topo_graph.graph.edge_weight(edge_index1).is_some());
622 assert!(topo_graph.graph.edge_weight(edge_index2).is_some());
623 println!("{}", Dot::new(&topo_graph.graph));
624
625 let edge_indices = topo_graph.find_edge_indices(1, 2);
626 assert!(edge_indices.is_some());
627 assert_eq!(edge_indices.unwrap().0, EdgeIndex::new(0));
628 }
629
630 #[test]
631 fn test_add_edge_with_accessibility_scenario_reachable() {
632 let mut topo_graph = TopologyGraph::new();
633
634 let node_ids: Vec<NodeId> = (0..5).collect();
636 for node_id in &node_ids {
637 topo_graph.add_node(*node_id);
638 }
639
640 let edge_id = 1;
642 let accessability = Accessability::ReachableNodes(vec![node_ids[0]]);
643 topo_graph.add_edge_with_accessibility(edge_id, node_ids[4], node_ids[0], accessability);
644
645 let edge_id = 2;
647 let accessability = Accessability::ReachableNodes(vec![]);
648 topo_graph.add_edge_with_accessibility(
649 edge_id,
650 node_ids[1],
651 node_ids[2],
652 accessability.clone(),
653 );
654 let edge_id = 3;
655 topo_graph.add_edge_with_accessibility(edge_id, node_ids[1], node_ids[3], accessability);
656
657 let edge_id = 4;
659 let accessability =
660 Accessability::ReachableNodes(vec![node_ids[4], node_ids[2], node_ids[3]]);
661
662 topo_graph.add_edge_with_accessibility(edge_id, node_ids[0], node_ids[1], accessability);
663
664 for i in 1..=4 {
666 let edge_index1 = EdgeIndex::new(i * 2 - 2);
667 let edge_index2 = EdgeIndex::new(i * 2 - 1);
668 assert!(topo_graph.graph.edge_weight(edge_index1).is_some());
669 assert!(topo_graph.graph.edge_weight(edge_index2).is_some());
670 }
671 }
672
673 #[test]
674 fn test_add_edge_with_accessibility_scenario_unreachable() {
675 let mut topo_graph = TopologyGraph::new();
676
677 let node_ids: Vec<NodeId> = (0..4).collect();
679 for node_id in &node_ids {
680 topo_graph.add_node(*node_id);
681 }
682
683 let node_idx0 = *topo_graph.id_to_index.get(&node_ids[0]).unwrap();
684 let node_idx1 = *topo_graph.id_to_index.get(&node_ids[1]).unwrap();
685 let node_idx2 = *topo_graph.id_to_index.get(&node_ids[2]).unwrap();
686 let node_idx3 = *topo_graph.id_to_index.get(&node_ids[3]).unwrap();
687
688 let topo_edge = TopoEdge {
689 id: EdgeIndex::new(0),
690 from: node_ids[0],
691 to: node_ids[1],
692 edge_id: 1,
693 };
694
695 topo_graph
697 .graph
698 .add_edge(node_idx0.0, node_idx1.0, topo_edge.clone());
699 topo_graph
700 .graph
701 .add_edge(node_idx1.1, node_idx0.1, topo_edge.clone());
702
703 let topo_edge = TopoEdge {
704 id: EdgeIndex::new(0),
705 from: node_ids[1],
706 to: node_ids[2],
707 edge_id: 2,
708 };
709
710 topo_graph
711 .graph
712 .add_edge(node_idx1.0, node_idx2.0, topo_edge.clone());
713 topo_graph
714 .graph
715 .add_edge(node_idx2.1, node_idx1.1, topo_edge.clone());
716
717 let edge_id = 3;
719 let accessability = Accessability::UnreachableNodes(vec![node_ids[2]]);
720
721 topo_graph.add_edge_with_accessibility(edge_id, node_ids[1], node_ids[3], accessability);
722
723 assert!(
724 topo_graph
725 .graph
726 .find_edge(node_idx1.0, node_idx3.0)
727 .is_some()
728 || topo_graph
729 .graph
730 .find_edge(node_idx1.0, node_idx3.1)
731 .is_some()
732 );
733
734 for i in 1..=3 {
736 let edge_index1 = EdgeIndex::new(i * 2 - 2);
737 let edge_index2 = EdgeIndex::new(i * 2 - 1);
738 assert!(topo_graph.graph.edge_weight(edge_index1).is_some());
739 assert!(topo_graph.graph.edge_weight(edge_index2).is_some());
740 }
741 }
742
743 #[test]
744 fn test_default() {
745 let topo_graph = TopologyGraph::default();
746
747 assert_eq!(topo_graph.graph.node_count(), 0);
749 assert_eq!(topo_graph.graph.edge_count(), 0);
750 assert_eq!(topo_graph.id_to_index.len(), 0);
751 assert_eq!(topo_graph.index_to_id.len(), 0);
752 }
753
754 #[test]
755 fn test_reverse_edge() {
756 let mut topo_graph = TopologyGraph::default();
757 let node1 = topo_graph.add_node(1);
758 let node2 = topo_graph.add_node(2);
759 let edge_index = topo_graph.add_edge(33, 1, 2);
760
761 assert_eq!(
763 topo_graph.graph.edge_endpoints(edge_index.0),
764 Some((node1.0, node2.0))
765 );
766
767 topo_graph.reverse_edge(edge_index.0);
768
769 assert_eq!(
770 topo_graph.graph.edge_endpoints(edge_index.0),
771 Some((node2.0, node1.0))
772 );
773 }
774}