Giving an example of a cycle in a directed graph - ruby

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.

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

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.

Related

create array with iterative assignment

Would like to exploit the following behaviour in Ruby
ary = Array.new(5) { |i|
[i, j=2*i, k=j+1]
}
p ary #> [[0, 0, 1], [1, 2, 3], [2, 4, 5], [3, 6, 7], [4, 8, 9]]
It works for my purposes, but I couldn't find in the language definition whether this is legal Ruby. Is it? Or is it likely to break in the future?
[Edit] A smaller working example raising the same issue is
i = 1
ary = [i, j=2*i, k=j+1]
p ary #> [1, 2, 3]
But of course this example only has theoretical relevance contrary to the first, which does have practical relevance.

Ruby - finding all paths through a graph from a given starting point

The hash map is populated as such:
{"1"=>["2"], "2"=>["3", "7"], "3"=>["4"], "5"=>["6", "2"], "6"=>["7"], "7"=>["8", "4"]}
so that each key can have multiple values. These values represent bus stops from a set of routes e.g from bus stop 1 you can get to 2, from bus stop 2 you can get to 3 or 7 and so on.
I am trying to traverse this graph structure and find all possible paths of length greater than 1 from a given starting point. For example, for starting point of 1, the list of all possible paths would be
[[1,2] , [1,2,3] , [1,2,3,4] , [1,2,7] , [1,2,7,8], [1,2,7,4]]
I am trying to solve this problem recursively, where I iterate over the children of the current key (the values of that key) and call a function which essentially expands the children of that key. Here is my code so far:
if hash.has_key?(origin.to_s)
tmp = origin.to_s
tmp << hash[origin.to_s][0]
paths.push(tmp)
expand_node(hash,paths,paths.length-1,tmp[tmp.length-1])
end
Origin is the starting point. To start, I add the first path (in this case [1,2]) to an array called paths, then I expand the last value added to the previous path (in this case 2).
def expand_node(hash,paths,curr_paths_index,node)
curr_node = node
if hash.has_key?(node.to_s)
counter = 0
hash[curr_node].each do |child|
tmp = paths[curr_paths_index]
tmp << child
paths << tmp
curr_paths_index += counter + 1
puts paths
expand_node(hash,paths,curr_paths_index,child)
end
end
end
The argument curr_paths_index keeps track of the path from which I expand.
The argument path is the whole list of paths currently found.
The argument node is the current value being expanded.
Printing paths after the function finishes yields:
123
123
1234
1234
1234
12347
12347
12347
12347
123478
123478
123478
123478
123478
1234784
1234784
1234784
1234784
1234784
1234784
Is there any way to modify this code so that it produces the desired output (shown above)? Is there a better way of solving this problem in general?
Thanks.
One way to solve a recursive problem is to first break it down into a single case that is easy to solve and then generalize that one case. Here is an easier case:
Given a graph and path through that graph, determine which nodes can be added to the end of that path without creating a loop.
If we can solve this problem we can easily solve the larger problem as well.
Start with a path that is just your starting node
Find all nodes that can be added to that path without creating a loop
For each such node, output a path which is your initial path plus that node and...
Recursively repeat from step 2, using the new path
Note that if no new nodes are found in step 2, the recursive call will terminate because steps 3 and 4 have nothing to do.
Here is how I would solve step 2, I'll leave the recursive part to you
def find_next_nodes graph, path
graph[path[-1]].reject { |node| path.include? node }
end
I would do it like this, pretty sure this can be optimized further and there maybe an issue with performance too.
require 'set'
dt = {"1"=>["2"], "2"=>["3", "7"], "3"=>["4"], "5"=>["6", "2"], "6"=>["7"], "7"=>["8", "4"]}
def traverse(initial_hash, key_arrays, traversed_keys = [])
value = []
key_arrays.map do |key|
n = [*traversed_keys, key]
value << n unless n.count == 1 # prevent first key to be added
another_keys = initial_hash.fetch(key, nil) # try to load the value, fallback to nil if key not found
if another_keys.nil? # stop condition
value << n
elsif another_keys.is_a?(Enumerable) # if key found
another_keys.map do |ank| # recursive
value.concat([*traverse(initial_hash, [ank], n)]) # splat operator to unpack the array
end
end
end
value.to_set # only return unique value, can be converted to array if needed
end
traverse(dt, [1].map(&:to_s)).map { |val| val.join('') }
Sorry, but I have not debugged your code, so I think there's an issue with the temp variable there since the path which can't be expanded anymore is carried over to next iteration.
def doit(graph, start)
return [] unless graph.key?(start)
recurse(graph, start).drop(1)
end
def recurse(graph, start)
(graph[start] || []).each_with_object([[start]]) { |next_node, arr|
recurse(graph, next_node).each { |a| arr << [start, *a] } }
end
graph = { 1=>[2], 2=>[3, 7], 3=>[4], 5=>[6, 2], 6=>[7], 7=>[8, 4] }
doit(graph, 1)
#=> [[1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 7], [1, 2, 7, 8],
# [1, 2, 7, 4]]
doit(graph, 2)
#=> [[2, 3], [2, 3, 4], [2, 7], [2, 7, 8], [2, 7, 4]]
doit(graph, 3)
#=> [[3, 4]]
doit(graph, 5)
#=> [[5, 6], [5, 6, 7], [5, 6, 7, 8], [5, 6, 7, 4], [5, 2],
# [5, 2, 3], [5, 2, 3, 4], [5, 2, 7], [5, 2, 7, 8], [5, 2, 7, 4]]
doit(graph, 6)
#=> [[6, 7], [6, 7, 8], [6, 7, 4]]
doit(graph, 7)
#=> [[7, 8], [7, 4]]
doit(graph, 4)
#=> []
doit(graph, 99)
#=> []

Maximise number of edges to cut in connected graph

This question is very similar to Leetcode's Critical Connections in a Network. Given an undirected graph, we want to find all bridges. An edge in an undirected connected graph is a bridge iff removing it disconnects the graph.
Variant
Instead of finding all bridges, I want to maximise the number of edges to remove so that the graph remains connected.
Example 1
Input: n = 5, edges = [[1, 2], [1, 3], [3, 4], [1, 4], [4, 5]]
Output: 1
Firstly, I can remove [3,4], [1,3], or [1,4]. Next, after removing either of the 3 edges, the remaining edges are all bridges. Hence, the maximum number of edges to remove so that the graph remains connected is 1.
Example 2
Input: n = 6, edges = [[1, 2], [1, 3], [2, 3], [2, 4], [2, 5], [4, 6], [5, 6]]
Output: 2
Well this is easy, if we have E edges and N nodes in a connected graph we can remove E-N+1 edges so that graph remains connected.
How to do this?:
Just do DFS/BFS to find any spanning tree of the graph, since spanning tree is connected we can just remove all other edges.

Intersect each array in a array - Ruby

I want to find the intersect of each array elements in a array and take the intersection.
The inputs are array of arrays e.g., "'list_arrays' as mentioned in this script below"
The 'filter' is a limit needed to be applied on the total length of intersections observed
The out put is expected as array like this "[[2,4]]"
list_arrays = [[1, 2, 3, 4], [2, 5, 6], [1, 5, 8], [8, 2, 4]]
filter = 2
first_element_array = Array.new
list_arrays.each_with_index do |each_array1, index1|
list_arrays.each_with_index do |each_array2, index2|
unless index1 < index2
intersection = each_array1 & each_array2
if intersection.length == filter.to_i
first_element_array.push(intersection)
end
end
end
end
puts first_element_array
This above procedure takes long execution time as I have too long array of array (In million lines). I need a simple rubistic way to handle this problem. Anyone have any simple idea for it?
Deciphering your code it seems what you are asking for is "Return the intersections between pair combinations of a collection if that intersection has a certain size (2 in the example)". I'd write (functional approach):
list_arrays = [[1, 2, 3, 4], [2, 5, 6], [1, 5, 8], [8, 2, 4]]
list_arrays.combination(2).map do |xs, ys|
zs = xs & ys
zs.size == 2 ? zs : nil
end.compact
#=> [[2, 4]]
Proposed optimizations: 1) Use sets, 2) Use a custom abstraction Enumerable#map_compact (equivalent to map+compact but it would discard nils on the fly, write it yourself). 3) Filter out subarrays which won't satisfy the predicate:
require 'set'
xss = list_arrays.select { |xs| xs.size >= 2 }.map(&:to_set)
xss.combination(2).map_compact do |xs, ys|
zs = xs & ys
zs.size == 2 ? zs : nil
end
#=> [#<Set: {2, 4}>]

Validating and normalizing a partially ordered set

I have an array of pairs like this:
[["a", "b"], ["b", "d"], ["a", "c"], ["e", "d"], ["a", "d"], ..., ["s", "f"]]
What is an efficient way to check if the given array can express a partial ordering? That is, there is no "loop" in the given array like ["a", "b"], ["b", "c"], ["c", "a"].
If it is confirmed that the array expresses a partial order, I want to normalize this by removing all of the pairs that can be derived by reflexivity or transitivity. For example, in the above, since there is ["a", "b"] and ["b", "d"], the pair ["a", "d"] is redundant, and should be removed.
The order between 1 and 2 does not matter. If 2 should be done before or within the process of 1, then, that is fine.
Preferably I want it in Ruby 1.9.3, but just pseudo-code will suffice.
For number 1:
You can module your problem as a graph, and each pair will be an edge, next you can run a topological sort - if the algorithm fails, the graph is not a DAG - and there is a "loop" - otherwise - you get a possible partial order, as the output of the topological sort.
For number2:
I am not sure regarding this part at all, so this answer is only partial actually, sorry about it - but just a priliminary thaught:
You can use a DFS, and remove edges from "already discovered" vertices to "just discovered vertices" [on the same path]. Though I don't think it is optimal, but prehaps doing it iteratively [until no changes were made] will improve it.
Deeper thaught for number2:
I am not sure what you mean here, but a forest created by DFS fulfill your request, however I am afraid you might lose too much data using it, for instance: ["a","b"],["a","c"],["b",d"],["c","d"] will trim one of ["b","d"] OR ["c","d"], which might be too much, but it will also trim all the "redundant" edges, as described in the example.
The second problem is known as transitive reduction.
For the first part of the question, I came up with my own answer here with the help of an answer at a mathematics site.
For the second part of the question, after following the suggestions given in the other answers, I implemented in Ruby (i) Floyd-Warshall algorithm to calculate the transitive closure, (ii) composition, and (iii) transitive reduction using the formula R^- = R - R \cdot R^+.
module Digraph; module_function
def vertices graph; graph.flatten(1).uniq end
## Floyd-Warshall algorithm
def transitive_closure graph
vs = vertices(graph)
path = graph.inject({}){|path, e| path[e] = true; path}
vs.each{|k| vs.each{|i| vs.each{|j| path[[i, j]] ||= true if path[[i, k]] && path[[k, j]]}}}
path.keys
end
def compose graph1, graph2
vs = (vertices(graph1) + vertices(graph2)).uniq
path1 = graph1.inject({}){|path, e| path[e] = true; path}
path2 = graph2.inject({}){|path, e| path[e] = true; path}
path = {}
vs.each{|k| vs.each{|i| vs.each{|j| path[[i, j]] ||= true if path1[[i, k]] && path2[[k, j]]}}}
path.keys
end
def transitive_reduction graph
graph - compose(graph, transitive_closure(graph))
end
end
Usage examples:
Digraph.transitive_closure([[1, 2], [2, 3], [3, 4]])
#=> [[1, 2], [2, 3], [3, 4], [1, 3], [1, 4], [2, 4]]
Digraph.compose([[1, 2], [2, 3]], [[2, 4], [3, 5]])
#=> [[1, 4], [2, 5]]
Digraph.transitive_reduction([[1, 2], [2, 3], [3, 4], [1, 3], [1, 4], [2, 4]])
#=> [[1, 2], [2, 3], [3, 4]]

Resources