Detecting Directed Cycles In Edge Weighted Digraphs

In this article we'll talk about detecting directed cycles in edge weighted digraphs and we'll implement the solution in swift.Edge weighted digraphs can be used for a large number of things. In some cases we want to know if there’s a directed cycle between the nodes (or vertices). For example, if we’re working on a scheduling app, we would be interested to know if there’s a cycle on the graph. In this article we’ll talk about detecting directed cycles in edge weighted digraphs and we’ll implement the solution in swift.

Directed Cycle

A few weeks ago we talked about edge weighted digraphs in swift. In that article we’ve used airports as our graph example. Just to refresh your memory, this is the graph we used as an example:

A directed cycle is a path that can lead you to the vertex you started the path from. Look at the graph above. There are many cycles on that graph, if you travel from Dublin to Paris, then to San Francisco, you can end up in Dublin again. This is a directed cycle. The graph above is representing airports and directed cycles are not a problem in this case, in fact, you would expect to see them. Think: return flights 🙂

In some cases, directed cycles are not desirable. And if you find a directed cycle on a graph it would mean something is wrong. A good example would be software development. Imagine you’re building a piece of software and your software project consists of four modules. Some modules have a dependency on other modules and you can’t start working on them before you finish working on those dependent modules. We could display this on a graph like this one:

As you can see from the graph above, this project will never get finished. ‘Module 2’ has a dependency on ‘Module 4’. This creates a dependency cycle:

Modules 2, 3 and 4 are creating a cycle. In a simple diagram like this one, it’s quite easy to detect a cycle. But imagine you’re working on a complex system that consist’s of hundreds of modules. Detecting a cycle in a system like that one could prove to be challenging.

In our example all we want to know is if a graph has a cycle or not. If there’s a cycle, we know that the project can’t be finished. Next, we’ll implement this algorithm…

Implementation

We’ll build on top of the project that we used for the Dijkstra’s algorithm and for edge weighted digraphs. You can find the project on GitLab. We’ll need a stack as well. We’ve talked about how to implement a stack using a linked list over a year ago. We slightly modified that example, here’s the implementation:

It’s actually quite easy to detect a cycle on a graph. We’ll be using a depth first search to traverse our graph. All we have to do is keep track of the current ‘path’, to be more precise, we need to keep track of our recursion stack. Take a look at the example on the diagram above. If we start traversing our graph from ‘Module 1’, there’s only one path that we can take. If we keep adding the vertices on the stack as we’re visiting them, we’ll eventually try to add a vertex into our recursion stack for the second time. In the diagram above, that would be ‘Module 2’. As soon as that happens we know that we have a cycle. This is exactly how our algorithm is going to work.

The Class

In our class, we’ll keep an array of visited vertices and an array of reachable destinations. We’ll use the array of reachable destinations to construct our cycle if we have one. Here are the instance variables that we’ll be using:

‘recursionStack’ will be used to push and pop vertices onto the stack as we’re performing the depth first search. We added a function to our stack implementation that checks if an object is already in the stack. We’ll use this to check if we’re entering a cycle:

‘cycleStack’ is a simple stack that will contain the vertices that are closing the cycle loop:

In the constructor we’ll fill our ‘destinations’ array and start the algorithm:

Now it’s time to move on to the actual algorithm…

The Algorithm

As you can see, the algorithm is quite simple:

We push a vertex on the recursion stack and mark it as visited by adding it to the ‘visitedVertices’ array. For every adjacent edge in the vertex we check if the destination vertex has been visited. If not, we’ll do a recursive call with the destination vertex.

If our recursion stack contains the destination, then we have our cycle. Next, we’ll create our cycle stack and backtrack from the current vertex all the way to back to the current vertex again. Thus completing the cycle. We push all the vertices that we encounter while backtracking onto the cycle stack.

All the subsequent calls to ‘depthFirstSearch’ will return early when the first ‘if’ branch gets executed (because now we have a cycle).

It’s important to pop the vertex off the stack at the bottom of the function. If you need some help trying to figure out recursion, this article on binary search trees has a section that explains recursion.

And that’s it. We can now detect cycles in any directed graph.

Test It Out

Let’s quickly test this out by implementing a graph from our example diagram:

We create our vertices and give some random weights to the edges. After which we initialise our class with the newly created graph and check for the cycle, if there is any.

In the console output we can clearly see the cycle. It starts with ‘Module 4’ and ends with ‘Module 4’.

We can run our new cycle detector on the same graph that we used for Dijkstra’s algorithm. If we do that we’ll see that all the vertices on the graph are a part of a cycle:

Conclusion

Detecting cycles in graphs sounds very complicated. But, as we can see, it’s quite simple. In some cases we won’t care if a graph has cycles, in some cases it’s even expected. But there are cases when it’s really important to find out if a graph has a cycle. In most cases we would only be interested in knowing that a graph has a cycle, not how many cycles it has. A scheduling app, project management app, or any other precedence constrained graph will not tolerate cycles. Finding a cycle in one of those would indicate an error. And now you know how to find them 🙂

If you want to have some fun, try to modify this code to find all the cycles on a graph. The current code will stop after finding the first cycle. Which is exactly what we need for one of the future algorithms that we’ll cover here.

You can find all the code from this article on GitLab along with all the code snippets. I hope you’ve enjoyed this article and that you’ve learned something new today.

Have a nice day 🙂
~D;

More resources

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.