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.
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