Module: Bundler::TSort
- Included in:
- Molinillo::DependencyGraph, SpecSet
- Defined in:
- lib/bundler/vendor/tsort/lib/tsort.rb
Defined Under Namespace
Classes: Cyclic
Class Method Summary collapse
-
.each_strongly_connected_component(each_node, each_child) ⇒ Object
The iterator version of the TSort.strongly_connected_components method.
-
.each_strongly_connected_component_from(node, each_child, id_map = {}, stack = []) ⇒ Object
Iterates over strongly connected components in a graph.
-
.strongly_connected_components(each_node, each_child) ⇒ Object
Returns strongly connected components as an array of arrays of nodes.
-
.tsort(each_node, each_child) ⇒ Object
Returns a topologically sorted array of nodes.
-
.tsort_each(each_node, each_child) ⇒ Object
The iterator version of the TSort.tsort method.
Instance Method Summary collapse
-
#each_strongly_connected_component(&block) ⇒ Object
The iterator version of the #strongly_connected_components method.
-
#each_strongly_connected_component_from(node, id_map = {}, stack = [], &block) ⇒ Object
Iterates over strongly connected component in the subgraph reachable from node.
-
#strongly_connected_components ⇒ Object
Returns strongly connected components as an array of arrays of nodes.
-
#tsort ⇒ Object
Returns a topologically sorted array of nodes.
-
#tsort_each(&block) ⇒ Object
The iterator version of the #tsort method.
-
#tsort_each_child(node) ⇒ Object
Should be implemented by a extended class.
-
#tsort_each_node ⇒ Object
Should be implemented by a extended class.
Class Method Details
.each_strongly_connected_component(each_node, each_child) ⇒ Object
The iterator version of the TSort.strongly_connected_components method.
The graph is represented by each_node and each_child. each_node should have call
method which yields for each node in the graph. each_child should have call
method which takes a node argument and yields for each child node.
g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
each_node = lambda {|&b| g.each_key(&b) }
each_child = lambda {|n, &b| g[n].each(&b) }
TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
#=> [4]
# [2]
# [3]
# [1]
g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
each_node = lambda {|&b| g.each_key(&b) }
each_child = lambda {|n, &b| g[n].each(&b) }
TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
#=> [4]
# [2, 3]
# [1]
342 343 344 345 346 347 348 349 350 351 352 353 354 355 |
# File 'lib/bundler/vendor/tsort/lib/tsort.rb', line 342 def TSort.each_strongly_connected_component(each_node, each_child) # :yields: nodes return to_enum(__method__, each_node, each_child) unless block_given? id_map = {} stack = [] each_node.call {|node| unless id_map.include? node TSort.each_strongly_connected_component_from(node, each_child, id_map, stack) {|c| yield c } end } nil end |
.each_strongly_connected_component_from(node, each_child, id_map = {}, stack = []) ⇒ Object
Iterates over strongly connected components in a graph. The graph is represented by node and each_child.
node is the first node. each_child should have call
method which takes a node argument and yields for each child node.
Return value is unspecified.
#TSort.each_strongly_connected_component_from is a class method and it doesn’t need a class to represent a graph which includes TSort.
graph = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
each_child = lambda {|n, &b| graph[n].each(&b) }
TSort.each_strongly_connected_component_from(1, each_child) {|scc|
p scc
}
#=> [4]
# [2, 3]
# [1]
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 |
# File 'lib/bundler/vendor/tsort/lib/tsort.rb', line 408 def TSort.each_strongly_connected_component_from(node, each_child, id_map={}, stack=[]) # :yields: nodes return to_enum(__method__, node, each_child, id_map, stack) unless block_given? minimum_id = node_id = id_map[node] = id_map.size stack_length = stack.length stack << node each_child.call(node) {|child| if id_map.include? child child_id = id_map[child] minimum_id = child_id if child_id && child_id < minimum_id else sub_minimum_id = TSort.each_strongly_connected_component_from(child, each_child, id_map, stack) {|c| yield c } minimum_id = sub_minimum_id if sub_minimum_id < minimum_id end } if node_id == minimum_id component = stack.slice!(stack_length .. -1) component.each {|n| id_map[n] = nil} yield component end minimum_id end |
.strongly_connected_components(each_node, each_child) ⇒ Object
Returns strongly connected components as an array of arrays of nodes. The array is sorted from children to parents. Each elements of the array represents a strongly connected component.
The graph is represented by each_node and each_child. each_node should have call
method which yields for each node in the graph. each_child should have call
method which takes a node argument and yields for each child node.
g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
each_node = lambda {|&b| g.each_key(&b) }
each_child = lambda {|n, &b| g[n].each(&b) }
p TSort.strongly_connected_components(each_node, each_child)
#=> [[4], [2], [3], [1]]
g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
each_node = lambda {|&b| g.each_key(&b) }
each_child = lambda {|n, &b| g[n].each(&b) }
p TSort.strongly_connected_components(each_node, each_child)
#=> [[4], [2, 3], [1]]
280 281 282 |
# File 'lib/bundler/vendor/tsort/lib/tsort.rb', line 280 def TSort.strongly_connected_components(each_node, each_child) TSort.each_strongly_connected_component(each_node, each_child).to_a end |
.tsort(each_node, each_child) ⇒ Object
Returns a topologically sorted array of nodes. The array is sorted from children to parents, i.e. the first element has no child and the last node has no parent.
The graph is represented by each_node and each_child. each_node should have call
method which yields for each node in the graph. each_child should have call
method which takes a node argument and yields for each child node.
If there is a cycle, TSort::Cyclic is raised.
g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
each_node = lambda {|&b| g.each_key(&b) }
each_child = lambda {|n, &b| g[n].each(&b) }
p TSort.tsort(each_node, each_child) #=> [4, 2, 3, 1]
g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
each_node = lambda {|&b| g.each_key(&b) }
each_child = lambda {|n, &b| g[n].each(&b) }
p TSort.tsort(each_node, each_child) # raises TSort::Cyclic
175 176 177 |
# File 'lib/bundler/vendor/tsort/lib/tsort.rb', line 175 def TSort.tsort(each_node, each_child) TSort.tsort_each(each_node, each_child).to_a end |
.tsort_each(each_node, each_child) ⇒ Object
The iterator version of the TSort.tsort method.
The graph is represented by each_node and each_child. each_node should have call
method which yields for each node in the graph. each_child should have call
method which takes a node argument and yields for each child node.
g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
each_node = lambda {|&b| g.each_key(&b) }
each_child = lambda {|n, &b| g[n].each(&b) }
TSort.tsort_each(each_node, each_child) {|n| p n }
#=> 4
# 2
# 3
# 1
223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/bundler/vendor/tsort/lib/tsort.rb', line 223 def TSort.tsort_each(each_node, each_child) # :yields: node return to_enum(__method__, each_node, each_child) unless block_given? TSort.each_strongly_connected_component(each_node, each_child) {|component| if component.size == 1 yield component.first else raise Cyclic.new("topological sort failed: #{component.inspect}") end } end |
Instance Method Details
#each_strongly_connected_component(&block) ⇒ Object
The iterator version of the #strongly_connected_components method. obj.each_strongly_connected_component
is similar to obj.strongly_connected_components.each
, but modification of obj during the iteration may lead to unexpected results.
#each_strongly_connected_component returns nil
.
class G
include TSort
def initialize(g)
@g = g
end
def tsort_each_child(n, &b) @g[n].each(&b) end
def tsort_each_node(&b) @g.each_key(&b) end
end
graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
graph.each_strongly_connected_component {|scc| p scc }
#=> [4]
# [2]
# [3]
# [1]
graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
graph.each_strongly_connected_component {|scc| p scc }
#=> [4]
# [2, 3]
# [1]
313 314 315 316 317 |
# File 'lib/bundler/vendor/tsort/lib/tsort.rb', line 313 def each_strongly_connected_component(&block) # :yields: nodes each_node = method(:tsort_each_node) each_child = method(:tsort_each_child) TSort.each_strongly_connected_component(each_node, each_child, &block) end |
#each_strongly_connected_component_from(node, id_map = {}, stack = [], &block) ⇒ Object
Iterates over strongly connected component in the subgraph reachable from node.
Return value is unspecified.
#each_strongly_connected_component_from doesn’t call #tsort_each_node.
class G
include TSort
def initialize(g)
@g = g
end
def tsort_each_child(n, &b) @g[n].each(&b) end
def tsort_each_node(&b) @g.each_key(&b) end
end
graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
graph.each_strongly_connected_component_from(2) {|scc| p scc }
#=> [4]
# [2]
graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
graph.each_strongly_connected_component_from(2) {|scc| p scc }
#=> [4]
# [2, 3]
383 384 385 |
# File 'lib/bundler/vendor/tsort/lib/tsort.rb', line 383 def each_strongly_connected_component_from(node, id_map={}, stack=[], &block) # :yields: nodes TSort.each_strongly_connected_component_from(node, method(:tsort_each_child), id_map, stack, &block) end |
#strongly_connected_components ⇒ Object
Returns strongly connected components as an array of arrays of nodes. The array is sorted from children to parents. Each elements of the array represents a strongly connected component.
class G
include TSort
def initialize(g)
@g = g
end
def tsort_each_child(n, &b) @g[n].each(&b) end
def tsort_each_node(&b) @g.each_key(&b) end
end
graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
p graph.strongly_connected_components #=> [[4], [2], [3], [1]]
graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
p graph.strongly_connected_components #=> [[4], [2, 3], [1]]
254 255 256 257 258 |
# File 'lib/bundler/vendor/tsort/lib/tsort.rb', line 254 def strongly_connected_components each_node = method(:tsort_each_node) each_child = method(:tsort_each_child) TSort.strongly_connected_components(each_node, each_child) end |
#tsort ⇒ Object
Returns a topologically sorted array of nodes. The array is sorted from children to parents, i.e. the first element has no child and the last node has no parent.
If there is a cycle, TSort::Cyclic is raised.
class G
include TSort
def initialize(g)
@g = g
end
def tsort_each_child(n, &b) @g[n].each(&b) end
def tsort_each_node(&b) @g.each_key(&b) end
end
graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
p graph.tsort #=> [4, 2, 3, 1]
graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
p graph.tsort # raises TSort::Cyclic
149 150 151 152 153 |
# File 'lib/bundler/vendor/tsort/lib/tsort.rb', line 149 def tsort each_node = method(:tsort_each_node) each_child = method(:tsort_each_child) TSort.tsort(each_node, each_child) end |
#tsort_each(&block) ⇒ Object
The iterator version of the #tsort method. obj.tsort_each
is similar to obj.tsort.each
, but modification of obj during the iteration may lead to unexpected results.
#tsort_each returns nil
. If there is a cycle, TSort::Cyclic is raised.
class G
include TSort
def initialize(g)
@g = g
end
def tsort_each_child(n, &b) @g[n].each(&b) end
def tsort_each_node(&b) @g.each_key(&b) end
end
graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
graph.tsort_each {|n| p n }
#=> 4
# 2
# 3
# 1
202 203 204 205 206 |
# File 'lib/bundler/vendor/tsort/lib/tsort.rb', line 202 def tsort_each(&block) # :yields: node each_node = method(:tsort_each_node) each_child = method(:tsort_each_child) TSort.tsort_each(each_node, each_child, &block) end |
#tsort_each_child(node) ⇒ Object
Should be implemented by a extended class.
#tsort_each_child is used to iterate for child nodes of node.
449 450 451 |
# File 'lib/bundler/vendor/tsort/lib/tsort.rb', line 449 def tsort_each_child(node) # :yields: child raise NotImplementedError.new end |
#tsort_each_node ⇒ Object
Should be implemented by a extended class.
#tsort_each_node is used to iterate for all nodes over a graph.
441 442 443 |
# File 'lib/bundler/vendor/tsort/lib/tsort.rb', line 441 def tsort_each_node # :yields: node raise NotImplementedError.new end |