// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. use choose::Choose; use graphs::common::OutNeighborFromOutEdge; use prelude::*; use props::{VecEdgeProp, VecVertexProp}; use fera_fun::vec; use fera_optional::OptionalMax; use std::cmp::Ordering; use std::fmt::Debug; use std::hash::{Hash, Hasher}; use std::iter::Cloned; use std::marker::PhantomData; use std::ops::Range; use std::slice::Iter; use num_traits::Bounded; use rand::Rng; pub type StaticDigraph = Static; pub type StaticGraph = Static; // Edge pub trait StaticEdgeKind: 'static { type Kind: UniformEdgeKind; // TODO: change to EdgeKind type Edge: 'static + GraphItem + Bounded + EdgeImpl; } #[doc(hidden)] pub trait EdgeImpl: Sized { fn new(e: usize) -> Self; fn new_checked(e: usize) -> Option; fn source(self, ends: &[T]) -> &T; fn target(self, ends: &[T]) -> &T; fn to_index(self) -> usize; fn reverse(self) -> Self; } // StaticDirectedEdge #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct StaticDirectedEdge(N); impl StaticEdgeKind for (Directed, E) { type Kind = Directed; type Edge = StaticDirectedEdge; } impl Bounded for StaticDirectedEdge { fn max_value() -> Self { StaticDirectedEdge(N::max_value()) } fn min_value() -> Self { StaticDirectedEdge(N::min_value()) } } impl EdgeImpl for StaticDirectedEdge { fn new(e: usize) -> Self { StaticDirectedEdge(N::from_usize(e)) } fn new_checked(e: usize) -> Option { if N::is_valid(e) { Some(Self::new(e)) } else { None } } fn source(self, ends: &[T]) -> &T { &ends[2 * N::to_usize(self.0)] } fn target(self, ends: &[T]) -> &T { &ends[2 * N::to_usize(self.0) + 1] } fn to_index(self) -> usize { N::to_usize(self.0) } fn reverse(self) -> Self { panic!("StaticDirectedEdge::reverse should not be called") } } // StaticUndirectedEdge #[derive(Copy, Clone, Debug, Eq)] pub struct StaticUndirectedEdge(N); impl StaticEdgeKind for (Undirected, E) { type Kind = Undirected; type Edge = StaticUndirectedEdge; } impl Bounded for StaticUndirectedEdge { fn max_value() -> Self { StaticUndirectedEdge(N::max_value()) } fn min_value() -> Self { StaticUndirectedEdge(N::min_value()) } } // TODO: Document the representation of StaticUndirectedEdge impl EdgeImpl for StaticUndirectedEdge { fn new(e: usize) -> Self { StaticUndirectedEdge(N::from_usize(e << 1)) } fn new_checked(e: usize) -> Option { e.checked_mul(2) .and_then(|x| { if N::is_valid(x) { Some(Self::new(e)) } else { None } }) } fn source(self, ends: &[T]) -> &T { &ends[N::to_usize(self.0)] } fn target(self, ends: &[T]) -> &T { &ends[N::to_usize(self.0) ^ 1] } fn to_index(self) -> usize { N::to_usize(self.0) >> 1 } fn reverse(self) -> Self { StaticUndirectedEdge(N::from_usize(N::to_usize(self.0) ^ 1)) } } impl PartialEq for StaticUndirectedEdge { fn eq(&self, other: &Self) -> bool { self.to_index() == other.to_index() } } impl PartialOrd for StaticUndirectedEdge { fn partial_cmp(&self, other: &Self) -> Option { self.to_index().partial_cmp(&other.to_index()) } } impl Ord for StaticUndirectedEdge { fn cmp(&self, other: &Self) -> Ordering { self.to_index().cmp(&other.to_index()) } } impl Hash for StaticUndirectedEdge { fn hash(&self, state: &mut H) where H: Hasher, { self.to_index().hash(state) } } // Vertex pub type StaticVertex = N; // Graph #[derive(Clone, Debug, PartialEq)] pub struct Static { num_vertices: usize, ends: Vec>, edges: Vec, edges_start: Vec, } impl Static { fn inc(&self, v: Vertex) -> &[Edge] { self.get_inc(v).unwrap() } fn get_inc(&self, v: Vertex) -> Option<&[Edge]> { let i = V::to_usize(v); self.edges.get(self.edges_start[i]..self.edges_start[i + 1]) } } impl WithBuilder for Static { type Builder = StaticBuilder; } pub struct StaticBuilder { num_vertices: usize, ends: Vec>, edges: Vec, } impl Builder for StaticBuilder { type Graph = Static; fn new(num_vertices: usize, num_edges: usize) -> Self { assert!(V::is_valid(num_vertices)); StaticBuilder { num_vertices: num_vertices, ends: Vec::with_capacity(2 * num_edges), edges: vec![], } } fn add_edge(&mut self, u: usize, v: usize) { self.ends.push(V::from_usize(u)); self.ends.push(V::from_usize(v)); let e = K::Edge::new_checked((self.ends.len() - 2) / 2).expect("too many edges"); self.edges.push(e); if K::Kind::is_undirected() { self.edges.push(e.reverse()); } } fn finalize(mut self) -> Self::Graph { // TODO: improve test let ends = self.ends; self.edges .sort_by_key(|e| (e.source(&ends), e.target(&ends))); let mut starts = Vec::with_capacity(self.num_vertices.checked_add(1).unwrap()); let mut last = V::from_usize(self.num_vertices); for (i, e) in self.edges.iter().enumerate() { let s = *e.source(&ends); if s != last { while starts.len() != V::to_usize(s) { starts.push(i) } assert_eq!(starts.len(), V::to_usize(s)); starts.push(i); last = s; } } while starts.len() <= self.num_vertices { starts.push(self.edges.len()); } Static { num_vertices: self.num_vertices, ends: ends, edges: self.edges, edges_start: starts, } } fn finalize_( self, ) -> ( Self::Graph, Vec>, Vec>, ) { let g = self.finalize(); let v = vec(g.vertices()); let e = vec(g.edges()); (g, v, e) } } // Graph implementation impl WithVertex for Static { type Vertex = StaticVertex; type OptionVertex = OptionalMax>; } impl WithEdge for Static { type Kind = K::Kind; type Edge = K::Edge; type OptionEdge = OptionalMax; fn orientation(&self, _e: Edge) -> Orientation { K::Kind::orientation() } fn source(&self, e: Edge) -> Vertex { *e.source(&self.ends) } fn target(&self, e: Edge) -> Vertex { *e.target(&self.ends) } fn get_reverse(&self, e: Edge) -> Option> { if K::Kind::is_undirected() { Some(e.reverse()) } else { let (u, v) = self.ends(e); self.get_edge_by_ends(v, u) } } } impl<'a, V: Num, K: StaticEdgeKind> VertexTypes<'a, Static> for Static { type VertexIter = V::Range; type OutNeighborIter = OutNeighborFromOutEdge<'a, Self, OutEdgeIter<'a, Self>>; } impl<'a, V: Num, K: StaticEdgeKind> EdgeTypes<'a, Static> for Static { type EdgeIter = SEdgeIter; type OutEdgeIter = Cloned>>; } impl VertexList for Static { fn num_vertices(&self) -> usize { self.num_vertices } fn vertices(&self) -> VertexIter { V::range(0, self.num_vertices) } } impl EdgeList for Static { fn num_edges(&self) -> usize { self.ends.len() / 2 } fn edges(&self) -> EdgeIter { // TODO: specialization undirect 1, 3, 5, ... SEdgeIter(0..self.num_edges(), PhantomData) } fn get_edge_by_ends(&self, u: Vertex, v: Vertex) -> Option> { self.get_inc(u).and_then(|out_edges| { out_edges .binary_search_by_key(&v, |e| self.target(*e)) .ok() .map(|i| out_edges[i]) }) } } impl Adjacency for Static { fn out_neighbors(&self, v: Vertex) -> OutNeighborIter { OutNeighborFromOutEdge::new(self, self.out_edges(v)) } fn out_degree(&self, v: Vertex) -> usize { self.inc(v).len() } } impl Incidence for Static { fn out_edges(&self, v: Vertex) -> OutEdgeIter { self.inc(v).iter().cloned() } } // Iter #[derive(Clone, Debug)] pub struct SEdgeIter(Range, PhantomData); impl Iterator for SEdgeIter { type Item = K::Edge; fn next(&mut self) -> Option { self.0.next().map(K::Edge::new) } fn size_hint(&self) -> (usize, Option) { self.0.size_hint() } } impl ExactSizeIterator for SEdgeIter {} // Props #[derive(Clone, Debug)] pub struct SVertexIndexProp; impl PropGet> for SVertexIndexProp { type Output = usize; fn get(&self, v: StaticVertex) -> usize { v.to_usize() } } impl WithVertexIndexProp for Static { type VertexIndexProp = SVertexIndexProp; fn vertex_index(&self) -> VertexIndexProp { SVertexIndexProp } } #[derive(Clone, Debug)] pub struct SEdgeIndexProp(PhantomData); impl PropGet for SEdgeIndexProp { type Output = usize; fn get(&self, e: K::Edge) -> usize { e.to_index() } } impl WithEdgeIndexProp for Static { type EdgeIndexProp = SEdgeIndexProp; fn edge_index(&self) -> EdgeIndexProp { SEdgeIndexProp(PhantomData) } } impl WithVertexProp for Static { type VertexProp = VecVertexProp; } impl BasicVertexProps for Static {} impl WithEdgeProp for Static { type EdgeProp = VecEdgeProp; } impl BasicEdgeProps for Static {} impl BasicProps for Static {} // Choose impl Choose for Static { fn choose_vertex(&self, mut rng: R) -> Option> { if self.num_vertices() == 0 { None } else { Some(V::from_usize(rng.gen_range(0, self.num_vertices()))) } } fn choose_out_neighbor(&self, v: Vertex, rng: R) -> Option> { self.choose_out_edge(v, rng).map(|e| self.target(e)) } fn choose_edge(&self, mut rng: R) -> Option> { use graphs::common::gen_range_bool; if self.num_edges() == 0 { None } else if K::Kind::is_undirected() { let (i, rev) = gen_range_bool(self.num_edges(), rng).unwrap(); let e = K::Edge::new(i); Some(if rev { e.reverse() } else { e }) } else { Some(K::Edge::new(rng.gen_range(0, self.num_edges()))) } } fn choose_out_edge(&self, v: Vertex, mut rng: R) -> Option> { if self.out_degree(v) == 0 { None } else { self.inc(v) .get(rng.gen_range(0, self.out_degree(v))) .cloned() } } } // Num pub trait Num: 'static + Eq + Copy + Clone + Debug + Hash + Bounded + Ord { type Range: Iterator; fn range(a: usize, b: usize) -> Self::Range; fn to_usize(self) -> usize; fn from_usize(v: usize) -> Self; fn is_valid(v: usize) -> bool; } macro_rules! impl_num { ($t:ident) => { impl Num for $t { type Range = Range<$t>; #[inline] fn range(a: usize, b: usize) -> Self::Range { Self::from_usize(a)..Self::from_usize(b) } #[inline] fn to_usize(self) -> usize { self as usize } #[inline] fn from_usize(v: usize) -> Self { v as Self } #[inline] fn is_valid(v: usize) -> bool { (v as u64) < (Self::max_value() as u64) } } }; } impl_num!(u8); impl_num!(u16); impl_num!(u32); impl_num!(u64); impl_num!(usize); // Tests #[cfg(test)] mod tests { pub use super::{EdgeImpl, StaticDigraph, StaticGraph, StaticUndirectedEdge}; pub use prelude::*; use tests::GraphTests; macro_rules! test { ($m:ident, $g:ident) => { mod $m { pub use super::*; struct Test; impl GraphTests for Test { type G = $g; fn new() -> (Self::G, Vec>, Vec>) { Self::new_with_builder() } } graph_tests!{Test} mod with_builder { use super::*; use builder::BuilderTests; struct Test; impl BuilderTests for Test { type G = StaticGraph; } graph_builder_tests!{Test} } } }; } test!(directed, StaticDigraph); test!(undirected, StaticGraph); }