rs_graph/
linkedlistgraph.rs

1/*
2 * Copyright (c) 2017-2022 Frank Fischer <frank-fischer@shadow-soft.de>
3 *
4 * This program is free software: you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation, either version 3 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program.  If not, see  <http://www.gnu.org/licenses/>
16 */
17
18//! A linked-list based graph implementation.
19//!
20//! This is an efficient default implementation of a graph.
21//!
22//! `LinkedListGraph` provides directed arc access (i.e. implements
23//! `Network`).
24//!
25//! Node and edge data are stored in an array (Vec), nodes and edges
26//! are identified by indices. Forward edges have even indices,
27//! backward edges have the odd indices directly following the
28//! corresponding forward edge. The external edge index is the edge
29//! index shifted right by one bit (the lsb is removed), but a user
30//! should not rely on that. The node and edge indices can be
31//! retrieved using the `IndexGraph` and `IndexNetwork` traits.
32//!
33//! `LinkedListGraph` takes additional parameters for node, edge
34//! and biedge attributes, thus, it implements `NodeAttributes`,
35//! `EdgeAttributes` and `BiEdgeAttributes`.
36//!
37//! `LinkedListGraph` can be constructed (it implements `Builder`),
38//! but nodes and edges cannot be removed.
39
40use crate::attributes::{EdgeAttributes, NodeAttributes};
41use crate::builder::{Buildable, Builder};
42use crate::traits::{Directed, DirectedEdge, FiniteDigraph, FiniteGraph, GraphType, Undirected};
43use crate::traits::{GraphIterator, IndexGraph, Indexable};
44
45use crate::num::iter::{range, range_step, Range, RangeStep};
46use crate::num::traits::{PrimInt, Unsigned};
47
48use std::fmt;
49use std::hash::{Hash, Hasher};
50
51#[cfg(feature = "serialize")]
52use serde_derive::{Deserialize, Serialize};
53
54/// Node of a linked list graph.
55///
56/// This is basically a newtype of the node index.
57#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
58pub struct Node<ID = u32>(ID)
59where
60    ID: PrimInt + Unsigned;
61
62impl<ID> fmt::Display for Node<ID>
63where
64    ID: PrimInt + Unsigned + fmt::Display,
65{
66    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
67        write!(f, "{}", self.0)
68    }
69}
70
71impl<ID> Indexable for Node<ID>
72where
73    ID: PrimInt + Unsigned,
74{
75    fn index(&self) -> usize {
76        self.0.to_usize().unwrap()
77    }
78}
79
80/// Edge of a linked list graph.
81///
82/// This is basically a newtype of the *arc* index. Note that
83/// `e == g.reverse(e)`.
84#[derive(Eq, Clone, Copy, Debug)]
85pub struct Edge<ID = u32>(ID)
86where
87    ID: PrimInt + Unsigned;
88
89impl<ID> PartialEq for Edge<ID>
90where
91    ID: PrimInt + Unsigned,
92{
93    fn eq(&self, other: &Self) -> bool {
94        (self.0 >> 1) == (other.0 >> 1)
95    }
96}
97
98impl<ID> fmt::Display for Edge<ID>
99where
100    ID: PrimInt + Unsigned + fmt::Display,
101{
102    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
103        write!(
104            f,
105            "{}{}",
106            if (self.0 & ID::one()).is_zero() { "+" } else { "-" },
107            self.0 >> 1
108        )
109    }
110}
111
112impl<ID> Hash for Edge<ID>
113where
114    ID: PrimInt + Unsigned + Hash,
115{
116    fn hash<H: Hasher>(&self, state: &mut H) {
117        (self.0 >> 1).hash(state)
118    }
119}
120
121impl<ID> Indexable for Edge<ID>
122where
123    ID: PrimInt + Unsigned,
124{
125    fn index(&self) -> usize {
126        (self.0 >> 1).to_usize().unwrap()
127    }
128}
129
130impl<ID> DirectedEdge for Edge<ID>
131where
132    ID: PrimInt + Unsigned,
133{
134    type Edge = Self;
135
136    fn is_incoming(&self) -> bool {
137        !(self.0 & ID::one()).is_zero()
138    }
139
140    fn edge(&self) -> Self::Edge {
141        *self
142    }
143}
144
145/// The linked list based graph data structure.
146#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
147pub struct LinkedListGraph<ID = u32, N = (), E = ()> {
148    /// List of nodes.
149    nodes: Vec<NodeData<ID, N>>,
150    /// List of edges.
151    edges: Vec<EdgeData<ID, E>>,
152}
153
154/// Data for a node in a linked list graph.
155#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
156struct NodeData<ID, N> {
157    /// The first outgoing adjacent edge.
158    first_out: ID,
159    /// The first incoming adjacent edge.
160    first_in: ID,
161    /// Associated node attributes.
162    attrs: N,
163}
164
165/// Data for an edge in the linked list graph.
166#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
167struct EdgeData<ID, E> {
168    /// The sink node.
169    snk: ID,
170    /// The next arc adjacent to the source node.
171    next: ID,
172    /// Associated edge attributes.
173    eattrs: E,
174}
175
176/// A graph iterator over all nodes of a linked list graph.
177#[derive(Clone)]
178pub struct NodeIt<ID>(Range<ID>);
179
180impl<ID, N, E> GraphIterator<LinkedListGraph<ID, N, E>> for NodeIt<ID>
181where
182    ID: PrimInt + Unsigned,
183{
184    type Item = Node<ID>;
185
186    fn next(&mut self, _g: &LinkedListGraph<ID, N, E>) -> Option<Self::Item> {
187        Iterator::next(&mut self.0).map(Node)
188    }
189
190    fn size_hint(&self, _g: &LinkedListGraph<ID, N, E>) -> (usize, Option<usize>) {
191        Iterator::size_hint(&self.0)
192    }
193
194    fn count(self, _g: &LinkedListGraph<ID, N, E>) -> usize {
195        Iterator::count(self.0)
196    }
197}
198
199/// An iterator over all edges of a linked list graph.
200///
201/// This iterator only returns the forward edges.
202#[derive(Clone)]
203pub struct EdgeIt<ID>(RangeStep<ID>);
204
205impl<ID, N, E> GraphIterator<LinkedListGraph<ID, N, E>> for EdgeIt<ID>
206where
207    ID: PrimInt + Unsigned,
208{
209    type Item = Edge<ID>;
210
211    fn next(&mut self, _g: &LinkedListGraph<ID, N, E>) -> Option<Self::Item> {
212        Iterator::next(&mut self.0).map(Edge)
213    }
214
215    fn size_hint(&self, _g: &LinkedListGraph<ID, N, E>) -> (usize, Option<usize>) {
216        Iterator::size_hint(&self.0)
217    }
218
219    fn count(self, _g: &LinkedListGraph<ID, N, E>) -> usize {
220        Iterator::count(self.0)
221    }
222}
223
224impl<ID, N, E> GraphType for LinkedListGraph<ID, N, E>
225where
226    ID: PrimInt + Unsigned,
227{
228    type Node<'a> = Node<ID>;
229    type Edge<'a> = Edge<ID>;
230}
231
232impl<ID, N, E> FiniteGraph for LinkedListGraph<ID, N, E>
233where
234    ID: PrimInt + Unsigned + 'static,
235{
236    type NodeIt<'a> = NodeIt<ID>
237    where
238        N: 'a,
239        E: 'a;
240    type EdgeIt<'a> = EdgeIt<ID>
241    where
242        N: 'a,
243        E: 'a;
244
245    fn num_nodes(&self) -> usize {
246        self.nodes.len()
247    }
248
249    fn num_edges(&self) -> usize {
250        self.edges.len() / 2
251    }
252
253    fn nodes_iter(&self) -> Self::NodeIt<'_> {
254        NodeIt(range(ID::zero(), ID::from(self.num_nodes()).unwrap()))
255    }
256
257    fn edges_iter(&self) -> Self::EdgeIt<'_> {
258        EdgeIt(range_step(
259            ID::zero(),
260            ID::from(self.edges.len()).unwrap(),
261            ID::from(2).unwrap(),
262        ))
263    }
264
265    fn enodes(&self, e: Self::Edge<'_>) -> (Self::Node<'_>, Self::Node<'_>) {
266        let eid = e.0.to_usize().unwrap();
267        (Node(self.edges[eid | 1].snk), Node(self.edges[eid & !1].snk))
268    }
269}
270
271impl<ID, N, E> FiniteDigraph for LinkedListGraph<ID, N, E>
272where
273    ID: PrimInt + Unsigned + 'static,
274{
275    fn src(&self, e: Self::Edge<'_>) -> Self::Node<'_> {
276        Node(self.edges[e.0.to_usize().unwrap() | 1].snk)
277    }
278
279    fn snk(&self, e: Self::Edge<'_>) -> Self::Node<'_> {
280        Node(self.edges[e.0.to_usize().unwrap() & !1].snk)
281    }
282}
283
284/// Graph iterator over edges incident with some node.
285#[derive(Clone)]
286pub struct NeighIt<ID>(ID);
287
288impl<ID, N, E> GraphIterator<LinkedListGraph<ID, N, E>> for NeighIt<ID>
289where
290    ID: PrimInt + Unsigned,
291{
292    type Item = (Edge<ID>, Node<ID>);
293
294    fn next(&mut self, g: &LinkedListGraph<ID, N, E>) -> Option<Self::Item> {
295        if self.0 != ID::max_value() {
296            let e = &g.edges[self.0.to_usize().unwrap()];
297            let x = (Edge(self.0), Node(e.snk));
298            self.0 = e.next;
299            Some(x)
300        } else {
301            None
302        }
303    }
304}
305
306impl<ID, N, E> Undirected for LinkedListGraph<ID, N, E>
307where
308    ID: PrimInt + Unsigned + 'static,
309{
310    type NeighIt<'a> = NeighIt<ID>
311    where
312        N: 'a,
313        E: 'a;
314
315    fn neigh_iter(&self, u: Self::Node<'_>) -> Self::NeighIt<'_> {
316        let u = &self.nodes[u.index()];
317        if u.first_out != ID::max_value() {
318            NeighIt(u.first_out)
319        } else {
320            NeighIt(u.first_in)
321        }
322    }
323}
324
325/// A graph iterator over edges leaving a node.
326#[derive(Clone)]
327pub struct OutIt<ID>(ID);
328
329impl<ID, N, E> GraphIterator<LinkedListGraph<ID, N, E>> for OutIt<ID>
330where
331    ID: PrimInt + Unsigned,
332{
333    type Item = (Edge<ID>, Node<ID>);
334
335    fn next(&mut self, g: &LinkedListGraph<ID, N, E>) -> Option<Self::Item> {
336        if (self.0 & ID::one()).is_zero() {
337            let e = &g.edges[self.0.to_usize().unwrap()];
338            let x = (Edge(self.0), Node(e.snk));
339            self.0 = e.next;
340            Some(x)
341        } else {
342            None
343        }
344    }
345}
346
347/// A graph iterator over edges entering a node.
348pub type InIt<ID> = NeighIt<ID>;
349
350/// A graph iterator over directed edges incident with some node.
351pub type IncidentIt<ID> = NeighIt<ID>;
352
353impl<ID, N, E> Directed for LinkedListGraph<ID, N, E>
354where
355    ID: PrimInt + Unsigned + 'static,
356{
357    type OutIt<'a> = OutIt<ID>
358    where
359        N: 'a,
360        E: 'a;
361
362    type InIt<'a> = InIt<ID>
363    where
364        N: 'a,
365        E: 'a;
366
367    type IncidentIt<'a> = IncidentIt<ID>
368    where
369        N: 'a,
370        E: 'a;
371
372    type DirectedEdge<'a> = Self::Edge<'a>
373    where
374        N: 'a,
375        E: 'a;
376
377    fn out_iter(&self, u: Self::Node<'_>) -> Self::OutIt<'_> {
378        OutIt(self.nodes[u.index()].first_out)
379    }
380
381    fn in_iter(&self, u: Self::Node<'_>) -> Self::InIt<'_> {
382        NeighIt(self.nodes[u.index()].first_in)
383    }
384
385    fn incident_iter(&self, u: Self::Node<'_>) -> Self::IncidentIt<'_> {
386        self.neigh_iter(u)
387    }
388}
389
390impl<ID, N, E> IndexGraph for LinkedListGraph<ID, N, E>
391where
392    ID: PrimInt + Unsigned + 'static,
393{
394    fn node_id(&self, u: Self::Node<'_>) -> usize {
395        u.index()
396    }
397
398    fn id2node(&self, id: usize) -> Self::Node<'_> {
399        debug_assert!(id < self.nodes.len(), "Invalid node id");
400        Node(ID::from(id).unwrap())
401    }
402
403    fn edge_id(&self, e: Self::Edge<'_>) -> usize {
404        e.index()
405    }
406
407    fn id2edge(&self, id: usize) -> Self::Edge<'_> {
408        debug_assert!(id << 1 < self.edges.len(), "Invalid edge id");
409        Edge(ID::from(id << 1).unwrap())
410    }
411}
412
413impl<ID, N, E> NodeAttributes<LinkedListGraph<ID, N, E>, N> for LinkedListGraph<ID, N, E>
414where
415    ID: PrimInt + Unsigned + 'static,
416{
417    fn node(&self, u: <Self as GraphType>::Node<'_>) -> &N {
418        &self.nodes[u.index()].attrs
419    }
420
421    fn node_mut(&mut self, u: <Self as GraphType>::Node<'_>) -> &mut N {
422        &mut self.nodes[u.index()].attrs
423    }
424}
425
426impl<ID, N, E> EdgeAttributes<LinkedListGraph<ID, N, E>, E> for LinkedListGraph<ID, N, E>
427where
428    ID: PrimInt + Unsigned + 'static,
429{
430    fn edge(&self, e: <Self as GraphType>::Edge<'_>) -> &E {
431        &self.edges[e.index()].eattrs
432    }
433
434    fn edge_mut(&mut self, e: <Self as GraphType>::Edge<'_>) -> &mut E {
435        &mut self.edges[e.index()].eattrs
436    }
437}
438
439/// A builder for a LinkedListGraph.
440///
441/// The basic task is to arrange the final outgoing and incoming edges in the
442/// linked lists appropriately (i.e. first outgoing, then incoming edges).
443pub struct LinkedListGraphBuilder<ID, N, E> {
444    /// The graph to be built.
445    graph: LinkedListGraph<ID, N, E>,
446    /// The last outgoing edge for each node (if there is one).
447    last_out: Vec<Option<ID>>,
448}
449
450impl<ID, N, E> Builder for LinkedListGraphBuilder<ID, N, E>
451where
452    ID: PrimInt + Unsigned + 'static,
453    N: Default,
454    E: Default,
455{
456    type Graph = LinkedListGraph<ID, N, E>;
457    type Node = Node<ID>;
458    type Edge = Edge<ID>;
459
460    fn with_capacities(nnodes: usize, nedges: usize) -> Self {
461        LinkedListGraphBuilder {
462            graph: LinkedListGraph {
463                nodes: Vec::with_capacity(nnodes),
464                edges: Vec::with_capacity(nedges),
465            },
466            last_out: Vec::with_capacity(nnodes),
467        }
468    }
469
470    fn reserve(&mut self, nnodes: usize, nedges: usize) {
471        self.graph.nodes.reserve(nnodes);
472        self.graph.edges.reserve(nedges);
473        self.last_out.reserve(nnodes);
474    }
475
476    fn num_nodes(&self) -> usize {
477        self.graph.nodes.len()
478    }
479
480    fn num_edges(&self) -> usize {
481        self.graph.edges.len() / 2
482    }
483
484    fn add_node(&mut self) -> Self::Node {
485        assert!(
486            self.graph.nodes.len() + 1 < ID::max_value().to_usize().unwrap(),
487            "Node capacity exceeded"
488        );
489        let id = self.graph.nodes.len();
490        self.graph.nodes.push(NodeData {
491            first_out: ID::max_value(),
492            first_in: ID::max_value(),
493            attrs: Default::default(),
494        });
495        self.last_out.push(None);
496        Node(ID::from(id).unwrap())
497    }
498
499    fn add_edge(&mut self, u: Self::Node, v: Self::Node) -> Self::Edge {
500        assert!(
501            self.graph.edges.len() + 2 < ID::max_value().to_usize().unwrap(),
502            "Edge capacity exceeded"
503        );
504        let eid = ID::from(self.graph.edges.len()).unwrap();
505        let uid = u.0.to_usize().unwrap();
506        let vid = v.0.to_usize().unwrap();
507        self.graph.edges.push(EdgeData {
508            snk: v.0,
509            next: self.graph.nodes[uid].first_out,
510            eattrs: Default::default(),
511        });
512        self.graph.edges.push(EdgeData {
513            snk: u.0,
514            next: self.graph.nodes[vid].first_in,
515            eattrs: Default::default(),
516        });
517        self.graph.nodes[uid].first_out = eid;
518        self.graph.nodes[vid].first_in = eid + ID::one();
519        if self.last_out[uid].is_none() {
520            self.last_out[uid] = Some(eid);
521        }
522        Edge(eid)
523    }
524
525    fn node2id(&self, u: Self::Node) -> usize {
526        IndexGraph::node_id(&self.graph, u)
527    }
528
529    fn edge2id(&self, e: Self::Edge) -> usize {
530        IndexGraph::edge_id(&self.graph, e)
531    }
532
533    fn id2node(&self, uid: usize) -> Self::Node {
534        IndexGraph::id2node(&self.graph, uid)
535    }
536
537    fn id2edge(&self, eid: usize) -> Self::Edge {
538        IndexGraph::id2edge(&self.graph, eid)
539    }
540
541    fn into_graph(self) -> LinkedListGraph<ID, N, E> {
542        // Append the list of incoming edges to the end of the list of outgoing
543        // edges.
544        let mut g = self.graph;
545        for (u, e) in self
546            .last_out
547            .into_iter()
548            .enumerate()
549            .filter_map(|(u, e)| e.map(|e| (u, e)))
550        {
551            g.edges[e.to_usize().unwrap()].next = g.nodes[u].first_in;
552        }
553        g
554    }
555}
556
557impl<ID, N, E> Buildable for LinkedListGraph<ID, N, E>
558where
559    ID: PrimInt + Unsigned + 'static,
560    N: Default,
561    E: Default,
562{
563    type Builder = LinkedListGraphBuilder<ID, N, E>;
564}
565
566impl<ID, N, E> LinkedListGraph<ID, N, E>
567where
568    ID: PrimInt + Unsigned,
569{
570    pub fn new() -> LinkedListGraph<ID, N, E> {
571        LinkedListGraph {
572            nodes: vec![],
573            edges: vec![],
574        }
575    }
576}
577
578impl<ID, N, E> Default for LinkedListGraph<ID, N, E>
579where
580    ID: PrimInt + Unsigned,
581{
582    fn default() -> Self {
583        LinkedListGraph::new()
584    }
585}
586
587#[cfg(test)]
588mod tests {
589    use crate::attributes::*;
590    use crate::classes::*;
591    use crate::traits::Indexable;
592    use crate::traits::*;
593    use crate::LinkedListGraph;
594    use std::cmp::{max, min};
595
596    #[test]
597    fn test_graph() {
598        const N: usize = 7;
599        let g = cycle::<LinkedListGraph>(N);
600
601        assert_eq!(g.num_nodes(), N);
602        assert_eq!(g.num_edges(), N);
603
604        let mut balances = vec![0; g.num_nodes()];
605
606        for u in g.nodes() {
607            balances[g.node_id(u)] = u.index();
608        }
609
610        for u in g.nodes() {
611            assert_eq!(balances[g.node_id(u)], u.index());
612        }
613
614        for u in g.nodes() {
615            let mut neighs: Vec<_> = g.neighs(u).collect();
616
617            for &(e, v) in &neighs {
618                eprintln!(
619                    "{} {}->{} {}-{}",
620                    e.index(),
621                    u.index(),
622                    v.index(),
623                    g.enodes(e).0.index(),
624                    g.enodes(e).1.index()
625                );
626                assert!((g.enodes(e) == (u, v)) || (g.enodes(e) == (v, u)));
627            }
628
629            neighs.sort_by_key(|&(_, u)| u.index());
630
631            let x = (u.index() + N - 1) % N;
632            let y = (u.index() + 1) % N;
633            assert_eq!(
634                neighs.iter().map(|&(_, v)| v).collect::<Vec<_>>(),
635                vec![g.id2node(min(x, y)), g.id2node(max(x, y))]
636            );
637        }
638    }
639
640    #[test]
641    fn test_edge_vec() {
642        let g = cycle::<LinkedListGraph>(7);
643
644        let mut x = vec![0; g.num_edges()];
645        for (i, e) in g.edges().enumerate() {
646            x[g.edge_id(e)] = i;
647        }
648
649        for u in g.nodes() {
650            for (e, _) in g.neighs(u) {
651                assert_eq!(x[g.edge_id(e)], e.index());
652            }
653        }
654    }
655
656    #[test]
657    fn test_digraph() {
658        for g in [cycle::<LinkedListGraph>(7), peterson(), hypercube(5)].iter() {
659            for u in g.nodes() {
660                for (e, v) in g.outedges(u) {
661                    assert_eq!(u, g.src(e));
662                    assert_eq!(v, g.snk(e));
663                }
664                for (e, v) in g.inedges(u) {
665                    assert_eq!(v, g.src(e));
666                    assert_eq!(u, g.snk(e));
667                }
668                for (e, v) in g.incident_edges(u) {
669                    assert_eq!(
670                        v,
671                        if e.is_incoming() {
672                            g.src(e.edge())
673                        } else {
674                            g.snk(e.edge())
675                        }
676                    );
677                }
678            }
679        }
680    }
681
682    #[test]
683    fn test_attrs() {
684        #[derive(Default)]
685        struct NodeData {
686            balance: usize,
687        }
688
689        #[derive(Default)]
690        struct EdgeData {
691            upper: usize,
692        }
693
694        let mut g = peterson::<LinkedListGraph<u32, NodeData, EdgeData>>();
695        for u in 0..g.num_nodes() {
696            g.node_mut(g.id2node(u)).balance = u;
697        }
698
699        for e in 0..g.num_edges() {
700            let uid = g.node_id(g.src(g.id2edge(e)));
701            g.edge_mut(g.id2edge(e)).upper = uid;
702        }
703
704        for u in g.nodes() {
705            assert_eq!(g.node(u).balance, g.node_id(u));
706            for (e, _) in g.outedges(u) {
707                assert_eq!(g.edge(e).upper, g.node_id(g.src(e)));
708            }
709            for (e, _) in g.inedges(u) {
710                assert_eq!(g.edge(e).upper, g.node_id(g.src(e)));
711            }
712        }
713    }
714
715    #[cfg(feature = "serialize")]
716    mod serialize {
717        use super::LinkedListGraph;
718        use crate::classes::peterson;
719        use crate::traits::{FiniteDigraph, FiniteGraph, IndexGraph};
720        use serde_json;
721
722        #[test]
723        fn test_serde() {
724            let g = peterson::<LinkedListGraph>();
725
726            let serialized = serde_json::to_string(&g).unwrap();
727
728            println!("serialized = {}", serialized);
729
730            let h: LinkedListGraph = serde_json::from_str(&serialized).unwrap();
731
732            assert_eq!(g.num_nodes(), h.num_nodes());
733            assert_eq!(g.num_edges(), h.num_edges());
734            for e in g.edges() {
735                let f = h.id2edge(g.edge_id(e));
736                assert_eq!(g.node_id(g.src(e)), h.node_id(h.src(f)));
737                assert_eq!(g.node_id(g.snk(e)), h.node_id(h.snk(f)));
738            }
739        }
740
741        #[test]
742        fn test_serialize() {
743            use crate::{Buildable, Builder};
744            let g = LinkedListGraph::<u32>::new_with(|b| {
745                let nodes = b.add_nodes(5);
746                b.add_edge(nodes[0], nodes[1]);
747                b.add_edge(nodes[0], nodes[2]);
748                b.add_edge(nodes[1], nodes[4]);
749                b.add_edge(nodes[2], nodes[3]);
750            });
751
752            let serialized = serde_json::to_string(&g).unwrap();
753            let g2: LinkedListGraph<u32> = serde_json::from_str(&serialized).unwrap();
754
755            assert_eq!(g.num_nodes(), g2.num_nodes());
756            let mut edges = g2
757                .edges()
758                .map(|e| {
759                    let (u, v) = g2.enodes(e);
760                    let (u, v) = (g2.node_id(u), g2.node_id(v));
761                    (u.min(v), u.max(v))
762                })
763                .collect::<Vec<_>>();
764            edges.sort();
765            assert_eq!(edges, vec![(0, 1), (0, 2), (1, 4), (2, 3)]);
766        }
767    }
768}