| 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)