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.

Example Graph: Before Filter

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.

Example Graph: After Filter

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)

Reference

petgraph

rust playground petgraph