bigraph/interface/
static_bigraph.rs

1use crate::interface::BidirectedData;
2use std::collections::HashSet;
3use traitgraph::interface::{GraphBase, StaticGraph};
4
5/**
6 * A node-centric bidirected graph.
7 * That is a graph in which each node has a unique mirror, and this relation is symmetric.
8 */
9pub trait StaticBigraph: StaticGraph {
10    /**
11     * Returns the unique mirror of the given node id, or `None` if the given node id has no mirror node.
12     */
13    fn mirror_node(&self, node_id: Self::NodeIndex) -> Option<Self::NodeIndex>;
14
15    /// Returns true if the mirror node of this node is itself.
16    /// Panics if the node has no mirror node.
17    fn is_self_mirror_node(&self, node_index: Self::NodeIndex) -> bool {
18        self.mirror_node(node_index).unwrap() == node_index
19    }
20
21    /// Returns a vector of all edges that mirror the given edge, without considering if the edge data mirrors the given edges edge data.
22    fn topological_mirror_edges(&self, edge_index: Self::EdgeIndex) -> Vec<Self::EdgeIndex> {
23        let endpoints = self.edge_endpoints(edge_index);
24        let reverse_from = if let Some(reverse_from) = self.mirror_node(endpoints.to_node) {
25            reverse_from
26        } else {
27            return Vec::new();
28        };
29        let reverse_to = if let Some(reverse_to) = self.mirror_node(endpoints.from_node) {
30            reverse_to
31        } else {
32            return Vec::new();
33        };
34        self.edges_between(reverse_from, reverse_to).collect()
35    }
36
37    /**
38     * Returns true if each node has exactly one mirror, and this relation is symmetric.
39     * This check allows nodes that are their own mirror.
40     */
41    fn verify_node_pairing(&self) -> bool {
42        for node_index in self.node_indices() {
43            let mirror_index = if let Some(mirror_node) = self.mirror_node(node_index) {
44                mirror_node
45            } else {
46                return false;
47            };
48            let mirror_mirror_index =
49                if let Some(mirror_mirror_node) = self.mirror_node(mirror_index) {
50                    mirror_mirror_node
51                } else {
52                    return false;
53                };
54            if node_index != mirror_mirror_index {
55                return false;
56            }
57        }
58
59        true
60    }
61
62    /**
63     * Returns true if each node has exactly one mirror, and this relation is symmetric and irreflexive (no node is its own mirror).
64     */
65    fn verify_node_pairing_without_self_mirrors(&self) -> bool {
66        for node_index in self.node_indices() {
67            let mirror_index = if let Some(mirror_node) = self.mirror_node(node_index) {
68                mirror_node
69            } else {
70                return false;
71            };
72            let mirror_mirror_index =
73                if let Some(mirror_mirror_node) = self.mirror_node(mirror_index) {
74                    mirror_mirror_node
75                } else {
76                    return false;
77                };
78            if node_index != mirror_mirror_index || node_index == mirror_index {
79                return false;
80            }
81        }
82
83        true
84    }
85
86    /// Computes the outdegree of the binode, accounting for inversion edges.
87    /// Panics if the given node has no mirror node.
88    /// Returns `None` if the node is a self-mirror, as the outdegree of self-mirrors is not well-defined.
89    fn out_bidegree(&self, node_index: Self::NodeIndex) -> Option<usize> {
90        let mirror_node = self.mirror_node(node_index).unwrap();
91        if mirror_node == node_index {
92            None
93        } else {
94            let mut out_neighbor_count = 0;
95            let mut inversion_count = 0;
96            for out_neighbor in self.out_neighbors(node_index) {
97                if out_neighbor.node_id == mirror_node {
98                    inversion_count += 1;
99                } else {
100                    out_neighbor_count += 1;
101                }
102            }
103
104            let in_degree = self.in_degree(node_index);
105            Some(out_neighbor_count + inversion_count.min(in_degree))
106        }
107    }
108
109    /// Computes the indegree of the binode, accounting for inversion edges.
110    /// Panics if the given node has no mirror node.
111    /// Returns `None` if the node is a self-mirror, as the indegree of self-mirrors is not well-defined.
112    fn in_bidegree(&self, node_index: Self::NodeIndex) -> Option<usize> {
113        let mirror_node = self.mirror_node(node_index).unwrap();
114        self.out_bidegree(mirror_node)
115    }
116
117    /// Computes the degree of inversion of this node.
118    /// That is the number of outgoing edges to the mirror node minus the number of incoming edges from the mirror node.
119    fn inversion_bidegree(&self, node_index: Self::NodeIndex) -> isize {
120        let mirror_node = self.mirror_node(node_index).unwrap();
121        self.out_neighbors(node_index)
122            .filter(|n| n.node_id == mirror_node)
123            .count() as isize
124            - self
125                .in_neighbors(node_index)
126                .filter(|n| n.node_id == mirror_node)
127                .count() as isize
128    }
129}
130
131/**
132 * A node-centric bidirected graph.
133 * That is a graph in which each node has a unique mirror, and this relation is symmetric.
134 * Additionally, the multiplicity of an edge equals the multiplicity of its mirrors.
135 */
136pub trait StaticNodeCentricBigraph: StaticBigraph {
137    /**
138     * Returns the unique mirror of the given edge id, or `None` if the given edge id has no mirror edge.
139     * If the edge is its own reverse complement, and an mirror edge with a different id exists, then the different id is returned.
140     * Otherwise, for an edge that is its own reverse complement, the given id is returned.
141     */
142    fn mirror_edge_node_centric(&self, edge_id: Self::EdgeIndex) -> Option<Self::EdgeIndex> {
143        let endpoints = self.edge_endpoints(edge_id);
144        let reverse_from = self.mirror_node(endpoints.to_node)?;
145        let reverse_to = self.mirror_node(endpoints.from_node)?;
146        let mut result = None;
147
148        for reverse_edge_id in self.edges_between(reverse_from, reverse_to) {
149            if let Some(node) = result {
150                if node == edge_id {
151                    return Some(reverse_edge_id);
152                }
153            } else if reverse_edge_id == edge_id {
154                result = Some(reverse_edge_id);
155            } else {
156                return Some(reverse_edge_id);
157            }
158        }
159
160        None
161    }
162
163    /**
164     * Returns true if the node-centric [mirror property] of edges is fulfilled.
165     * Assumes that the node pairing is correct (See [verify_node_pairing()](StaticBigraph::verify_node_pairing))
166     *
167     * [mirror property]: https://github.com/GATB/bcalm/blob/master/bidirected-graphs-in-bcalm2/bidirected-graphs-in-bcalm2.md
168     */
169    fn verify_node_mirror_property(&self) -> bool {
170        for from_node in self.node_indices() {
171            for to_node in self.out_neighbors(from_node) {
172                let from_node_mirror = self.mirror_node(from_node).unwrap();
173                let to_node_mirror = self.mirror_node(to_node.node_id).unwrap();
174                if self.edge_count_between(to_node_mirror, from_node_mirror)
175                    != self.edge_count_between(from_node, to_node.node_id)
176                {
177                    return false;
178                }
179            }
180        }
181
182        true
183    }
184}
185
186/**
187 * A edge-centric bidirected graph.
188 * That is a graph in which each node and each edge has a unique mirror, and this relation is symmetric.
189 */
190pub trait StaticEdgeCentricBigraph: StaticBigraph
191where
192    <Self as GraphBase>::EdgeData: BidirectedData + Eq,
193{
194    /**
195     * Returns the unique mirror of the given edge id, or `None` if the given edge id has no mirror edge.
196     * If the edge is its own reverse complement, and a mirror edge with a different id exists, then the different id is returned.
197     * Otherwise, for an edge that is its own reverse complement, the given id is returned.
198     */
199    fn mirror_edge_edge_centric(&self, edge_id: Self::EdgeIndex) -> Option<Self::EdgeIndex> {
200        let endpoints = self.edge_endpoints(edge_id);
201        let reverse_from = self.mirror_node(endpoints.to_node)?;
202        let reverse_to = self.mirror_node(endpoints.from_node)?;
203        let edge_data = self.edge_data(edge_id);
204        let mut result = None;
205
206        for reverse_edge_id in self.edges_between(reverse_from, reverse_to) {
207            if &edge_data.mirror() == self.edge_data(reverse_edge_id) {
208                if let Some(node) = result {
209                    if node == edge_id {
210                        return Some(reverse_edge_id);
211                    }
212                } else if reverse_edge_id == edge_id {
213                    result = Some(reverse_edge_id);
214                } else {
215                    return Some(reverse_edge_id);
216                }
217            }
218        }
219
220        None
221    }
222
223    /**
224     * Returns true if the edge-centric [mirror property] of edges is fulfilled.
225     * Assumes that the node pairing is correct (See [verify_node_pairing()](StaticBigraph::verify_node_pairing)) and that no two edges are the same, except for self mirrors.
226     *
227     * [mirror property]: https://github.com/GATB/bcalm/blob/master/bidirected-graphs-in-bcalm2/bidirected-graphs-in-bcalm2.md
228     */
229    fn verify_edge_mirror_property(&self) -> bool {
230        let mut edge_set = HashSet::new();
231
232        for from_node in self.node_indices() {
233            for neighbor in self.out_neighbors(from_node) {
234                let edge = neighbor.edge_id;
235                if let Some(mirror_edge) = self.mirror_edge_edge_centric(edge) {
236                    let to_node = neighbor.node_id;
237                    let complete_edge = (from_node, to_node, edge);
238                    let mirror_complete_edge = (
239                        self.mirror_node(to_node).unwrap(),
240                        self.mirror_node(from_node).unwrap(),
241                        mirror_edge,
242                    );
243
244                    if edge_set.contains(&mirror_complete_edge) {
245                        edge_set.remove(&mirror_complete_edge);
246                        if &self.edge_data(edge).mirror() != self.edge_data(mirror_edge) {
247                            //println!("Removed edge with wrong mirror data");
248                            return false;
249                        }
250                    } else {
251                        edge_set.insert(complete_edge);
252                    }
253                } else {
254                    //println!("Edge has no mirror edge");
255                    return false;
256                }
257            }
258        }
259
260        /*println!("Returning true if edge set is empty\n{:?}", edge_set);
261        let edge_vec: Vec<_> = edge_set.iter().copied().collect();
262        for (i, &(from_node_1, to_node_1, edge_1)) in edge_vec.iter().enumerate() {
263            for &(from_node_2, to_node_2, edge_2) in edge_vec.iter().skip(i + 1) {
264                let from_node_2_mirror = self.mirror_node(to_node_2).unwrap();
265                let to_node_2_mirror = self.mirror_node(from_node_2).unwrap();
266                if from_node_2_mirror != from_node_1 || to_node_2_mirror != to_node_1 {
267                    continue;
268                }
269
270                if self.edge_data(edge_1).mirror() == *self.edge_data(edge_2) {
271                    println!("Found unresolved mirror {} and {}", edge_1.as_usize(), edge_2.as_usize());
272                } else {
273                    println!("Mirror candidate is no mirror {} and {}", edge_1.as_usize(), edge_2.as_usize());
274                }
275            }
276        }*/
277        edge_set.is_empty()
278    }
279}
280
281/**
282 * A static bigraph that can be created from a static digraph.
283 * Since the graph is static, the resulting topology will be the input topology, only the
284 * bigraph node mapping function will be computed on top.
285 */
286pub trait StaticBigraphFromDigraph: StaticBigraph {
287    /** The type of directed topology the bigraph is created from. */
288    type Topology: StaticGraph<NodeData = Self::NodeData, EdgeData = Self::EdgeData>;
289
290    /**
291     * Converts the given topology into a bigraph with the given mapping function.
292     * If the resulting graph has wrongly mapped nodes, the method panics.
293     */
294    fn new(topology: Self::Topology) -> Self;
295
296    /**
297     * Converts the given topology into a bigraph with the given mapping function.
298     * Unmapped nodes are stored without mapping.
299     * If a node maps to another node, but the other node does not map back, then this method panics.
300     */
301    fn new_unchecked(topology: Self::Topology) -> Self;
302}
303
304#[cfg(test)]
305mod test {
306    use crate::implementation::node_bigraph_wrapper::NodeBigraphWrapper;
307    use crate::interface::dynamic_bigraph::DynamicBigraph;
308    use crate::interface::static_bigraph::StaticBigraph;
309    use crate::interface::static_bigraph::StaticBigraphFromDigraph;
310    use crate::interface::static_bigraph::StaticEdgeCentricBigraph;
311    use crate::interface::static_bigraph::StaticNodeCentricBigraph;
312    use crate::interface::BidirectedData;
313    use traitgraph::implementation::petgraph_impl::PetGraph;
314    use traitgraph::interface::ImmutableGraphContainer;
315    use traitgraph::interface::MutableGraphContainer;
316
317    #[derive(Debug, Clone, Copy, Eq, PartialEq)]
318    struct EdgeData(usize);
319
320    impl BidirectedData for EdgeData {
321        fn mirror(&self) -> Self {
322            EdgeData(1000 - self.0)
323        }
324    }
325
326    #[test]
327    fn test_verify_node_mirror_property_positive() {
328        #[derive(Clone, Eq, PartialEq, Hash, Debug)]
329        struct NodeData(i32);
330        impl BidirectedData for NodeData {
331            fn mirror(&self) -> Self {
332                Self(if self.0 % 2 == 0 {
333                    self.0 + 1
334                } else {
335                    self.0 - 1
336                })
337            }
338        }
339
340        let mut graph = PetGraph::new();
341        let n1 = graph.add_node(NodeData(0));
342        let n2 = graph.add_node(NodeData(1));
343        let n3 = graph.add_node(NodeData(2));
344        let n4 = graph.add_node(NodeData(3));
345        graph.add_edge(n1, n3, EdgeData(10));
346        graph.add_edge(n4, n2, EdgeData(11));
347        graph.add_edge(n3, n1, EdgeData(12));
348        graph.add_edge(n2, n4, EdgeData(13));
349        let bigraph = NodeBigraphWrapper::new(graph);
350        debug_assert!(bigraph.verify_node_pairing());
351        debug_assert!(bigraph.verify_node_mirror_property());
352    }
353
354    #[test]
355    fn test_verify_node_mirror_property_unpaired() {
356        #[derive(Clone, Eq, PartialEq, Hash, Debug)]
357        struct NodeData(i32);
358        impl BidirectedData for NodeData {
359            fn mirror(&self) -> Self {
360                Self(if self.0 % 2 == 0 {
361                    self.0 + 1
362                } else {
363                    self.0 - 1
364                })
365            }
366        }
367
368        let mut graph = PetGraph::new();
369        let n1 = graph.add_node(NodeData(0));
370        let n2 = graph.add_node(NodeData(1));
371        let n3 = graph.add_node(NodeData(2));
372        let n4 = graph.add_node(NodeData(3));
373        graph.add_edge(n1, n3, EdgeData(10));
374        graph.add_edge(n4, n2, EdgeData(11));
375        graph.add_edge(n3, n1, EdgeData(12));
376        let bigraph = NodeBigraphWrapper::new(graph);
377        debug_assert!(bigraph.verify_node_pairing());
378        debug_assert!(!bigraph.verify_node_mirror_property());
379    }
380
381    #[test]
382    fn test_verify_node_mirror_property_duplicate_edges() {
383        #[derive(Clone, Eq, PartialEq, Hash, Debug)]
384        struct NodeData(i32);
385        impl BidirectedData for NodeData {
386            fn mirror(&self) -> Self {
387                Self(if self.0 % 2 == 0 {
388                    self.0 + 1
389                } else {
390                    self.0 - 1
391                })
392            }
393        }
394
395        let mut graph = PetGraph::new();
396        let n1 = graph.add_node(NodeData(0));
397        let n2 = graph.add_node(NodeData(1));
398        let n3 = graph.add_node(NodeData(2));
399        let n4 = graph.add_node(NodeData(3));
400        graph.add_edge(n1, n3, EdgeData(10));
401        graph.add_edge(n4, n2, EdgeData(11));
402        graph.add_edge(n3, n1, EdgeData(12));
403        graph.add_edge(n2, n4, EdgeData(13));
404
405        let mut bigraph = NodeBigraphWrapper::new(graph);
406        debug_assert!(bigraph.verify_node_pairing());
407        debug_assert!(bigraph.verify_node_mirror_property());
408
409        bigraph.add_edge(n1, n3, EdgeData(14));
410        debug_assert!(bigraph.verify_node_pairing());
411        debug_assert!(!bigraph.verify_node_mirror_property());
412
413        bigraph.add_edge(n4, n2, EdgeData(15));
414        debug_assert!(bigraph.verify_node_pairing());
415        debug_assert!(bigraph.verify_node_mirror_property());
416    }
417
418    #[test]
419    fn test_verify_edge_mirror_property_positive() {
420        #[derive(Clone, Eq, PartialEq, Hash, Debug)]
421        struct NodeData(i32);
422        impl BidirectedData for NodeData {
423            fn mirror(&self) -> Self {
424                Self(if self.0 % 2 == 0 {
425                    self.0 + 1
426                } else {
427                    self.0 - 1
428                })
429            }
430        }
431
432        let mut graph = PetGraph::new();
433        let n1 = graph.add_node(NodeData(0));
434        let n2 = graph.add_node(NodeData(1));
435        let n3 = graph.add_node(NodeData(2));
436        let n4 = graph.add_node(NodeData(3));
437        graph.add_edge(n1, n3, EdgeData(10));
438        graph.add_edge(n4, n2, EdgeData(990));
439        graph.add_edge(n3, n1, EdgeData(12));
440        graph.add_edge(n2, n4, EdgeData(988));
441        let bigraph = NodeBigraphWrapper::new(graph);
442        debug_assert!(bigraph.verify_node_pairing());
443        debug_assert!(bigraph.verify_edge_mirror_property());
444    }
445
446    #[test]
447    fn test_verify_edge_mirror_property_unpaired() {
448        #[derive(Clone, Eq, PartialEq, Hash, Debug)]
449        struct NodeData(i32);
450        impl BidirectedData for NodeData {
451            fn mirror(&self) -> Self {
452                Self(if self.0 % 2 == 0 {
453                    self.0 + 1
454                } else {
455                    self.0 - 1
456                })
457            }
458        }
459
460        let mut graph = PetGraph::new();
461        let n1 = graph.add_node(NodeData(0));
462        let n2 = graph.add_node(NodeData(1));
463        let n3 = graph.add_node(NodeData(2));
464        let n4 = graph.add_node(NodeData(3));
465        graph.add_edge(n1, n3, EdgeData(10));
466        graph.add_edge(n4, n2, EdgeData(990));
467        graph.add_edge(n3, n1, EdgeData(12));
468        graph.add_edge(n4, n2, EdgeData(990));
469        let bigraph = NodeBigraphWrapper::new(graph);
470        debug_assert!(bigraph.verify_node_pairing());
471        debug_assert!(!bigraph.verify_edge_mirror_property());
472    }
473
474    #[test]
475    fn test_verify_edge_mirror_property_duplicate_edges_with_differing_data() {
476        #[derive(Clone, Eq, PartialEq, Hash, Debug)]
477        struct NodeData(i32);
478        impl BidirectedData for NodeData {
479            fn mirror(&self) -> Self {
480                Self(if self.0 % 2 == 0 {
481                    self.0 + 1
482                } else {
483                    self.0 - 1
484                })
485            }
486        }
487
488        let mut graph = PetGraph::new();
489        let n1 = graph.add_node(NodeData(0));
490        let n2 = graph.add_node(NodeData(1));
491        let n3 = graph.add_node(NodeData(2));
492        let n4 = graph.add_node(NodeData(3));
493        graph.add_edge(n1, n3, EdgeData(10));
494        graph.add_edge(n4, n2, EdgeData(990));
495        graph.add_edge(n3, n1, EdgeData(12));
496        graph.add_edge(n2, n4, EdgeData(988));
497
498        let mut bigraph = NodeBigraphWrapper::new(graph);
499        debug_assert!(bigraph.verify_node_pairing());
500        debug_assert!(bigraph.verify_edge_mirror_property());
501
502        bigraph.add_edge(n1, n3, EdgeData(14));
503        debug_assert!(bigraph.verify_node_pairing());
504        debug_assert!(!bigraph.verify_edge_mirror_property());
505
506        bigraph.add_edge(n4, n2, EdgeData(986));
507        debug_assert!(bigraph.verify_node_pairing());
508        debug_assert!(bigraph.verify_edge_mirror_property());
509    }
510
511    #[test]
512    fn test_verify_edge_mirror_property_duplicate_edges_with_plus_minus_loop() {
513        #[derive(Clone, Eq, PartialEq, Hash, Debug)]
514        struct NodeData(i32);
515        impl BidirectedData for NodeData {
516            fn mirror(&self) -> Self {
517                Self(1000 - self.0)
518            }
519        }
520
521        let mut graph = NodeBigraphWrapper::new(PetGraph::new());
522        let n1 = graph.add_node(NodeData(0));
523        let n2 = graph.add_node(NodeData(1000));
524        let n3 = graph.add_node(NodeData(500));
525        graph.set_mirror_nodes(n1, n2);
526        graph.set_mirror_nodes(n3, n3);
527        graph.add_edge(n1, n3, EdgeData(10));
528        graph.add_edge(n3, n2, EdgeData(990));
529        graph.add_edge(n3, n1, EdgeData(12));
530        graph.add_edge(n2, n3, EdgeData(988));
531
532        debug_assert!(graph.verify_node_pairing());
533        debug_assert!(graph.verify_edge_mirror_property());
534
535        graph.add_edge(n1, n3, EdgeData(14));
536        debug_assert!(graph.verify_node_pairing());
537        debug_assert!(!graph.verify_edge_mirror_property());
538
539        graph.add_edge(n3, n2, EdgeData(986));
540        debug_assert!(graph.verify_node_pairing());
541        debug_assert!(graph.verify_edge_mirror_property());
542
543        debug_assert_eq!(graph.edge_count(), 6);
544        let mirror_copy = graph.clone();
545
546        graph.add_edge(n1, n3, EdgeData(14));
547        debug_assert!(graph.verify_node_pairing());
548        debug_assert!(!graph.verify_edge_mirror_property());
549
550        graph.add_edge(n3, n2, EdgeData(986));
551        debug_assert!(graph.verify_node_pairing());
552        debug_assert!(!graph.verify_edge_mirror_property());
553        debug_assert_eq!(graph.edge_count(), 8);
554
555        let mut graph = mirror_copy.clone();
556
557        graph.add_edge(n1, n3, EdgeData(100));
558        debug_assert!(graph.verify_node_pairing());
559        debug_assert!(!graph.verify_edge_mirror_property());
560
561        graph.add_edge(n1, n3, EdgeData(100));
562        debug_assert!(graph.verify_node_pairing());
563        debug_assert!(!graph.verify_edge_mirror_property());
564
565        graph.add_edge(n3, n2, EdgeData(900));
566        debug_assert!(graph.verify_node_pairing());
567        debug_assert!(!graph.verify_edge_mirror_property());
568
569        graph.add_edge(n3, n2, EdgeData(900));
570        debug_assert!(graph.verify_node_pairing());
571        debug_assert!(!graph.verify_edge_mirror_property());
572        debug_assert_eq!(graph.edge_count(), 10);
573
574        let mut graph = mirror_copy.clone();
575
576        graph.add_edge(n3, n2, EdgeData(900));
577        debug_assert!(graph.verify_node_pairing());
578        debug_assert!(!graph.verify_edge_mirror_property());
579
580        graph.add_edge(n1, n3, EdgeData(100));
581        debug_assert!(graph.verify_node_pairing());
582        debug_assert!(graph.verify_edge_mirror_property());
583
584        graph.add_edge(n1, n3, EdgeData(100));
585        debug_assert!(graph.verify_node_pairing());
586        debug_assert!(!graph.verify_edge_mirror_property());
587
588        graph.add_edge(n3, n2, EdgeData(900));
589        debug_assert!(graph.verify_node_pairing());
590        debug_assert!(!graph.verify_edge_mirror_property());
591        debug_assert_eq!(graph.edge_count(), 10);
592
593        let mut graph = mirror_copy.clone();
594
595        graph.add_edge(n3, n2, EdgeData(986));
596        debug_assert!(graph.verify_node_pairing());
597        debug_assert!(!graph.verify_edge_mirror_property());
598
599        graph.add_edge(n1, n3, EdgeData(14));
600        debug_assert!(graph.verify_node_pairing());
601        debug_assert!(!graph.verify_edge_mirror_property());
602        debug_assert_eq!(graph.edge_count(), 8);
603
604        let mut graph = mirror_copy;
605
606        graph.add_edge(n3, n3, EdgeData(500));
607        debug_assert!(graph.verify_node_pairing());
608        debug_assert!(!graph.verify_edge_mirror_property());
609
610        graph.add_edge(n3, n3, EdgeData(500));
611        debug_assert!(graph.verify_node_pairing());
612        debug_assert!(graph.verify_edge_mirror_property());
613        debug_assert_eq!(graph.edge_count(), 8);
614
615        graph.add_edge(n3, n3, EdgeData(500));
616        debug_assert!(graph.verify_node_pairing());
617        debug_assert!(!graph.verify_edge_mirror_property());
618
619        graph.add_edge(n3, n3, EdgeData(500));
620        debug_assert!(graph.verify_node_pairing());
621        debug_assert!(!graph.verify_edge_mirror_property());
622        debug_assert_eq!(graph.edge_count(), 10);
623    }
624}