algograph 0.4.0

A (both directed and undirected) graph and their algorithms implemented in Rust
Documentation
//! Implementations of low-level directed graph

mod adjacent_list;
pub use self::adjacent_list::*;
mod tree_backed;
pub use self::tree_backed::*;

#[cfg(test)]
pub use self::tests::*;

#[cfg(test)]
mod tests {
    use crate::graph::*;
    use rs_quickcheck_util::*;
    use std::collections::BTreeSet;

    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    pub enum Op {
        AddVertex(VertexId),
        RemoveVertex(VertexId),
        AddEdge((VertexId, VertexId, EdgeId)),
        RemoveEdge(EdgeId),
    }

    #[derive(Clone)]
    pub struct Ops {
        pub ops: Vec<Op>,
    }

    impl std::fmt::Debug for Ops {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            write!(f, "{:?}", self.ops)
        }
    }

    impl Ops {
        pub fn iter(&self) -> impl Iterator<Item = &Op> + '_ {
            self.ops.iter()
        }
    }

    impl quickcheck::Arbitrary for Ops {
        fn arbitrary(g: &mut quickcheck::Gen) -> Self {
            let mut vid_factory = VertexIdFactory::new();
            let mut eid_factory = EdgeIdFactory::new();
            let mut known_vid = BTreeSet::new();
            let mut known_eid = BTreeSet::new();
            let ops = gen_bytes(g, b"abcd.", b'.', 0..)
                .iter()
                .filter_map(|_| match u8::arbitrary(g) % 4 {
                    0 => {
                        let vid = vid_factory.one_more();
                        known_vid.insert(vid);
                        Some(Op::AddVertex(vid))
                    }
                    1 => {
                        if known_vid.is_empty() {
                            None
                        } else {
                            let vid = {
                                let idx = usize::arbitrary(g) % known_vid.len();
                                *known_vid.iter().nth(idx).unwrap()
                            };
                            known_vid.remove(&vid);
                            Some(Op::RemoveVertex(vid))
                        }
                    }
                    2 => {
                        if known_vid.is_empty() {
                            None
                        } else {
                            let src_vid = {
                                let idx = usize::arbitrary(g) % known_vid.len();
                                *known_vid.iter().nth(idx).unwrap()
                            };
                            let sink_vid = {
                                let idx = usize::arbitrary(g) % known_vid.len();
                                *known_vid.iter().nth(idx).unwrap()
                            };
                            let eid = eid_factory.one_more();
                            known_eid.insert(eid);
                            Some(Op::AddEdge((src_vid, sink_vid, eid)))
                        }
                    }
                    3 => {
                        if known_eid.is_empty() {
                            None
                        } else {
                            let eid = {
                                let idx = usize::arbitrary(g) % known_eid.len();
                                *known_eid.iter().nth(idx).unwrap()
                            };
                            known_eid.remove(&eid);
                            Some(Op::RemoveEdge(eid))
                        }
                    }
                    _ => unreachable!(),
                })
                .collect();
            Self { ops }
        }

        fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
            let l = self.ops.len();
            let me = self.clone();
            let it = std::iter::successors(Some(l / 2), move |n| {
                let nxt = (n + l) / 2 + 1;
                if nxt >= l {
                    None
                } else {
                    Some(nxt)
                }
            })
            .map(move |n| {
                let mut res = me.clone();
                res.ops = me.ops[0..n].to_vec();
                res
            });
            Box::new(it)
        }
    }

    #[test]
    fn to_graphviz() {
        let mut g = directed::AdjacentListGraph::new();
        let v = g.add_vertex();
        g.add_edge(v, v);
        let trial = {
            let mut trial = vec![];
            g.dump_in_graphviz(&mut trial, "trial").unwrap();
            String::from_utf8(trial).unwrap()
        };
        assert_eq!(
            trial,
            r#"digraph trial {
  0 ;
  0 -> 0 ;
}
"#
        );
    }
}