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,90 @@
1
+ #--
2
+ # Copyright (c) 2006 Shawn Patrick Garbett
3
+ # Copyright (c) 2002,2004,2005 by Horst Duchene
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without modification,
6
+ # are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice(s),
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of the Shawn Garbett nor the names of its contributors
14
+ # may be used to endorse or promote products derived from this software
15
+ # without specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ #++
28
+
29
+ require 'set'
30
+
31
+ module Graphy
32
+ # Graphy internals: graph builders and additionnal behaviors
33
+ autoload :GraphAPI, 'graphy/graph_api'
34
+
35
+ autoload :GraphBuilder, 'graphy/graph'
36
+ autoload :AdjacencyGraphBuilder, 'graphy/adjacency_graph'
37
+
38
+ autoload :DirectedGraphBuilder, 'graphy/directed_graph'
39
+ autoload :DigraphBuilder, 'graphy/directed_graph'
40
+ autoload :DirectedPseudoGraphBuilder, 'graphy/directed_graph'
41
+ autoload :DirectedMultiGraphBuilder, 'graphy/directed_graph'
42
+
43
+ autoload :UndirectedGraphBuilder, 'graphy/undirected_graph'
44
+ autoload :UndirectedPseudoGraphBuilder, 'graphy/undirected_graph'
45
+ autoload :UndirectedMultiGraphBuilder, 'graphy/undirected_graph'
46
+
47
+ autoload :Arc, 'graphy/arc'
48
+ autoload :ArcNumber, 'graphy/arc_number'
49
+ autoload :Biconnected, 'graphy/biconnected'
50
+ autoload :ChinesePostman, 'graphy/chinese_postman'
51
+ autoload :Common, 'graphy/common'
52
+ autoload :Comparability, 'graphy/comparability'
53
+
54
+ autoload :Dot, 'graphy/dot'
55
+ autoload :Edge, 'graphy/edge'
56
+ autoload :Labels, 'graphy/labels'
57
+ autoload :MaximumFlow, 'graphy/maximum_flow'
58
+ #autoload :Rdot, 'graphy/dot'
59
+ autoload :Search, 'graphy/search'
60
+ autoload :StrongComponents, 'graphy/strong_components'
61
+
62
+ # Graphy classes
63
+ autoload :AdjacencyGraph, 'graphy/classes/graph_classes'
64
+ autoload :DirectedGraph, 'graphy/classes/graph_classes'
65
+ autoload :Digraph, 'graphy/classes/graph_classes'
66
+ autoload :DirectedPseudoGraph, 'graphy/classes/graph_classes'
67
+ autoload :DirectedMultiGraph, 'graphy/classes/graph_classes'
68
+ autoload :UndirectedGraph, 'graphy/classes/graph_classes'
69
+ autoload :UndirectedPseudoGraph, 'graphy/classes/graph_classes'
70
+ autoload :UndirectedMultiGraph, 'graphy/classes/graph_classes'
71
+
72
+ # ruby stdlib extensions
73
+ require 'graphy/ext'
74
+ # ruby 1.8.x/1.9.x compatibility
75
+ require 'graphy/ruby_compatibility'
76
+ end
77
+
78
+ # Vendored libraries
79
+
80
+ require 'pathname'
81
+ path = Pathname.new(__FILE__)
82
+ $LOAD_PATH.unshift(path + '../../vendor')
83
+ $LOAD_PATH.unshift(path + '../../vendor/priority-queue/lib')
84
+
85
+ require 'rdot'
86
+ require 'facets/hash'
87
+
88
+ require 'priority_queue/ruby_priority_queue'
89
+ PriorityQueue = RubyPriorityQueue
90
+
@@ -0,0 +1,224 @@
1
+ module Graphy
2
+
3
+ # This module provides the basic routines needed to implement the specialized builders:
4
+ # {DigraphBuilder}, {UndirectedGraphBuilder}, {DirectedPseudoGraphBuilder},
5
+ # {UndirectedPseudoGraphBuilder}, {DirectedMultiGraphBuilder} and {UndirectedMultiGraphBuilder}
6
+ # modules, each of them streamlining {AdjacencyGraphBuilder}'s behavior. Those
7
+ # implementations rely on the {GraphBuilder}, under the control of the {GraphAPI}.
8
+ module AdjacencyGraphBuilder
9
+
10
+ # Defines a useful `push` -> `add` alias for arrays.
11
+ class ArrayWithAdd < Array
12
+ alias add push
13
+ end
14
+
15
+ # This method is called by the specialized implementations
16
+ # upon graph creation.
17
+ #
18
+ # Initialization parameters can include:
19
+ #
20
+ # * an array of edges to add
21
+ # * one or several graphs to copy (will be merged if multiple)
22
+ # * `:parallel_edges` denotes that duplicate edges are allowed
23
+ # * `:loops denotes` that loops are allowed
24
+ #
25
+ # @param *params [Hash] the initialization parameters
26
+ def implementation_initialize(*params)
27
+ @vertex_dict = Hash.new
28
+ clear_all_labels
29
+
30
+ # FIXME: could definitely make use of the activesupport helper
31
+ # extract_options! and facets' reverse_merge! technique
32
+ # to handle parameters
33
+ args = (params.pop if params.last.is_a? Hash) || {}
34
+
35
+ # Basic configuration of adjacency.
36
+ @allow_loops = args[:loops] || false
37
+ @parallel_edges = args[:parallel_edges] || false
38
+ @edgelist_class = @parallel_edges ? ArrayWithAdd : Set
39
+ if @parallel_edges
40
+ @edge_number = Hash.new
41
+ @next_edge_number = 0
42
+ end
43
+
44
+ # Copy any given graph into this graph.
45
+ params.select { |p| p.is_a? Graphy::GraphBuilder }.each do |g|
46
+ g.edges.each do |e|
47
+ add_edge!(e)
48
+ edge_label_set(e, edge_label(e)) if edge_label(e)
49
+ end
50
+ g.vertices.each do |v|
51
+ add_vertex!(v)
52
+ vertex_label_set(v, vertex_label(v)) if vertex_label(v)
53
+ end
54
+ end
55
+
56
+ # Add all array edges specified.
57
+ params.select { |p| p.is_a? Array }.each do |a|
58
+ 0.step(a.size-1, 2) { |i| add_edge!(a[i], a[i+1]) }
59
+ end
60
+ end
61
+
62
+ # Returns true if v is a vertex of this Graph
63
+ # (an "O(1)" implementation of `vertex?`).
64
+ #
65
+ # @param [vertex] v
66
+ # @return [Boolean]
67
+ def vertex?(v)
68
+ @vertex_dict.has_key?(v)
69
+ end
70
+
71
+ # Returns true if [u,v] or u is an {Arc}
72
+ # (an "O(1)" implementation of `edge?`).
73
+ #
74
+ # @param [vertex] u
75
+ # @param [vertex] v (nil)
76
+ # @return [Boolean]
77
+ def edge?(u, v = nil)
78
+ u, v = u.source, u.target if u.is_a? Graphy::Arc
79
+ vertex?(u) and @vertex_dict[u].include?(v)
80
+ end
81
+
82
+ # Adds a vertex to the graph with an optional label.
83
+ #
84
+ # @param [vertex(Object)] vertex any kind of Object can act as a vertex
85
+ # @param [#to_s] label (nil)
86
+ def add_vertex!(vertex, label = nil)
87
+ @vertex_dict[vertex] ||= @edgelist_class.new
88
+ self[vertex] = label if label
89
+ self
90
+ end
91
+
92
+ # Adds an edge to the graph.
93
+ #
94
+ # Can be called in two basic ways, label is optional:
95
+ # @overload add_edge!(arc)
96
+ # Using an explicit {Arc}
97
+ # @param [Arc] arc an {Arc}[source, target, label = nil] object
98
+ # @return [AdjacencyGraph] `self`
99
+ # @overload add_edge!(source, target, label = nil)
100
+ # Using vertices to define an arc implicitly
101
+ # @param [vertex] u
102
+ # @param [vertex] v (nil)
103
+ # @param [Label] l (nil)
104
+ # @param [Integer] n (nil) {Arc arc} number of `(u, v)` (if `nil` and if `u`
105
+ # has an {ArcNumber}, then it will be used)
106
+ # @return [AdjacencyGraph] `self`
107
+ def add_edge!(u, v = nil, l = nil, n = nil)
108
+ n = u.number if u.class.include? ArcNumber and n.nil?
109
+ u, v, l = u.source, u.target, u.label if u.is_a? Graphy::Arc
110
+
111
+ return self if not @allow_loops and u == v
112
+
113
+ n = (@next_edge_number += 1) unless n if @parallel_edges
114
+ add_vertex!(u)
115
+ add_vertex!(v)
116
+ @vertex_dict[u].add(v)
117
+ (@edge_number[u] ||= @edgelist_class.new).add(n) if @parallel_edges
118
+
119
+ unless directed?
120
+ @vertex_dict[v].add(u)
121
+ (@edge_number[v] ||= @edgelist_class.new).add(n) if @parallel_edges
122
+ end
123
+
124
+ self[n ? edge_class[u,v,n] : edge_class[u,v]] = l if l
125
+ self
126
+ end
127
+
128
+ # Removes a given vertex from the graph.
129
+ #
130
+ # @param [vertex] v
131
+ # @return [AdjacencyGraph] `self`
132
+ def remove_vertex!(v)
133
+ # FIXME This is broken for multi graphs
134
+ @vertex_dict.delete(v)
135
+ @vertex_dict.each_value { |adjList| adjList.delete(v) }
136
+ @vertex_dict.keys.each do |u|
137
+ delete_label(edge_class[u,v])
138
+ delete_label(edge_class[v,u])
139
+ end
140
+ delete_label(v)
141
+ self
142
+ end
143
+
144
+ # Removes an edge from the graph.
145
+ #
146
+ # Can be called with both source and target as vertex,
147
+ # or with source and object of {Graphy::Arc} derivation.
148
+ #
149
+ # @overload remove_edge!(a)
150
+ # @param [Graphy::Arc] a
151
+ # @return [AdjacencyGraph] `self`
152
+ # @raise [ArgumentError] if parallel edges are enabled
153
+ # @overload remove_edge!(u, v)
154
+ # @param [vertex] u
155
+ # @param [vertex] v
156
+ # @return [AdjacencyGraph] `self`
157
+ # @raise [ArgumentError] if parallel edges are enabled and the {ArcNumber} of `u` is zero
158
+ def remove_edge!(u, v = nil)
159
+ unless u.is_a? Graphy::Arc
160
+ raise ArgumentError if @parallel_edges
161
+ u = edge_class[u,v]
162
+ end
163
+ raise ArgumentError if @parallel_edges and (u.number || 0) == 0
164
+ return self unless @vertex_dict[u.source] # It doesn't exist
165
+ delete_label(u) # Get rid of label
166
+ if @parallel_edges
167
+ index = @edge_number[u.source].index(u.number)
168
+ raise NoArcError unless index
169
+ @vertex_dict[u.source].delete_at(index)
170
+ @edge_number[u.source].delete_at(index)
171
+ else
172
+ @vertex_dict[u.source].delete(u.target)
173
+ end
174
+ self
175
+ end
176
+
177
+ # Returns an array of vertices that the graph has.
178
+ #
179
+ # @return [Array] graph's vertices
180
+ def vertices
181
+ @vertex_dict.keys
182
+ end
183
+
184
+ # Returns an array of edges, most likely of class {Arc} or {Edge} depending
185
+ # upon the type of graph.
186
+ #
187
+ # @return [Array]
188
+ def edges
189
+ @vertex_dict.keys.inject(Set.new) do |a,v|
190
+ if @parallel_edges and @edge_number[v]
191
+ @vertex_dict[v].zip(@edge_number[v]).each do |w|
192
+ s, t, n = v, w[0], w[1]
193
+ a.add(edge_class[s, t, n, edge_label(s, t, n)])
194
+ end
195
+ else
196
+ @vertex_dict[v].each do |w|
197
+ a.add(edge_class[v, w, edge_label(v, w)])
198
+ end
199
+ end
200
+ a
201
+ end.to_a
202
+ end
203
+
204
+ # FIXME, EFFED UP (but why?)
205
+ #
206
+ # @fixme
207
+ def adjacent(x, options = {})
208
+ options[:direction] ||= :out
209
+ if !x.is_a?(Graphy::Arc) and (options[:direction] == :out || !directed?)
210
+ if options[:type] == :edges
211
+ i = -1
212
+ @parallel_edges ?
213
+ @vertex_dict[x].map { |v| e = edge_class[x, v, @edge_number[x][i+=1]]; e.label = self[e]; e } :
214
+ @vertex_dict[x].map { |v| e = edge_class[x, v]; e.label = self[e]; e }
215
+ else
216
+ @vertex_dict[x].to_a
217
+ end
218
+ else
219
+ graph_adjacent(x,options)
220
+ end
221
+ end
222
+
223
+ end # Adjacency Graph
224
+ end # Graphy
@@ -0,0 +1,65 @@
1
+ module Graphy
2
+
3
+ # Arc includes classes for representing egdes of directed and
4
+ # undirected graphs. There is no need for a Vertex class, because any ruby
5
+ # object can be a vertex of a graph.
6
+ #
7
+ # Arc's base is a Struct with a :source, a :target and a :label
8
+ Struct.new("ArcBase", :source, :target, :label)
9
+
10
+ class Arc < Struct::ArcBase
11
+
12
+ def initialize(p_source, p_target, p_label = nil)
13
+ super(p_source, p_target, p_label)
14
+ end
15
+
16
+ # Ignore labels for equality.
17
+ def eql?(other)
18
+ self.class == other.class and target == other.target and source == other.source
19
+ end
20
+ alias == eql?
21
+
22
+ # Returns (v,u) if self == (u,v).
23
+ def reverse() self.class.new(target, source, label); end
24
+
25
+ # Sort support.
26
+ def <=>(rhs)
27
+ [source, target] <=> [rhs.source, rhs.target]
28
+ end
29
+
30
+ # Arc.new[1,2].to_s => "(1-2 'label')"
31
+ def to_s
32
+ l = label ? " '#{label.to_s}'" : ''
33
+ "(#{source}-#{target}#{l})"
34
+ end
35
+
36
+ # Hash is defined in such a way that label is not
37
+ # part of the hash value
38
+ # FIXME: I had to get rid of that in order to make to_dot_graph
39
+ # work, but I can't figure it out (doesn't show up in the stack!)
40
+ #def hash
41
+ #puts "--- #{caller}"
42
+ ##puts source.inspect
43
+ ##puts target.inspect
44
+ #source.hash ^ (target.hash + 1)
45
+ #puts "---"
46
+ #end
47
+
48
+ # Shortcut constructor.
49
+ #
50
+ # Instead of Arc.new(1,2) one can use Arc[1,2].
51
+ def self.[](p_source, p_target, p_label = nil)
52
+ new(p_source, p_target, p_label)
53
+ end
54
+
55
+ #def inspect
56
+ #"#{self.class.to_s}[#{source.inspect},#{target.inspect},#{label.inspect}]"
57
+ #end
58
+
59
+ end # Arc
60
+
61
+ class MultiArc < Arc
62
+ include ArcNumber
63
+ end
64
+
65
+ end # Graphy
@@ -0,0 +1,52 @@
1
+ module Graphy
2
+ # This module handles internal numbering of edges in order to differente between mutliple edges.
3
+ module ArcNumber
4
+
5
+ # Used to differentiate between mutli-edges
6
+ attr_accessor :number
7
+
8
+ def initialize(p_source, p_target, p_number, p_label = nil)
9
+ self.number = p_number
10
+ super(p_source, p_target, p_label)
11
+ end
12
+
13
+ # Returns (v,u) if self == (u,v).
14
+ def reverse
15
+ self.class.new(target, source, number, label)
16
+ end
17
+
18
+ # Allow for hashing of self loops.
19
+ def hash
20
+ super ^ number.hash
21
+ end
22
+
23
+ def to_s
24
+ super + "[#{number}]"
25
+ end
26
+
27
+ def <=>(rhs)
28
+ (result = super(rhs)) == 0 ? number <=> rhs.number : result
29
+ end
30
+
31
+ def inspect
32
+ "#{self.class.to_s}[#{source.inspect},#{target.inspect},#{number.inspect},#{label.inspect}]"
33
+ end
34
+
35
+ def eql?(rhs)
36
+ super(rhs) and (rhs.number.nil? or number.nil? or number == rhs.number)
37
+ end
38
+
39
+ def ==(rhs)
40
+ eql?(rhs)
41
+ end
42
+
43
+ # Shortcut constructor. Instead of Arc.new(1,2) one can use Arc[1,2]
44
+ def self.included(cl)
45
+ # FIXME: lacks a cl.class_eval, no?
46
+ def cl.[](p_source, p_target, p_number = nil, p_label = nil)
47
+ new(p_source, p_target, p_number, p_label)
48
+ end
49
+ end
50
+
51
+ end # ArcNumber
52
+ end # Graphy
@@ -0,0 +1,84 @@
1
+ module Graphy
2
+
3
+ # Biconnected is a module for adding the biconnected algorithm to
4
+ # UndirectedGraphs
5
+ module Biconnected
6
+
7
+ # biconnected computes the biconnected subgraphs
8
+ # of a graph using Tarjan's algorithm based on DFS. See: Robert E. Tarjan
9
+ # _Depth_First_Search_and_Linear_Graph_Algorithms_. SIAM Journal on
10
+ # Computing, 1(2):146-160, 1972
11
+ #
12
+ # The output of the algorithm is a pair, the first value is an
13
+ # array of biconnected subgraphs. The second is the set of
14
+ # articulation vertices.
15
+ #
16
+ # A connected graph is biconnected if the removal of any single vertex
17
+ # (and all edges incident on that vertex) cannot disconnect the graph.
18
+ # More generally, the biconnected components of a graph are the maximal
19
+ # subsets of vertices such that the removal of a vertex from a particular
20
+ # component will not disconnect the component. Unlike connected components,
21
+ # vertices may belong to multiple biconnected components: those vertices
22
+ # that belong to more than one biconnected component are called articulation
23
+ # points or, equivalently, cut vertices. Articulation points are vertices
24
+ # whose removal would increase the number of connected components in the graph.
25
+ # Thus, a graph without articulation points is biconnected.
26
+ def biconnected
27
+ dfs_num = 0
28
+ number = {}; predecessor = {}; low_point = {}
29
+ stack = []; result = []; articulation= []
30
+
31
+ root_vertex = Proc.new {|v| predecessor[v]=v }
32
+ enter_vertex = Proc.new {|u| number[u]=low_point[u]=(dfs_num+=1) }
33
+ tree_edge = Proc.new do |e|
34
+ stack.push(e)
35
+ predecessor[e.target] = e.source
36
+ end
37
+ back_edge = Proc.new do |e|
38
+ if e.target != predecessor[e.source]
39
+ stack.push(e)
40
+ low_point[e.source] = [low_point[e.source], number[e.target]].min
41
+ end
42
+ end
43
+ exit_vertex = Proc.new do |u|
44
+ parent = predecessor[u]
45
+ is_articulation_point = false
46
+ if number[parent] > number[u]
47
+ parent = predecessor[parent]
48
+ is_articulation_point = true
49
+ end
50
+ if parent == u
51
+ is_articulation_point = false if (number[u] + 1) == number[predecessor[u]]
52
+ else
53
+ low_point[parent] = [low_point[parent], low_point[u]].min
54
+ if low_point[u] >= number[parent]
55
+ if number[parent] > number[predecessor[parent]]
56
+ predecessor[u] = predecessor[parent]
57
+ predecessor[parent] = u
58
+ end
59
+ result << (component = self.class.new)
60
+ while number[stack[-1].source] >= number[u]
61
+ component.add_edge!(stack.pop)
62
+ end
63
+ component.add_edge!(stack.pop)
64
+ if stack.empty?
65
+ predecessor[u] = parent
66
+ predecessor[parent] = u
67
+ end
68
+ end
69
+ end
70
+ articulation << u if is_articulation_point
71
+ end
72
+
73
+ # Execute depth first search
74
+ dfs({:root_vertex => root_vertex,
75
+ :enter_vertex => enter_vertex,
76
+ :tree_edge => tree_edge,
77
+ :back_edge => back_edge,
78
+ :exit_vertex => exit_vertex})
79
+
80
+ [result, articulation]
81
+ end # biconnected
82
+
83
+ end # Biconnected
84
+ end # Graphy