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,94 @@
1
+ module Graphy
2
+ module Dot
3
+
4
+ #FIXME: don't really understood where we stand with the dot generators.
5
+ # RDoc ships with a dot.rb which seems pretty efficient.
6
+ # Are these helpers still needed, and if not, how should we replace them?
7
+
8
+ # Creates a DOT::DOTDigraph for directed graphs or a DOT::DOTSubgraph for
9
+ # undirected graphs.
10
+ #
11
+ # @param [Hash] params can contain any graph property specified in
12
+ # rdot.rb. If an edge or vertex label is a kind of Hash, then the keys
13
+ # which match dot properties will be used as well.
14
+ # @return [DOT::DOTDigraph, DOT::DOTSubgraph]
15
+ def to_dot_graph(params = {})
16
+ params['name'] ||= self.class.name.gsub(/:/, '_')
17
+ fontsize = params['fontsize'] ? params['fontsize'] : '8'
18
+ graph = (directed? ? DOT::DOTDigraph : DOT::DOTSubgraph).new(params)
19
+ edge_klass = directed? ? DOT::DOTDirectedArc : DOT::DOTArc
20
+
21
+ vertices.each do |v|
22
+ name = v.to_s || v.__id__.to_s
23
+ name = name.dup.gsub(/"/, "'")
24
+
25
+ params = { 'name' => '"'+ name +'"',
26
+ 'fontsize' => fontsize,
27
+ 'label' => name}
28
+
29
+ v_label = vertex_label(v)
30
+ params.merge!(v_label) if v_label and v_label.kind_of? Hash
31
+
32
+ graph << DOT::DOTNode.new(params)
33
+ end
34
+
35
+ edges.each do |e|
36
+ if e.source.to_s.nil?
37
+ source_label = e.source.__id__.to_s
38
+ else
39
+ source_label = e.source.to_s.dup
40
+ end
41
+
42
+ if e.target.to_s.nil?
43
+ target_label = e.target.__id__.to_s
44
+ else
45
+ target_label = e.target.to_s.dup
46
+ end
47
+
48
+ source_label.gsub!(/"/, "'")
49
+ target_label.gsub!(/"/, "'")
50
+
51
+ params = { 'from' => '"'+ source_label + '"',
52
+ 'to' => '"'+ target_label + '"',
53
+ 'fontsize' => fontsize }
54
+
55
+ e_label = edge_label(e)
56
+ params.merge!(e_label) if e_label and e_label.kind_of? Hash
57
+
58
+ graph << edge_klass.new(params)
59
+ end
60
+
61
+ graph
62
+ end
63
+
64
+ # Output the dot format as a string
65
+ def to_dot(params = {})
66
+ to_dot_graph(params).to_s
67
+ end
68
+
69
+ # Call +dotty+ for the graph which is written to the file 'graph.dot'
70
+ # in the # current directory.
71
+ def dotty(params = {}, dotfile = 'graph.dot')
72
+ File.open(dotfile, 'w') {|f| f << to_dot(params) }
73
+ system('dotty', dotfile)
74
+ end
75
+
76
+ # Use +dot+ to create a graphical representation of the graph. Returns the
77
+ # filename of the graphics file.
78
+ def write_to_graphic_file(fmt = 'png', dotfile = 'graph')
79
+ src = dotfile + '.dot'
80
+ dot = dotfile + '.' + fmt
81
+
82
+ # DOT::DOTSubgraph creates subgraphs, but that's broken.
83
+ buffer = self.to_dot
84
+ buffer.gsub!(/^subgraph/, "graph")
85
+
86
+ File.open(src, 'w') {|f| f << buffer << "\n"}
87
+ system( "dot -T#{fmt} #{src} -o #{dot}" )
88
+
89
+ dot
90
+ end
91
+ alias as_dot_graphic write_to_graphic_file
92
+
93
+ end # Dot
94
+ end # module Graphy
@@ -0,0 +1,37 @@
1
+ module Graphy
2
+
3
+ # An undirected edge is simply an undirected pair (source, target) used in
4
+ # undirected graphs. Edge[u,v] == Edge[v,u]
5
+ class Edge < Arc
6
+
7
+ # Equality allows for the swapping of source and target
8
+ def eql?(other) super or (self.class == other.class and target==other.source and source==other.target); end
9
+
10
+ # Alias for eql?
11
+ alias == eql?
12
+
13
+ # Hash is defined such that source and target can be reversed and the
14
+ # hash value will be the same
15
+ def hash() source.hash ^ target.hash; end
16
+
17
+ # Sort support
18
+ def <=>(rhs)
19
+ [[source,target].max,[source,target].min] <=>
20
+ [[rhs.source,rhs.target].max,[rhs.source,rhs.target].min]
21
+ end
22
+
23
+ # Edge[1,2].to_s == "(1=2 'label)"
24
+ def to_s
25
+ l = label ? " '#{label.to_s}'" : ''
26
+ s = source.to_s
27
+ t = target.to_s
28
+ "(#{[s,t].min}=#{[s,t].max}#{l})"
29
+ end
30
+
31
+ end
32
+
33
+ class MultiEdge < Edge
34
+ include ArcNumber
35
+ end
36
+
37
+ end
@@ -0,0 +1,79 @@
1
+ class Object
2
+ # Get the singleton class of the object.
3
+ # Depending on the object which requested its singleton class,
4
+ # a `module_eval` or a `class_eval` will be performed.
5
+ # Object of special constant type (`Fixnum`, `NilClass`, `TrueClass`,
6
+ # `FalseClass` and `Symbol`) return `nil` as they do not have a
7
+ # singleton class.
8
+ #
9
+ # @return the singleton class
10
+ def singleton_class
11
+ if self.respond_to? :module_eval
12
+ self.module_eval("class << self; self; end")
13
+ elsif self.respond_to? :instance_eval
14
+ begin
15
+ self.instance_eval("class << self; self; end")
16
+ rescue TypeError
17
+ nil
18
+ end
19
+ end
20
+ end
21
+
22
+ # Check wether the object is of the specified kind.
23
+ # If the receiver has a singleton class, will also perform
24
+ # the check on its singleton class' ancestors, so as to catch
25
+ # any included modules for object instances.
26
+ #
27
+ # Example:
28
+ #
29
+ # class A; include Digraph; end
30
+ # a.singleton_class.ancestors
31
+ # # => [Graphy::GraphAPI, Graphy::DirectedGraph::Algorithms, ...
32
+ # Graphy::Labels, Enumerable, Object, Graphy, Kernel, BasicObject]
33
+ # a.is_a? Graphy::Graph
34
+ # # => true
35
+ #
36
+ # @param [Class] klass
37
+ # @return [Boolean]
38
+ def is_a? klass
39
+ sc = self.singleton_class
40
+ if not sc.nil?
41
+ self.singleton_class.ancestors.include?(klass) || super
42
+ else
43
+ super
44
+ end
45
+ end
46
+ end
47
+
48
+ class Module
49
+ # Helper which purpose is, given a class including a module,
50
+ # to make each methods defined within a module's submodule `ClassMethods`
51
+ # available as class methods to the receiving class.
52
+ #
53
+ # Example:
54
+ #
55
+ # module A
56
+ # extends_host
57
+ # module ClassMethods
58
+ # def selfy; puts "class method for #{self}"; end
59
+ # end
60
+ # end
61
+ #
62
+ # class B; include A; end
63
+ #
64
+ # B.selfy
65
+ # # => class method for B
66
+ #
67
+ # @option *params [Symbol] :with (:ClassMethods) the name of the
68
+ # module to extend the receiver with
69
+ def extends_host(*params)
70
+ args = (params.pop if params.last.is_a? Hash) || {}
71
+ @_extension_module = args[:with] || :ClassMethods
72
+
73
+ def included(base)
74
+ unless @_extension_module.nil?
75
+ base.extend(self.const_get(@_extension_module))
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,631 @@
1
+ module Graphy
2
+
3
+ # Using the methods required by the {GraphAPI}, it implements all the
4
+ # *basic* functions of a {Graph} using *only* functions
5
+ # requested in {GraphAPI}. The process is under the control of the pattern
6
+ # {AdjacencyGraphBuilder}, unless a specific implementation is specified
7
+ # during initialization.
8
+ #
9
+ # An actual, complete implementation still needs to be done using this cheap result,
10
+ # hence {Digraph}, {UndirectedGraph} and their roomates.
11
+ module GraphBuilder
12
+
13
+ include Enumerable
14
+ include Labels
15
+ include Dot
16
+
17
+ #def self.[](*a)
18
+ #puts self
19
+ #self.new.from_array(*a)
20
+ #end
21
+ # after the class->module transition, has been moved at implementation level,
22
+ # using a helper (extends_host)
23
+ extends_host
24
+ module ClassMethods
25
+ def [](*a)
26
+ self.new.from_array(*a)
27
+ end
28
+ end
29
+
30
+ # Creates a generic graph.
31
+ #
32
+ # @param [Hash(Graphy::Graph, Array)] *params initialization parameters.
33
+ # See {AdjacencyGraphBuilder#implementation_initialize} for more details.
34
+ # @return [Graph]
35
+ def initialize(*params)
36
+ raise ArgumentError if params.any? do |p|
37
+ # FIXME: checking wether it's a GraphBuilder (module) is not sufficient
38
+ # and the is_a? redefinition trick (instance_evaling) should be
39
+ # completed by a clever way to check the actual class of p.
40
+ # Maybe using ObjectSpace to get the available Graph classes?
41
+ !(p.is_a? Graphy::GraphBuilder or p.is_a? Array or p.is_a? Hash)
42
+ end
43
+
44
+ args = params.last || {}
45
+
46
+ class << self
47
+ self
48
+ end.module_eval do
49
+ # These inclusions trigger some validations checks by the way.
50
+ include(args[:implementation] ? args[:implementation] : Graphy::AdjacencyGraphBuilder)
51
+ include(args[:algorithmic_category] ? args[:algorithmic_category] : Graphy::DigraphBuilder )
52
+ include Graphy::GraphAPI
53
+ end
54
+
55
+ implementation_initialize(*params)
56
+ end
57
+
58
+ # Shortcut for creating a Graph.
59
+ #
60
+ # Using an arry of implicit {Arc}, specifying the vertices:
61
+ #
62
+ # Graphy::Graph[1,2, 2,3, 2,4, 4,5].edges.to_a.to_s
63
+ # # => "(1-2)(2-3)(2-4)(4-5)"
64
+ #
65
+ # Using a Hash for specifying labels along the way:
66
+ #
67
+ # Graphy::Graph[ [:a,:b] => 3, [:b,:c] => 4 ] (note: do not use for Multi or Pseudo graphs)
68
+ #
69
+ # @param [Array, Hash] *a
70
+ # @return [Graph]
71
+ def from_array(*a)
72
+ if a.size == 1 and a[0].is_a? Hash
73
+ # Convert to edge class
74
+ a[0].each do |k,v|
75
+ #FIXME, edge class shouldn't be assume here!!!
76
+ if edge_class.include? Graphy::ArcNumber
77
+ add_edge!(edge_class[k[0],k[1],nil,v])
78
+ else
79
+ add_edge!(edge_class[k[0],k[1],v])
80
+ end
81
+ end
82
+ #FIXME, edge class shouldn't be assume here!!!
83
+ elsif a[0].is_a? Graphy::Arc
84
+ a.each{ |e| add_edge!(e); self[e] = e.label}
85
+ elsif a.size % 2 == 0
86
+ 0.step(a.size-1, 2) {|i| add_edge!(a[i], a[i+1])}
87
+ else
88
+ raise ArgumentError
89
+ end
90
+ self
91
+ end
92
+
93
+ # Non destructive version of {AdjacencyGraphBuilder#add_vertex!} (works on a copy of the graph).
94
+ #
95
+ # @param [vertex] v
96
+ # @param [Label] l
97
+ # @return [Graph] a new graph with the supplementary vertex
98
+ def add_vertex(v, l = nil)
99
+ x = self.class.new(self)
100
+ x.add_vertex!(v, l)
101
+ end
102
+
103
+ # Non destructive version {AdjacencyGraphBuilder#add_edge!} (works on a copy of the graph).
104
+ #
105
+ # @param [vertex] u
106
+ # @param [vertex] v
107
+ # @param [Label] l
108
+ # @return [Graph] a new graph with the supplementary edge
109
+ def add_edge(u, v = nil, l = nil)
110
+ x = self.class.new(self)
111
+ x.add_edge!(u, v, l)
112
+ end
113
+ alias add_arc add_edge
114
+
115
+ # Non destructive version of {AdjacencyGraphBuilder#remove_vertex!} (works on a copy of the graph).
116
+ #
117
+ # @param [vertex] v
118
+ # @return [Graph] a new graph without the specified vertex
119
+ def remove_vertex(v)
120
+ x = self.class.new(self)
121
+ x.remove_vertex!(v)
122
+ end
123
+
124
+ # Non destructive version {AdjacencyGraphBuilder#remove_edge!} (works on a copy of the graph).
125
+ #
126
+ # @param [vertex] u
127
+ # @param [vertex] v
128
+ # @return [Graph] a new graph without the specified edge
129
+ def remove_edge(u, v = nil)
130
+ x = self.class.new(self)
131
+ x.remove_edge!(u, v)
132
+ end
133
+ alias remove_arc remove_edge
134
+
135
+ # Computes the adjacent portions of the Graph.
136
+ #
137
+ # The options specify the parameters about the adjacency search.
138
+ # Note: it is probably more efficently done in the implementation class.
139
+ #
140
+ # @param [vertex, Edge] x can either be a vertex an edge
141
+ # @option options [Symbol] :type (:vertices) can be either `:edges` or `:vertices`
142
+ # @option options [Symbol] :direction (:all) can be `:in`, `:out` or `:all`
143
+ # @return [Array] an array of the adjacent portions
144
+ # @fixme
145
+ def adjacent(x, options = {})
146
+ d = directed? ? (options[:direction] || :out) : :all
147
+
148
+ # Discharge the easy ones first.
149
+ return [x.source] if x.is_a? Arc and options[:type] == :vertices and d == :in
150
+ return [x.target] if x.is_a? Arc and options[:type] == :vertices and d == :out
151
+ return [x.source, x.target] if x.is_a? Arc and options[:type] != :edges and d == :all
152
+
153
+ (options[:type] == :edges ? edges : to_a).select { |u| adjacent?(x,u,d) }
154
+ end
155
+ #FIXME: This is a hack around a serious problem
156
+ alias graph_adjacent adjacent
157
+
158
+
159
+ # Adds all specified vertices to the vertex set.
160
+ #
161
+ # @param [#each] *a an Enumerable vertices set
162
+ # @return [Graph] `self`
163
+ def add_vertices!(*a)
164
+ a.each { |v| add_vertex! v }
165
+ self
166
+ end
167
+
168
+ # Same as {GraphBuilder#add_vertices! add_vertices!} but works on copy of the receiver.
169
+ #
170
+ # @param [#each] *a
171
+ # @return [Graph] a modified copy of `self`
172
+ def add_vertices(*a)
173
+ x = self.class.new(self)
174
+ x.add_vertices!(*a)
175
+ self
176
+ end
177
+
178
+ # Adds all edges mentionned in the specified Enumerable to the edge set.
179
+ #
180
+ # Elements of the Enumerable can be either two-element arrays or instances of
181
+ # {Edge} or {Arc}.
182
+ #
183
+ # @param [#each] *a an Enumerable edges set
184
+ # @return [Graph] `self`
185
+ def add_edges!(*a)
186
+ a.each { |edge| add_edge!(edge) }
187
+ self
188
+ end
189
+ alias add_arcs! add_edges!
190
+
191
+ # Same as {GraphBuilder#add_egdes! add_edges!} but works on a copy of the receiver.
192
+ #
193
+ # @param [#each] *a an Enumerable edges set
194
+ # @return [Graph] a modified copy of `self`
195
+ def add_edges(*a)
196
+ x = self.class.new(self)
197
+ x.add_edges!(*a)
198
+ self
199
+ end
200
+ alias add_arcs add_edges
201
+
202
+ # Removes all vertices mentionned in the specified Enumerable from the graph.
203
+ #
204
+ # The process relies on {GraphBuilder#remove_vertex! remove_vertex!}.
205
+ #
206
+ # @param [#each] *a an Enumerable vertices set
207
+ # @return [Graph] `self`
208
+ def remove_vertices!(*a)
209
+ a.each { |v| remove_vertex! v }
210
+ end
211
+ alias delete_vertices! remove_vertices!
212
+
213
+ # Same as {GraphBuilder#remove_vertices! remove_vertices!} but works on a copy of the receiver.
214
+ #
215
+ # @param [#each] *a a vertex Enumerable set
216
+ # @return [Graph] a modified copy of `self`
217
+ def remove_vertices(*a)
218
+ x = self.class.new(self)
219
+ x.remove_vertices(*a)
220
+ end
221
+ alias delete_vertices remove_vertices
222
+
223
+ # Removes all edges mentionned in the specified Enumerable from the graph.
224
+ #
225
+ # The process relies on {GraphBuilder#remove_edges! remove_edges!}.
226
+ #
227
+ # @param [#each] *a an Enumerable edges set
228
+ # @return [Graph] `self`
229
+ def remove_edges!(*a)
230
+ a.each { |e| remove_edge! e }
231
+ end
232
+ alias remove_arcs! remove_edges!
233
+ alias delete_edges! remove_edges!
234
+ alias delete_arcs! remove_edges!
235
+
236
+ # Same as {GraphBuilder#remove_edges! remove_edges!} but works on a copy of the receiver.
237
+ #
238
+ # @param [#each] *a an Enumerable edges set
239
+ # @return [Graph] a modified copy of `self`
240
+ def remove_edges(*a)
241
+ x = self.class.new(self)
242
+ x.remove_edges!(*a)
243
+ end
244
+ alias remove_arcs remove_edges
245
+ alias delete_edges remove_edges
246
+ alias delete_arcs remove_edges
247
+
248
+ # Executes the given block for each vertex. It allows for mixing Enumerable in.
249
+ def each(&block)
250
+ vertices.each(&block)
251
+ end
252
+
253
+ # Returns true if the specified vertex belongs to the graph.
254
+ #
255
+ # This is a default implementation that is of O(n) average complexity.
256
+ # If a subclass uses a hash to store vertices, then this can be
257
+ # made into an O(1) average complexity operation.
258
+ #
259
+ # @param [vertex] v
260
+ # @return [Boolean]
261
+ def vertex?(v)
262
+ vertices.include?(v)
263
+ end
264
+ alias has_vertex? vertex?
265
+ # TODO: (has_)vertices?
266
+
267
+ # Returns true if u or (u,v) is an {Edge edge} of the graph.
268
+ #
269
+ # @overload edge?(a)
270
+ # @param [Arc, Edge] a
271
+ # @overload edge?(u, v)
272
+ # @param [vertex] u
273
+ # @param [vertex] v
274
+ # @return [Boolean]
275
+ def edge?(*args)
276
+ edges.include?(edge_convert(*args))
277
+ end
278
+ alias arc? edge?
279
+ alias has_edge? edge?
280
+ alias has_arc? edge?
281
+
282
+ # Tests two objects to see if they are adjacent.
283
+ #
284
+ # Note that in this method, one is primarily concerned with finding
285
+ # all adjacent objects in a graph to a given object. The concern is primarily on seeing
286
+ # if two objects touch. For two vertexes, any edge between the two will usually do, but
287
+ # the direction can be specified if needed.
288
+ #
289
+ # @param [vertex] source
290
+ # @param [vertex] target
291
+ # @param [Symbol] direction (:all) constraint on the direction of adjacency; may be either `:in`, `:out` or `:all`
292
+ def adjacent?(source, target, direction = :all)
293
+ if source.is_a? Graphy::Arc
294
+ raise NoArcError unless edge? source
295
+ if target.is_a? Graphy::Arc
296
+ raise NoArcError unless edge? target
297
+ (direction != :out and source.source == target.target) or (direction != :in and source.target == target.source)
298
+ else
299
+ raise NoVertexError unless vertex? target
300
+ (direction != :out and source.source == target) or (direction != :in and source.target == target)
301
+ end
302
+ else
303
+ raise NoVertexError unless vertex? source
304
+ if target.is_a? Graphy::Arc
305
+ raise NoArcError unless edge? target
306
+ (direction != :out and source == target.target) or (direction != :in and source == target.source)
307
+ else
308
+ raise NoVertexError unless vertex? target
309
+ (direction != :out and edge?(target,source)) or (direction != :in and edge?(source,target))
310
+ end
311
+ end
312
+ end
313
+
314
+ # Is the graph connected?
315
+ #
316
+ # A graph is called connected if every pair of distinct vertices in the graph
317
+ # can be connected through some path. The exact definition depends on whether
318
+ # the graph is directed or not, hence this method should overriden in specific
319
+ # implementations.
320
+ #
321
+ # This methods implements a lazy routine using the internal vertices hash.
322
+ # If you ever want to check connectivity state using a bfs/dfs algorithm, use
323
+ # the `:algo => :bfs` or `:dfs` option.
324
+ #
325
+ # @return [Boolean] `true` if the graph is connected, `false` otherwise
326
+ def connected?(options = {})
327
+ options = options.reverse_merge! :algo => :bfs
328
+ if options[:algo] == (:bfs || :dfs)
329
+ num_nodes = 0
330
+ send(options[:algo]) { |n| num_nodes += 1 }
331
+ return num_nodes == @vertex_dict.size
332
+ else
333
+ !@vertex_dict.collect { |v| degree(v) > 0 }.any? { |check| check == false }
334
+ end
335
+ end
336
+ # TODO: do it!
337
+ # TODO: for directed graphs, add weakly_connected? and strongly_connected? (aliased as strong?)
338
+ # TODO: in the context of vertices/Arc, add connected_vertices? and disconnected_vertices?
339
+ # TODO: maybe implement some routine which would compute cuts and connectivity? tricky though,
340
+ # but would be useful (k_connected?(k))
341
+
342
+ # Returns true if the graph has no vertex.
343
+ #
344
+ # @return [Boolean]
345
+ def empty?
346
+ puts "yan"
347
+ vertices.size.zero?
348
+ end
349
+
350
+ # Returns true if the given object is a vertex or an {Arc arc} of the graph.
351
+ #
352
+ # @param [vertex, Arc] x
353
+ def include?(x)
354
+ x.is_a?(Graphy::Arc) ? edge?(x) : vertex?(x)
355
+ end
356
+ alias has? include?
357
+
358
+ # Returns the neighborhood of the given vertex or {Arc arc}.
359
+ #
360
+ # This is equivalent to {GraphBuilder#adjacent adjacent}, but the type is based on the
361
+ # type of the specified object.
362
+ #
363
+ # @param [vertex, Arc] x
364
+ # @param [Symbol] direction (:all) can be either `:all`, `:in` or `:out`
365
+ def neighborhood(x, direction = :all)
366
+ adjacent(x, :direction => direction, :type => ((x.is_a? Graphy::Arc) ? :edges : :vertices ))
367
+ end
368
+
369
+ # Union of all neighborhoods of vertices (or edges) in the Enumerable x minus the contents of x.
370
+ #
371
+ # Definition taken from: Jorgen Bang-Jensen, Gregory Gutin, *Digraphs: Theory, Algorithms and Applications*, pg. 4
372
+ #
373
+ # @param [vertex] x
374
+ # @param [Symbol] direction can be either `:all`, `:in` or `:out`
375
+ def set_neighborhood(x, direction = :all)
376
+ x.inject(Set.new) { |a,v| a.merge(neighborhood(v, idirection))}.reject { |v2| x.include?(v2) }
377
+ end
378
+
379
+ # Union of all {GraphBuilder#set_neighborhood set_neighborhoods} reachable
380
+ # among the specified edges.
381
+ #
382
+ # Definition taken from Jorgen Bang-Jensen, Gregory Gutin, *Digraphs:
383
+ # Theory, Algorithms and Applications*, pg. 46
384
+ #
385
+ # @param [vertex] w
386
+ # @param [Edges] p
387
+ # @param [Symbol] direction can be `:all`, `:in`, or `:out`
388
+ def closed_pth_neighborhood(w, p, direction = :all)
389
+ if p <= 0
390
+ w
391
+ elsif p == 1
392
+ (w + set_neighborhood(w, direction)).uniq
393
+ else
394
+ n = set_neighborhood(w, direction)
395
+ (w + n + closed_pth_neighborhood(n, p-1, direction)).uniq
396
+ end
397
+ end
398
+
399
+ # Returns the neighboorhoods reachable in a certain amount of steps from
400
+ # every vertex (or edge) in the specified Enumerable.
401
+ #
402
+ # Definition taken from Jorgen Bang-Jensen, Gregory Gutin, _Digraphs:
403
+ # Theory, Algorithms and Applications_, pg. 46
404
+ #
405
+ # @param [Enumerable] x
406
+ # @param [Integer] p number of steps to perform
407
+ # @param [Symbol] direction can be `:all`, `:in`, or `:out`
408
+ def open_pth_neighborhood(x, p, direction = :all)
409
+ if p <= 0
410
+ x
411
+ elsif p == 1
412
+ set_neighborhood(x,direction)
413
+ else
414
+ set_neighborhood(open_pth_neighborhood(x, p-1, direction), direction) -
415
+ closed_pth_neighborhood(x, p-1, direction)
416
+ end
417
+ end
418
+
419
+ # Returns the number of out-edges (for directed graphs) or the number of
420
+ # incident edges (for undirected graphs) of the specified vertex.
421
+ #
422
+ # @param [vertex] v
423
+ # @return [Integer] number of matching edges
424
+ def out_degree(v)
425
+ adjacent(v, :direction => :out).size
426
+ end
427
+
428
+ # Returns the number of in-edges (for directed graphs) or the number of
429
+ # incident edges (for undirected graphs) of the specified vertex
430
+ #
431
+ # @param [vertex] v
432
+ # @return [Integer] number of matching edges
433
+ def in_degree(v)
434
+ adjacent(v, :direction => :in).size
435
+ end
436
+
437
+ # Returns the sum of the number in and out edges for the specified vertex.
438
+ #
439
+ # @param [vertex] v
440
+ # @return [Integer] degree
441
+ def degree(v)
442
+ in_degree(v) + out_degree(v)
443
+ end
444
+
445
+ # Minimum in-degree of the graph.
446
+ #
447
+ # @return [Integer, nil] returns `nil` if the graph is empty
448
+ def min_in_degree
449
+ return nil if to_a.empty?
450
+ to_a.map { |v| in_degree(v) }.min
451
+ end
452
+
453
+ # Minimum out-degree of the graph.
454
+ #
455
+ # @return [Integer, nil] returns `nil` if the graph is empty
456
+ def min_out_degree
457
+ return nil if to_a.empty?
458
+ to_a.map {|v| out_degree(v)}.min
459
+ end
460
+
461
+ # Minimum degree of all vertexes of the graph.
462
+ #
463
+ # @return [Integer] `min` between {GraphBuilder#min_in_degree min_in_degree}
464
+ # and {GraphBuilder#min_out_degree max_out_degree}
465
+ def min_degree
466
+ [min_in_degree, min_out_degree].min
467
+ end
468
+
469
+ # Maximum in-degree of the graph.
470
+ #
471
+ # @return [Integer, nil] returns `nil` if the graph is empty
472
+ def max_in_degree
473
+ return nil if to_a.empty?
474
+ vertices.map { |v| in_degree(v)}.max
475
+ end
476
+
477
+ # Maximum out-degree of the graph.
478
+ #
479
+ # @return [Integer, nil] returns nil if the graph is empty
480
+ def max_out_degree
481
+ return nil if to_a.empty?
482
+ vertices.map { |v| out_degree(v)}.max
483
+ end
484
+
485
+ # Maximum degree of all vertexes of the graph.
486
+ #
487
+ # @return [Integer] `max` between {GraphBuilder#max_in_degree max_in_degree}
488
+ # and {GraphBuilder#max_out_degree max_out_degree}
489
+ def max_degree
490
+ [max_in_degree, max_out_degree].max
491
+ end
492
+
493
+ # Is the graph regular, that is are its min degree and max degree equal?
494
+ #
495
+ # @return [Boolean]
496
+ def regular?
497
+ min_degree == max_degree
498
+ end
499
+
500
+ # Number of vertices.
501
+ #
502
+ # @return [Integer]
503
+ def size
504
+ vertices.size
505
+ end
506
+ alias num_vertices size
507
+ alias number_of_vertices size
508
+
509
+ # Number of vertices.
510
+ #
511
+ # @return [Integer]
512
+ def num_vertices
513
+ vertices.size
514
+ end
515
+ alias number_of_vertices num_vertices
516
+
517
+ # Number of edges.
518
+ #
519
+ # @return [Integer]
520
+ def num_edges
521
+ edges.size
522
+ end
523
+ alias number_of_edges num_edges
524
+
525
+ # Utility method to show a string representation of the edges of the graph.
526
+ #def to_s
527
+ #edges.to_s
528
+ #end
529
+
530
+ # Equality is defined to be same set of edges and directed?
531
+ def eql?(g)
532
+ return false unless g.is_a? Graphy::Graph
533
+
534
+ (g.directed? == self.directed?) and
535
+ (vertices.sort == g.vertices.sort) and
536
+ (g.edges.sort == edges.sort)
537
+ end
538
+ alias == eql?
539
+
540
+ # Merges another graph into the receiver.
541
+ #
542
+ # @param [Graph] other the graph to merge in
543
+ # @return [Graph] `self`
544
+ def merge(other)
545
+ other.vertices.each { |v| add_vertex!(v) }
546
+ other.edges.each { |e| add_edge!(e) }
547
+ other.edges.each { |e| add_edge!(e.reverse) } if directed? and !other.directed?
548
+ self
549
+ end
550
+
551
+ # A synonym for {GraphBuilder#merge merge}, but doesn't modify the current graph.
552
+ #
553
+ # @param [Graph, Arc] other
554
+ # @return [Graph] a new graph
555
+ def +(other)
556
+ result = self.class.new(self)
557
+ case other
558
+ when Graphy::Graph
559
+ result.merge(other)
560
+ when Graphy::Arc
561
+ result.add_edge!(other)
562
+ else
563
+ result.add_vertex!(other)
564
+ end
565
+ end
566
+
567
+ # Removes all vertices in the specified graph.
568
+ #
569
+ # @param [Graph, Arc] other
570
+ # @return [Graph]
571
+ def -(other)
572
+ case other
573
+ when Graphy::Graph
574
+ induced_subgraph(vertices - other.vertices)
575
+ when Graphy::Arc
576
+ self.class.new(self).remove_edge!(other)
577
+ else
578
+ self.class.new(self).remove_vertex!(other)
579
+ end
580
+ end
581
+
582
+ # A synonym for {AdjacencyGraphBuilder#add_edge! add_edge!}.
583
+ def <<(edge)
584
+ add_edge!(edge)
585
+ end
586
+
587
+ # Computes the complement of the current graph.
588
+ #
589
+ # @return [Graph]
590
+ def complement
591
+ vertices.inject(self.class.new) do |a,v|
592
+ a.add_vertex!(v)
593
+ vertices.each { |v2| a.add_edge!(v, v2) unless edge?(v, v2) }; a
594
+ end
595
+ end
596
+
597
+ # Given an array of vertices, computes the induced subgraph.
598
+ #
599
+ # @param [Array(vertex)] v
600
+ # @return [Graph]
601
+ def induced_subgraph(v)
602
+ edges.inject(self.class.new) do |a,e|
603
+ (v.include?(e.source) and v.include?(e.target)) ? (a << e) : a
604
+ end
605
+ end
606
+
607
+ #def inspect
608
+ ## FIXME: broken, it's not updated. The issue's not with inspect, but it's worth mentionning here.
609
+ ## Example:
610
+ ## dg = Digraph[1,2, 2,3, 2,4, 4,5, 6,4, 1,6]
611
+ ## dg.add_vertices! 1, 5, "yosh"
612
+ ## # => Graphy::Digraph[Graphy::Arc[1,2,nil], Graphy::Arc[1,6,nil], Graphy::Arc[2,3,nil], Graphy::Arc[2,4,nil], Graphy::Arc[4,5,nil], Graphy::Arc[6,4,nil]]
613
+ ## dg.vertex?("yosh")
614
+ ## # => true
615
+ ## dg
616
+ ## # =>Graphy::Digraph[Graphy::Arc[1,2,nil], Graphy::Arc[1,6,nil], Graphy::Arc[2,3,nil], Graphy::Arc[2,4,nil], Graphy::Arc[4,5,nil], Graphy::Arc[6,4,nil]]
617
+ ## the new vertex doesn't show up.
618
+ ## Actually this version of inspect is far too verbose IMO :)
619
+ #l = vertices.select { |v| self[v]}.map { |u| "vertex_label_set(#{u.inspect}, #{self[u].inspect})"}.join('.')
620
+ #self.class.to_s + '[' + edges.map {|e| e.inspect}.join(', ') + ']' + (l && l != '' ? '.'+l : '')
621
+ #end
622
+
623
+ private
624
+
625
+ # ?
626
+ def edge_convert(*args)
627
+ args[0].is_a?(Graphy::Arc) ? args[0] : edge_class[*args]
628
+ end
629
+
630
+ end # Graph
631
+ end # Graphy