gratr 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. data/Grater.xcf +0 -0
  2. data/README +328 -0
  3. data/Rakefile +220 -0
  4. data/examples/graph_self.rb +54 -0
  5. data/examples/module_graph.jpg +0 -0
  6. data/examples/module_graph.rb +12 -0
  7. data/examples/self_graph.jpg +0 -0
  8. data/examples/visualize.jpg +0 -0
  9. data/examples/visualize.rb +8 -0
  10. data/install.rb +49 -0
  11. data/lib/gratr.rb +33 -0
  12. data/lib/gratr/adjacency_graph.rb +230 -0
  13. data/lib/gratr/base.rb +34 -0
  14. data/lib/gratr/biconnected.rb +116 -0
  15. data/lib/gratr/chinese_postman.rb +123 -0
  16. data/lib/gratr/common.rb +73 -0
  17. data/lib/gratr/comparability.rb +92 -0
  18. data/lib/gratr/digraph.rb +113 -0
  19. data/lib/gratr/digraph_distance.rb +185 -0
  20. data/lib/gratr/dot.rb +90 -0
  21. data/lib/gratr/edge.rb +145 -0
  22. data/lib/gratr/graph.rb +315 -0
  23. data/lib/gratr/graph_api.rb +82 -0
  24. data/lib/gratr/import.rb +44 -0
  25. data/lib/gratr/labels.rb +103 -0
  26. data/lib/gratr/maximum_flow.rb +107 -0
  27. data/lib/gratr/rdot.rb +326 -0
  28. data/lib/gratr/search.rb +409 -0
  29. data/lib/gratr/strong_components.rb +127 -0
  30. data/lib/gratr/undirected_graph.rb +153 -0
  31. data/tests/TestBiconnected.rb +53 -0
  32. data/tests/TestChinesePostman.rb +53 -0
  33. data/tests/TestComplement.rb +54 -0
  34. data/tests/TestDigraph.rb +333 -0
  35. data/tests/TestDigraphDistance.rb +138 -0
  36. data/tests/TestEdge.rb +171 -0
  37. data/tests/TestInspection.rb +57 -0
  38. data/tests/TestMultiEdge.rb +57 -0
  39. data/tests/TestNeighborhood.rb +64 -0
  40. data/tests/TestProperties.rb +160 -0
  41. data/tests/TestSearch.rb +257 -0
  42. data/tests/TestStrongComponents.rb +85 -0
  43. data/tests/TestTriagulated.rb +137 -0
  44. data/tests/TestUndirectedGraph.rb +219 -0
  45. metadata +92 -0
@@ -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
+ # Minimal Dot support, based on Dave Thomas's dot module (included in rdoc).
30
+ # rdot.rb is a modified version which also contains support for undirected
31
+ # graphs.
32
+
33
+ require 'gratr/rdot'
34
+
35
+ module GRATR
36
+ module Graph
37
+
38
+ # Return a DOT::DOTDigraph for directed graphs or a DOT::DOTSubgraph for an
39
+ # undirected Graph. _params_ can contain any graph property specified in
40
+ # rdot.rb. If an edge or vertex label is a kind of Hash then the keys
41
+ # which match +dot+ properties will be used as well.
42
+ def to_dot_graph (params = {})
43
+ params['name'] ||= self.class.name.gsub(/:/,'_')
44
+ fontsize = params['fontsize'] ? params['fontsize'] : '8'
45
+ graph = (directed? ? DOT::DOTDigraph : DOT::DOTSubgraph).new(params)
46
+ edge_klass = directed? ? DOT::DOTDirectedArc : DOT::DOTArc
47
+ vertices.each do |v|
48
+ name = v.to_s
49
+ params = {'name' => '"'+name+'"',
50
+ 'fontsize' => fontsize,
51
+ 'label' => name}
52
+ v_label = vertex_label(v)
53
+ params.merge!(v_label) if v_label and v_label.kind_of? Hash
54
+ graph << DOT::DOTNode.new(params)
55
+ end
56
+ edges.each do |e|
57
+ params = {'from' => '"'+ e.source.to_s + '"',
58
+ 'to' => '"'+ e.target.to_s + '"',
59
+ 'fontsize' => fontsize }
60
+ e_label = edge_label(e)
61
+ params.merge!(e_label) if e_label and e_label.kind_of? Hash
62
+ graph << edge_klass.new(params)
63
+ end
64
+ graph
65
+ end
66
+
67
+ # Output the dot format as a string
68
+ def to_dot (params={}) to_dot_graph(params).to_s; end
69
+
70
+ # Call +dotty+ for the graph which is written to the file 'graph.dot'
71
+ # in the # current directory.
72
+ def dotty (params = {}, dotfile = 'graph.dot')
73
+ File.open(dotfile, 'w') {|f| f << to_dot(params) }
74
+ system('dotty', dotfile)
75
+ end
76
+
77
+ # Use +dot+ to create a graphical representation of the graph. Returns the
78
+ # filename of the graphics file.
79
+ def write_to_graphic_file (fmt='png', dotfile='graph')
80
+ src = dotfile + '.dot'
81
+ dot = dotfile + '.' + fmt
82
+
83
+ File.open(src, 'w') {|f| f << self.to_dot << "\n"}
84
+
85
+ system( "dot -T#{fmt} #{src} -o #{dot}" )
86
+ dot
87
+ end
88
+
89
+ end # module Graph
90
+ end # module GRATR
@@ -0,0 +1,145 @@
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
+
30
+ module GRATR
31
+
32
+ # Arc includes classes for representing egdes of directed and
33
+ # undirected graphs. There is no need for a Vertex class, because any ruby
34
+ # object can be a vertex of a graph.
35
+ #
36
+ # Arc's base is a Struct with a :source, a :target and a :label
37
+ Struct.new("ArcBase",:source, :target, :label)
38
+
39
+ class Arc < Struct::ArcBase
40
+
41
+ def initialize(p_source,p_target,p_label=nil)
42
+ super(p_source, p_target, p_label)
43
+ end
44
+
45
+ # Ignore labels for equality
46
+ def eql?(other) self.class == other.class and target==other.target and source==other.source; end
47
+
48
+ # Alias for eql?
49
+ alias == eql?
50
+
51
+ # Returns (v,u) if self == (u,v).
52
+ def reverse() self.class.new(target, source, label); end
53
+
54
+ # Sort support
55
+ def <=>(rhs) [source,target] <=> [rhs.source,rhs.target]; end
56
+
57
+ # Arc.new[1,2].to_s => "(1-2 'label')"
58
+ def to_s
59
+ l = label ? " '#{label.to_s}'" : ''
60
+ "(#{source}-#{target}#{l})"
61
+ end
62
+
63
+ # Hash is defined in such a way that label is not
64
+ # part of the hash value
65
+ def hash() source.hash ^ (target.hash+1); end
66
+
67
+ # Shortcut constructor. Instead of Arc.new(1,2) one can use Arc[1,2]
68
+ def self.[](p_source, p_target, p_label=nil)
69
+ new(p_source, p_target, p_label)
70
+ end
71
+
72
+ def inspect() "#{self.class.to_s}[#{source.inspect},#{target.inspect},#{label.inspect}]"; end
73
+
74
+ end
75
+
76
+ # An undirected edge is simply an undirected pair (source, target) used in
77
+ # undirected graphs. Edge[u,v] == Edge[v,u]
78
+ class Edge < Arc
79
+
80
+ # Equality allows for the swapping of source and target
81
+ def eql?(other) super or (self.class == other.class and target==other.source and source==other.target); end
82
+
83
+ # Alias for eql?
84
+ alias == eql?
85
+
86
+ # Hash is defined such that source and target can be reversed and the
87
+ # hash value will be the same
88
+ #
89
+ # This will cause problems with self loops
90
+ def hash() source.hash ^ target.hash; end
91
+
92
+ # Sort support
93
+ def <=>(rhs)
94
+ [[source,target].max,[source,target].min] <=>
95
+ [[rhs.source,rhs.target].max,[rhs.source,rhs.target].min]
96
+ end
97
+
98
+ # Edge[1,2].to_s == "(1=2 'label)"
99
+ def to_s
100
+ l = label ? " '#{label.to_s}'" : ''
101
+ s = source.to_s
102
+ t = target.to_s
103
+ "(#{[s,t].min}=#{[s,t].max}#{l})"
104
+ end
105
+
106
+ end
107
+
108
+ # This module provides for internal numbering of edges for differentiating between mutliple edges
109
+ module ArcNumber
110
+
111
+ attr_accessor :number # Used to differentiate between mutli-edges
112
+
113
+ def initialize(p_source,p_target,p_number,p_label=nil)
114
+ self.number = p_number
115
+ super(p_source, p_target, p_label)
116
+ end
117
+
118
+ # Returns (v,u) if self == (u,v).
119
+ def reverse() self.class.new(target, source, number, label); end
120
+ def hash() super ^ number.hash; end
121
+ def to_s() super + "[#{number}]"; end
122
+ def <=>(rhs) (result = super(rhs)) == 0 ? number <=> rhs.number : result; end
123
+ def inspect() "#{self.class.to_s}[#{source.inspect},#{target.inspect},#{number.inspect},#{label.inspect}]"; end
124
+ def eql?(rhs) super(rhs) and (rhs.number.nil? or number.nil? or number == rhs.number); end
125
+ def ==(rhs) eql?(rhs); end
126
+
127
+ # Shortcut constructor. Instead of Arc.new(1,2) one can use Arc[1,2]
128
+ def self.included(cl)
129
+
130
+ def cl.[](p_source, p_target, p_number=nil, p_label=nil)
131
+ new(p_source, p_target, p_number, p_label)
132
+ end
133
+ end
134
+
135
+ end
136
+
137
+ class MultiArc < Arc
138
+ include ArcNumber
139
+ end
140
+
141
+ class MultiEdge < Edge
142
+ include ArcNumber
143
+ end
144
+
145
+ end
@@ -0,0 +1,315 @@
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
+
30
+ require 'gratr/edge'
31
+ require 'gratr/labels'
32
+ require 'gratr/graph_api'
33
+
34
+ module GRATR
35
+
36
+ # Using the functions required by the GraphAPI, it implements all the
37
+ # basic functions of a Graph class by using only functions in GraphAPI.
38
+ # An actual implementation still needs to be done, as in Digraph or
39
+ # UndirectedGraph.
40
+ module Graph
41
+ include Enumerable
42
+ include Labels
43
+ include GraphAPI
44
+
45
+ alias remove_arc! remove_edge!
46
+ alias add_arc! add_edge!
47
+ alias arcs edges
48
+ alias arc_class edge_class
49
+
50
+ # Non destructive version of add_vertex!, returns modified copy of Graph
51
+ def add_vertex(v, l=nil) x=self.class.new(self); x.add_vertex!(v,l); end
52
+
53
+ # Non destructive version add_edge!, returns modified copy of Graph
54
+ def add_edge(u, v=nil, l=nil) x=self.class.new(self); x.add_edge!(u,v,l); end
55
+ alias add_arc add_edge
56
+
57
+ # Non destructive version of remove_vertex!, returns modified copy of Graph
58
+ def remove_vertex(v) x=self.class.new(self); x.remove_vertex!(v); end
59
+
60
+ # Non destructive version of remove_edge!, returns modified copy of Graph
61
+ def remove_edge(u,v=nil) x=self.class.new(self); x.remove_edge!(u,v); end
62
+ alias remove_arc remove_edge
63
+
64
+ # Return Array of adjacent portions of the Graph
65
+ # x can either be a vertex an edge.
66
+ # options specifies parameters about the adjacency search
67
+ # :type can be either :edges or :vertices (default).
68
+ # :direction can be :in, :out(default) or :all.
69
+ #
70
+ # Note: It is probably more efficently done in implementation.
71
+ def adjacent(x, options={})
72
+ d = directed? ? (options[:direction] || :out) : :all
73
+
74
+ # Discharge the easy ones first
75
+ return [x.source] if x.kind_of? Arc and options[:type] == :vertices and d == :in
76
+ return [x.target] if x.kind_of? Arc and options[:type] == :vertices and d == :out
77
+ return [x.source, x.target] if x.kind_of? Arc and options[:type] != :edges and d == :all
78
+
79
+ (options[:type] == :edges ? edges : to_a).select {|u| adjacent?(x,u,d)}
80
+ end
81
+
82
+ # Add all objects in _a_ to the vertex set.
83
+ def add_vertices!(*a) a.each {|v| add_vertex! v}; self; end
84
+
85
+ # See add_vertices!
86
+
87
+ def add_vertices(*a) x=self.class.new(self); x.add_vertices(*a); self; end
88
+
89
+ # Add all edges in the _edges_ Enumerable to the edge set. Elements of the
90
+ # Enumerable can be both two-element arrays or instances of DirectedArc or
91
+ # UnDirectedArc.
92
+ def add_edges!(*args) args.each { |edge| add_edge!(edge) }; self; end
93
+ alias add_arc! add_edges!
94
+
95
+ # See add_edge!
96
+ def add_edges(*a) x=self.class.new(self); x.add_edges!(*a); self; end
97
+ alias add_arcs add_edges
98
+
99
+ # Remove all vertices specified by the Enumerable a from the graph by
100
+ # calling remove_vertex!.
101
+ def remove_vertices!(*a) a.each { |v| remove_vertex! v }; end
102
+
103
+ # See remove_vertices!
104
+ def remove_vertices(*a) x=self.class.new(self); x.remove_vertices(*a); end
105
+
106
+ # Remove all vertices edges by the Enumerable a from the graph by
107
+ # calling remove_edge!
108
+ def remove_edges!(*a) a.each { |e| remove_edges! e }; end
109
+ alias remove_arc! remove_edges!
110
+
111
+ # See remove_edges
112
+ def remove_edges(*a) x=self.class.new(self); x.remove_edges(*a); end
113
+ alias remove_arcs remove_edges
114
+
115
+ # Execute given block for each vertex, provides for methods in Enumerable
116
+ def each(&block) vertices.each(&block); end
117
+
118
+ # Returns true if _v_ is a vertex of the graph.
119
+ # This is a default implementation that is of O(n) average complexity.
120
+ # If a subclass uses a hash to store vertices, then this can be
121
+ # made into an O(1) average complexity operation.
122
+ def vertex?(v) vertices.include?(v); end
123
+
124
+ # Returns true if u or (u,v) is an Arc of the graph.
125
+ def edge?(*arg) edges.include?(edge_convert(*args)); end
126
+ alias arc? edge?
127
+
128
+ # Tests two objects to see if they are adjacent.
129
+ # direction parameter specifies direction of adjacency, :in, :out, or :all(default)
130
+ # All denotes that if there is any adjacency, then it will return true.
131
+ # Note that the default is different than adjacent where one is primarily concerned with finding
132
+ # all adjacent objects in a graph to a given object. Here the concern is primarily on seeing
133
+ # if two objects touch. For vertexes, any edge between the two will usually do, but the direction
134
+ # can be specified if need be.
135
+ def adjacent?(source, target, direction=:all)
136
+ if source.kind_of? GRATR::Arc
137
+ raise NoArcError unless edge? source
138
+ if target.kind_of? GRATR::Arc
139
+ raise NoArcError unless edge? target
140
+ (direction != :out and source.source == target.target) or (direction != :in and source.target == target.source)
141
+ else
142
+ raise NoVertexError unless vertex? target
143
+ (direction != :out and source.source == target) or (direction != :in and source.target == target)
144
+ end
145
+ else
146
+ raise NoVertexError unless vertex? source
147
+ if target.kind_of? GRATR::Arc
148
+ raise NoArcError unless edge? target
149
+ (direction != :out and source == target.target) or (direction != :in and source == target.source)
150
+ else
151
+ raise NoVertexError unless vertex? target
152
+ (direction != :out and edge?(target,source)) or (direction != :in and edge?(source,target))
153
+ end
154
+ end
155
+ end
156
+
157
+ # Returns true if the graph has no vertex, i.e. num_vertices == 0.
158
+ def empty?() vertices.size.zero?; end
159
+
160
+ # Returns true if the given object is a vertex or Arc in the Graph.
161
+ #
162
+ def include?(x) x.kind_of?(GRATR::Arc) ? edge?(x) : vertex?(x); end
163
+
164
+ # Returns the neighboorhood of the given vertex (or Arc)
165
+ # This is equivalent to adjacent, but bases type on the type of object.
166
+ # direction can be :all, :in, or :out
167
+ def neighborhood(x, direction = :all)
168
+ adjacent(x, :direction => direction, :type => ((x.kind_of? GRATR::Arc) ? :edges : :vertices ))
169
+ end
170
+
171
+ # Union of all neighborhoods of vertices (or edges) in the Enumerable x minus the contents of x
172
+ # Definition taken from Jorgen Bang-Jensen, Gregory Gutin, _Digraphs: Theory, Algorithms and Applications_, pg 4
173
+ def set_neighborhood(x, direction = :all)
174
+ x.inject(Set.new) {|a,v| a.merge(neighborhood(v,direction))}.reject {|v2| x.include?(v2)}
175
+ end
176
+
177
+ # Union of all set_neighborhoods reachable in p edges
178
+ # Definition taken from Jorgen Bang-Jensen, Gregory Gutin, _Digraphs: Theory, Algorithms and Applications_, pg 46
179
+ def closed_pth_neighborhood(w,p,direction=:all)
180
+ if p <= 0
181
+ w
182
+ elsif p == 1
183
+ (w + set_neighborhood(w,direction)).uniq
184
+ else
185
+ n = set_neighborhood(w, direction)
186
+ (w + n + closed_pth_neighborhood(n,p-1,direction)).uniq
187
+ end
188
+ end
189
+
190
+ # Returns the neighboorhoods reachable in p steps from every vertex (or edge)
191
+ # in the Enumerable x
192
+ # Definition taken from Jorgen Bang-Jensen, Gregory Gutin, _Digraphs: Theory, Algorithms and Applications_, pg 46
193
+ def open_pth_neighborhood(x, p, direction=:all)
194
+ if p <= 0
195
+ x
196
+ elsif p == 1
197
+ set_neighborhood(x,direction)
198
+ else
199
+ set_neighborhood(open_pth_neighborhood(x, p-1, direction),direction) - closed_pth_neighborhood(x,p-1,direction)
200
+ end
201
+ end
202
+
203
+ # Returns the number of out-edges (for directed graphs) or the number of
204
+ # incident edges (for undirected graphs) of vertex _v_.
205
+ def out_degree(v) adjacent(v, :direction => :out).size; end
206
+
207
+ # Returns the number of in-edges (for directed graphs) or the number of
208
+ # incident edges (for undirected graphs) of vertex _v_.
209
+ def in_degree(v) adjacent(v, :direction => :in ).size; end
210
+
211
+ # Returns the sum of the number in and out edges for a vertex
212
+ def degree(v) in_degree(v) + out_degree(v); end
213
+
214
+ # Minimum in-degree
215
+ def min_in_degree() to_a.map {|v| in_degree(v)}.min; end
216
+
217
+ # Minimum out-degree
218
+ def min_out_degree() to_a.map {|v| out_degree(v)}.min; end
219
+
220
+ # Minimum degree of all vertexes
221
+ def min_degree() [min_in_degree, min_out_degree].min; end
222
+
223
+ # Maximum in-degree
224
+ def max_in_degree() vertices.map {|v| in_degree(v)}.max; end
225
+
226
+ # Maximum out-degree
227
+ def max_out_degree() vertices.map {|v| out_degree(v)}.max; end
228
+
229
+ # Minimum degree of all vertexes
230
+ def max_degree() [max_in_degree, max_out_degree].max; end
231
+
232
+ # Regular
233
+ def regular?() min_degree == max_degree; end
234
+
235
+ # Returns the number of vertices.
236
+ def size() vertices.size; end
237
+
238
+ # Synonym for size.
239
+ def num_vertices() vertices.size; end
240
+
241
+ # Returns the number of edges.
242
+ def num_edges() edges.size; end
243
+
244
+ # Utility method to show a string representation of the edges of the graph.
245
+ def to_s() edges.to_s; end
246
+
247
+ # Equality is defined to be same set of edges and directed?
248
+ def eql?(g)
249
+ return false unless g.kind_of? GRATR::Graph
250
+
251
+ (g.directed? == self.directed?) and
252
+ (vertices.sort == g.vertices.sort) and
253
+ (g.edges.sort == edges.sort)
254
+ end
255
+
256
+ # Synonym for eql?
257
+ def ==(rhs) eql?(rhs); end
258
+
259
+ # Merge another graph into this one
260
+ def merge(other)
261
+ other.vertices.each {|v| add_vertex!(v) }
262
+ other.edges.each {|e| add_edge!(e) }
263
+ other.edges.each {|e| add_edge!(e.reverse) } if directed? and !other.directed?
264
+ self
265
+ end
266
+
267
+ # A synonym for merge, that doesn't modify the current graph
268
+ def +(other)
269
+ result = self.class.new(self)
270
+ case other
271
+ when GRATR::Graph : result.merge(other)
272
+ when GRATR::Arc : result.add_edge!(other)
273
+ else result.add_vertex!(other)
274
+ end
275
+ end
276
+
277
+ # Remove all vertices in the specified right hand side graph
278
+ def -(other)
279
+ case other
280
+ when GRATR::Graph : induced_subgraph(vertices - other.vertices)
281
+ when GRATR::Arc : self.class.new(self).remove_edge!(other)
282
+ else self.class.new(self).remove_vertex!(other)
283
+ end
284
+ end
285
+
286
+ # A synonym for add_edge!
287
+ def <<(edge) add_edge!(edge); end
288
+
289
+ # Return the complement of the current graph
290
+ def complement
291
+ vertices.inject(self.class.new) do |a,v|
292
+ a.add_vertex!(v)
293
+ vertices.each {|v2| a.add_edge!(v,v2) unless edge?(v,v2) }; a
294
+ end
295
+ end
296
+
297
+ # Given an array of vertices return the induced subgraph
298
+ def induced_subgraph(v)
299
+ edges.inject(self.class.new) do |a,e|
300
+ ( v.include?(e.source) and v.include?(e.target) ) ? (a << e) : a
301
+ end;
302
+ end
303
+
304
+ def inspect
305
+ l = vertices.select {|v| self[v]}.map {|u| "vertex_label_set(#{u.inspect},#{self[u].inspect})"}.join('.')
306
+ self.class.to_s + '[' + edges.map {|e| e.inspect}.join(', ') + ']' + (l ? '.'+l : '')
307
+ end
308
+
309
+ private
310
+ def edge_convert(*args) args[0].kind_of?(GRATR::Arc) ? args[0] : edge_class[*args]; end
311
+
312
+
313
+ end # Graph
314
+
315
+ end # GRATR