jumoku 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. data/Gemfile +4 -0
  2. data/lib/jumoku.rb +4 -2
  3. data/lib/jumoku/version.rb +1 -1
  4. data/spec/raw_tree_spec.rb +353 -0
  5. data/spec/spec.opts +4 -0
  6. data/spec/spec_helper.rb +14 -0
  7. data/spec/tree_spec.rb +553 -0
  8. data/vendor/git/graphy/CREDITS.md +31 -0
  9. data/vendor/git/graphy/LICENSE +35 -0
  10. data/vendor/git/graphy/README.md +186 -0
  11. data/vendor/git/graphy/Rakefile +61 -0
  12. data/vendor/git/graphy/TODO.md +20 -0
  13. data/vendor/git/graphy/VERSION +1 -0
  14. data/vendor/git/graphy/examples/graph_self.rb +56 -0
  15. data/vendor/git/graphy/examples/module_graph.jpg +0 -0
  16. data/vendor/git/graphy/examples/module_graph.rb +14 -0
  17. data/vendor/git/graphy/examples/self_graph.jpg +0 -0
  18. data/vendor/git/graphy/examples/visualize.jpg +0 -0
  19. data/vendor/git/graphy/examples/visualize.rb +10 -0
  20. data/vendor/git/graphy/graphy.gemspec +149 -0
  21. data/vendor/git/graphy/lib/graphy.rb +90 -0
  22. data/vendor/git/graphy/lib/graphy/adjacency_graph.rb +224 -0
  23. data/vendor/git/graphy/lib/graphy/arc.rb +65 -0
  24. data/vendor/git/graphy/lib/graphy/arc_number.rb +52 -0
  25. data/vendor/git/graphy/lib/graphy/biconnected.rb +84 -0
  26. data/vendor/git/graphy/lib/graphy/chinese_postman.rb +91 -0
  27. data/vendor/git/graphy/lib/graphy/classes/graph_classes.rb +28 -0
  28. data/vendor/git/graphy/lib/graphy/common.rb +63 -0
  29. data/vendor/git/graphy/lib/graphy/comparability.rb +63 -0
  30. data/vendor/git/graphy/lib/graphy/directed_graph.rb +76 -0
  31. data/vendor/git/graphy/lib/graphy/directed_graph/algorithms.rb +92 -0
  32. data/vendor/git/graphy/lib/graphy/directed_graph/distance.rb +167 -0
  33. data/vendor/git/graphy/lib/graphy/dot.rb +94 -0
  34. data/vendor/git/graphy/lib/graphy/edge.rb +37 -0
  35. data/vendor/git/graphy/lib/graphy/ext.rb +79 -0
  36. data/vendor/git/graphy/lib/graphy/graph.rb +631 -0
  37. data/vendor/git/graphy/lib/graphy/graph_api.rb +35 -0
  38. data/vendor/git/graphy/lib/graphy/labels.rb +113 -0
  39. data/vendor/git/graphy/lib/graphy/maximum_flow.rb +77 -0
  40. data/vendor/git/graphy/lib/graphy/ruby_compatibility.rb +17 -0
  41. data/vendor/git/graphy/lib/graphy/search.rb +511 -0
  42. data/vendor/git/graphy/lib/graphy/strong_components.rb +93 -0
  43. data/vendor/git/graphy/lib/graphy/support/support.rb +9 -0
  44. data/vendor/git/graphy/lib/graphy/undirected_graph.rb +57 -0
  45. data/vendor/git/graphy/lib/graphy/undirected_graph/algorithms.rb +90 -0
  46. data/vendor/git/graphy/spec/biconnected_spec.rb +27 -0
  47. data/vendor/git/graphy/spec/chinese_postman_spec.rb +27 -0
  48. data/vendor/git/graphy/spec/community_spec.rb +44 -0
  49. data/vendor/git/graphy/spec/complement_spec.rb +27 -0
  50. data/vendor/git/graphy/spec/digraph_distance_spec.rb +121 -0
  51. data/vendor/git/graphy/spec/digraph_spec.rb +339 -0
  52. data/vendor/git/graphy/spec/dot_spec.rb +48 -0
  53. data/vendor/git/graphy/spec/edge_spec.rb +159 -0
  54. data/vendor/git/graphy/spec/inspection_spec.rb +40 -0
  55. data/vendor/git/graphy/spec/multi_edge_spec.rb +32 -0
  56. data/vendor/git/graphy/spec/neighborhood_spec.rb +38 -0
  57. data/vendor/git/graphy/spec/properties_spec.rb +146 -0
  58. data/vendor/git/graphy/spec/search_spec.rb +227 -0
  59. data/vendor/git/graphy/spec/spec.opts +4 -0
  60. data/vendor/git/graphy/spec/spec_helper.rb +56 -0
  61. data/vendor/git/graphy/spec/strong_components_spec.rb +61 -0
  62. data/vendor/git/graphy/spec/triangulated_spec.rb +125 -0
  63. data/vendor/git/graphy/spec/undirected_graph_spec.rb +220 -0
  64. data/vendor/git/graphy/vendor/priority-queue/CHANGELOG +33 -0
  65. data/vendor/git/graphy/vendor/priority-queue/Makefile +140 -0
  66. data/vendor/git/graphy/vendor/priority-queue/README +133 -0
  67. data/vendor/git/graphy/vendor/priority-queue/benchmark/dijkstra.rb +171 -0
  68. data/vendor/git/graphy/vendor/priority-queue/compare_comments.rb +49 -0
  69. data/vendor/git/graphy/vendor/priority-queue/doc/c-vs-rb.png +0 -0
  70. data/vendor/git/graphy/vendor/priority-queue/doc/compare_big.gp +14 -0
  71. data/vendor/git/graphy/vendor/priority-queue/doc/compare_big.png +0 -0
  72. data/vendor/git/graphy/vendor/priority-queue/doc/compare_small.gp +15 -0
  73. data/vendor/git/graphy/vendor/priority-queue/doc/compare_small.png +0 -0
  74. data/vendor/git/graphy/vendor/priority-queue/doc/results.csv +37 -0
  75. data/vendor/git/graphy/vendor/priority-queue/ext/priority_queue/CPriorityQueue/extconf.rb +2 -0
  76. data/vendor/git/graphy/vendor/priority-queue/ext/priority_queue/CPriorityQueue/priority_queue.c +947 -0
  77. data/vendor/git/graphy/vendor/priority-queue/lib/priority_queue.rb +14 -0
  78. data/vendor/git/graphy/vendor/priority-queue/lib/priority_queue/c_priority_queue.rb +1 -0
  79. data/vendor/git/graphy/vendor/priority-queue/lib/priority_queue/poor_priority_queue.rb +46 -0
  80. data/vendor/git/graphy/vendor/priority-queue/lib/priority_queue/ruby_priority_queue.rb +526 -0
  81. data/vendor/git/graphy/vendor/priority-queue/priority_queue.so +0 -0
  82. data/vendor/git/graphy/vendor/priority-queue/setup.rb +1551 -0
  83. data/vendor/git/graphy/vendor/priority-queue/test/priority_queue_test.rb +371 -0
  84. data/vendor/git/graphy/vendor/rdot.rb +360 -0
  85. metadata +83 -1
@@ -0,0 +1,91 @@
1
+ module Graphy
2
+ module ChinesePostman
3
+
4
+ # Returns the shortest walk that traverses all arcs at least
5
+ # once, returning to the specified start node.
6
+ def closed_chinese_postman_tour(start, weight=nil, zero=0)
7
+ cost, path, delta = floyd_warshall(weight, zero)
8
+ return nil unless cp_valid_least_cost? cost, zero
9
+ positive, negative = cp_unbalanced(delta)
10
+ f = cp_find_feasible(delta, positive, negative, zero)
11
+ while cp_improve(f, positive, negative, cost, zero); end
12
+ cp_euler_circuit(start, f, path)
13
+ end
14
+
15
+ private
16
+
17
+ def cp_euler_circuit(start, f, path) # :nodoc:
18
+ circuit = [u=v=start]
19
+ bridge_taken = Hash.new {|h,k| h[k] = Hash.new}
20
+ until v.nil?
21
+ if v=f[u].keys.detect {|k| f[u][k] > 0}
22
+ f[u][v] -= 1
23
+ circuit << (u = path[u][v]) while u != v
24
+ else
25
+ unless bridge_taken[u][bridge = path[u][start]]
26
+ v = vertices.detect {|v1| v1 != bridge && edge?(u,v1) && !bridge_taken[u][v1]} || bridge
27
+ bridge_taken[u][v] = true
28
+ circuit << v
29
+ end
30
+ end
31
+ u=v
32
+ end; circuit
33
+ end
34
+
35
+ def cp_cancel_cycle(cost, path, f, start, zero) # :nodoc:
36
+ u = start; k = nil
37
+ begin
38
+ v = path[u][start]
39
+ k = f[v][u] if cost[u][v] < zero and (k.nil? || k > f[v][u])
40
+ end until (u=v) != start
41
+ u = start
42
+ begin
43
+ v = path[u][start]
44
+ cost[u][v] < zero ? f[v][u] -= k : f[u][v] += k
45
+ end until (u=v) != start
46
+ true # This routine always returns true to make cp_improve easier
47
+ end
48
+
49
+ def cp_improve(f, positive, negative, cost, zero) # :nodoc:
50
+ residual = self.class.new
51
+ negative.each do |u|
52
+ positive.each do |v|
53
+ residual.add_edge!(u,v,cost[u][v])
54
+ residual.add_edge!(v,u,-cost[u][v]) if f[u][v] != 0
55
+ end
56
+ end
57
+ r_cost, r_path, r_delta = residual.floyd_warshall(nil, zero)
58
+ i = residual.vertices.detect {|v| r_cost[v][v] and r_cost[v][v] < zero}
59
+ i ? cp_cancel_cycle(r_cost, r_path, f, i) : false
60
+ end
61
+
62
+ def cp_find_feasible(delta, positive, negative, zero) # :nodoc:
63
+ f = Hash.new {|h,k| h[k] = Hash.new}
64
+ negative.each do |i|
65
+ positive.each do |j|
66
+ f[i][j] = -delta[i] < delta[j] ? -delta[i] : delta[j]
67
+ delta[i] += f[i][j]
68
+ delta[j] -= f[i][j]
69
+ end
70
+ end; f
71
+ end
72
+
73
+ def cp_valid_least_cost?(c, zero) # :nodoc:
74
+ vertices.each do |i|
75
+ vertices.each do |j|
76
+ return false unless c[i][j] and c[i][j] >= zero
77
+ end
78
+ end; true
79
+ end
80
+
81
+ def cp_unbalanced(delta) # :nodoc:
82
+ negative = []; positive = []
83
+ vertices.each do |v|
84
+ negative << v if delta[v] < 0
85
+ positive << v if delta[v] > 0
86
+ end; [positive, negative]
87
+ end
88
+
89
+ end # Chinese Postman
90
+ end # Graphy
91
+
@@ -0,0 +1,28 @@
1
+ module Graphy
2
+ # A generic {GraphBuilder Graph} class you can inherit from.
3
+ class Graph; include GraphBuilder; end
4
+
5
+ # A generic {AdjacencyGraphBuilder AdjacencyGraph} class you can inherit from.
6
+ class AdjacencyGraph; include AdjacencyGraphBuilder; end
7
+
8
+ # A generic {DirectedGraphBuilder DirectedGraph} class you can inherit from.
9
+ class DirectedGraph; include DirectedGraphBuilder; end
10
+
11
+ # A generic {DigraphBuilder Digraph} class you can inherit from.
12
+ class Digraph; include DigraphBuilder; end
13
+
14
+ # A generic {DirectedPseudoGraphBuilder DirectedPseudoGraph} class you can inherit from.
15
+ class DirectedPseudoGraph; include DirectedPseudoGraphBuilder; end
16
+
17
+ # A generic {DirectedMultiGraphBuilder DirectedMultiGraph} class you can inherit from.
18
+ class DirectedMultiGraph; include DirectedMultiGraphBuilder; end
19
+
20
+ # A generic {UndirectedGraphBuilder UndirectedGraph} class you can inherit from.
21
+ class UndirectedGraph; include UndirectedGraphBuilder; end
22
+
23
+ # A generic {UndirectedPseudoGraphBuilder UndirectedPseudoGraph} class you can inherit from.
24
+ class UndirectedPseudoGraph; include UndirectedPseudoGraphBuilder; end
25
+
26
+ # A generic {UndirectedMultiGraphBuilder UndirectedMultiGraph} class you can inherit from.
27
+ class UndirectedMultiGraph; include UndirectedMultiGraphBuilder; end
28
+ end
@@ -0,0 +1,63 @@
1
+ module Graphy
2
+
3
+ # This class defines a cycle graph of size n.
4
+ # This is easily done by using the base Graph
5
+ # class and implemeting the minimum methods needed to
6
+ # make it work. This is a good example to look
7
+ # at for making one's own graph classes.
8
+ module CycleBuilder
9
+ def initialize(n)
10
+ @size = n;
11
+ end
12
+
13
+ def directed?
14
+ false
15
+ end
16
+
17
+ def vertices
18
+ (1..@size).to_a
19
+ end
20
+
21
+ def vertex?(v)
22
+ v > 0 and v <= @size
23
+ end
24
+
25
+ def edge?(u,v = nil)
26
+ u, v = [u.source, v.target] if u.is_a? Graphy::Arc
27
+ vertex?(u) && vertex?(v) && ((v-u == 1) or (u == @size && v = 1))
28
+ end
29
+
30
+ def edges
31
+ Array.new(@size) { |i| Graphy::Edge[i+1, (i+1) == @size ? 1 : i+2]}
32
+ end
33
+ end # CycleBuilder
34
+
35
+ # This class defines a complete graph of size n.
36
+ # This is easily done by using the base Graph
37
+ # class and implemeting the minimum methods needed to
38
+ # make it work. This is a good example to look
39
+ # at for making one's own graph classes.
40
+ module CompleteBuilder
41
+ include CycleBuilder
42
+
43
+ def initialize(n)
44
+ @size = n
45
+ @edges = nil
46
+ end
47
+
48
+ def edges
49
+ return @edges if @edges # cache edges
50
+ @edges = []
51
+ @size.times do |u|
52
+ @size.times { |v| @edges << Graphy::Edge[u+1, v+1]}
53
+ end
54
+ @edges
55
+ end
56
+
57
+ def edge?(u, v = nil)
58
+ u, v = [u.source, v.target] if u.kind_of? Graphy::Arc
59
+ vertex?(u) && vertex?(v)
60
+ end
61
+ end # CompleteBuilder
62
+
63
+ end # Graphy
@@ -0,0 +1,63 @@
1
+ module Graphy
2
+ module Comparability
3
+
4
+ # A comparability graph is an UndirectedGraph that has a transitive
5
+ # orientation. This returns a boolean that says if this graph
6
+ # is a comparability graph.
7
+ def comparability?() gamma_decomposition[1]; end
8
+
9
+ # Returns an array with two values, the first being a hash of edges
10
+ # with a number containing their class assignment, the second valud
11
+ # is a boolean which states whether or not the graph is a
12
+ # comparability graph
13
+ #
14
+ # Complexity in time O(d*|E|) where d is the maximum degree of a vertex
15
+ # Complexity in space O(|V|+|E|)
16
+ def gamma_decomposition
17
+ k = 0; comparability=true; classification={}
18
+ edges.map {|edge| [edge.source,edge.target]}.each do |e|
19
+ if classification[e].nil?
20
+ k += 1
21
+ classification[e] = k; classification[e.reverse] = -k
22
+ comparability &&= graphy_comparability_explore(e, k, classification)
23
+ end
24
+ end; [classification, comparability]
25
+ end
26
+
27
+ # Returns one of the possible transitive orientations of
28
+ # the UndirectedGraph as a Digraph
29
+ def transitive_orientation(digraph_class=Digraph)
30
+ raise NotImplementError
31
+ end
32
+
33
+ private
34
+
35
+ # Taken from Figure 5.10, on pg. 130 of Martin Golumbic's, _Algorithmic_Graph_
36
+ # _Theory_and_Perfect_Graphs.
37
+ def graphy_comparability_explore(edge, k, classification, space='')
38
+ ret = graphy_comparability_explore_inner(edge, k, classification, :forward, space)
39
+ graphy_comparability_explore_inner(edge.reverse, k, classification, :backward, space) && ret
40
+ end
41
+
42
+ def graphy_comparability_explore_inner(edge, k, classification, direction,space)
43
+ comparability = true
44
+ adj_target = adjacent(edge[1])
45
+ adjacent(edge[0]).select do |mt|
46
+ (classification[[edge[1],mt]] || k).abs < k or
47
+ not adj_target.any? {|adj_t| adj_t == mt}
48
+ end.each do |m|
49
+ e = (direction == :forward) ? [edge[0], m] : [m,edge[0]]
50
+ if classification[e].nil?
51
+ classification[e] = k
52
+ classification[e.reverse] = -k
53
+ comparability = graphy_comparability_explore(e, k, classification, ' '+space) && comparability
54
+ elsif classification[e] == -k
55
+ classification[e] = k
56
+ graphy_comparability_explore(e, k, classification, ' '+space)
57
+ comparability = false
58
+ end
59
+ end; comparability
60
+ end # graphy_comparability_explore_inner
61
+
62
+ end # Comparability
63
+ end # Graphy
@@ -0,0 +1,76 @@
1
+ module Graphy
2
+
3
+ # This implements a directed graph which does not allow parallel
4
+ # edges nor loops. That is, only one arc per nodes couple,
5
+ # and only one parent per node. Mimics the typical hierarchy
6
+ # structure.
7
+ module DirectedGraphBuilder
8
+ include GraphBuilder
9
+
10
+ autoload :Algorithms, "graphy/directed_graph/algorithms"
11
+ autoload :Distance, "graphy/directed_graph/distance"
12
+
13
+ # FIXME: DRY this snippet, I didn't find a clever way to
14
+ # to dit though
15
+ # TODO: well, extends_host_with do ... end would be cool,
16
+ # using Module.new.module_eval(&block) in the helper.
17
+ extends_host
18
+ module ClassMethods
19
+ def [](*a)
20
+ self.new.from_array(*a)
21
+ end
22
+ end
23
+
24
+ def initialize(*params)
25
+ # FIXME/TODO: setting args to the hash or {} while getting rid
26
+ # on the previous parameters prevents from passing another
27
+ # graph to the initializer, so you cannot do things like:
28
+ # UndirectedGraph.new(Digraph[1,2, 2,3, 2,4, 4,5, 6,4, 1,6])
29
+ # As args must be a hash, if we're to allow such syntax,
30
+ # we should provide a way to handle the graph as a hash
31
+ # member.
32
+ args = (params.pop if params.last.kind_of? Hash) || {}
33
+ args[:algorithmic_category] = DirectedGraphBuilder::Algorithms
34
+ super *(params << args)
35
+ end
36
+ end # DirectedGraphBuilder
37
+
38
+ # DirectedGraph is just an alias for Digraph should one desire
39
+ DigraphBuilder = DirectedGraphBuilder
40
+
41
+ # This is a Digraph that allows for parallel edges, but does not
42
+ # allow loops.
43
+ module DirectedPseudoGraphBuilder
44
+ include DirectedGraphBuilder
45
+ extends_host
46
+ module ClassMethods
47
+ def [](*a)
48
+ self.new.from_array(*a)
49
+ end
50
+ end
51
+
52
+ def initialize(*params)
53
+ args = (params.pop if params.last.kind_of? Hash) || {}
54
+ args[:parallel_edges] = true
55
+ super *(params << args)
56
+ end
57
+ end # DirectedPseudoGraphBuilder
58
+
59
+ # This is a Digraph that allows for both parallel edges and loops.
60
+ module DirectedMultiGraphBuilder
61
+ include DirectedPseudoGraphBuilder
62
+ extends_host
63
+ module ClassMethods
64
+ def [](*a)
65
+ self.new.from_array(*a)
66
+ end
67
+ end
68
+
69
+ def initialize(*params)
70
+ args = (params.pop if params.last.kind_of? Hash) || {}
71
+ args[:loops] = true
72
+ super *(params << args)
73
+ end
74
+ end # DirectedMultiGraphBuilder
75
+
76
+ end # Graphy
@@ -0,0 +1,92 @@
1
+ module Graphy
2
+
3
+ # Digraph is a directed graph which is a finite set of vertices
4
+ # and a finite set of edges connecting vertices. It cannot contain parallel
5
+ # edges going from the same source vertex to the same target. It also
6
+ # cannot contain loops, i.e. edges that go have the same vertex for source
7
+ # and target.
8
+ #
9
+ # DirectedPseudoGraph is a class that allows for parallel edges, and
10
+ # DirectedMultiGraph is a class that allows for parallel edges and loops
11
+ # as well.
12
+ module DirectedGraphBuilder
13
+ module Algorithms
14
+
15
+ include Search
16
+ include StrongComponents
17
+ include Distance
18
+ include ChinesePostman
19
+
20
+ # A directed graph is directed by definition
21
+ #
22
+ # @return [Boolean] always true
23
+ def directed?
24
+ true
25
+ end
26
+
27
+ # A digraph uses the Arc class for edges
28
+ #
29
+ # @return [Graphy::MultiArc, Graphy::Arc] `Graphy::MultiArc` if the graph allows for parallel edges,
30
+ # `Graphy::Arc` otherwise.
31
+ def edge_class
32
+ @parallel_edges ? Graphy::MultiArc : Graphy::Arc
33
+ end
34
+
35
+ # Reverse all edges in a graph
36
+ #
37
+ # @return [DirectedGraph] a copy of the receiver for which the direction of edges has
38
+ # been inverted.
39
+ def reversal
40
+ result = self.class.new
41
+ edges.inject(result) { |a,e| a << e.reverse}
42
+ vertices.each { |v| result.add_vertex!(v) unless result.vertex?(v) }
43
+ result
44
+ end
45
+
46
+ # Check whether the Graph is oriented or not.
47
+ #
48
+ # @return [Boolean]
49
+ def oriented?
50
+ e = edges
51
+ re = e.map { |x| x.reverse}
52
+ not e.any? { |x| re.include?(x)}
53
+ end
54
+
55
+ # Balanced is when the out edge count is equal to the in edge count
56
+ #
57
+ # @return [Boolean]
58
+ def balanced?(v)
59
+ out_degree(v) == in_degree(v)
60
+ end
61
+
62
+ # Returns out_degree(v) - in_degree(v)
63
+ def delta(v)
64
+ out_degree(v) - in_degree(v)
65
+ end
66
+
67
+ def community(node, direction)
68
+ nodes, stack = {}, adjacent(node, :direction => direction)
69
+ while n = stack.pop
70
+ unless nodes[n.object_id] || node == n
71
+ nodes[n.object_id] = n
72
+ stack += adjacent(n, :direction => direction)
73
+ end
74
+ end
75
+ nodes.values
76
+ end
77
+
78
+ def descendants(node)
79
+ community(node, :out)
80
+ end
81
+
82
+ def ancestors(node)
83
+ community(node, :in)
84
+ end
85
+
86
+ def family(node)
87
+ community(node, :all)
88
+ end
89
+
90
+ end # Algorithms
91
+ end # DirectedGraphBuilder
92
+ end # Graphy
@@ -0,0 +1,167 @@
1
+ module Graphy
2
+ module DirectedGraphBuilder
3
+
4
+ # This module provides algorithms computing distance between
5
+ # vertices.
6
+ module Distance
7
+
8
+ # Shortest path computation.
9
+ #
10
+ # From: Jorgen Band-Jensen and Gregory Gutin,
11
+ # [*Digraphs: Theory, Algorithms and Applications*](http://www.springer.com/mathematics/numbers/book/978-1-84800-997-4), pg. 53-54.
12
+ # Complexity `O(n+m)`.
13
+ #
14
+ # Requires the graph to be acyclic. If the graph is not acyclic,
15
+ # then see {Distance#dijkstras_algorithm} or {Distance#bellman_ford_moore}
16
+ # for possible solutions.
17
+ #
18
+ # @param [vertex] start the starting vertex
19
+ # @param [Proc, #[]] weight can be a `Proc`, or anything else accessed using the `[]`
20
+ # operator. If not a `Proc`, and if no label accessible through `[]`, it will
21
+ # default to using the value stored in the label for the {Arc}. If a `Proc`, it will
22
+ # pass the edge to the proc and use the resulting value.
23
+ # @param [Integer] zero used for math systems with a different definition of zero
24
+ #
25
+ # @return [Hash] a hash with the key being a vertex and the value being the
26
+ # distance. A missing vertex from the hash is equivalent to an infinite distance.
27
+ def shortest_path(start, weight = nil, zero = 0)
28
+ dist = { start => zero }
29
+ path = {}
30
+ topsort(start) do |vi|
31
+ next if vi == start
32
+ dist[vi], path[vi] = adjacent(vi, :direction => :in).map do |vj|
33
+ [dist[vj] + cost(vj,vi,weight), vj]
34
+ end.min { |a,b| a[0] <=> b[0]}
35
+ end;
36
+ dist.keys.size == vertices.size ? [dist, path] : nil
37
+ end
38
+
39
+ # Finds the distance from a given vertex in a weighted digraph
40
+ # to the rest of the vertices, provided all the weights of arcs
41
+ # are non-negative.
42
+ #
43
+ # If negative arcs exist in the graph, two basic options exist:
44
+ #
45
+ # * modify all weights to be positive using an offset (temporary at least)
46
+ # * use the {Distance#bellman_ford_moore} algorithm.
47
+ #
48
+ # Also, if the graph is acyclic, use the {Distance#shortest_path algorithm}.
49
+ #
50
+ # From: Jorgen Band-Jensen and Gregory Gutin,
51
+ # [*Digraphs: Theory, Algorithms and Applications*](http://www.springer.com/mathematics/numbers/book/978-1-84800-997-4), pg. 53-54.
52
+ #
53
+ # Complexity `O(n*log(n) + m)`.
54
+ #
55
+ # @param [vertex] s
56
+ # @param [Proc, #[]] weight can be a `Proc`, or anything else accessed using the `[]`
57
+ # operator. If not a `Proc`, and if no label accessible through `[]`, it will
58
+ # default to using the value stored in the label for the {Arc}. If a `Proc`, it will
59
+ # pass the edge to the proc and use the resulting value.
60
+ # @param [Integer] zero used for math systems with a different definition of zero
61
+ # @return [Hash] a hash with the key being a vertex and the value being the
62
+ # distance. A missing vertex from the hash is equivalent to an infinite distance.
63
+ def dijkstras_algorithm(s, weight = nil, zero = 0)
64
+ q = vertices; distance = { s => zero }
65
+ path = {}
66
+ while not q.empty?
67
+ v = (q & distance.keys).inject(nil) { |a,k| (!a.nil?) && (distance[a] < distance[k]) ? a : k}
68
+ q.delete(v)
69
+ (q & adjacent(v)).each do |u|
70
+ c = cost(v, u, weight)
71
+ if distance[u].nil? or distance[u] > (c + distance[v])
72
+ distance[u] = c + distance[v]
73
+ path[u] = v
74
+ end
75
+ end
76
+ end
77
+ [distance, path]
78
+ end
79
+
80
+ # Finds the distances from a given vertex in a weighted digraph
81
+ # to the rest of the vertices, provided the graph has no negative cycle.
82
+ #
83
+ # If no negative weights exist, then {Distance#dijkstras_algorithm} is more
84
+ # efficient in time and space. Also, if the graph is acyclic, use the
85
+ # {Distance#shortest_path} algorithm.
86
+ #
87
+ # From: Jorgen Band-Jensen and Gregory Gutin,
88
+ # [*Digraphs: Theory, Algorithms and Applications*](http://www.springer.com/mathematics/numbers/book/978-1-84800-997-4), pg. 56-58..
89
+ #
90
+ # Complexity `O(nm)`.
91
+ #
92
+ # @param [vertex] s
93
+ # @param [Proc, #[]] weight can be a `Proc`, or anything else accessed using the `[]`
94
+ # operator. If not a `Proc`, and if no label accessible through `[]`, it will
95
+ # default to using the value stored in the label for the {Arc}. If a `Proc`, it will
96
+ # pass the edge to the proc and use the resulting value.
97
+ # @param [Integer] zero used for math systems with a different definition of zero
98
+ # @return [Hash] a hash with the key being a vertex and the value being the
99
+ # distance. A missing vertex from the hash is equivalent to an infinite distance.
100
+ def bellman_ford_moore(start, weight = nil, zero = 0)
101
+ distance = { start => zero }
102
+ path = {}
103
+ 2.upto(vertices.size) do
104
+ edges.each do |e|
105
+ u, v = e[0], e[1]
106
+ unless distance[u].nil?
107
+ c = cost(u, v, weight) + distance[u]
108
+ if distance[v].nil? or c < distance[v]
109
+ distance[v] = c
110
+ path[v] = u
111
+ end
112
+ end
113
+ end
114
+ end
115
+ [distance, path]
116
+ end
117
+
118
+ # Uses the Floyd-Warshall algorithm to efficiently find
119
+ # and record shortest paths while establishing at the same time
120
+ # the costs for all vertices in a graph.
121
+ #
122
+ # See S.Skiena, *The Algorithm Design Manual*, Springer Verlag, 1998 for more details.
123
+ #
124
+ # O(n^3) complexity in time.
125
+ #
126
+ # @param [Proc, nil] weight specifies how an edge weight is determined.
127
+ # If it's a `Proc`, the {Arc} is passed to it; if it's `nil`, it will just use
128
+ # the value in the label for the Arc; otherwise the weight is
129
+ # determined by applying the `[]` operator to the value in the
130
+ # label for the {Arc}.
131
+ # @param [Integer] zero defines the zero value in the math system used.
132
+ # This allows for no assumptions to be made about the math system and
133
+ # fully functional duck typing.
134
+ # @return [Array(matrice, matrice, Hash)] a pair of matrices and a hash of delta values.
135
+ # The matrices will be indexed by two vertices and are implemented as a Hash of Hashes.
136
+ # The first matrix is the cost, the second matrix is the shortest path spanning tree.
137
+ # The delta (difference of number of in-edges and out-edges) is indexed by vertex.
138
+ def floyd_warshall(weight = nil, zero = 0)
139
+ c = Hash.new { |h,k| h[k] = Hash.new }
140
+ path = Hash.new { |h,k| h[k] = Hash.new }
141
+ delta = Hash.new { |h,k| h[k] = 0 }
142
+ edges.each do |e|
143
+ delta[e.source] += 1
144
+ delta[e.target] -= 1
145
+ path[e.source][e.target] = e.target
146
+ c[e.source][e.target] = cost(e, weight)
147
+ end
148
+ vertices.each do |k|
149
+ vertices.each do |i|
150
+ if c[i][k]
151
+ vertices.each do |j|
152
+ if c[k][j] &&
153
+ (c[i][j].nil? or c[i][j] > (c[i][k] + c[k][j]))
154
+ path[i][j] = path[i][k]
155
+ c[i][j] = c[i][k] + c[k][j]
156
+ return nil if i == j and c[i][j] < zero
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
162
+ [c, path, delta]
163
+ end
164
+
165
+ end # Distance
166
+ end # DirectedGraph
167
+ end # Graphy