rgl 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/ChangeLog +19 -10
  2. data/Gemfile +3 -0
  3. data/{README → README.rdoc} +70 -98
  4. data/Rakefile +44 -150
  5. data/examples/canvas.rb +63 -64
  6. data/examples/examples.rb +42 -42
  7. data/examples/graph.dot +46 -0
  8. data/examples/images/example.jpg +0 -0
  9. data/examples/images/module_graph.jpg +0 -0
  10. data/examples/images/rgl_modules.png +0 -0
  11. data/examples/{insel-der-tausend-gefahren.rb → insel_der_tausend_gefahren.rb} +18 -19
  12. data/examples/north.rb +2 -2
  13. data/examples/north2.rb +11 -11
  14. data/examples/rdep-rgl.rb +218 -222
  15. data/lib/rgl/adjacency.rb +78 -74
  16. data/lib/rgl/base.rb +160 -78
  17. data/lib/rgl/bellman_ford.rb +115 -0
  18. data/lib/rgl/bidirectional.rb +17 -10
  19. data/lib/rgl/bipartite.rb +87 -0
  20. data/lib/rgl/condensation.rb +13 -4
  21. data/lib/rgl/connected_components.rb +38 -30
  22. data/lib/rgl/dijkstra.rb +158 -0
  23. data/lib/rgl/dijkstra_visitor.rb +42 -0
  24. data/lib/rgl/dot.rb +40 -32
  25. data/lib/rgl/edge_properties_map.rb +55 -0
  26. data/lib/rgl/edmonds_karp.rb +136 -0
  27. data/lib/rgl/enumerable_ext.rb +4 -1
  28. data/lib/rgl/graph_iterator.rb +15 -0
  29. data/lib/rgl/graph_visitor.rb +138 -0
  30. data/lib/rgl/graph_wrapper.rb +15 -0
  31. data/lib/rgl/graphxml.rb +20 -10
  32. data/lib/rgl/implicit.rb +68 -66
  33. data/lib/rgl/mutable.rb +37 -31
  34. data/lib/rgl/path_builder.rb +40 -0
  35. data/lib/rgl/prim.rb +52 -0
  36. data/lib/rgl/rdot.rb +411 -374
  37. data/lib/rgl/topsort.rb +23 -16
  38. data/lib/rgl/transitivity.rb +29 -27
  39. data/lib/rgl/traversal.rb +67 -205
  40. data/rakelib/dep_graph.rake +4 -3
  41. data/test/bellman_ford_test.rb +187 -0
  42. data/test/bipartite_test.rb +47 -0
  43. data/test/components_test.rb +80 -0
  44. data/test/cycles_test.rb +60 -0
  45. data/test/dijkstra_test.rb +148 -0
  46. data/test/directed_graph_test.rb +118 -0
  47. data/test/dot_test.rb +26 -0
  48. data/test/edge_properties_map_test.rb +63 -0
  49. data/test/edge_test.rb +35 -0
  50. data/test/edmonds_karp_test.rb +105 -0
  51. data/{tests/TestGraph.rb → test/graph_test.rb} +6 -6
  52. data/test/graph_xml_test.rb +57 -0
  53. data/test/implicit_test.rb +53 -0
  54. data/test/prim_test.rb +98 -0
  55. data/{tests/TestRdot.rb → test/rdot_test.rb} +309 -308
  56. data/{tests → test}/test_helper.rb +4 -1
  57. data/{tests/TestTransitivity.rb → test/transitivity_test.rb} +43 -43
  58. data/test/traversal_test.rb +221 -0
  59. data/test/undirected_graph_test.rb +103 -0
  60. metadata +226 -145
  61. data/examples/example.jpg +0 -0
  62. data/examples/module_graph.jpg +0 -0
  63. data/install.rb +0 -49
  64. data/tests/TestComponents.rb +0 -65
  65. data/tests/TestCycles.rb +0 -61
  66. data/tests/TestDirectedGraph.rb +0 -125
  67. data/tests/TestDot.rb +0 -18
  68. data/tests/TestEdge.rb +0 -34
  69. data/tests/TestGraphXML.rb +0 -57
  70. data/tests/TestImplicit.rb +0 -52
  71. data/tests/TestTraversal.rb +0 -220
  72. 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 neigbors in our test graphs.
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
- [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]
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
- [1,2],[1,6],
22
- [2,3],[2,4],
23
- [4,5],
24
- [6,4]
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
- [1,1],[1,2],
37
- [2,3],
38
- [3,4],
39
- [4,5],
40
- [5,6],
41
- [6,3]
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
- [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]
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
- [1,1],[1,2],
55
- [2,3],
56
- [3,4],
57
- [4,5],
58
- [5,6],
59
- [6,3]
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
- @dg.transitive_closure,
71
- @dg.transitive_closure.transitive_closure
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
- @dg_loner.transitive_closure,
81
- @dg_loner.transitive_closure.transitive_closure
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
- @dg_cyclic.transitive_closure,
91
- @dg_cyclic.transitive_closure.transitive_closure
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
- @dg.transitive_closure,
113
- @dg.transitive_reduction.transitive_closure
112
+ @dg.transitive_closure,
113
+ @dg.transitive_reduction.transitive_closure
114
114
  )
115
115
  assert_equal(
116
- @dg_loner.transitive_closure,
117
- @dg_loner.transitive_reduction.transitive_closure
116
+ @dg_loner.transitive_closure,
117
+ @dg_loner.transitive_reduction.transitive_closure
118
118
  )
119
119
  assert_equal(
120
- @dg_cyclic.transitive_closure,
121
- @dg_cyclic.transitive_reduction.transitive_closure
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