graphene/
lib.rs

1
2//!
3//! `graphene` is a general purpose, extensible [Graph Theory](https://en.wikipedia.org/wiki/Graph_theory)
4//! data type and algorithm library.
5//!
6//! ### Quick Examples:
7//!
8//! Using `common::AdjListGraph`, we define a graph with 3 vertices
9//! **1** , **2** , **3** and 3 weighted edges ( **1** -(1)-> **2** -(2)-> **3** -(3)-> **1**):
10//!
11//! ```
12//! # #![allow(unused_variables)]
13//! use graphene::core::{BaseGraph, BaseEdge};
14//! use graphene::common::AdjListGraph;
15//!
16//! // `graph()` takes a Vec of vertex values and a Vec of edges
17//! // where an edge is a tuple, (v1,v2,w), of the source v1, the sink v2, and the weight w.
18//! let mut g = AdjListGraph::graph(vec![1,2,3], vec![(1,2,1),(2,3,2),(3,1,3)]).unwrap();
19//! //Adding a vertex
20//! assert!(g.add_vertex(4).is_ok());
21//! //Adding an edge
22//!	assert!(g.add_edge(BaseEdge::new(3,4,2)).is_ok());
23//! ```
24//! ---
25//!
26//! We can declare a different graph that does not allow edge duplicates (a unique graph) and
27//! is undirected (the previous graph wasn't Unique and was directed):
28//!
29//! ```
30//! #[macro_use]
31//! extern crate graphene;
32//! use graphene::core::{*,constraint::*};
33//! use graphene::common::AdjListGraph;
34//!
35//! custom_graph!{
36//! 	// Name of the resulting graph type
37//! 	struct MyGraph<V,W>
38//! 	// The BaseGraph implementation to base the new graph on.
39//! 	as AdjListGraph<V,W>
40//! 	// The graph wrappers that will constrain the BaseGraph implementation so that
41//! 	// it upholds the constraint traits.
42//! 	use UniqueGraph,UndirectedGraph
43//! 	// The constraint traits the new graph implements
44//! 	impl Unique,Undirected
45//! 	// The generic bounds
46//! 	where V: Vertex, W: Weight
47//! }
48//!
49//!	fn main(){
50//! 	let mut g = MyGraph::graph(vec![1,2,3], vec![(1,2,1),(2,3,2),(3,1,3)]).unwrap();
51//!		assert_eq!(g.edges_between(1,2).len(), 2);
52//!
53//! 	// Cannot add an edge that is already there because the graph
54//!		// is declared as Unique, meaning no two edges may be incident
55//!		// on the same vertices and have the weight.
56//! 	assert!(g.add_edge(BaseEdge::new(1,2,1)).is_err());
57//! 	assert_eq!(g.edges_between(1,2).len(), 2);
58//!
59//! 	// When a graph is undirected, the direction of the given edge
60//! 	// (whether 1 -> 2 or 2 -> 1) makes no difference.
61//! 	// Since the graph is unique, adding an edge in the opposite
62//! 	// direction as an existing edge is therefore illegal.
63//! 	assert!(g.add_edge(BaseEdge::new(2,1,1)).is_err());
64//! 	assert_eq!(g.edges_between(1,2).len(), 2);
65//! }
66//! ```
67//!
68//! # About
69//!
70//! `graphene` aims at providing general purpose traits, structs, and macros for defining
71//! graphs, and functions that implement various algorithms that will run on any implementer of the library. Additionally,
72//! general purpose graph implementations will be provided.
73//!
74//! Because of the promise of generality, `graphene` is designed in a way that will allow
75//! users to implement their own graph types for their specific needs that can easily be integrated
76//! with the library's algorithms. Additionally, `graphene` aims at avoiding graph type bloat,
77//! i.e. defining many similar graph types:
78//!
79//! - `SimpleWeightedDirectedGraph`
80//! - `SimpleUnweightedDirectedGraph`
81//! - `SimpleWeightedUndirectedGraph`
82//! - `WeightedUndirectedGraph`
83//! - ...
84//!
85//! Instead, the user can semi-dynamically specify constraints on basic graph implementation to suit
86//! his needs. More on that later.
87//!
88//! `graphene` will use the terminology used by
89//! [Wolfram MathWorld](http://mathworld.wolfram.com/topics/GraphTheory.html)
90//! where possible. More specifically, 'vertex' and 'edge' will be used. We define that
91//! given a directed edge **v1** -> **v2**, then the `source` vertex is **v1** and the
92//! `sink` vertex is **v2**. Likewise, the edge is *sourced* in **v1** and *sinked* (the misspelling
93//! of 'sunk' is intentional) in **v2**. For both directed and undirected graphs the edge is
94//! *incident* on **v1** and **v2**.
95//!
96//! The crate is divided in three modules:
97//!
98//! - `core`: Contains the general purpose traits, structs, functions, and macros for graph implementation.
99//! - `algo` (**TODO**) : Contains graph algorithms that accept any graph that implements `core`.
100//! - `common`: Contains general purpose and commonly used graph implementations of `core` for quick usage.
101//!
102//! # Vertices and Edges
103//!
104//! In `graphene` vertices have a value, which is use to identify each vertex. Therefore, these
105//! values must be unique for every vertex in the graph. Internally, a graph implementation may
106//! manage its vertices as it wishes, but it must comminicate with  the outside world using the vertices'
107//! values.
108//!
109//! Edges are identified by the tuple `(source,sink,weight)`. Edges do not have to be unique in the
110//! graph, which means two edges with the same source, sink and weight are practically indistinguishable.
111//! This is by design, as if the information in the tuple is not enough to distinguish two edges,
112//! then choosing either one should not make a difference.
113//!
114//! # Directionality
115//!
116//! By default, edges in any graph are directed. If an undirected graph is needed, the `core`
117//! provides an `Undirected` constraint trait which can be implemented for a given graph. However,
118//! behind the scenes, any `Undirected` graph is a directed graph with edges in both directions.
119//! Therefore, given that any BaseGraph may be `Undirected`, an additional constraint trait, `Directed`
120//! is provided (**TODO**) which defines a graph as being specifically directed.
121//!
122//! This may seem confusing, so here is a deeper explanation:
123//!
124//! A BaseGraph uses directed edges. An `Undirected` BaseGraph will still use directed edges, but
125//! it will treat all edges it receives from the user as undirected. This means, if the user wants
126//! to add an undirected edge **1** - **2**, the graph will actually add **1** -> **2** and **1** <- **2**.
127//! On the other hand, when the graph outputs edges to the user, they are given as their directed pairs,
128//! e.g. **1** -> **2** and **1** <- **2** for the undirected edge **1** - **2**. This means that the
129//! user must handle these two directed edges as one undirected one.
130//!
131//! Consider then a function which takes a BaseGraph as its input. Since the input is not bounded
132//! by `Directed` it may be `Undirected`. If the function cannot handle undirected graphs
133//! it will fail if given any such graph. Therefore it should bound its input with `Directed`.
134//!
135//! So, when to actually bound a function with `Directed` instead of just `BaseGraph`?:
136//!
137//! - If it cannot handle there are an edge in each directed between two vertices.
138//!
139//! - If it cannot handle that two edges between two vertices, one in each direction, have the same weight.
140//!
141//! - If it needs to keep track of specific edges. Consider an algorithm that tracks whether an edge has been used,
142//! if the graph is 'Directed`, then an edge in each direction between two vertices must be tracked independently,
143//! but if its `Undirected`, then a pair in each direction must be tracked as one edge.
144//!
145//! The formal requirements and definitions have only been presented in a way sufficient for
146//! understanding the idea. Therefore, the formal definition should be consulted for complete
147//! accuracy.
148//!
149//! ### FAQ on directionality
150//!
151//! - Why does an `Undirected` graph output edges in directed pairs?
152//!
153//! In short, to allow functions to be directionality-agnostic. Consider implementing an algorithm
154//! that works on both directed and undirected graphs. If `Undirected` did not return pairs, then the function
155//! would have to know that the outputted edge was undirected, which means it would have to bound its input with `Undirected`
156//! forcing you to implement another, differently named function for the `Directed` case. But if `Undirected` outputs
157//! directed pairs, the function will be able to use them as if they were one undirected edge, since they tell
158//! the function that both directions are available between the two vertices. Therefore, the function can just bound
159//! its input with `BaseGraph` and handle both directionalities at once.
160//!
161//! - Why does an `Undirected` graph treat input edges as undirected and not require a directed pair instead?
162//!
163//! For similar reasons as the above answer. If a function is directionality-agnostic, but does
164//! mutate the graph, then it wouldn't know that a graph is `Undirected` and therefore wouldn't know to add a pair
165//! for each edge. By having the graph itself handle the splitting of an undirected edge into a directed pair,
166//! the function can bound its input by just `BaseGraph` and handle both directionalities at the same time.
167//!
168//! ### Directionality example
169//!
170//! Consider the constraint trait `Unique`. A graph is unique if for all edges, no two
171//! edges are incident on the same two vertices in the same direction. Consequently, for undirected
172//! graphs this means that only one undirected edge is allowed between any two vertices, while an edge
173//! in each direction is allowed for directed graphs.
174//!
175//! The `graphene::core::constaint` module is able to simply implement this constraint by iterating
176//! over all the directed edges a graph has, and reject it if any two edges have the same source
177//! and sink. This implementation is directionality agnostic since undirected graphs return a directed
178//! pair, which is allowed of a directed unique graph. Had `Undirected` graphs returned only one
179//! undirected edge, two constraint traits `UniqueDirection` and `UniqueUndirected` would have been needed.
180//! This is because the following two edges, (1,2) and (2,1), would be invalid for undirected graphs,
181//! as the edges are identical when disregarding direction (which undirected graphs do). For directed
182//! graphs the two edges are acceptable, as they have different directions.
183//!
184//! Therefore, the `graphene`'s directionality design allows for a single implementation for
185//! the `Unique` constraint that works for both directed and undirected graphs.
186//!
187//!
188//! # FAQ
189//!
190//! - How do i initialize an unweighted graph, it seems then all require a weight, e.g. AdjListGraph<V,W>?
191//!
192//! By convention, `()` is treated as the lack of a weight. Therefore, AdjListGraph<V,()> is
193//! an unweighted graph.
194//!
195//!
196
197#[macro_use]
198pub mod core;
199pub mod common;
200
201