| tags: [ development ] categories: [Development ]
Rust PetGraph filter to connected
Home Electrical Notes
I’m working on modeling house electrical system using directed graph. Learning Rust while I work through this. Rust is an interesting language, but it really does take some concentration to get something working the way you want it. I am very much out of practice having to think through the ownership of memory. As well as the appropriate ways to handle errors. Rust puts all these topics up in front.
Anyway, thought I would share something that I finally got working successfully.
The code deceptively easy. It just took a long time for me to get it to compile and work as I expected.
Building an Example Graph
First I implemented a function to produce a directed graph using the petgraph package:
pub fn simple_digraph() -> Graph<&'static str, u8> {
let mut deps = DiGraph::<&str, u8>::new();
let a = deps.add_node("A");
let b = deps.add_node("B");
let c = deps.add_node("C");
let d = deps.add_node("D");
let e = deps.add_node("E");
let f = deps.add_node("F");
let g = deps.add_node("G");
let _h = deps.add_node("H");
deps.add_edge(a, b, 1);
deps.add_edge(a, c, 1);
deps.add_edge(c, d, 2);
deps.add_edge(c, e, 2);
deps.add_edge(e, f, 3);
deps.add_edge(f, g, 4);
deps
}
This function creates a DiGraph instance with a few nodes.
Notice that node H has no links in or out.
Building a Trait
Next I implemented the trait. This trait Connected implements the function connected_graph which interrogates
the graph creating a new graph. The new graph will exclude any nodes that are not connected.
pub trait Connected {
fn connected_graph(&self) -> Self;
}
impl<N: Clone, E: Clone> Connected for Graph<N, E> {
fn connected_graph(&self) -> Self {
self.filter_map(
|ni, nwvr| {
if self.neighbors_undirected(ni).count() > 0 {
Some((*nwvr).clone())
} else {
None
}
}, |_ei, ev| { Some((*ev).clone()) })
}
}
Since this connected_graph function creates a new graph, I chose to clone the nodes and edges that are created.
The important bit, and the bit that took so much time to comprehend is the type definitions needed on the
connected_graph function to get it to work on any type of node or edge.
For example, I plan to use this function where the node weight is some electrical component structure. I wanted this function to work for either the example case or the more interesting electrical component case.
After calling the connected_graph function on the example graph, I get the following structure.
Notice that node H has been removed from the graph.
Rendering graphs using graphviz
graphviz is a collection of graph tools that is very helpful for rendering graph structures. petgraph will
output a dot format file that contains all the information about the graph. Here’s the dot output from the
playground code:
digraph {
0 [ label = "A" ]
1 [ label = "B" ]
2 [ label = "C" ]
3 [ label = "D" ]
4 [ label = "E" ]
5 [ label = "F" ]
6 [ label = "G" ]
0 -> 1 [ label = "1" ]
0 -> 2 [ label = "1" ]
2 -> 3 [ label = "2" ]
2 -> 4 [ label = "2" ]
4 -> 5 [ label = "3" ]
5 -> 6 [ label = "4" ]
}
To render the dot output into an svg file for viewing in this page, I used
the dot program, which is part the graphviz package to render the graph into an svg. In my case, that command line
commandline looks like this
target/debug/petgraph_play| dot -Tsvg -o petgraph_play.svg
Then you can open the rendered .svg file in the viewer of your choice. (chrome or inkscape for example)
