Skip to content

Commit

Permalink
Add lifetime parameter to all graph traits.
Browse files Browse the repository at this point in the history
I tried to write a Subgraph struct that implements the graph traits
(backed by any graph implementation) but got stuck because of
lifetimes. This changes allowed me to make some progress. May be
it can be simplified with associated lifetimes. See
rust-lang/rust#17307.
  • Loading branch information
malbarbo committed Aug 21, 2015
1 parent 4e29620 commit 7d44c9c
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 122 deletions.
85 changes: 39 additions & 46 deletions src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@ use std::ops::IndexMut;

// Basic

pub trait Basic {
pub trait Types {
type Vertex: Copy + Eq;
type Edge: Copy + Eq;
}

pub trait Basic<'a>: Types {
type VertexIter: Iterator<Item=Self::Vertex>;
type EdgeIter: Iterator<Item=Self::Edge>;

fn num_vertices(&self) -> usize;
fn vertices(&self) -> Self::VertexIter;
fn vertices(&'a self) -> Self::VertexIter;

fn num_edges(&self) -> usize;
fn edges(&self) -> Self::EdgeIter;
fn edges(&'a self) -> Self::EdgeIter;

fn source(&self, e: Self::Edge) -> Self::Vertex;
fn target(&self, e: Self::Edge) -> Self::Vertex;
Expand All @@ -27,55 +30,43 @@ pub trait Basic {

// Degree

pub trait Degree: Basic {
pub trait Degree<'a>: Basic<'a> {
fn degree(&self, v: Self::Vertex) -> usize;
}


// Inc

pub trait IncIterType<'a>: Basic {
type Type: Iterator<Item=Self::Edge>;
}
pub type IncIter<'a, G> = <G as Inc<'a>>::Type;

// FIXME: change definition when [E0122] is resolved
// pub type IncIter<'a, G: Inc> = <G as IncIterType<'a>>::Type;
pub type IncIter<'a, G> = <G as IncIterType<'a>>::Type;

pub trait Inc: Basic + for<'a> IncIterType<'a> {
fn inc_edges(&self, v: Self::Vertex) -> IncIter<Self>;
pub trait Inc<'a>: Basic<'a> {
type Type: Iterator<Item=Self::Edge>;
fn inc_edges(&'a self, v: Self::Vertex) -> IncIter<Self>;
}


// Adj

pub trait AdjIterType<'a>: Basic {
type Type: Iterator<Item=Self::Vertex>;
}

// FIXME: change definition when [E0122] is resolved
// pub type AdjIter<'a, G: Adj> = <G as AdjIterType<'a>>::Type;
pub type AdjIter<'a, G> = <G as AdjIterType<'a>>::Type;
pub type AdjIter<'a, G> = <G as Adj<'a>>::Type;

pub trait Adj: Basic + for<'a> AdjIterType<'a> {
fn neighbors(&self, v: Self::Vertex) -> AdjIter<Self>;
pub trait Adj<'a>: Basic<'a> {
type Type: Iterator<Item=Self::Vertex>;
fn neighbors(&'a self, v: Self::Vertex) -> AdjIter<Self>;
}

// Implementation of Adj traits for Graphs which implements Inc
impl<'a, G: Inc> AdjIterType<'a> for G {
impl<'a, G> Adj<'a> for G
where G: Inc<'a>
{
type Type = Map1<'a, IncIter<'a, G>, G, fn(&G, G::Edge) -> G::Vertex>;
}

impl<G: Inc> Adj for G {
fn neighbors(&self, v: Self::Vertex) -> AdjIter<Self> {
fn neighbors(&'a self, v: Self::Vertex) -> AdjIter<Self> {
self.inc_edges(v).map1(self, Self::target)
}
}


// Vertex Property

pub trait VertexPropType<'a, T>: Basic {
pub trait VertexPropType<'a, T>: Basic<'a> {
type Type: IndexMut<Self::Vertex, Output=T>;
}

Expand All @@ -86,7 +77,7 @@ pub type VertexProp<'a, G, T> = <G as VertexPropType<'a, T>>::Type;

// Edge Property

pub trait EdgePropType<'a, T>: Basic {
pub trait EdgePropType<'a, T>: Basic<'a> {
type Type: IndexMut<Self::Edge, Output=T>;
}

Expand All @@ -99,20 +90,22 @@ pub type EdgeProp<'a, G, T> = <G as EdgePropType<'a, T>>::Type;

macro_rules! with_prop {
($t:ty, $($ty:ty),*) => (
pub trait WithVertexProp: for<'a> VertexPropType<'a, $t> +
for<'a> VertexPropType<'a, Option<$t>>
$(+ for<'a> VertexPropType<'a, $ty>)*
$(+ for<'a> VertexPropType<'a, Option<$ty>>)*
pub trait WithVertexProp<'a>: VertexPropType<'a, $t> +
VertexPropType<'a, Option<$t>>
$(+ VertexPropType<'a, $ty>)*
$(+ VertexPropType<'a, Vec<$ty>>)*
$(+ VertexPropType<'a, Option<$ty>>)*
{
fn vertex_prop<T: Clone>(&self, value: T) -> VertexProp<Self, T>;
fn vertex_prop<T: Clone>(&'a self, value: T) -> VertexProp<Self, T>;
}

pub trait WithEdgeProp: for<'a> EdgePropType<'a, $t> +
for<'a> EdgePropType<'a, Option<$t>>
$(+ for<'a> EdgePropType<'a, $ty>)*
$(+ for<'a> EdgePropType<'a, Option<$ty>>)*
pub trait WithEdgeProp<'a>: EdgePropType<'a, $t> +
EdgePropType<'a, Option<$t>>
$(+ EdgePropType<'a, $ty>)*
$(+ EdgePropType<'a, Vec<$ty>>)*
$(+ EdgePropType<'a, Option<$ty>>)*
{
fn edge_prop<T: Clone>(&self, value: T) -> EdgeProp<Self, T>;
fn edge_prop<T: Clone>(&'a self, value: T) -> EdgeProp<Self, T>;
}
)
}
Expand All @@ -123,15 +116,15 @@ with_prop! {
i8, i16, i32, i64, isize,
u8, u16, u32, u64, usize,
&'a str, String,
<Self as Basic>::Vertex,
<Self as Basic>::Edge
<Self as Types>::Vertex,
<Self as Types>::Edge
}


// Graph alias

trait_alias!(GraphInc: Basic + Degree + Inc);
trait_alias!(GraphIncWithProps: GraphInc + WithVertexProp + WithEdgeProp);
trait_alias!(GraphInc: Basic<'a> + Degree<'a> + Inc<'a>);
trait_alias!(GraphIncWithProps: GraphInc<'a> + WithVertexProp<'a> + WithEdgeProp<'a>);

trait_alias!(GraphAdj: Basic + Degree + Adj);
trait_alias!(GraphAdjWithProps: GraphAdj + WithVertexProp + WithEdgeProp);
trait_alias!(GraphAdj: Basic<'a> + Degree<'a> + Adj<'a>);
trait_alias!(GraphAdjWithProps: GraphAdj<'a> + WithVertexProp<'a> + WithEdgeProp<'a>);
25 changes: 13 additions & 12 deletions src/kruskal.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
use graph::*;
use unionfind::DisjointSet;

pub trait Visitor<G: Basic> {
pub trait Visitor<'a, G: Basic<'a>> {
fn visit(&mut self, e: G::Edge, in_same_set: bool) -> bool;
}

impl<F, G> Visitor< G> for F
where G: Basic,
impl<'a, F, G> Visitor<'a, G> for F
where G: Basic<'a>,
F: FnMut(G::Edge, bool) -> bool {
fn visit(&mut self, e: G::Edge, in_same_set: bool) -> bool {
self(e, in_same_set)
}
}

pub trait Kruskal: Basic + WithVertexProp + Sized {
fn kruskal_edges<I, V>(&self, edges: I, mut visitor: V)
pub trait Kruskal<'a>: Basic<'a> + WithVertexProp<'a> + Sized {
fn kruskal_edges<I, V>(&'a self, edges: I, mut visitor: V)
where I: Iterator<Item = Self::Edge>,
V: Visitor<Self>
V: Visitor<'a, Self>
{
let mut ds = DisjointSet::new(self);
for e in edges {
Expand All @@ -31,19 +31,19 @@ pub trait Kruskal: Basic + WithVertexProp + Sized {
}
}

fn kruskal<T, V>(&self, weight: &EdgeProp<Self, T>, visitor: V)
fn kruskal<T, V>(&'a self, weight: &'a EdgeProp<'a, Self, T>, visitor: V)
where T: Ord,
V: Visitor<Self>,
Self: for<'a> EdgePropType<'a, T>
V: Visitor<'a, Self>,
Self: EdgePropType<'a, T>
{
let mut edges = self.edges().collect::<Vec<_>>();
edges.sort_by(|a, b| weight[*a].cmp(&weight[*b]));
self.kruskal_edges(edges.iter().cloned(), visitor);
}

fn kruskal_mst<T>(&self, weight: &EdgeProp<Self, T>) -> Vec<Self::Edge>
fn kruskal_mst<T>(&'a self, weight: &'a EdgeProp<'a, Self, T>) -> Vec<Self::Edge>
where T: Ord,
Self: for<'a> EdgePropType<'a, T>
Self: EdgePropType<'a, T>
{
let mut tree = vec![];
self.kruskal::<T, _>(weight, |e: Self::Edge, in_same_set: bool| {
Expand All @@ -56,7 +56,8 @@ pub trait Kruskal: Basic + WithVertexProp + Sized {
}
}

impl<G> Kruskal for G where G: Basic + WithVertexProp { }
impl<'a, G> Kruskal<'a> for G
where G: Basic<'a> + WithVertexProp<'a> { }


#[cfg(test)]
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ macro_rules! items {
macro_rules! trait_alias {
($name:ident : $($base:tt)+) => {
items! {
pub trait $name: $($base)+ { }
impl<T: $($base)+> $name for T { }
pub trait $name<'a>: $($base)+ { }
impl<'a, T> $name<'a> for T where T: $($base)+ { }
}
};
}
Expand Down
19 changes: 10 additions & 9 deletions src/path.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
use graph::*;
use traverse::*;

pub type Path<G> = Vec<<G as Basic>::Edge>;
pub type Path<G> = Vec<<G as Types>::Edge>;

pub type ParentTree<'a, G> = VertexProp<'a, G, Option<<G as Basic>::Edge>>;
pub type ParentTree<'a, G> = VertexProp<'a, G, Option<<G as Types>::Edge>>;

pub trait FindPath: Basic + Sized {
fn find_path_on_parent_tree(&self,
tree: &ParentTree<Self>,
pub trait FindPath<'a>: Basic<'a> + Sized {
fn find_path_on_parent_tree(&'a self,
tree: &ParentTree<'a, Self>,
u: Self::Vertex,
v: Self::Vertex)
-> Option<Path<Self>>
where Self: WithVertexProp
where Self: WithVertexProp<'a>
{
if u == v {
return None;
Expand All @@ -30,8 +30,8 @@ pub trait FindPath: Basic + Sized {
None
}

fn find_path(&self, u: Self::Vertex, v: Self::Vertex) -> Option<Path<Self>>
where Self: GraphIncWithProps
fn find_path(&'a self, u: Self::Vertex, v: Self::Vertex) -> Option<Path<Self>>
where Self: GraphIncWithProps<'a>
{
if u == v {
return None;
Expand All @@ -52,7 +52,8 @@ pub trait FindPath: Basic + Sized {
}
}

impl<G: Basic> FindPath for G { }
impl<'a, G> FindPath<'a> for G
where G: Basic<'a> { }

#[cfg(test)]
mod tests {
Expand Down
17 changes: 9 additions & 8 deletions src/props.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use graph::*;
use traverse::*;

pub trait Props: Basic + Sized {
fn is_acyclic(&self) -> bool
where Self: GraphIncWithProps
pub trait Props<'a>: Basic<'a> + Sized {
fn is_acyclic(&'a self) -> bool
where Self: GraphIncWithProps<'a>
{
let mut acyclic = true;
Dfs::run(self, &mut BackEdgeVisitor(|_| {
Expand All @@ -13,8 +13,8 @@ pub trait Props: Basic + Sized {
acyclic
}

fn is_connected(&self) -> bool
where Self: GraphIncWithProps
fn is_connected(&'a self) -> bool
where Self: GraphIncWithProps<'a>
{
self.num_vertices() == 0 || {
let mut count = 0;
Expand All @@ -26,16 +26,17 @@ pub trait Props: Basic + Sized {
}
}

fn is_tree(&self) -> bool
where Self: GraphIncWithProps
fn is_tree(&'a self) -> bool
where Self: GraphIncWithProps<'a>
{
self.num_vertices() == 0 || {
self.num_edges() == self.num_vertices() - 1 && self.is_acyclic()
}
}
}

impl<G> Props for G where G: Basic { }
impl<'a, G> Props<'a> for G
where G: Basic<'a> { }

#[cfg(test)]
mod tests {
Expand Down
24 changes: 12 additions & 12 deletions src/static_.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,17 +114,20 @@ impl StaticGraphBuilder {
}


impl Basic for StaticGraph {
impl Types for StaticGraph {
type Vertex = usize;
type Edge = Edge;
}

impl<'a> Basic<'a> for StaticGraph {
type VertexIter = Range<Self::Vertex>;
type EdgeIter = Map<Range<usize>, fn(usize) -> Self::Edge>;

fn num_vertices(&self) -> usize {
self.num_vertices
}

fn vertices(&self) -> Self::VertexIter {
fn vertices(&'a self) -> Self::VertexIter {
0..self.num_vertices
}

Expand All @@ -140,22 +143,19 @@ impl Basic for StaticGraph {
self.endvertices.len() / 2
}

fn edges(&self) -> Self::EdgeIter {
fn edges(&'a self) -> Self::EdgeIter {
(0..self.num_edges()).map(Edge::new)
}
}

impl Degree for StaticGraph {
impl<'a> Degree<'a> for StaticGraph {
fn degree(&self, v: Self::Vertex) -> usize {
self.inc[v].len()
}
}

impl<'a> IncIterType<'a> for StaticGraph {
impl<'a> Inc<'a> for StaticGraph {
type Type = Cloned<Iter<'a, Self::Edge>>;
}

impl Inc for StaticGraph {
fn inc_edges(&self, v: Self::Vertex) -> IncIter<Self> {
self.inc[v].iter().cloned()
}
Expand All @@ -165,8 +165,8 @@ impl<'a, T> VertexPropType<'a, T> for StaticGraph {
type Type = Vec<T>;
}

impl WithVertexProp for StaticGraph {
fn vertex_prop<T: Clone>(&self, value: T) -> VertexProp<Self, T> {
impl<'a> WithVertexProp<'a> for StaticGraph {
fn vertex_prop<T: Clone>(&'a self, value: T) -> VertexProp<Self, T> {
vec![value; self.num_vertices()]
}
}
Expand All @@ -175,8 +175,8 @@ impl<'a, T> EdgePropType<'a, T> for StaticGraph {
type Type = EdgePropVec<T>;
}

impl WithEdgeProp for StaticGraph {
fn edge_prop<T: Clone>(&self, value: T) -> EdgeProp<Self, T> {
impl<'a> WithEdgeProp<'a> for StaticGraph {
fn edge_prop<T: Clone>(&'a self, value: T) -> EdgeProp<Self, T> {
EdgePropVec(vec![value; self.num_edges()])
}
}
Expand Down
Loading

0 comments on commit 7d44c9c

Please sign in to comment.