rgl 0.4.0 → 0.5.0
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.
- data/ChangeLog +19 -10
- data/Gemfile +3 -0
- data/{README → README.rdoc} +70 -98
- data/Rakefile +44 -150
- data/examples/canvas.rb +63 -64
- data/examples/examples.rb +42 -42
- data/examples/graph.dot +46 -0
- data/examples/images/example.jpg +0 -0
- data/examples/images/module_graph.jpg +0 -0
- data/examples/images/rgl_modules.png +0 -0
- data/examples/{insel-der-tausend-gefahren.rb → insel_der_tausend_gefahren.rb} +18 -19
- data/examples/north.rb +2 -2
- data/examples/north2.rb +11 -11
- data/examples/rdep-rgl.rb +218 -222
- data/lib/rgl/adjacency.rb +78 -74
- data/lib/rgl/base.rb +160 -78
- data/lib/rgl/bellman_ford.rb +115 -0
- data/lib/rgl/bidirectional.rb +17 -10
- data/lib/rgl/bipartite.rb +87 -0
- data/lib/rgl/condensation.rb +13 -4
- data/lib/rgl/connected_components.rb +38 -30
- data/lib/rgl/dijkstra.rb +158 -0
- data/lib/rgl/dijkstra_visitor.rb +42 -0
- data/lib/rgl/dot.rb +40 -32
- data/lib/rgl/edge_properties_map.rb +55 -0
- data/lib/rgl/edmonds_karp.rb +136 -0
- data/lib/rgl/enumerable_ext.rb +4 -1
- data/lib/rgl/graph_iterator.rb +15 -0
- data/lib/rgl/graph_visitor.rb +138 -0
- data/lib/rgl/graph_wrapper.rb +15 -0
- data/lib/rgl/graphxml.rb +20 -10
- data/lib/rgl/implicit.rb +68 -66
- data/lib/rgl/mutable.rb +37 -31
- data/lib/rgl/path_builder.rb +40 -0
- data/lib/rgl/prim.rb +52 -0
- data/lib/rgl/rdot.rb +411 -374
- data/lib/rgl/topsort.rb +23 -16
- data/lib/rgl/transitivity.rb +29 -27
- data/lib/rgl/traversal.rb +67 -205
- data/rakelib/dep_graph.rake +4 -3
- data/test/bellman_ford_test.rb +187 -0
- data/test/bipartite_test.rb +47 -0
- data/test/components_test.rb +80 -0
- data/test/cycles_test.rb +60 -0
- data/test/dijkstra_test.rb +148 -0
- data/test/directed_graph_test.rb +118 -0
- data/test/dot_test.rb +26 -0
- data/test/edge_properties_map_test.rb +63 -0
- data/test/edge_test.rb +35 -0
- data/test/edmonds_karp_test.rb +105 -0
- data/{tests/TestGraph.rb → test/graph_test.rb} +6 -6
- data/test/graph_xml_test.rb +57 -0
- data/test/implicit_test.rb +53 -0
- data/test/prim_test.rb +98 -0
- data/{tests/TestRdot.rb → test/rdot_test.rb} +309 -308
- data/{tests → test}/test_helper.rb +4 -1
- data/{tests/TestTransitivity.rb → test/transitivity_test.rb} +43 -43
- data/test/traversal_test.rb +221 -0
- data/test/undirected_graph_test.rb +103 -0
- metadata +226 -145
- data/examples/example.jpg +0 -0
- data/examples/module_graph.jpg +0 -0
- data/install.rb +0 -49
- data/tests/TestComponents.rb +0 -65
- data/tests/TestCycles.rb +0 -61
- data/tests/TestDirectedGraph.rb +0 -125
- data/tests/TestDot.rb +0 -18
- data/tests/TestEdge.rb +0 -34
- data/tests/TestGraphXML.rb +0 -57
- data/tests/TestImplicit.rb +0 -52
- data/tests/TestTraversal.rb +0 -220
- data/tests/TestUnDirectedGraph.rb +0 -102
data/lib/rgl/adjacency.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# adjacency.rb
|
2
|
-
#
|
3
|
-
# $Id
|
4
|
-
#
|
2
|
+
#
|
3
|
+
# $Id$
|
4
|
+
#
|
5
5
|
# The DirectedAdjacencyGraph class implements a generalized adjacency list
|
6
|
-
# graph structure.
|
7
|
-
# (ie, a list of lists).
|
8
|
-
# vertex.
|
6
|
+
# graph structure. An AdjacencyGraph is basically a two-dimensional structure
|
7
|
+
# (ie, a list of lists). Each element of the first dimension represents a
|
8
|
+
# vertex. Each of the vertices contains a one-dimensional structure that is
|
9
9
|
# the list of all adjacent vertices.
|
10
10
|
#
|
11
11
|
# The class for representing the adjacency list of a vertex is, by default, a
|
12
|
-
# Set.
|
12
|
+
# Set. This can be configured by the client, however, when an AdjacencyGraph
|
13
13
|
# is created.
|
14
14
|
|
15
15
|
require 'rgl/mutable'
|
@@ -25,156 +25,159 @@ module RGL
|
|
25
25
|
#
|
26
26
|
# RGL::DirectedAdjacencyGraph[1,2, 2,3, 2,4, 4,5].edges.to_a.to_s =>
|
27
27
|
# "(1-2)(2-3)(2-4)(4-5)"
|
28
|
-
|
29
|
-
def self.[]
|
28
|
+
#
|
29
|
+
def self.[](*a)
|
30
30
|
result = new
|
31
|
-
0.step(a.size-1, 2) { |i| result.add_edge(a[i], a[i+1]) }
|
31
|
+
0.step(a.size - 1, 2) { |i| result.add_edge(a[i], a[i + 1]) }
|
32
32
|
result
|
33
33
|
end
|
34
34
|
|
35
35
|
# Returns a new empty DirectedAdjacencyGraph which has as its edgelist
|
36
|
-
# class the given class.
|
36
|
+
# class the given class. The default edgelist class is Set, to ensure
|
37
37
|
# set semantics for edges and vertices.
|
38
38
|
#
|
39
39
|
# If other graphs are passed as parameters their vertices and edges are
|
40
40
|
# added to the new graph.
|
41
|
-
|
41
|
+
#
|
42
|
+
def initialize(edgelist_class = Set, *other_graphs)
|
42
43
|
@edgelist_class = edgelist_class
|
43
|
-
@
|
44
|
+
@vertices_dict = Hash.new
|
44
45
|
other_graphs.each do |g|
|
45
|
-
g.each_vertex {|v| add_vertex v}
|
46
|
-
g.each_edge {|v,w| add_edge v,w}
|
46
|
+
g.each_vertex { |v| add_vertex v }
|
47
|
+
g.each_edge { |v, w| add_edge v, w }
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
50
|
-
# Copy internal
|
51
|
+
# Copy internal vertices_dict
|
52
|
+
#
|
51
53
|
def initialize_copy(orig)
|
52
|
-
@
|
53
|
-
@
|
54
|
-
@
|
54
|
+
@vertices_dict = orig.instance_eval { @vertices_dict }.dup
|
55
|
+
@vertices_dict.keys.each do |v|
|
56
|
+
@vertices_dict[v] = @vertices_dict[v].dup
|
55
57
|
end
|
56
58
|
end
|
57
59
|
|
58
|
-
# Iterator for the keys of the
|
59
|
-
|
60
|
-
def each_vertex
|
61
|
-
@
|
60
|
+
# Iterator for the keys of the vertices list hash.
|
61
|
+
#
|
62
|
+
def each_vertex(&b)
|
63
|
+
@vertices_dict.each_key(&b)
|
62
64
|
end
|
63
65
|
|
64
|
-
def each_adjacent
|
65
|
-
adjacency_list = (@
|
66
|
-
raise NoVertexError, "No vertex #{v}.")
|
66
|
+
def each_adjacent(v, &b) # :nodoc:
|
67
|
+
adjacency_list = (@vertices_dict[v] or raise NoVertexError, "No vertex #{v}.")
|
67
68
|
adjacency_list.each(&b)
|
68
69
|
end
|
69
70
|
|
70
71
|
# Returns true.
|
71
|
-
|
72
|
+
#
|
72
73
|
def directed?
|
73
74
|
true
|
74
75
|
end
|
75
76
|
|
76
77
|
# Complexity is O(1), because the vertices are kept in a Hash containing
|
77
78
|
# as values the lists of adjacent vertices of _v_.
|
78
|
-
|
79
|
+
#
|
79
80
|
def has_vertex? (v)
|
80
|
-
@
|
81
|
+
@vertices_dict.has_key?(v)
|
81
82
|
end
|
82
83
|
|
83
|
-
# Complexity is O(1), if a Set is used as adjacency list.
|
84
|
+
# Complexity is O(1), if a Set is used as adjacency list. Otherwise,
|
84
85
|
# complexity is O(out_degree(v)).
|
85
86
|
#
|
86
87
|
# ---
|
87
88
|
# MutableGraph interface.
|
88
|
-
|
89
|
+
#
|
89
90
|
def has_edge? (u, v)
|
90
|
-
has_vertex?(u)
|
91
|
+
has_vertex?(u) && @vertices_dict[u].include?(v)
|
91
92
|
end
|
92
93
|
|
93
94
|
# See MutableGraph#add_vertex.
|
94
95
|
#
|
95
96
|
# If the vertex is already in the graph (using eql?), the method does
|
96
97
|
# nothing.
|
97
|
-
|
98
|
-
def add_vertex
|
99
|
-
@
|
98
|
+
#
|
99
|
+
def add_vertex(v)
|
100
|
+
@vertices_dict[v] ||= @edgelist_class.new
|
100
101
|
end
|
101
102
|
|
102
103
|
# See MutableGraph#add_edge.
|
103
|
-
|
104
|
-
def add_edge
|
105
|
-
add_vertex(u)
|
106
|
-
add_vertex(v)
|
104
|
+
#
|
105
|
+
def add_edge(u, v)
|
106
|
+
add_vertex(u) # ensure key
|
107
|
+
add_vertex(v) # ensure key
|
107
108
|
basic_add_edge(u, v)
|
108
109
|
end
|
109
110
|
|
110
111
|
# See MutableGraph#remove_vertex.
|
112
|
+
#
|
113
|
+
def remove_vertex(v)
|
114
|
+
@vertices_dict.delete(v)
|
111
115
|
|
112
|
-
def remove_vertex (v)
|
113
|
-
@vertice_dict.delete(v)
|
114
|
-
|
115
116
|
# remove v from all adjacency lists
|
116
|
-
|
117
|
-
@vertice_dict.each_value { |adjList| adjList.delete(v) }
|
117
|
+
@vertices_dict.each_value { |adjList| adjList.delete(v) }
|
118
118
|
end
|
119
119
|
|
120
120
|
# See MutableGraph::remove_edge.
|
121
|
-
|
122
|
-
def remove_edge
|
123
|
-
@
|
121
|
+
#
|
122
|
+
def remove_edge(u, v)
|
123
|
+
@vertices_dict[u].delete(v) unless @vertices_dict[u].nil?
|
124
124
|
end
|
125
125
|
|
126
126
|
# Converts the adjacency list of each vertex to be of type _klass_. The
|
127
|
-
# class is expected to have a new
|
127
|
+
# class is expected to have a new constructor which accepts an enumerable as
|
128
128
|
# parameter.
|
129
|
+
#
|
129
130
|
def edgelist_class=(klass)
|
130
|
-
@
|
131
|
-
|
131
|
+
@vertices_dict.keys.each do |v|
|
132
|
+
@vertices_dict[v] = klass.new @vertices_dict[v].to_a
|
132
133
|
end
|
133
134
|
end
|
134
135
|
|
135
136
|
protected
|
136
137
|
|
137
|
-
def basic_add_edge
|
138
|
-
@
|
138
|
+
def basic_add_edge(u, v)
|
139
|
+
@vertices_dict[u].add(v)
|
139
140
|
end
|
140
141
|
|
141
|
-
end
|
142
|
+
end # class DirectedAdjacencyGraph
|
142
143
|
|
143
|
-
# AdjacencyGraph is an undirected Graph.
|
144
|
-
# remove_edge are reimplemented:
|
144
|
+
# AdjacencyGraph is an undirected Graph. The methods add_edge and
|
145
|
+
# remove_edge are reimplemented: if an edge (u,v) is added or removed,
|
145
146
|
# then the reverse edge (v,u) is also added or removed.
|
147
|
+
#
|
148
|
+
class AdjacencyGraph < DirectedAdjacencyGraph
|
146
149
|
|
147
|
-
|
148
|
-
|
149
|
-
def directed?
|
150
|
+
# Always returns false.
|
151
|
+
#
|
152
|
+
def directed?
|
150
153
|
false
|
151
154
|
end
|
152
|
-
|
153
|
-
# Also removes (v,u)
|
154
155
|
|
155
|
-
|
156
|
+
# Also removes (v,u)
|
157
|
+
#
|
158
|
+
def remove_edge(u, v)
|
156
159
|
super
|
157
|
-
@
|
160
|
+
@vertices_dict[v].delete(u) unless @vertices_dict[v].nil?
|
158
161
|
end
|
159
162
|
|
160
163
|
protected
|
161
164
|
|
162
|
-
def basic_add_edge
|
165
|
+
def basic_add_edge(u, v)
|
163
166
|
super
|
164
|
-
@
|
167
|
+
@vertices_dict[v].add(u) # Insert backwards edge
|
165
168
|
end
|
166
169
|
|
167
|
-
end
|
170
|
+
end # class AdjacencyGraph
|
168
171
|
|
169
172
|
module Graph
|
170
173
|
|
171
|
-
# Convert a general graph to an AdjacencyGraph.
|
174
|
+
# Convert a general graph to an AdjacencyGraph. If the graph is directed,
|
172
175
|
# returns a DirectedAdjacencyGraph; otherwise, returns an AdjacencyGraph.
|
173
|
-
|
176
|
+
#
|
174
177
|
def to_adjacency
|
175
178
|
result = (directed? ? DirectedAdjacencyGraph : AdjacencyGraph).new
|
176
179
|
each_vertex { |v| result.add_vertex(v) }
|
177
|
-
each_edge { |u,v| result.add_edge(u, v) }
|
180
|
+
each_edge { |u, v| result.add_edge(u, v) }
|
178
181
|
result
|
179
182
|
end
|
180
183
|
|
@@ -182,25 +185,26 @@ module RGL
|
|
182
185
|
# If (u,v) is an edge of the graph, then (v,u) is an edge of the result.
|
183
186
|
#
|
184
187
|
# If the graph is undirected, the result is self.
|
185
|
-
|
188
|
+
#
|
186
189
|
def reverse
|
187
190
|
return self unless directed?
|
188
191
|
result = DirectedAdjacencyGraph.new
|
189
192
|
each_vertex { |v| result.add_vertex v }
|
190
|
-
each_edge { |u,v| result.add_edge(v, u) }
|
193
|
+
each_edge { |u, v| result.add_edge(v, u) }
|
191
194
|
result
|
192
195
|
end
|
193
196
|
|
194
|
-
# Return a new AdjacencyGraph which has the same set of vertices.
|
197
|
+
# Return a new AdjacencyGraph which has the same set of vertices. If (u,v)
|
195
198
|
# is an edge of the graph, then (u,v) and (v,u) (which are the same edges)
|
196
199
|
# are edges of the result.
|
197
200
|
#
|
198
201
|
# If the graph is undirected, the result is self.
|
199
|
-
|
202
|
+
#
|
200
203
|
def to_undirected
|
201
204
|
return self unless directed?
|
202
205
|
AdjacencyGraph.new(Set, self)
|
203
206
|
end
|
204
207
|
|
205
|
-
end
|
206
|
-
|
208
|
+
end # module Graph
|
209
|
+
|
210
|
+
end # module RGL
|
data/lib/rgl/base.rb
CHANGED
@@ -3,114 +3,144 @@
|
|
3
3
|
# Module RGL defines the namespace for all modules and classes of the graph
|
4
4
|
# library. The main module is RGL::Graph which defines the abstract behavior of
|
5
5
|
# all graphs in the library.
|
6
|
+
|
6
7
|
require 'rgl/enumerable_ext'
|
7
8
|
|
8
|
-
RGL_VERSION = "0.
|
9
|
+
RGL_VERSION = "0.5.0"
|
9
10
|
|
10
11
|
module RGL
|
11
12
|
class NotDirectedError < RuntimeError; end
|
13
|
+
|
12
14
|
class NotUndirectedError < RuntimeError; end
|
13
15
|
|
14
16
|
class NoVertexError < IndexError; end
|
17
|
+
|
15
18
|
class NoEdgeError < IndexError; end
|
16
19
|
|
17
|
-
|
20
|
+
INFINITY = 1.0 / 0.0 # positive infinity
|
21
|
+
|
22
|
+
# Module Edge includes classes for representing edges of directed and
|
18
23
|
# undirected graphs. There is no need for a Vertex class, because every ruby
|
19
24
|
# object can be a vertex of a graph.
|
25
|
+
#
|
20
26
|
module Edge
|
21
27
|
# Simply a directed pair (source -> target). Most library functions try do
|
22
28
|
# omit to instantiate edges. They instead use two vertex parameters for
|
23
29
|
# representing edges (see each_edge). If a client wants to store edges
|
24
|
-
# explicitly
|
30
|
+
# explicitly DirectedEdge or UnDirectedEdge instances are returned
|
25
31
|
# (i.e. Graph#edges).
|
32
|
+
#
|
26
33
|
class DirectedEdge
|
27
|
-
attr_accessor :source, :target
|
28
34
|
|
35
|
+
attr_accessor :source, :target
|
29
36
|
# Can be used to create an edge from a two element array.
|
37
|
+
#
|
30
38
|
def self.[](*a)
|
31
|
-
new(a[0],a[1])
|
39
|
+
new(a[0], a[1])
|
32
40
|
end
|
33
41
|
|
34
42
|
# Create a new DirectedEdge with source _a_ and target _b_.
|
35
|
-
|
36
|
-
|
43
|
+
#
|
44
|
+
def initialize(a, b)
|
45
|
+
@source, @target = a, b
|
37
46
|
end
|
38
|
-
|
47
|
+
|
39
48
|
# Two directed edges (u,v) and (x,y) are equal iff u == x and v == y. eql?
|
40
49
|
# is needed when edges are inserted into a Set. eql? is aliased to ==.
|
50
|
+
#
|
41
51
|
def eql?(edge)
|
42
|
-
source == edge.source
|
52
|
+
(source == edge.source) && (target == edge.target)
|
43
53
|
end
|
54
|
+
|
44
55
|
alias == eql?
|
45
56
|
|
57
|
+
def hash
|
58
|
+
source.hash ^ target.hash
|
59
|
+
end
|
60
|
+
|
46
61
|
# Returns (v,u) if self == (u,v).
|
62
|
+
#
|
47
63
|
def reverse
|
48
64
|
self.class.new(target, source)
|
49
65
|
end
|
50
66
|
|
51
67
|
# Edges can be indexed. edge[0] == edge.source, edge[n] == edge.target for
|
52
68
|
# all n>0. Edges can thus be used as a two element array.
|
53
|
-
|
69
|
+
#
|
70
|
+
def [](index)
|
71
|
+
index.zero? ? source : target
|
72
|
+
end
|
54
73
|
|
55
74
|
# DirectedEdge[1,2].to_s == "(1-2)"
|
75
|
+
#
|
56
76
|
def to_s
|
57
77
|
"(#{source}-#{target})"
|
58
78
|
end
|
79
|
+
|
59
80
|
# Returns the array [source,target].
|
60
|
-
|
81
|
+
#
|
82
|
+
def to_a
|
83
|
+
[source, target]
|
84
|
+
end
|
61
85
|
|
62
86
|
# Sort support is dispatched to the <=> method of Array
|
87
|
+
#
|
63
88
|
def <=> e
|
64
89
|
self.to_a <=> e.to_a
|
65
90
|
end
|
66
|
-
|
91
|
+
|
92
|
+
end # DirectedEdge
|
67
93
|
|
68
94
|
# An undirected edge is simply an undirected pair (source, target) used in
|
69
95
|
# undirected graphs. UnDirectedEdge[u,v] == UnDirectedEdge[v,u]
|
96
|
+
#
|
70
97
|
class UnDirectedEdge < DirectedEdge
|
71
98
|
def eql?(edge)
|
72
|
-
super
|
99
|
+
super || ((target == edge.source) && (source == edge.target))
|
73
100
|
end
|
74
|
-
|
75
|
-
def hash
|
76
|
-
source.hash ^ target.hash
|
77
|
-
end
|
78
|
-
|
101
|
+
|
79
102
|
# UnDirectedEdge[1,2].to_s == "(1=2)"
|
80
|
-
|
103
|
+
#
|
104
|
+
def to_s
|
105
|
+
"(#{source}=#{target})"
|
106
|
+
end
|
107
|
+
|
81
108
|
end
|
82
109
|
|
83
|
-
end
|
110
|
+
end # Edge
|
84
111
|
|
85
112
|
# In BGL terminology the module Graph defines the graph concept (see
|
86
113
|
# http://www.boost.org/libs/graph/doc/graph_concepts.html). We however do not
|
87
114
|
# distinguish between the IncidenceGraph, EdgeListGraph and VertexListGraph
|
88
|
-
|
89
|
-
|
90
|
-
|
115
|
+
# concepts, which would complicate the interface too much. These concepts are
|
116
|
+
# defined in BGL to differentiate between efficient access to edges and
|
117
|
+
# vertices.
|
91
118
|
#
|
92
119
|
# The RGL Graph concept contains only a few requirements that are common to
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
120
|
+
# all the graph concepts. These include, especially, the iterators defining
|
121
|
+
# the sets of vertices and edges (see each_vertex and each_adjacent). Most
|
122
|
+
# other functions are derived from these fundamental iterators, i.e.
|
123
|
+
# num_vertices or num_edges.
|
97
124
|
#
|
98
125
|
# Each graph is an enumerable of vertices.
|
126
|
+
#
|
99
127
|
module Graph
|
128
|
+
|
100
129
|
include Enumerable
|
101
130
|
include Edge
|
102
|
-
|
103
131
|
# The each_vertex iterator defines the set of vertices. This method must be
|
104
132
|
# defined by concrete graph classes. It defines the BGL VertexListGraph
|
105
133
|
# concept.
|
106
|
-
|
134
|
+
#
|
135
|
+
def each_vertex() # :yields: v
|
107
136
|
raise NotImplementedError
|
108
137
|
end
|
109
138
|
|
110
139
|
# The each_adjacent iterator defines the out edges of vertex _v_. This
|
111
140
|
# method must be defined by concrete graph classes. Its defines the BGL
|
112
141
|
# IncidenceGraph concept.
|
113
|
-
|
142
|
+
#
|
143
|
+
def each_adjacent(v) # :yields: v
|
114
144
|
raise NotImplementedError
|
115
145
|
end
|
116
146
|
|
@@ -121,109 +151,161 @@ module RGL
|
|
121
151
|
# can be implemented using each_vertex and each_adjacent. However for
|
122
152
|
# undirected graph the function is inefficient because we must not yield
|
123
153
|
# (v,u) if we already visited edge (u,v).
|
124
|
-
|
154
|
+
#
|
155
|
+
def each_edge(&block)
|
125
156
|
if directed?
|
126
|
-
each_vertex
|
127
|
-
each_adjacent(u) { |v| yield u,v }
|
128
|
-
|
157
|
+
each_vertex do |u|
|
158
|
+
each_adjacent(u) { |v| yield u, v }
|
159
|
+
end
|
129
160
|
else
|
130
|
-
each_edge_aux(&block)
|
161
|
+
each_edge_aux(&block) # concrete graphs should to this better
|
131
162
|
end
|
132
163
|
end
|
133
164
|
|
134
165
|
# Vertices get enumerated. A graph is thus an enumerable of vertices.
|
135
|
-
#
|
136
|
-
|
137
|
-
|
166
|
+
#
|
167
|
+
def each(&block)
|
168
|
+
each_vertex(&block)
|
169
|
+
end
|
138
170
|
|
139
171
|
# Is the graph directed? The default returns false.
|
140
|
-
|
172
|
+
#
|
173
|
+
def directed?
|
174
|
+
false
|
175
|
+
end
|
141
176
|
|
142
177
|
# Returns true if _v_ is a vertex of the graph. Same as #include? inherited
|
143
178
|
# from Enumerable. Complexity is O(num_vertices) by default. Concrete graph
|
144
179
|
# may be better here (see AdjacencyGraph).
|
145
|
-
|
180
|
+
#
|
181
|
+
def has_vertex?(v)
|
182
|
+
include?(v) # inherited from enumerable
|
183
|
+
end
|
146
184
|
|
147
185
|
# Returns true if the graph has no vertices, i.e. num_vertices == 0.
|
148
|
-
#
|
149
|
-
|
150
|
-
|
186
|
+
#
|
187
|
+
def empty?
|
188
|
+
num_vertices.zero?
|
189
|
+
end
|
151
190
|
|
152
191
|
# Return the array of vertices. Synonym for #to_a inherited by Enumerable.
|
153
|
-
|
192
|
+
#
|
193
|
+
def vertices
|
194
|
+
to_a
|
195
|
+
end
|
154
196
|
|
155
197
|
# Returns the class for edges: DirectedEdge or UnDirectedEdge.
|
156
|
-
|
198
|
+
#
|
199
|
+
def edge_class
|
200
|
+
directed? ? DirectedEdge : UnDirectedEdge
|
201
|
+
end
|
157
202
|
|
158
203
|
# Return the array of edges (DirectedEdge or UnDirectedEdge) of the graph
|
159
204
|
# using each_edge, depending whether the graph is directed or not.
|
160
205
|
def edges
|
161
206
|
result = []
|
162
207
|
c = edge_class
|
163
|
-
each_edge { |u,v| result << c.new(u,v) }
|
208
|
+
each_edge { |u, v| result << c.new(u, v) }
|
164
209
|
result
|
165
210
|
end
|
166
211
|
|
167
212
|
# Returns an array of vertices adjacent to vertex _v_.
|
168
|
-
|
213
|
+
#
|
214
|
+
def adjacent_vertices(v)
|
169
215
|
r = []
|
170
|
-
each_adjacent(v) {|u| r << u}
|
216
|
+
each_adjacent(v) { |u| r << u }
|
171
217
|
r
|
172
218
|
end
|
173
219
|
|
174
220
|
# Returns the number of out-edges (for directed graphs) or the number of
|
175
|
-
|
176
|
-
|
221
|
+
# incident edges (for undirected graphs) of vertex _v_.
|
222
|
+
#
|
223
|
+
def out_degree(v)
|
177
224
|
r = 0
|
178
|
-
each_adjacent(v) { |u| r += 1}
|
225
|
+
each_adjacent(v) { |u| r += 1 }
|
179
226
|
r
|
180
227
|
end
|
181
228
|
|
182
229
|
# Returns the number of vertices.
|
183
|
-
|
230
|
+
#
|
231
|
+
def size # Why not in Enumerable?
|
184
232
|
inject(0) { |n, v| n + 1 }
|
185
233
|
end
|
186
|
-
|
234
|
+
|
235
|
+
alias num_vertices size
|
187
236
|
|
188
237
|
# Returns the number of edges.
|
189
|
-
|
238
|
+
#
|
239
|
+
def num_edges
|
240
|
+
r = 0
|
241
|
+
each_edge { |u, v| r +=1 }
|
242
|
+
r
|
243
|
+
end
|
190
244
|
|
191
245
|
# Utility method to show a string representation of the edges of the graph.
|
246
|
+
#
|
192
247
|
def to_s
|
193
|
-
edges.sort.
|
194
|
-
end
|
195
|
-
|
196
|
-
#
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
g.is_a?(Graph) and directed? == g.directed? and
|
201
|
-
g.inject(0) { |n, v| has_vertex?(v) or return false; n+1} ==
|
202
|
-
num_vertices and begin
|
203
|
-
ng = 0
|
204
|
-
g.each_edge {|u,v| has_edge? u,v or return false; ng += 1}
|
205
|
-
ng == num_edges
|
206
|
-
end
|
207
|
-
end
|
248
|
+
edges.collect {|e| e.to_s}.sort.join
|
249
|
+
end
|
250
|
+
|
251
|
+
# Two graphs are equal iff they have equal directed? property as well as vertices and edges sets.
|
252
|
+
#
|
253
|
+
def eql?(other)
|
254
|
+
equal?(other) || eql_graph?(other)
|
208
255
|
end
|
256
|
+
|
209
257
|
alias == eql?
|
210
258
|
|
211
259
|
private
|
212
260
|
|
261
|
+
def eql_graph?(other)
|
262
|
+
other.is_a?(Graph) && directed? == other.directed? && eql_vertices_set?(other) && eql_edges_set?(other)
|
263
|
+
end
|
264
|
+
|
265
|
+
def eql_vertices_set?(other)
|
266
|
+
other_num_vertices = 0
|
267
|
+
|
268
|
+
other.each_vertex do |v|
|
269
|
+
if has_vertex?(v)
|
270
|
+
other_num_vertices += 1
|
271
|
+
else
|
272
|
+
return false
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
other_num_vertices == num_vertices
|
277
|
+
end
|
278
|
+
|
279
|
+
def eql_edges_set?(other)
|
280
|
+
other_num_edges = 0
|
281
|
+
|
282
|
+
other.each_edge do |u, v|
|
283
|
+
if has_edge?(u, v)
|
284
|
+
other_num_edges += 1
|
285
|
+
else
|
286
|
+
return false
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
other_num_edges == num_edges
|
291
|
+
end
|
292
|
+
|
213
293
|
def each_edge_aux
|
214
294
|
# needed in each_edge
|
215
295
|
visited = Hash.new
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
296
|
+
|
297
|
+
each_vertex do |u|
|
298
|
+
each_adjacent(u) do |v|
|
299
|
+
edge = UnDirectedEdge.new(u, v)
|
300
|
+
|
301
|
+
unless visited.has_key?(edge)
|
302
|
+
visited[edge] = true
|
221
303
|
yield u, v
|
222
304
|
end
|
223
|
-
|
224
|
-
|
305
|
+
end
|
306
|
+
end
|
225
307
|
end
|
226
|
-
end # module Graph
|
227
308
|
|
228
|
-
end
|
309
|
+
end # module Graph
|
229
310
|
|
311
|
+
end # module RGL
|