Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Giving an example of a cycle in a directed graph

I want an algorithm that gives one instance of a cycle in a directed graph if there is any. Can anyone show me a direction? In pseudo-code, or preferably, in Ruby?

I previously asked a similar question, and following the suggestions there, I implemented Kahn's algorithm in Ruby that detects if a graph has a cycle, but I want not only whether it has a cycle, but also one possible instance of such cycle.

example_graph = [[1, 2], [2, 3], [3, 4], [3, 5], [3, 6], [6, 2]]

Kahn's algorithm

def cyclic? graph
  ## The set of edges that have not been examined
  graph = graph.dup
  n, m = graph.transpose
  ## The set of nodes that are the supremum in the graph
  sup = (n - m).uniq
  while sup_old = sup.pop do
    sup_old = graph.select{|n, _| n == sup_old}
    graph -= sup_old
    sup_old.each {|_, ssup| sup.push(ssup) unless graph.any?{|_, n| n == ssup}}
  end
  !graph.empty?
end

The above algorithm tells whether a graph has a cycle:

cyclic?(example_graph) #=> true

but I want not only that but an example of a cycle like this:

#=> [[2, 3], [3, 6], [6, 2]]

If I were to output the variable graph in the above code at the end of examination, it will give:

#=> [[2, 3], [3, 4], [3, 5], [3, 6], [6, 2]]

which includes the cycle I want, but it also includes extra edges that are irrelevant to the cycle.

like image 272
sawa Avatar asked Mar 15 '12 22:03

sawa


People also ask

What is a cycle in a directed graph?

In graph theory, a cycle in a graph is a non-empty trail in which only the first and last vertices are equal. A directed cycle in a directed graph is a non-empty directed trail in which only the first and last vertices are equal.

What is a cycle in a graph example?

3. What Is a Cycle? In graph theory, a path that starts from a given vertex and ends at the same vertex is called a cycle.

What are the examples of directed graph?

A directed graph (or digraph) is a set of nodes connected by edges, where the edges have a direction associated with them. For example, an arc (x, y) is considered to be directed from x to y, and the arc (y, x) is the inverted link. Y is a direct successor of x, and x is a direct predecessor of y.

How do you check if a directed graph has a cycle?

To detect cycle, check for a cycle in individual trees by checking back edges. To detect a back edge, keep track of vertices currently in the recursion stack of function for DFS traversal. If a vertex is reached that is already in the recursion stack, then there is a cycle in the tree.


2 Answers

I asked the same question in the math stackexchange site, and got an answer. It turned out that Tarjan's algorithm is good for solving this problem. I implemented it in Ruby as follows:

module DirectedGraph; module_function
    ## Tarjan's algorithm
    def strongly_connected_components graph
        @index, @stack, @indice, @lowlink, @scc = 0, [], {}, {}, []
        @graph = graph
        @graph.flatten(1).uniq.each{|v| strong_connect(v) unless @indice[v]}
        @scc
    end
    def strong_connect v
        @indice[v] = @index
        @lowlink[v] = @index
        @index += 1
        @stack.push(v)
        @graph.each do |vv, w|
            next unless vv == v
            if !@indice[w]
                strong_connect(w)
                @lowlink[v] = [@lowlink[v], @lowlink[w]].min
            elsif @stack.include?(w)
                @lowlink[v] = [@lowlink[v], @indice[w]].min
            end
        end
        if @lowlink[v] == @indice[v]
            i = @stack.index(v)
            @scc.push(@stack[i..-1])
            @stack = @stack[0...i]
        end
    end
end

So if I apply it to the example above, I get a list of strongly connected components of the graph:

example_graph = [[1, 2], [2, 3], [3, 4], [3, 5], [3, 6], [6, 2]]
DirectedGraph.strongly_connected_components(example_graph)
#=> [[4], [5], [2, 3, 6], [1]]

By selecting those components that are longer than one, I get the cycles:

DirectedGraph.strongly_connected_components(example_graph)
.select{|a| a.length > 1}
#=> [[2, 3, 6]]

And further if I select from the graph the edges whose both vertices are included in the components, I get the crucial edges that constitute the cycles:

DirectedGraph.strongly_connected_components(example_graph)
.select{|a| a.length > 1}
.map{|a| example_graph.select{|v, w| a.include?(v) and a.include?(w)}}
#=> [[[2, 3], [3, 6], [6, 2]]]
like image 176
sawa Avatar answered Dec 01 '22 01:12

sawa


Depth first search, where you keep track of the visited vertices and the parent will give you the cycle. If you see an edge to a previously visited vertex then you have detected a cycle between your parent, yourself, and that vertex. A slight problem you may encounter is, if it is a cycle of length > 3, you'll only be able to tell the three vertices involved and will have to do some investigation into finding the rest of the vertices in the cycle.

For the investigation, you can start a breadth first search 'up' the tree starting from the parent and looking for the visited vertex, you should be able to find the whole cycle by doing that.

like image 24
Justin Avatar answered Dec 01 '22 01:12

Justin