rgl 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +75 -2
- data/README +52 -28
- data/Rakefile +3 -3
- data/TAGS +242 -198
- data/examples/debgraph.rb +118 -0
- data/examples/examples.rb +5 -3
- data/examples/graph.dot +731 -17
- data/examples/insel.rb +141 -0
- data/lib/rgl/adjacency.rb +172 -139
- data/lib/rgl/base.rb +247 -251
- data/lib/rgl/connected_components.rb +125 -112
- data/lib/rgl/dot.rb +54 -46
- data/lib/rgl/graphxml.rb +48 -37
- data/lib/rgl/implicit.rb +159 -136
- data/lib/rgl/mutable.rb +69 -48
- data/lib/rgl/rdot.rb +268 -205
- data/lib/rgl/topsort.rb +63 -52
- data/lib/rgl/transitiv_closure.rb +40 -28
- data/lib/rgl/traversal.rb +300 -247
- data/tests/TestDirectedGraph.rb +22 -2
- data/tests/TestUnDirectedGraph.rb +4 -0
- metadata +7 -7
- data/Makefile +0 -72
- data/examples/graph.png +0 -0
data/examples/insel.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
# Some graph examples
|
2
|
+
|
3
|
+
require 'rubygems' rescue nil
|
4
|
+
require 'rgl/adjacency'
|
5
|
+
require 'rgl/implicit'
|
6
|
+
require 'rgl/dot'
|
7
|
+
|
8
|
+
g = RGL::DirectedAdjacencyGraph[
|
9
|
+
8, 9,
|
10
|
+
8, 10,
|
11
|
+
|
12
|
+
9, 11,
|
13
|
+
9, 12,
|
14
|
+
|
15
|
+
10, 13,
|
16
|
+
10, 14,
|
17
|
+
|
18
|
+
11, 15,
|
19
|
+
11, 16,
|
20
|
+
|
21
|
+
12, 17,
|
22
|
+
12, 18,
|
23
|
+
|
24
|
+
13, 19,
|
25
|
+
13, 20,
|
26
|
+
|
27
|
+
14, 21,
|
28
|
+
14, 22,
|
29
|
+
|
30
|
+
15, 23,
|
31
|
+
15, 24,
|
32
|
+
|
33
|
+
16, 25,
|
34
|
+
16, 26,
|
35
|
+
|
36
|
+
17, 27,
|
37
|
+
17, 28,
|
38
|
+
|
39
|
+
18, 29,
|
40
|
+
18, 30,
|
41
|
+
|
42
|
+
18, 31,
|
43
|
+
18, 32,
|
44
|
+
|
45
|
+
19, 31,
|
46
|
+
19, 32,
|
47
|
+
|
48
|
+
20, 33,
|
49
|
+
20, 34,
|
50
|
+
|
51
|
+
21, 35,
|
52
|
+
21, 36,
|
53
|
+
|
54
|
+
22, 37,
|
55
|
+
22, 38,
|
56
|
+
|
57
|
+
23, 39,
|
58
|
+
23, 40,
|
59
|
+
|
60
|
+
24, 41,
|
61
|
+
24, 42,
|
62
|
+
|
63
|
+
25, 43,
|
64
|
+
25, 44,
|
65
|
+
|
66
|
+
26, 45,
|
67
|
+
26, 46,
|
68
|
+
|
69
|
+
27, 47,
|
70
|
+
27, 48,
|
71
|
+
|
72
|
+
28, 49,
|
73
|
+
28, 50,
|
74
|
+
|
75
|
+
29, 51,
|
76
|
+
29, 52,
|
77
|
+
|
78
|
+
30, 53,
|
79
|
+
30, 54,
|
80
|
+
|
81
|
+
31, 55,
|
82
|
+
31, 56,
|
83
|
+
|
84
|
+
32, 57,
|
85
|
+
32, 58,
|
86
|
+
|
87
|
+
33, 59,
|
88
|
+
33, 60,
|
89
|
+
|
90
|
+
34, 61,
|
91
|
+
34, 62,
|
92
|
+
|
93
|
+
35, 63,
|
94
|
+
35, 64,
|
95
|
+
#
|
96
|
+
36, 65,
|
97
|
+
36, 66,
|
98
|
+
|
99
|
+
37, 67,
|
100
|
+
|
101
|
+
38, 13,
|
102
|
+
|
103
|
+
39, 68,
|
104
|
+
39, 69,
|
105
|
+
|
106
|
+
40, 70,
|
107
|
+
40, 71,
|
108
|
+
|
109
|
+
42, 72,
|
110
|
+
42, 73,
|
111
|
+
|
112
|
+
43, 74,
|
113
|
+
43, 75,
|
114
|
+
|
115
|
+
44, 76,
|
116
|
+
44, 77,
|
117
|
+
|
118
|
+
46, 78,
|
119
|
+
46, 79,
|
120
|
+
|
121
|
+
47, 80,
|
122
|
+
47, 81,
|
123
|
+
|
124
|
+
48, 82,
|
125
|
+
48, 83,
|
126
|
+
|
127
|
+
50, 84,
|
128
|
+
50, 85,
|
129
|
+
|
130
|
+
51, 86,
|
131
|
+
51, 87,
|
132
|
+
|
133
|
+
53, 90,
|
134
|
+
53, 91,
|
135
|
+
|
136
|
+
55, 93,
|
137
|
+
55, 94
|
138
|
+
|
139
|
+
]
|
140
|
+
g.dotty
|
141
|
+
|
data/lib/rgl/adjacency.rb
CHANGED
@@ -1,151 +1,184 @@
|
|
1
|
+
# adjacency.rb
|
1
2
|
#
|
2
|
-
# $Id: adjacency.rb,v 1.
|
3
|
+
# $Id: adjacency.rb,v 1.7 2005/03/30 21:25:34 monora Exp $
|
3
4
|
#
|
4
5
|
# The DirectedAdjacencyGraph class implements a generalized adjacency list
|
5
|
-
# graph structure.
|
6
|
-
#
|
7
|
-
# the vertices contains a one-dimensional structure that is
|
8
|
-
# adjacent vertices.
|
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
|
+
# the list of all adjacent vertices.
|
9
10
|
#
|
10
|
-
# The class for representing the adjacency list of a vertex is by default a
|
11
|
-
# Set
|
11
|
+
# The class for representing the adjacency list of a vertex is, by default, a
|
12
|
+
# Set. This can be configured by the client, however, when an AdjacencyGraph
|
13
|
+
# is created.
|
12
14
|
|
13
15
|
require 'rgl/mutable'
|
14
16
|
require 'set'
|
15
17
|
|
16
18
|
module RGL
|
19
|
+
|
17
20
|
class DirectedAdjacencyGraph
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
21
|
+
|
22
|
+
include MutableGraph
|
23
|
+
|
24
|
+
# Shortcut for creating a DirectedAdjacencyGraph:
|
25
|
+
#
|
26
|
+
# RGL::DirectedAdjacencyGraph[1,2, 2,3, 2,4, 4,5].edges.to_a.to_s =>
|
27
|
+
# "(1-2)(2-3)(2-4)(4-5)"
|
28
|
+
|
29
|
+
def self.[] (*a)
|
30
|
+
result = new
|
31
|
+
0.step(a.size-1, 2) { |i| result.add_edge(a[i], a[i+1]) }
|
32
|
+
result
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns a new empty DirectedAdjacencyGraph which has as its edgelist
|
36
|
+
# class the given class. The default edgelist class is Set, to ensure
|
37
|
+
# set semantics for edges and vertices.
|
38
|
+
|
39
|
+
def initialize (edgelist_class = Set)
|
40
|
+
@edgelist_class = edgelist_class
|
41
|
+
@vertice_dict = Hash.new
|
42
|
+
end
|
43
|
+
|
44
|
+
# Iterator for the keys of the vertice list hash.
|
45
|
+
|
46
|
+
def each_vertex (&b)
|
47
|
+
@vertice_dict.each_key(&b)
|
48
|
+
end
|
49
|
+
|
50
|
+
def each_adjacent (v, &b) # :nodoc:
|
51
|
+
adjacency_list = @vertice_dict[v] or
|
52
|
+
raise NoVertexError, "No vertex #{v}."
|
53
|
+
adjacency_list.each(&b)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns true.
|
57
|
+
|
58
|
+
def directed?
|
59
|
+
true
|
60
|
+
end
|
61
|
+
|
62
|
+
# Complexity is O(1), because the vertices are kept in a Hash containing
|
63
|
+
# as values the lists of adjacent vertices of _v_.
|
64
|
+
|
65
|
+
def has_vertex? (v)
|
66
|
+
@vertice_dict.has_key?(v)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Complexity is O(1), if a Set is used as adjacency list. Otherwise,
|
70
|
+
# complexity is O(out_degree(v)).
|
71
|
+
#
|
72
|
+
# ---
|
73
|
+
# MutableGraph interface.
|
74
|
+
|
75
|
+
def has_edge? (u, v)
|
76
|
+
has_vertex?(u) and @vertice_dict[u].include?(v)
|
77
|
+
end
|
78
|
+
|
79
|
+
# See MutableGraph#add_vertex.
|
80
|
+
#
|
81
|
+
# If the vertex is already in the graph (using eql?), the method does
|
82
|
+
# nothing.
|
83
|
+
|
84
|
+
def add_vertex (v)
|
85
|
+
@vertice_dict[v] ||= @edgelist_class.new
|
86
|
+
end
|
87
|
+
|
88
|
+
# See MutableGraph#add_edge.
|
89
|
+
|
90
|
+
def add_edge (u, v)
|
91
|
+
add_vertex(u) # ensure key
|
92
|
+
add_vertex(v) # ensure key
|
93
|
+
basic_add_edge(u, v)
|
94
|
+
end
|
95
|
+
|
96
|
+
# See MutableGraph#remove_vertex.
|
97
|
+
|
98
|
+
def remove_vertex (v)
|
99
|
+
@vertice_dict.delete(v)
|
100
|
+
|
101
|
+
# remove v from all adjacency lists
|
102
|
+
|
103
|
+
@vertice_dict.each_value { |adjList| adjList.delete(v) }
|
104
|
+
end
|
105
|
+
|
106
|
+
# See MutableGraph::remove_edge.
|
107
|
+
|
108
|
+
def remove_edge (u, v)
|
109
|
+
@vertice_dict[u].delete(v) unless @vertice_dict[u].nil?
|
110
|
+
end
|
111
|
+
|
112
|
+
protected
|
113
|
+
|
114
|
+
def basic_add_edge (u, v)
|
115
|
+
@vertice_dict[u].add(v)
|
116
|
+
end
|
117
|
+
|
118
|
+
end # class DirectedAdjacencyGraph
|
119
|
+
|
120
|
+
# AdjacencyGraph is an undirected Graph. The methods add_edge and
|
121
|
+
# remove_edge are reimplemented: If an edge (u,v) is added or removed,
|
122
|
+
# then the reverse edge (v,u) is also added or removed.
|
123
|
+
|
124
|
+
class AdjacencyGraph < DirectedAdjacencyGraph
|
125
|
+
|
126
|
+
def directed? # Always returns false.
|
127
|
+
false
|
128
|
+
end
|
129
|
+
|
130
|
+
# Also removes (v,u)
|
131
|
+
|
132
|
+
def remove_edge (u, v)
|
133
|
+
super
|
134
|
+
@vertice_dict[v].delete(u) unless @vertice_dict[v].nil?
|
135
|
+
end
|
136
|
+
|
137
|
+
protected
|
138
|
+
|
139
|
+
def basic_add_edge (u,v)
|
140
|
+
super
|
141
|
+
@vertice_dict[v].add(u) # Insert backwards edge
|
142
|
+
end
|
143
|
+
|
144
|
+
end # class AdjacencyGraph
|
118
145
|
|
119
146
|
module Graph
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
147
|
+
|
148
|
+
# Convert a general graph to an AdjacencyGraph. If the graph is directed,
|
149
|
+
# returns a DirectedAdjacencyGraph; otherwise, returns an AdjacencyGraph.
|
150
|
+
|
151
|
+
def to_adjacency
|
152
|
+
result = (directed? ? DirectedAdjacencyGraph : AdjacencyGraph).new
|
153
|
+
each_edge { |u,v| result.add_edge(u, v) }
|
154
|
+
result
|
155
|
+
end
|
156
|
+
|
157
|
+
# Return a new DirectedAdjacencyGraph which has the same set of vertices.
|
158
|
+
# If (u,v) is an edge of the graph, then (v,u) is an edge of the result.
|
159
|
+
#
|
160
|
+
# If the graph is undirected, the result is self.
|
161
|
+
|
162
|
+
def reverse
|
163
|
+
return self unless directed?
|
164
|
+
result = DirectedAdjacencyGraph.new
|
165
|
+
each_vertex { |v| result.add_vertex v }
|
166
|
+
each_edge { |u,v| result.add_edge(v, u) }
|
167
|
+
result
|
168
|
+
end
|
169
|
+
|
170
|
+
# Return a new AdjacencyGraph which has the same set of vertices. If (u,v)
|
171
|
+
# is an edge of the graph, then (u,v) and (v,u) (which are the same edges)
|
172
|
+
# are edges of the result.
|
173
|
+
#
|
174
|
+
# If the graph is undirected, the result is self.
|
175
|
+
|
176
|
+
def to_undirected
|
177
|
+
return self unless directed?
|
178
|
+
result = AdjacencyGraph.new
|
179
|
+
each_edge { |u,v| result.add_edge(u, v) }
|
180
|
+
result
|
181
|
+
end
|
182
|
+
|
183
|
+
end # module Graph
|
184
|
+
end # module RGL
|