Skip to content

Commit 380d440

Browse files
committed
Added vertex labeling api
1 parent 424457a commit 380d440

9 files changed

Lines changed: 267 additions & 82 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
**/*.rs.bk
33

44
Cargo.lock
5+
example1.dot
56
.DS_Store

examples/dot.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@ pub fn main() {
2121
graph.add_edge(&v5, &v6).unwrap();
2222

2323
#[cfg(feature = "dot")]
24-
Graph::<String>::to_dot(&graph, &mut f);
24+
graph.to_dot("example1", &mut f);
2525
}

src/dot.rs

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,74 @@
1+
use crate::graph::Graph;
2+
use crate::graph::GraphErr;
3+
4+
#[cfg(feature = "no_std")]
5+
use core::io::Write;
6+
7+
#[cfg(not(feature = "no_std"))]
18
use std::io::Write;
9+
10+
#[cfg(feature = "no_std")]
11+
use core::borrow::Cow;
12+
13+
#[cfg(not(feature = "no_std"))]
214
use std::borrow::Cow;
315

4-
use crate::graph::Graph;
5-
use std::fmt::Display;
16+
#[cfg(feature = "no_std")]
17+
use core::fmt::Debug;
18+
19+
#[cfg(not(feature = "no_std"))]
20+
use std::fmt::Debug;
621

722
/*
823
Bounds on types throw warnings
9-
type Nd<D: Display + Clone + Ord> = D;
10-
type Ed<D: Display + Clone + Ord> = (D, D);
24+
type Nd<D: Clone + Debug> = D;
25+
type Ed<D: Clone + Debug> = (D, D);
1126
*/
12-
type Nd<D> = D;
13-
type Ed<D> = (D, D);
27+
type Nd = String;
28+
type Ed = (String, String);
29+
30+
pub(crate) struct Edges<'a> {
31+
pub(crate) edges: Vec<Ed>,
32+
pub(crate) graph_name: dot::Id<'a>,
33+
}
1434

15-
pub(crate) struct Edges<D: Display + Clone>(pub(crate) Vec<Ed<D>>);
35+
impl<'a> Edges<'a> {
36+
pub fn new(edges: Vec<Ed>, graph_name: &'a str) -> Result<Edges<'a>, GraphErr> {
37+
let graph_name = dot::Id::new(graph_name).map_err(|_| GraphErr::InvalidGraphName)?;
38+
39+
Ok(Edges {
40+
edges,
41+
graph_name,
42+
})
43+
}
44+
}
1645

17-
impl<'a, D: Display + Clone + Ord> dot::Labeller<'a, Nd<D>, Ed<D>> for Edges<D> {
18-
//TODO make it possible to rename Id
19-
fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new("example1").unwrap() }
46+
impl<'a> dot::Labeller<'a, Nd, Ed> for Edges<'a> {
47+
fn graph_id(&'a self) -> dot::Id { dot::Id::new(self.graph_name.as_slice()).unwrap() }
2048

21-
fn node_id(&'a self, n: &Nd<D>) -> dot::Id<'a> {
22-
dot::Id::new(format!("{}", *n)).unwrap()
49+
fn node_id(&'a self, n: &Nd) -> dot::Id {
50+
dot::Id::new(n.clone()).unwrap()
2351
}
2452
}
2553

26-
impl <'a, D: Display + Clone + Ord> dot::GraphWalk<'a, Nd<D>, Ed<D>> for Edges<D> {
27-
fn nodes(&self) -> dot::Nodes<'a, Nd<D>> {
28-
let &Edges(ref v) = self;
54+
impl<'a> dot::GraphWalk<'a, Nd, Ed> for Edges<'a> {
55+
fn nodes(&self) -> dot::Nodes<'a, Nd> {
56+
let &Edges { edges: ref v, .. } = self;
2957
let mut nodes = Vec::with_capacity(v.len());
3058

3159
for (s, t) in v.iter() {
32-
nodes.push(s.clone()); nodes.push(t.clone());
60+
nodes.push(s.clone());
61+
nodes.push(t.clone());
3362
}
3463

35-
nodes.sort();
36-
nodes.dedup();
3764
Cow::Owned(nodes)
3865
}
3966

40-
fn edges(&'a self) -> dot::Edges<'a,Ed<D>> {
41-
let &Edges(ref edges) = self;
67+
fn edges(&'a self) -> dot::Edges<'a, Ed> {
68+
let &Edges { edges: ref edges, .. } = self;
4269
Cow::Borrowed(&edges[..])
4370
}
4471

45-
fn source(&self, e: &Ed<D>) -> Nd<D> { e.0.clone() }
46-
fn target(&self, e: &Ed<D>) -> Nd<D> { e.1.clone() }
72+
fn source(&self, e: &Ed) -> Nd { e.0.clone() }
73+
fn target(&self, e: &Ed) -> Nd { e.1.clone() }
4774
}

src/graph.rs

Lines changed: 151 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,18 @@ use core::iter;
1010
#[cfg(not(feature = "no_std"))]
1111
use std::iter;
1212

13+
#[cfg(feature = "no_std")]
14+
use core::fmt::Debug;
15+
16+
#[cfg(not(feature = "no_std"))]
17+
use std::fmt::Debug;
18+
19+
#[cfg(feature = "no_std")]
20+
use core::cell::RefCell;
21+
22+
#[cfg(not(feature = "no_std"))]
23+
use std::cell::RefCell;
24+
1325
#[cfg(feature = "no_std")]
1426
extern crate alloc;
1527
#[cfg(feature = "no_std")]
@@ -19,27 +31,70 @@ use alloc::vec;
1931
#[cfg(feature = "no_std")]
2032
use alloc::vec::Vec;
2133

34+
#[cfg(feature = "dot")]
35+
use super::SEED;
36+
2237
#[derive(Clone, Debug, PartialEq)]
2338
/// Graph operation error
2439
pub enum GraphErr {
40+
/// There is no vertex with the given id in the graph
2541
NoSuchVertex,
42+
43+
/// There is no such edge in the graph
2644
NoSuchEdge,
45+
46+
/// Could not add an edge to the graph
2747
CannotAddEdge,
28-
InvalidWeight
48+
49+
/// The given weight is invalid
50+
InvalidWeight,
51+
52+
#[cfg(feature = "dot")]
53+
/// Could not render .dot file
54+
CouldNotRender,
55+
56+
#[cfg(feature = "dot")]
57+
/// The name of the graph is invalid. Check [this](https://docs.rs/dot/0.1.1/dot/struct.Id.html#method.new)
58+
/// out for more information.
59+
InvalidGraphName,
60+
61+
#[cfg(feature = "dot")]
62+
/// The name of the given label is invalid. Check [this](https://docs.rs/dot/0.1.1/dot/struct.Id.html#method.new)
63+
/// out for more information.
64+
InvalidLabel,
2965
}
3066

3167
#[derive(Clone, Debug)]
3268
/// Graph data-structure
33-
pub struct Graph<T> {
69+
pub struct Graph<T>
70+
where T: Clone + Debug
71+
{
72+
/// Mapping of vertex ids and vertex values
3473
vertices: HashMap<VertexId, (T, VertexId)>,
74+
75+
/// Mapping between edges and weights
3576
edges: HashMap<Edge, f32>,
77+
78+
/// Set containing the roots of the graph
3679
roots: HashSet<VertexId>,
80+
81+
/// Set containing the tips of the graph
3782
tips: HashSet<VertexId>,
83+
84+
/// Mapping between vertex ids and inbound edges
3885
inbound_table: HashMap<VertexId, Vec<VertexId>>,
86+
87+
/// Mapping between vertex ids and outbound edges
3988
outbound_table: HashMap<VertexId, Vec<VertexId>>,
89+
90+
#[cfg(feature = "dot")]
91+
/// Mapping between vertices and labels
92+
labels: RefCell<HashMap<VertexId, String>>,
4093
}
4194

42-
impl<T> Graph<T> {
95+
impl<T> Graph<T>
96+
where T: Clone + Debug
97+
{
4398
/// Creates a new graph.
4499
///
45100
/// ## Example
@@ -59,6 +114,9 @@ impl<T> Graph<T> {
59114
tips: HashSet::new(),
60115
inbound_table: HashMap::new(),
61116
outbound_table: HashMap::new(),
117+
118+
#[cfg(feature = "dot")]
119+
labels: RefCell::new(HashMap::new()),
62120
}
63121
}
64122

@@ -84,6 +142,9 @@ impl<T> Graph<T> {
84142
tips: HashSet::with_capacity(capacity),
85143
inbound_table: HashMap::with_capacity(capacity),
86144
outbound_table: HashMap::with_capacity(capacity),
145+
146+
#[cfg(feature = "dot")]
147+
labels: RefCell::new(HashMap::with_capacity(capacity)),
87148
}
88149
}
89150

@@ -145,6 +206,9 @@ impl<T> Graph<T> {
145206
self.vertices.reserve(additional);
146207
self.outbound_table.reserve(additional);
147208
self.inbound_table.reserve(additional);
209+
210+
#[cfg(feature = "dot")]
211+
self.labels.borrow_mut().reserve(additional);
148212
}
149213

150214
/// Shrinks the capacity of the graph as much as possible.
@@ -170,6 +234,9 @@ impl<T> Graph<T> {
170234
self.outbound_table.shrink_to_fit();
171235
self.inbound_table.shrink_to_fit();
172236

237+
#[cfg(feature = "dot")]
238+
self.labels.borrow_mut().shrink_to_fit();
239+
173240
// Calculate additional value for edges vector
174241
// such that it is always n^2 where n is the
175242
// number of vertices that are currently placed
@@ -196,7 +263,7 @@ impl<T> Graph<T> {
196263
pub fn add_vertex(&mut self, item: T) -> VertexId {
197264
let id = VertexId::random();
198265

199-
self.vertices.insert(id.clone(), (item, id.clone()));
266+
self.vertices.insert(id, (item, id));
200267
self.roots.insert(id);
201268
self.tips.insert(id);
202269

@@ -641,7 +708,7 @@ impl<T> Graph<T> {
641708
/// assert_eq!(mapped.fetch(&id1).unwrap(), &3);
642709
/// assert_eq!(mapped.fetch(&id2).unwrap(), &4);
643710
/// ```
644-
pub fn map<R>(&self, fun: impl Fn(&T) -> R) -> Graph<R> {
711+
pub fn map<R: Clone + Debug>(&self, fun: impl Fn(&T) -> R) -> Graph<R> {
645712
let mut graph: Graph<R> = Graph::new();
646713

647714
// Copy edge and vertex information
@@ -655,6 +722,11 @@ impl<T> Graph<T> {
655722
.map(|(id, (v, i))| (id.clone(), (fun(v), i.clone())))
656723
.collect();
657724

725+
#[cfg(feature = "dot")]
726+
{
727+
graph.labels = self.labels.clone();
728+
}
729+
658730
graph
659731
}
660732

@@ -1127,6 +1199,7 @@ impl<T> Graph<T> {
11271199
Topo::new(self)
11281200
}
11291201

1202+
#[cfg(feature = "dot")]
11301203
/// Creates a file with the dot representation of the graph.
11311204
/// This method requires the `dot` feature.
11321205
///
@@ -1152,19 +1225,85 @@ impl<T> Graph<T> {
11521225
/// graph.add_edge(&v1, &v4).unwrap();
11531226
/// graph.add_edge(&v5, &v6).unwrap();
11541227
///
1155-
/// Graph::<String>::to_dot(&graph, &mut f);
1228+
/// assert!(graph.to_dot("example1", &mut f).is_ok());
11561229
/// ```
1157-
#[cfg(feature = "dot")]
1158-
pub fn to_dot(graph: &Graph<impl ::std::fmt::Display + Clone + Ord>, output: &mut impl ::std::io::Write) {
1159-
let vertices = graph.vertex_hm_ref();
1160-
let edges : Vec<(_, _)> = graph.edges_hm_ref().unwrap().iter().map(|(w, _)| {
1230+
pub fn to_dot(&self, graph_name: &str, output: &mut impl ::std::io::Write) -> Result<(), GraphErr> {
1231+
let edges : Vec<(_, _)> = self.edges.iter().map(|(w, _)| {
11611232
let inbound = w.inbound();
11621233
let outbound = w.outbound();
11631234

1164-
(vertices.get(inbound).unwrap().0.clone(), vertices.get(outbound).unwrap().0.clone())
1235+
(self.label(inbound).unwrap(), self.label(outbound).unwrap())
11651236
}).collect();
11661237

1167-
dot::render(&crate::dot::Edges(edges), output).unwrap()
1238+
let edges = crate::dot::Edges::new(edges, graph_name)?;
1239+
dot::render(&edges, output).map_err(|_| GraphErr::CouldNotRender)
1240+
}
1241+
1242+
#[cfg(feature = "dot")]
1243+
/// Labels the vertex with the given id. Returns the old label if successful.
1244+
///
1245+
/// ## Example
1246+
/// ```rust
1247+
/// use graphlib::{Graph, VertexId};
1248+
///
1249+
/// let mut graph: Graph<usize> = Graph::new();
1250+
/// let random_id = VertexId::random();
1251+
///
1252+
/// let v1 = graph.add_vertex(0);
1253+
/// let v2 = graph.add_vertex(1);
1254+
/// let v3 = graph.add_vertex(2);
1255+
///
1256+
/// assert!(graph.label_vertex(&v1, "V1").is_ok());
1257+
/// assert!(graph.label_vertex(&v2, "V2").is_ok());
1258+
/// assert!(graph.label_vertex(&v3, "V3").is_ok());
1259+
/// assert!(graph.label_vertex(&random_id, "will fail").is_err());
1260+
/// ```
1261+
pub fn label_vertex(&mut self, vertex_id: &VertexId, label: &str) -> Result<String, GraphErr> {
1262+
// Check label validity
1263+
let _ = dot::Id::new(label.to_owned()).map_err(|_| GraphErr::InvalidLabel)?;
1264+
1265+
if self.vertices.get(vertex_id).is_none() {
1266+
return Err(GraphErr::NoSuchVertex);
1267+
}
1268+
1269+
let old_label = self.label(vertex_id).unwrap();
1270+
self.labels.borrow_mut().insert(vertex_id.clone(), label.to_owned());
1271+
1272+
Ok(old_label)
1273+
}
1274+
1275+
#[cfg(feature = "dot")]
1276+
/// Retrieves the label of the vertex with the given id.
1277+
///
1278+
/// This function will return a default label if no label is set. Returns
1279+
/// `None` if there is no vertex associated with the given id in the graph.
1280+
pub fn label(&self, vertex_id: &VertexId) -> Option<String> {
1281+
if self.vertices.get(vertex_id).is_none() {
1282+
return None;
1283+
}
1284+
1285+
if let Some(label) = self.labels.borrow().get(vertex_id) {
1286+
return Some(label.clone());
1287+
}
1288+
1289+
let bytes = super::gen_bytes();
1290+
1291+
// Take only 8 bytes out of 16
1292+
let to_encode: Vec<u8> = bytes
1293+
.iter()
1294+
.take(8)
1295+
.cloned()
1296+
.collect();
1297+
1298+
let encoded = hex::encode(&to_encode);
1299+
let label = format!("N_{}", encoded);
1300+
assert!(dot::Id::new(label.to_owned()).is_ok());
1301+
1302+
{
1303+
self.labels.borrow_mut().insert(vertex_id.clone(), label);
1304+
}
1305+
1306+
self.labels.borrow().get(vertex_id).map(|s| s.clone())
11681307
}
11691308

11701309
fn do_add_edge(&mut self, a: &VertexId, b: &VertexId, weight: f32) -> Result<(), GraphErr> {
@@ -1268,16 +1407,6 @@ impl<T> Graph<T> {
12681407
None => None,
12691408
}
12701409
}
1271-
1272-
/// Returns a reference to the inner edges hash map.
1273-
fn edges_hm_ref(&self) -> Result<(&HashMap<Edge, f32>), GraphErr> {
1274-
Ok(&self.edges)
1275-
}
1276-
1277-
/// Returns a reference to the inner vertices hashmap.
1278-
fn vertex_hm_ref(&self) -> &HashMap<VertexId, (T, VertexId)> {
1279-
&self.vertices
1280-
}
12811410
}
12821411

12831412
#[cfg(test)]

0 commit comments

Comments
 (0)