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
@@ -1,7 +1,10 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
|
1
4
|
# Some helper utilities used in test classes
|
2
5
|
|
3
6
|
class Array
|
4
7
|
# We need Array#add in test classes to be able to use Arrays as adjacency lists
|
5
|
-
# This is needed to have ordered lists as
|
8
|
+
# This is needed to have ordered lists as neighbors in our test graphs.
|
6
9
|
alias add push
|
7
10
|
end
|
@@ -1,27 +1,27 @@
|
|
1
|
-
require 'test/unit'
|
2
|
-
require 'rgl/transitivity'
|
3
1
|
require 'test_helper'
|
4
2
|
|
3
|
+
require 'rgl/transitivity'
|
4
|
+
|
5
5
|
include RGL
|
6
6
|
|
7
7
|
class TestTransitiveClosure < Test::Unit::TestCase
|
8
8
|
|
9
9
|
def setup
|
10
10
|
@dg = DirectedAdjacencyGraph.new
|
11
|
-
@dg.add_edges([1,2],[2,3],[2,4],[4,5],[1,6],[6,4])
|
11
|
+
@dg.add_edges([1, 2], [2, 3], [2, 4], [4, 5], [1, 6], [6, 4])
|
12
12
|
@dg_tc = DirectedAdjacencyGraph.new
|
13
13
|
@dg_tc.add_edges(
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
[1, 2], [1, 3], [1, 4], [1, 5], [1, 6],
|
15
|
+
[2, 3], [2, 4], [2, 5],
|
16
|
+
[4, 5],
|
17
|
+
[6, 4], [6, 5]
|
18
18
|
)
|
19
19
|
@dg_tr = DirectedAdjacencyGraph.new
|
20
20
|
@dg_tr.add_edges(
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
[1, 2], [1, 6],
|
22
|
+
[2, 3], [2, 4],
|
23
|
+
[4, 5],
|
24
|
+
[6, 4]
|
25
25
|
)
|
26
26
|
|
27
27
|
@dg_loner = @dg.dup
|
@@ -33,30 +33,30 @@ class TestTransitiveClosure < Test::Unit::TestCase
|
|
33
33
|
|
34
34
|
@dg_cyclic = DirectedAdjacencyGraph.new
|
35
35
|
@dg_cyclic.add_edges(
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
36
|
+
[1, 1], [1, 2],
|
37
|
+
[2, 3],
|
38
|
+
[3, 4],
|
39
|
+
[4, 5],
|
40
|
+
[5, 6],
|
41
|
+
[6, 3]
|
42
42
|
)
|
43
43
|
@dg_cyclic_tc = DirectedAdjacencyGraph.new
|
44
44
|
@dg_cyclic_tc.add_edges(
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
45
|
+
[1, 1], [1, 2], [1, 3], [1, 4], [1, 5], [1, 6],
|
46
|
+
[2, 3], [2, 4], [2, 5], [2, 6],
|
47
|
+
[3, 3], [3, 4], [3, 5], [3, 6],
|
48
|
+
[4, 3], [4, 4], [4, 5], [4, 6],
|
49
|
+
[5, 3], [5, 4], [5, 5], [5, 6],
|
50
|
+
[6, 3], [6, 4], [6, 5], [6, 6]
|
51
51
|
)
|
52
52
|
@dg_cyclic_tr = DirectedAdjacencyGraph.new
|
53
53
|
@dg_cyclic_tr.add_edges(
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
54
|
+
[1, 1], [1, 2],
|
55
|
+
[2, 3],
|
56
|
+
[3, 4],
|
57
|
+
[4, 5],
|
58
|
+
[5, 6],
|
59
|
+
[6, 3]
|
60
60
|
)
|
61
61
|
end
|
62
62
|
|
@@ -67,8 +67,8 @@ class TestTransitiveClosure < Test::Unit::TestCase
|
|
67
67
|
# Iterative applications of transitive closure should return the same result
|
68
68
|
# as a single application.
|
69
69
|
assert_equal(
|
70
|
-
|
71
|
-
|
70
|
+
@dg.transitive_closure,
|
71
|
+
@dg.transitive_closure.transitive_closure
|
72
72
|
)
|
73
73
|
|
74
74
|
# Compute for a graph containing vertices without edges.
|
@@ -77,8 +77,8 @@ class TestTransitiveClosure < Test::Unit::TestCase
|
|
77
77
|
# Iterative applications of transitive closure should return the same result
|
78
78
|
# as a single application.
|
79
79
|
assert_equal(
|
80
|
-
|
81
|
-
|
80
|
+
@dg_loner.transitive_closure,
|
81
|
+
@dg_loner.transitive_closure.transitive_closure
|
82
82
|
)
|
83
83
|
|
84
84
|
# Compute for a graph with cycles.
|
@@ -87,13 +87,13 @@ class TestTransitiveClosure < Test::Unit::TestCase
|
|
87
87
|
# Iterative applications of transitive closure should return the same result
|
88
88
|
# as a single application.
|
89
89
|
assert_equal(
|
90
|
-
|
91
|
-
|
90
|
+
@dg_cyclic.transitive_closure,
|
91
|
+
@dg_cyclic.transitive_closure.transitive_closure
|
92
92
|
)
|
93
93
|
end
|
94
94
|
|
95
95
|
def test_transitive_closure_undirected
|
96
|
-
assert_raises(NotDirectedError) {AdjacencyGraph.new.transitive_closure}
|
96
|
+
assert_raises(NotDirectedError) { AdjacencyGraph.new.transitive_closure }
|
97
97
|
end
|
98
98
|
|
99
99
|
def test_transitive_reduction
|
@@ -109,21 +109,21 @@ class TestTransitiveClosure < Test::Unit::TestCase
|
|
109
109
|
# Test that the transitive closure of a transitive reduction is the same as
|
110
110
|
# the transitive closure of the original graph.
|
111
111
|
assert_equal(
|
112
|
-
|
113
|
-
|
112
|
+
@dg.transitive_closure,
|
113
|
+
@dg.transitive_reduction.transitive_closure
|
114
114
|
)
|
115
115
|
assert_equal(
|
116
|
-
|
117
|
-
|
116
|
+
@dg_loner.transitive_closure,
|
117
|
+
@dg_loner.transitive_reduction.transitive_closure
|
118
118
|
)
|
119
119
|
assert_equal(
|
120
|
-
|
121
|
-
|
120
|
+
@dg_cyclic.transitive_closure,
|
121
|
+
@dg_cyclic.transitive_reduction.transitive_closure
|
122
122
|
)
|
123
123
|
end
|
124
124
|
|
125
125
|
def test_transitive_reduction_undirected
|
126
|
-
assert_raises(NotDirectedError) {AdjacencyGraph.new.transitive_reduction}
|
126
|
+
assert_raises(NotDirectedError) { AdjacencyGraph.new.transitive_reduction }
|
127
127
|
end
|
128
128
|
end
|
129
129
|
|
@@ -0,0 +1,221 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'rgl/adjacency'
|
4
|
+
require 'rgl/traversal'
|
5
|
+
require 'rgl/topsort'
|
6
|
+
require 'rgl/implicit'
|
7
|
+
|
8
|
+
include RGL
|
9
|
+
|
10
|
+
class TestTraversal < Test::Unit::TestCase
|
11
|
+
|
12
|
+
def setup
|
13
|
+
@dg = DirectedAdjacencyGraph.new(Array)
|
14
|
+
edges = [[1, 2], [2, 3], [2, 4], [4, 5], [1, 6], [6, 4]]
|
15
|
+
edges.each do |(src, target)|
|
16
|
+
@dg.add_edge(src, target)
|
17
|
+
end
|
18
|
+
@bfs = @dg.bfs_iterator(1)
|
19
|
+
@dfs = @dg.dfs_iterator(1)
|
20
|
+
|
21
|
+
@ug = AdjacencyGraph.new(Array)
|
22
|
+
@ug.add_edges(*edges)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_bfs_iterator_creation
|
26
|
+
assert(@bfs.at_beginning?)
|
27
|
+
assert(!@bfs.at_end?)
|
28
|
+
assert_equal(1, @bfs.start_vertex)
|
29
|
+
assert_equal(@dg, @bfs.graph)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_bfs_visiting
|
33
|
+
expected = [1, 2, 6, 3, 4, 5]
|
34
|
+
assert_equal(expected, @bfs.to_a)
|
35
|
+
assert_equal(expected, @ug.bfs_iterator(1).to_a)
|
36
|
+
assert_equal([2, 1, 3, 4, 6, 5], @ug.bfs_iterator(2).to_a)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_bfs_event_handlers
|
40
|
+
expected = <<END
|
41
|
+
tree_edge : -1
|
42
|
+
examine_vertex : 1
|
43
|
+
examine_edge : 1-2
|
44
|
+
tree_edge : 1-2
|
45
|
+
examine_edge : 1-6
|
46
|
+
tree_edge : 1-6
|
47
|
+
finished_vertex: 1
|
48
|
+
examine_vertex : 2
|
49
|
+
examine_edge : 2-3
|
50
|
+
tree_edge : 2-3
|
51
|
+
examine_edge : 2-4
|
52
|
+
tree_edge : 2-4
|
53
|
+
finished_vertex: 2
|
54
|
+
examine_vertex : 6
|
55
|
+
examine_edge : 6-4
|
56
|
+
back_edge : 6-4
|
57
|
+
finished_vertex: 6
|
58
|
+
examine_vertex : 3
|
59
|
+
finished_vertex: 3
|
60
|
+
examine_vertex : 4
|
61
|
+
examine_edge : 4-5
|
62
|
+
tree_edge : 4-5
|
63
|
+
finished_vertex: 4
|
64
|
+
examine_vertex : 5
|
65
|
+
examine_edge : 5-3
|
66
|
+
forward_edge : 5-3
|
67
|
+
finished_vertex: 5
|
68
|
+
END
|
69
|
+
|
70
|
+
s = ''
|
71
|
+
@dg.add_edge 5, 3 # for the forward_edge 5-3
|
72
|
+
@bfs.set_examine_vertex_event_handler { |v| s << "examine_vertex : #{v}\n" }
|
73
|
+
@bfs.set_examine_edge_event_handler { |u, v| s << "examine_edge : #{u}-#{v}\n" }
|
74
|
+
@bfs.set_tree_edge_event_handler { |u, v| s << "tree_edge : #{u}-#{v}\n" }
|
75
|
+
@bfs.set_back_edge_event_handler { |u, v| s << "back_edge : #{u}-#{v}\n" }
|
76
|
+
@bfs.set_forward_edge_event_handler { |u, v| s << "forward_edge : #{u}-#{v}\n" }
|
77
|
+
|
78
|
+
@bfs.each { |v| s << "finished_vertex: #{v}\n" }
|
79
|
+
puts "BFS: ", s if $DEBUG
|
80
|
+
assert_equal(expected, s)
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_dfs_visiting
|
84
|
+
assert_equal([1, 6, 4, 5, 2, 3], @dg.dfs_iterator(1).to_a)
|
85
|
+
assert_equal([2, 4, 5, 3], @dg.dfs_iterator(2).to_a)
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_dfs_event_handlers
|
89
|
+
expected = <<END
|
90
|
+
tree_edge : -1
|
91
|
+
examine_vertex : 1
|
92
|
+
examine_edge : 1-2
|
93
|
+
tree_edge : 1-2
|
94
|
+
examine_edge : 1-6
|
95
|
+
tree_edge : 1-6
|
96
|
+
finished_vertex: 1
|
97
|
+
examine_vertex : 6
|
98
|
+
examine_edge : 6-4
|
99
|
+
tree_edge : 6-4
|
100
|
+
finished_vertex: 6
|
101
|
+
examine_vertex : 4
|
102
|
+
examine_edge : 4-5
|
103
|
+
tree_edge : 4-5
|
104
|
+
finished_vertex: 4
|
105
|
+
examine_vertex : 5
|
106
|
+
examine_edge : 5-3
|
107
|
+
tree_edge : 5-3
|
108
|
+
finished_vertex: 5
|
109
|
+
examine_vertex : 3
|
110
|
+
finished_vertex: 3
|
111
|
+
examine_vertex : 2
|
112
|
+
examine_edge : 2-3
|
113
|
+
forward_edge : 2-3
|
114
|
+
examine_edge : 2-4
|
115
|
+
forward_edge : 2-4
|
116
|
+
finished_vertex: 2
|
117
|
+
END
|
118
|
+
|
119
|
+
s = ''
|
120
|
+
@dg.add_edge 5, 3
|
121
|
+
@dfs.set_examine_vertex_event_handler { |v| s << "examine_vertex : #{v}\n" }
|
122
|
+
@dfs.set_examine_edge_event_handler { |u, v| s << "examine_edge : #{u}-#{v}\n" }
|
123
|
+
@dfs.set_tree_edge_event_handler { |u, v| s << "tree_edge : #{u}-#{v}\n" }
|
124
|
+
@dfs.set_back_edge_event_handler { |u, v| s << "back_edge : #{u}-#{v}\n" }
|
125
|
+
@dfs.set_forward_edge_event_handler { |u, v| s << "forward_edge : #{u}-#{v}\n" }
|
126
|
+
|
127
|
+
@dfs.each { |v| s << "finished_vertex: #{v}\n" }
|
128
|
+
puts "DFS: ", s if $DEBUG
|
129
|
+
assert_equal(expected, s)
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_bfs_search_tree
|
133
|
+
assert_equal("(1-2)(1-6)(2-3)(2-4)(4-5)", @dg.bfs_search_tree_from(1).edges.sort.join)
|
134
|
+
end
|
135
|
+
|
136
|
+
def aux(it)
|
137
|
+
it.attach_distance_map
|
138
|
+
it.set_to_end
|
139
|
+
it.graph.vertices.sort.collect { |v|
|
140
|
+
"#{v}-#{it.distance_to_root(v)}"
|
141
|
+
}.join(', ')
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_distance_map
|
145
|
+
assert_equal("1-0, 2-1, 3-2, 4-2, 5-3, 6-1", aux(@bfs))
|
146
|
+
@dg.add_edge 5, 3
|
147
|
+
assert_equal("1-0, 2-1, 3-4, 4-2, 5-3, 6-1", aux(@dfs))
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_topsort
|
151
|
+
ts_it = @dg.topsort_iterator
|
152
|
+
assert(ts_it.at_beginning?)
|
153
|
+
assert_equal(@dg, ts_it.graph)
|
154
|
+
assert(!ts_it.at_end?)
|
155
|
+
ts_order = ts_it.to_a # do the traversal
|
156
|
+
assert_equal(@dg.num_vertices, ts_order.size)
|
157
|
+
|
158
|
+
# Check topsort contraint:
|
159
|
+
@dg.each_edge { |u, v|
|
160
|
+
assert(ts_order.index(u) < ts_order.index(v))
|
161
|
+
}
|
162
|
+
ts_it.set_to_begin
|
163
|
+
assert(ts_it.at_beginning?)
|
164
|
+
|
165
|
+
# Topsort on undirected graphs is empty
|
166
|
+
assert(@ug.topsort_iterator.at_end?)
|
167
|
+
end
|
168
|
+
|
169
|
+
# depth_first_search can also be used to compute a topsort!
|
170
|
+
def test_dfs_search_as_topsort
|
171
|
+
ts_order = []
|
172
|
+
@dg.depth_first_search { |v| ts_order << v }
|
173
|
+
ts_order = ts_order.reverse
|
174
|
+
@dg.each_edge { |u, v|
|
175
|
+
assert(ts_order.index(u) < ts_order.index(v))
|
176
|
+
}
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_acyclic
|
180
|
+
assert(@dg.acyclic?)
|
181
|
+
@dg.add_edge 5, 2 # add cycle
|
182
|
+
assert(!@dg.acyclic?)
|
183
|
+
end
|
184
|
+
|
185
|
+
def test_dfs_visit
|
186
|
+
a = []
|
187
|
+
@dg.depth_first_visit(1) { |x| a << x }
|
188
|
+
assert_equal([3, 5, 4, 2, 6, 1], a)
|
189
|
+
|
190
|
+
a = []
|
191
|
+
@dg.add_edge 10, 11
|
192
|
+
@dg.depth_first_visit(10) { |x| a << x }
|
193
|
+
assert_equal([11, 10], a)
|
194
|
+
end
|
195
|
+
|
196
|
+
def test_dfs_visit_with_parens
|
197
|
+
a = ""
|
198
|
+
vis = DFSVisitor.new(@dg)
|
199
|
+
vis.set_examine_vertex_event_handler { |v| a << "(#{v} " }
|
200
|
+
vis.set_finish_vertex_event_handler { |v| a << " #{v})" }
|
201
|
+
@dg.depth_first_visit(1, vis) { |x| }
|
202
|
+
assert_equal("(1 (2 (3 3)(4 (5 5) 4) 2)(6 6) 1)", a)
|
203
|
+
end
|
204
|
+
|
205
|
+
def test_depth_first_search_with_parens
|
206
|
+
@dg.add_edge 10, 11
|
207
|
+
# We must ensure, that the order of the traversal is not dependend on the
|
208
|
+
# order of the each iterator in the hash map of the adjacency graph. Therefor we
|
209
|
+
# wrap the graph with an implicit graph that simply ensures a sort order on
|
210
|
+
# the vertices.
|
211
|
+
dg = @dg.implicit_graph { |g|
|
212
|
+
g.vertex_iterator { |b| @dg.vertices.sort.each(&b) }
|
213
|
+
}
|
214
|
+
a = ""
|
215
|
+
vis = DFSVisitor.new(dg)
|
216
|
+
vis.set_examine_vertex_event_handler { |v| a << "(#{v} " }
|
217
|
+
vis.set_finish_vertex_event_handler { |v| a << " #{v})" }
|
218
|
+
dg.depth_first_search(vis) { |x| }
|
219
|
+
assert_equal("(1 (2 (3 3)(4 (5 5) 4) 2)(6 6) 1)(10 (11 11) 10)", a)
|
220
|
+
end
|
221
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'rgl/adjacency'
|
4
|
+
|
5
|
+
include RGL
|
6
|
+
include RGL::Edge
|
7
|
+
|
8
|
+
class TestUnDirectedGraph < Test::Unit::TestCase
|
9
|
+
|
10
|
+
def setup
|
11
|
+
@dg = AdjacencyGraph.new
|
12
|
+
[[1, 2], [2, 3], [3, 2], [2, 4]].each do |(src, target)|
|
13
|
+
@dg.add_edge(src, target)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_empty_graph
|
18
|
+
dg = AdjacencyGraph.new
|
19
|
+
assert(dg.empty?)
|
20
|
+
assert(!dg.directed?)
|
21
|
+
assert(!dg.has_edge?(2, 1))
|
22
|
+
assert(!dg.has_vertex?(3))
|
23
|
+
# Non existent vertex result in a Name Error because each_key is
|
24
|
+
# called for nil
|
25
|
+
assert_raises(NoVertexError) { dg.out_degree(3) }
|
26
|
+
assert_equal([], dg.vertices)
|
27
|
+
assert_equal(0, dg.size)
|
28
|
+
assert_equal(0, dg.num_vertices)
|
29
|
+
assert_equal(0, dg.num_edges)
|
30
|
+
assert_equal(UnDirectedEdge, dg.edge_class)
|
31
|
+
assert([].eql?(dg.edges))
|
32
|
+
assert([].eql?(dg.to_a))
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_add
|
36
|
+
dg = AdjacencyGraph.new
|
37
|
+
dg.add_edge(1, 2)
|
38
|
+
assert(!dg.empty?)
|
39
|
+
assert(dg.has_edge?(1, 2))
|
40
|
+
assert(dg.has_edge?(2, 1), "Backwards edge not included!")
|
41
|
+
assert(dg.has_vertex?(1) && dg.has_vertex?(2))
|
42
|
+
assert(!dg.has_vertex?(3))
|
43
|
+
|
44
|
+
assert_equal([1, 2], dg.vertices.sort)
|
45
|
+
assert([DirectedEdge.new(1, 2)].eql?(dg.edges))
|
46
|
+
assert_equal("(1=2)", dg.edges.join)
|
47
|
+
|
48
|
+
assert_equal([2], dg.adjacent_vertices(1))
|
49
|
+
assert_equal([1], dg.adjacent_vertices(2))
|
50
|
+
|
51
|
+
assert_equal(1, dg.out_degree(1))
|
52
|
+
assert_equal(1, dg.out_degree(2))
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_edges
|
56
|
+
assert_equal(3, @dg.edges.length)
|
57
|
+
edges = [[1, 2], [2, 3], [2, 4]].map { |x| UnDirectedEdge.new(*x) }
|
58
|
+
assert_equal(edges, @dg.edges.sort)
|
59
|
+
# assert_equal([0,1,2,3], @dg.edges.map {|l| l.info}.sort)
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_vertices
|
63
|
+
assert_equal([1, 2, 3, 4], @dg.vertices.sort)
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_edges_from_to?
|
67
|
+
assert @dg.has_edge?(1, 2)
|
68
|
+
assert @dg.has_edge?(2, 3)
|
69
|
+
assert @dg.has_edge?(3, 2)
|
70
|
+
assert @dg.has_edge?(2, 4)
|
71
|
+
assert @dg.has_edge?(2, 1)
|
72
|
+
assert !@dg.has_edge?(3, 1)
|
73
|
+
assert !@dg.has_edge?(4, 1)
|
74
|
+
assert @dg.has_edge?(4, 2)
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_remove_edges
|
78
|
+
@dg.remove_edge 1, 2
|
79
|
+
assert !@dg.has_edge?(1, 2), "(1,2) should not be an edge any more."
|
80
|
+
@dg.remove_edge 1, 2
|
81
|
+
assert !@dg.has_edge?(2, 1)
|
82
|
+
@dg.remove_vertex 3
|
83
|
+
assert !@dg.has_vertex?(3), "3 should not be a vertex any more."
|
84
|
+
assert !@dg.has_edge?(2, 3)
|
85
|
+
assert_equal([UnDirectedEdge.new(2, 4)], @dg.edges)
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_add_vertices
|
89
|
+
dg = AdjacencyGraph.new
|
90
|
+
dg.add_vertices 1, 3, 2, 4
|
91
|
+
assert_equal dg.vertices.sort, [1, 2, 3, 4]
|
92
|
+
|
93
|
+
dg.remove_vertices 1, 3
|
94
|
+
assert_equal dg.vertices.sort, [2, 4]
|
95
|
+
|
96
|
+
dg.remove_vertices 1, 3, Object # ones again
|
97
|
+
assert_equal dg.vertices.sort, [2, 4]
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_reverse
|
101
|
+
assert_equal(@dg, @dg.reverse)
|
102
|
+
end
|
103
|
+
end
|