gonum / graph

Graph packages for the Go language [DEPRECATED]

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

simple: Self-referential nodes

mewmew opened this issue · comments

commented

The current implementation of simple directed graphs disallow self-referential nodes, and panic with the error message "simple: adding self edge".

Is there an implementation detail which prevents self-referential nodes from being represented?

For instance, how would one represent the following DOT graph, using a simple.DirectedGraph?

digraph {
    A -> A
}

Or, is there another gonum graph implementation which is better suited for this purpose?

When analyzing the control flow of basic blocks, infinite loops are represented as self-referential nodes in the control flow graph. E.g.

foo:
   jmp foo

I recently had the opportunity of playing around with the gonum graph representation, and it has been a very pleasant experience so far! Thanks a lot to those involved in its inception.

Cheers /u

Welcome.

There is an intention to add multigraph support, which would allow self edges, but the details of how to do that have not been resolved. The main issue is how to deal with edge modification in multigraphs (deletion and update).

Simple graphs (depending on who you believe) do not allow self edges, so we are following that (with some quiet evasion internally in some algorithms).

If you are using graphs, then I'd really appreciate looking at some of the issues that have been a cause for contention (at least in my mind). Writing a good graph API is not trivial and I'm still not sure we are there yet, though the mass of code is sort of ossifying what we have.

Relevant issues are #109, #87, #46.

commented

Welcome.

Thanks Dan. I'm glad to be here.

Simple graphs (depending on who you believe) do not allow self edges, so we are following that (with some quiet evasion internally in some algorithms).

If you are using graphs, then I'd really appreciate looking at some of the issues that have been a cause for contention (at least in my mind). Writing a good graph API is not trivial and I'm still not sure we are there yet, though the mass of code is sort of ossifying what we have.

I've really enjoyed playing around with graphs for my latest few hobby projects, and have now come to the point where I would love to develop a solid theoretical background and learn the proper graph terminology. Sorry for my ignorance during this phase, I do still have a lot to learn, and thanks for introducing me to some of the very basic ideas. Hopefully I will be given a chance to attend a course on graph theory this autumn, and should have a stronger foundation to stand on after that.

I can truly appreciate the difficulties in developing a good graph API. Truth to be told, I think you've done a great job so far! I just finished porting an old project of mine to use gonum instead, and the API feels great. It takes a bit of time to get adjusted, as I had a very different work-flow before, but I do like working with the gonum graph representation quite a bit. The main difference is that instead of using graph.From(node) and graph.To(node), I had been using something along the lines of node.Succs() node.Preds(). From a data structure point of view, it does indeed make sense to place this information in the graph, instead of the individual nodes. From a users perspective, you now tend to pass the graph around to a lot of places where you otherwise did not have to, but this is not really an issue.

When it comes to the API of multigraphs, I have been thinking, and also reviewing the issues you pointed out. While I do see the issue of identifying specific edges for modification, where multiple edges between the same source and destination nodes exist, I have not yet fallen attached to any of the proposed solutions. I think an edge ID would make most sense, seeing as what we are trying to achieve is really to identify which out of a set of edges that we care about. The other available information (such as weight information), may not necessarily be unique or enough to distinguish the edges from one another.

While my specific application does require a multigraph, as it uses self-referential nodes, I do not have any play project in mind which requires multiple edges to and from the same source and destination nodes. Therefore, I have a difficult time imagining how the API would feel like using, even though I agree that something along the lines of Edges() []Edge does make sense. Still, developing an API without a specific use-case in mind is very similar to premature optimization, you seldom end up where you want.

Another issue that was covered is that of performance, and in particular concerns related to allocation of the returned nodes slice. I understand the desire for performant applications, but the iterator API feels a bit strange, and perhaps unidiomatic (even if there are cases to point to in the standard library). I wish we may give this some more time, and hopefully we may end up with a cleaner approach after further pondering and discussions.

Well, as already mentioned, you know that I'm still quite new to graphs, and still have a lovely amount to learn. Luckily I'm enjoying every minute of the learning experience :) I'm sure I will revisit and revise many of my thoughts, so take them with a grain of salt.

Hope to talk with you more in the following months.

Cheers /u

If you have any views on #87 I'd be happy to hear them.

To answer the actual question here.

There are two ways you can get a self loop. 1) Make a fork of the simple.Directed type which doesn't preclude the self edge connection or 2) use an intermediate node.

commented
  1. Make a fork of the simple.Directed type which doesn't preclude the self edge connection

Thanks. A fork works for now (and may hopefully be removed once the API for multigraphs matures). After removing the "adding self edge" panic it works perfectly.

Last night I finished porting one of my old projects to use the gonum graph representation, and it feels great to be working with! The only API which felt a bit strange was that of dominator relationships. For this, I made a wrapper with the following method

// Dominates reports whether A dominates B.
Dominates(a, b graph.Node) bool

the behaviour of which is analogous to the following code,

dom[b.ID()].Has(a)
commented

Should I close this issue, as the implementation is working as intended? Or rename the title to something multigraph related?

We have a multigraph issue. I think this can be closed.

BTW on the Dominator API, please feel free to suggest improvements. I have not touched it since it's not used in my domain. I'd suggest a type like the path package Shortest/AllShortest types that carries the structure (possibly more efficiently) with appropriate accessor methods.

commented

We have a multigraph issue. I think this can be closed.

Perfect, closing this issue.

BTW on the Dominator API, please feel free to suggest improvements. I have not touched it since it's not used in my domain. I'd suggest a type like the path package Shortest/AllShortest types that carries the structure (possibly more efficiently) with appropriate accessor methods.

I'll take a look at the dominator API, and perhaps file an issue for suggested improvement, or a preliminary PR which we may discuss and iteratively improve upon, until we reach an API that everyone is happy with and at that point merge.