gratr19 0.4.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README +335 -0
- data/examples/graph_self.rb +54 -0
- data/examples/module_graph.jpg +0 -0
- data/examples/module_graph.rb +12 -0
- data/examples/self_graph.jpg +0 -0
- data/examples/visualize.jpg +0 -0
- data/examples/visualize.rb +8 -0
- data/install.rb +49 -0
- data/lib/gratr.rb +42 -0
- data/lib/gratr/adjacency_graph.rb +230 -0
- data/lib/gratr/base.rb +34 -0
- data/lib/gratr/biconnected.rb +116 -0
- data/lib/gratr/chinese_postman.rb +123 -0
- data/lib/gratr/common.rb +74 -0
- data/lib/gratr/comparability.rb +92 -0
- data/lib/gratr/digraph.rb +115 -0
- data/lib/gratr/digraph_distance.rb +185 -0
- data/lib/gratr/dot.rb +90 -0
- data/lib/gratr/edge.rb +145 -0
- data/lib/gratr/graph.rb +314 -0
- data/lib/gratr/graph_api.rb +82 -0
- data/lib/gratr/import.rb +44 -0
- data/lib/gratr/labels.rb +103 -0
- data/lib/gratr/maximum_flow.rb +107 -0
- data/lib/gratr/rdot.rb +332 -0
- data/lib/gratr/search.rb +422 -0
- data/lib/gratr/strong_components.rb +127 -0
- data/lib/gratr/undirected_graph.rb +153 -0
- data/lib/gratr/version.rb +6 -0
- data/lib/priority-queue/benchmark/dijkstra.rb +171 -0
- data/lib/priority-queue/compare_comments.rb +49 -0
- data/lib/priority-queue/ext/priority_queue/CPriorityQueue/extconf.rb +2 -0
- data/lib/priority-queue/lib/priority_queue.rb +14 -0
- data/lib/priority-queue/lib/priority_queue/c_priority_queue.rb +1 -0
- data/lib/priority-queue/lib/priority_queue/poor_priority_queue.rb +46 -0
- data/lib/priority-queue/lib/priority_queue/ruby_priority_queue.rb +525 -0
- data/lib/priority-queue/setup.rb +1551 -0
- data/lib/priority-queue/test/priority_queue_test.rb +371 -0
- data/tests/TestBiconnected.rb +53 -0
- data/tests/TestChinesePostman.rb +53 -0
- data/tests/TestComplement.rb +54 -0
- data/tests/TestDigraph.rb +333 -0
- data/tests/TestDigraphDistance.rb +138 -0
- data/tests/TestDot.rb +75 -0
- data/tests/TestEdge.rb +171 -0
- data/tests/TestInspection.rb +57 -0
- data/tests/TestMultiEdge.rb +57 -0
- data/tests/TestNeighborhood.rb +64 -0
- data/tests/TestProperties.rb +160 -0
- data/tests/TestSearch.rb +277 -0
- data/tests/TestStrongComponents.rb +85 -0
- data/tests/TestTriagulated.rb +137 -0
- data/tests/TestUndirectedGraph.rb +219 -0
- metadata +152 -0
data/tests/TestSearch.rb
ADDED
@@ -0,0 +1,277 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2006 Shawn Patrick Garbett
|
3
|
+
# Copyright (c) 2002,2004,2005 by Horst Duchene
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
6
|
+
# are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# * Redistributions of source code must retain the above copyright notice(s),
|
9
|
+
# this list of conditions and the following disclaimer.
|
10
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
# this list of conditions and the following disclaimer in the documentation
|
12
|
+
# and/or other materials provided with the distribution.
|
13
|
+
# * Neither the name of the Shawn Garbett nor the names of its contributors
|
14
|
+
# may be used to endorse or promote products derived from this software
|
15
|
+
# without specific prior written permission.
|
16
|
+
#
|
17
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
18
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
19
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
20
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
21
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
22
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
23
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
24
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
25
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
26
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
#++
|
28
|
+
|
29
|
+
|
30
|
+
require 'test/unit'
|
31
|
+
require 'gratr/import'
|
32
|
+
|
33
|
+
class TestSearch < Test::Unit::TestCase # :nodoc:
|
34
|
+
|
35
|
+
def setup
|
36
|
+
@directed = Digraph[1,2, 2,3, 2,4, 4,5, 1,6, 6,4]
|
37
|
+
@undirected = UndirectedGraph[1,2, 2,3, 2,4, 4,5, 1,6]
|
38
|
+
@tree = Digraph[ 1,2, 1,3, 1,4, 2,5, 2,4, 2,6, 6,7, 23,24 ]
|
39
|
+
end
|
40
|
+
|
41
|
+
# "Algorithmic Graph Theory and Perfect Graphs", Martin Charles
|
42
|
+
# Golumbic, 1980, Academic Press, page 38, Figure 2.6
|
43
|
+
def assign_dfsnumber_ancestry(graph, dfsnumber, father, start)
|
44
|
+
i = 0
|
45
|
+
dfsnumber.clear
|
46
|
+
father.clear
|
47
|
+
ev = Proc.new {|v| dfsnumber[v] = (i+=1) }
|
48
|
+
te = Proc.new {|e| father[e.target] = e.source }
|
49
|
+
graph.dfs({:enter_vertex => ev, :tree_edge => te, :start => start})
|
50
|
+
end
|
51
|
+
|
52
|
+
# Is v an ancestor of u
|
53
|
+
def ancestor?(father, u, v)
|
54
|
+
i = 1
|
55
|
+
while v
|
56
|
+
return i if father[v] == u
|
57
|
+
v = father[v]
|
58
|
+
i += 1
|
59
|
+
end; nil
|
60
|
+
end
|
61
|
+
|
62
|
+
# Is there any relationship?
|
63
|
+
def related?(father,u,v) ancestor?(father,u,v) or ancestor?(father,v,u); end
|
64
|
+
|
65
|
+
# "Algorithmic Graph Theory and Perfect Graphs", Martin Charles
|
66
|
+
# Golumbic, 1980, Academic Press, page 39, Propery (D1) and (D2) of
|
67
|
+
# depth first search
|
68
|
+
def test_dfs_properties
|
69
|
+
dfs = {}
|
70
|
+
father = {}
|
71
|
+
@directed.each do |vertex|
|
72
|
+
assign_dfsnumber_ancestry(@directed, dfs, father, vertex)
|
73
|
+
# Property (D1)
|
74
|
+
father.keys.each {|v| assert(dfs[father[v]] < dfs[v])}
|
75
|
+
# Property (D2)
|
76
|
+
# FIXME: Huh? Doesn't work
|
77
|
+
#@directed.edges.each {|e| assert(related?(father, e.source, e.target))}
|
78
|
+
#@directed.edges.each {|e| assert(dfs[e.source] < dfs[e.target])}
|
79
|
+
end
|
80
|
+
assert_equal 6, @directed.dfs.size
|
81
|
+
assert_equal @directed.vertices.sort, @directed.dfs.sort
|
82
|
+
end
|
83
|
+
|
84
|
+
# "Algorithmic Graph Theory and Perfect Graphs", Martin Charles
|
85
|
+
# Golumbic, 1980, Academic Press, page 40, Figure 2.7
|
86
|
+
def assign_bfsnumber_ancestry(graph, bfsnum, level, father, start)
|
87
|
+
i = 0
|
88
|
+
bfsnum.clear
|
89
|
+
level.clear
|
90
|
+
father.clear
|
91
|
+
rt = Proc.new {|v| level[v] = 0 }
|
92
|
+
ev = Proc.new {|v| bfsnum[v]=(i+=1);level[v]=(level[father[v]]+1) if father[v]}
|
93
|
+
te = Proc.new {|e| father[e.target] = e.source }
|
94
|
+
graph.dfs({:enter_vertex => ev, :tree_edge => te,
|
95
|
+
:root_vertex => rt, :start => start})
|
96
|
+
end
|
97
|
+
|
98
|
+
# "Algorithmic Graph Theory and Perfect Graphs", Martin Charles
|
99
|
+
# Golumbic, 1980, Academic Press, page 40, Propery (B1), (B2) and (B3) of
|
100
|
+
# breadth first search
|
101
|
+
def test_bfs_properties
|
102
|
+
level = {}
|
103
|
+
father = {}
|
104
|
+
bfs = {}
|
105
|
+
@directed.each do |vertex|
|
106
|
+
assign_bfsnumber_ancestry(@directed, bfs, level, father, vertex)
|
107
|
+
# Property (B1)
|
108
|
+
father.keys.each {|v| assert(bfs[father[v]] < bfs[v])}
|
109
|
+
# Property (B2)
|
110
|
+
@directed.edges.each {|e| assert((level[e.source]-level[e.target]).abs<2)}
|
111
|
+
# Property (B3)
|
112
|
+
# FIXME: How can one test this?
|
113
|
+
#@directed.vertex.each {|v| assert((level[e.source]-level[e.target]).abs<2)}
|
114
|
+
end
|
115
|
+
assert_equal 6, @directed.dfs.size
|
116
|
+
assert_equal @directed.vertices.sort, @directed.dfs.sort
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_cyclic
|
120
|
+
assert @directed.acyclic?
|
121
|
+
assert @undirected.acyclic?
|
122
|
+
assert !@directed.cyclic?
|
123
|
+
assert !@undirected.cyclic?
|
124
|
+
@undirected.add_edge!(4,6)
|
125
|
+
@directed.add_edge!(3,1)
|
126
|
+
assert !@directed.acyclic?
|
127
|
+
assert !@undirected.acyclic?
|
128
|
+
assert @directed.cyclic?
|
129
|
+
assert @undirected.cyclic?
|
130
|
+
|
131
|
+
# Test empty graph
|
132
|
+
x = Digraph.new
|
133
|
+
assert !x.cyclic?
|
134
|
+
assert x.acyclic?
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_astar
|
138
|
+
# Graph from "Artificial Intelligence: A Modern Approach" by Stuart
|
139
|
+
# Russell ande Peter Norvig, Prentice-Hall 2nd Edition, pg 63
|
140
|
+
romania = UndirectedGraph.new.
|
141
|
+
add_edge!('Oradea', 'Zerind', 71).
|
142
|
+
add_edge!('Oradea', 'Sibiu', 151).
|
143
|
+
add_edge!('Zerind', 'Arad', 75).
|
144
|
+
add_edge!('Arad', 'Sibiu', 99).
|
145
|
+
add_edge!('Arad', 'Timisoara', 138).
|
146
|
+
add_edge!('Timisoara', 'Lugoj', 111).
|
147
|
+
add_edge!('Lugoj', 'Mehadia', 70).
|
148
|
+
add_edge!('Mehadia', 'Dobreta', 75).
|
149
|
+
add_edge!('Dobreta', 'Craiova', 120).
|
150
|
+
add_edge!('Sibiu', 'Fagaras', 99).
|
151
|
+
add_edge!('Fagaras', 'Bucharest', 211).
|
152
|
+
add_edge!('Sibiu', 'Rimnicu Vilcea', 80).
|
153
|
+
add_edge!('Rimnicu Vilcea', 'Craiova', 146).
|
154
|
+
add_edge!('Rimnicu Vilcea', 'Pitesti', 97).
|
155
|
+
add_edge!('Craiova', 'Pitesti', 138).
|
156
|
+
add_edge!('Pitesti', 'Bucharest', 101).
|
157
|
+
add_edge!('Bucharest', 'Giurgin', 90).
|
158
|
+
add_edge!('Bucharest', 'Urzieni', 85).
|
159
|
+
add_edge!('Urzieni', 'Hirsova', 98).
|
160
|
+
add_edge!('Urzieni', 'Vaslui', 142).
|
161
|
+
add_edge!('Hirsova', 'Eforie', 86).
|
162
|
+
add_edge!('Vaslui', 'Iasi', 92).
|
163
|
+
add_edge!('Iasi', 'Neamt', 87)
|
164
|
+
|
165
|
+
# Heuristic from "Artificial Intelligence: A Modern Approach" by Stuart
|
166
|
+
# Russell ande Peter Norvig, Prentice-Hall 2nd Edition, pg 95
|
167
|
+
straight_line_to_Bucharest =
|
168
|
+
{
|
169
|
+
'Arad' => 366,
|
170
|
+
'Bucharest' => 0,
|
171
|
+
'Craiova' => 160,
|
172
|
+
'Dobreta' => 242,
|
173
|
+
'Eforie' => 161,
|
174
|
+
'Fagaras' => 176,
|
175
|
+
'Giurgiu' => 77,
|
176
|
+
'Hirsova' => 151,
|
177
|
+
'Iasi' => 226,
|
178
|
+
'Lugoj' => 244,
|
179
|
+
'Mehadia' => 241,
|
180
|
+
'Neamt' => 234,
|
181
|
+
'Oradea' => 380,
|
182
|
+
'Pitesti' => 100,
|
183
|
+
'Rimnicu Vilcea' => 193,
|
184
|
+
'Sibiu' => 253,
|
185
|
+
'Timisoara' => 329,
|
186
|
+
'Urziceni' => 80,
|
187
|
+
'Vaslui' => 199,
|
188
|
+
'Zerind' => 374
|
189
|
+
}
|
190
|
+
|
191
|
+
# Heuristic is distance as crow flies, always under estimates costs.
|
192
|
+
h = Proc.new {|v| straight_line_to_Bucharest[v]}
|
193
|
+
|
194
|
+
list = []
|
195
|
+
|
196
|
+
dv = Proc.new {|v| list << "dv #{v}" }
|
197
|
+
ev = Proc.new {|v| list << "ev #{v}" }
|
198
|
+
bt = Proc.new {|v| list << "bt #{v}" }
|
199
|
+
fv = Proc.new {|v| list << "fv #{v}" }
|
200
|
+
er = Proc.new {|e| list << "er #{e}" }
|
201
|
+
enr = Proc.new {|e| list << "enr #{e}" }
|
202
|
+
|
203
|
+
options = { :discover_vertex => dv,
|
204
|
+
:examine_vertex => ev,
|
205
|
+
:black_target => bt,
|
206
|
+
:finish_vertex => fv,
|
207
|
+
:edge_relaxed => er,
|
208
|
+
:edge_not_relaxed => enr }
|
209
|
+
|
210
|
+
result = romania.astar('Arad', 'Bucharest', h, options)
|
211
|
+
|
212
|
+
assert_equal ["Arad", "Sibiu", "Rimnicu Vilcea", "Pitesti", "Bucharest"], result
|
213
|
+
# This isn't the greatest test since the exact ordering is not
|
214
|
+
# not specified by the algorithm. If someone has a better idea, please fix
|
215
|
+
assert_equal ["ev Arad",
|
216
|
+
"er (Arad=Sibiu '99')",
|
217
|
+
"dv Sibiu",
|
218
|
+
"er (Arad=Timisoara '138')",
|
219
|
+
"dv Timisoara",
|
220
|
+
"er (Arad=Zerind '75')",
|
221
|
+
"dv Zerind",
|
222
|
+
"fv Arad",
|
223
|
+
"ev Sibiu",
|
224
|
+
"er (Rimnicu Vilcea=Sibiu '80')",
|
225
|
+
"dv Rimnicu Vilcea",
|
226
|
+
"er (Fagaras=Sibiu '99')",
|
227
|
+
"dv Fagaras",
|
228
|
+
"er (Oradea=Sibiu '151')",
|
229
|
+
"dv Oradea",
|
230
|
+
"enr (Arad=Sibiu '99')",
|
231
|
+
"fv Sibiu",
|
232
|
+
"ev Rimnicu Vilcea",
|
233
|
+
"enr (Rimnicu Vilcea=Sibiu '80')",
|
234
|
+
"er (Craiova=Rimnicu Vilcea '146')",
|
235
|
+
"dv Craiova",
|
236
|
+
"er (Pitesti=Rimnicu Vilcea '97')",
|
237
|
+
"dv Pitesti",
|
238
|
+
"fv Rimnicu Vilcea",
|
239
|
+
"ev Fagaras",
|
240
|
+
"enr (Fagaras=Sibiu '99')",
|
241
|
+
"er (Bucharest=Fagaras '211')",
|
242
|
+
"dv Bucharest",
|
243
|
+
"fv Fagaras",
|
244
|
+
"ev Pitesti",
|
245
|
+
"enr (Pitesti=Rimnicu Vilcea '97')",
|
246
|
+
"er (Bucharest=Pitesti '101')",
|
247
|
+
"enr (Craiova=Pitesti '138')",
|
248
|
+
"fv Pitesti",
|
249
|
+
"ev Bucharest"], list
|
250
|
+
end
|
251
|
+
|
252
|
+
def test_bfs_spanning_forest
|
253
|
+
predecessor, roots = @tree.bfs_spanning_forest(1)
|
254
|
+
assert_equal({2=>1, 3=>1, 4=>1, 5=>2, 6=>2, 7=>6, 24=>23}, predecessor)
|
255
|
+
assert_equal [1,23], roots.sort
|
256
|
+
predecessor, roots = @tree.bfs_spanning_forest(3)
|
257
|
+
assert_equal({7=>6, 24=>23, 2=>1, 4=>1}, predecessor)
|
258
|
+
assert_equal [1,3,5,6,23], roots.sort
|
259
|
+
end
|
260
|
+
|
261
|
+
def test_dfs_spanning_forest
|
262
|
+
predecessor, roots = @tree.dfs_spanning_forest(1)
|
263
|
+
assert_equal({5=>2, 6=>2, 7=>6, 24=>23, 2=>1, 3=>1, 4=>2}, predecessor)
|
264
|
+
assert_equal [1,23], roots.sort
|
265
|
+
predecessor, roots = @tree.dfs_spanning_forest(3)
|
266
|
+
assert_equal({7=>6, 24=>23, 2=>1, 4=>2}, predecessor)
|
267
|
+
assert_equal [1,3,5,6,23], roots.sort
|
268
|
+
end
|
269
|
+
|
270
|
+
def test_tree_from_vertex
|
271
|
+
assert_equal({5=>2, 6=>2, 7=>6, 2=>1, 3=>1, 4=>1}, @tree.bfs_tree_from_vertex(1))
|
272
|
+
assert_equal({}, @tree.bfs_tree_from_vertex(3))
|
273
|
+
assert_equal({5=>2, 6=>2, 7=>6, 2=>1, 3=>1, 4=>2}, @tree.dfs_tree_from_vertex(1))
|
274
|
+
assert_equal({}, @tree.dfs_tree_from_vertex(3))
|
275
|
+
end
|
276
|
+
|
277
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2006 Shawn Patrick Garbett
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
5
|
+
# are permitted provided that the following conditions are met:
|
6
|
+
#
|
7
|
+
# * Redistributions of source code must retain the above copyright notice(s),
|
8
|
+
# this list of conditions and the following disclaimer.
|
9
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
# this list of conditions and the following disclaimer in the documentation
|
11
|
+
# and/or other materials provided with the distribution.
|
12
|
+
# * Neither the name of the Shawn Garbett nor the names of its contributors
|
13
|
+
# may be used to endorse or promote products derived from this software
|
14
|
+
# without specific prior written permission.
|
15
|
+
#
|
16
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
17
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
19
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
20
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
21
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
22
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
23
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
24
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
25
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
26
|
+
#++
|
27
|
+
|
28
|
+
|
29
|
+
require 'test/unit'
|
30
|
+
require 'gratr/import'
|
31
|
+
|
32
|
+
class TestStrongComponents < Test::Unit::TestCase # :nodoc:
|
33
|
+
# Test from boost strong_components.cpp
|
34
|
+
# Original Copyright 1997-2001, University of Notre Dame.
|
35
|
+
# Original Authors: Andrew Lumsdaine, Lie-Quan Lee, Jermey G. Siek
|
36
|
+
def test_boost
|
37
|
+
g = Digraph[ 'a', 'b', 'a', 'f', 'a', 'h',
|
38
|
+
'b', 'c', 'b', 'a',
|
39
|
+
'c', 'd', 'c', 'b',
|
40
|
+
'd', 'e',
|
41
|
+
'e', 'd',
|
42
|
+
'f', 'g',
|
43
|
+
'g', 'f', 'g', 'd',
|
44
|
+
'h', 'i',
|
45
|
+
'i', 'h', 'i', 'j', 'i', 'e', 'i', 'c']
|
46
|
+
|
47
|
+
c = g.strong_components.map {|x| x.sort}
|
48
|
+
assert_equal 10, g.vertices.size
|
49
|
+
assert_equal 4, c.size
|
50
|
+
assert c.include?(['d','e'])
|
51
|
+
assert c.include?(['f','g'])
|
52
|
+
assert c.include?(['j'])
|
53
|
+
assert c.include?(['a','b','c','h','i'])
|
54
|
+
|
55
|
+
cg = g.condensation
|
56
|
+
cg_vertices = cg.map {|v| v.sort}
|
57
|
+
assert_equal 4, cg_vertices.size
|
58
|
+
assert cg_vertices.include?(['j'])
|
59
|
+
assert cg_vertices.include?(['d','e'])
|
60
|
+
assert cg_vertices.include?(['f', 'g'])
|
61
|
+
assert cg_vertices.include?(['a', 'b', 'c', 'h', 'i'])
|
62
|
+
assert cg.edges.map {|e| [e.source.sort.join, e.target.sort.join] }.sort ==
|
63
|
+
[['abchi','de'], ['abchi', 'fg'], ['abchi', 'j'], ['fg', 'de']]
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
# Figure #3, from 'Depth-First Search and Linear Graph Algorithms'
|
68
|
+
# by Robert Tarjan, SIAM J. Comput. Vol 1, No.2, June 1972
|
69
|
+
def test_tarjan_fig_3
|
70
|
+
g = Digraph[ 1,2,
|
71
|
+
2,3, 2,8,
|
72
|
+
3,4, 3,7,
|
73
|
+
4,5,
|
74
|
+
5,3, 5,6,
|
75
|
+
7,4, 7,6,
|
76
|
+
8,1, 8,7 ]
|
77
|
+
|
78
|
+
c = g.strong_components.map {|x| x.sort}
|
79
|
+
assert_equal 8, g.vertices.size
|
80
|
+
assert_equal 3, c.size
|
81
|
+
assert c.include?([6])
|
82
|
+
assert c.include?([1,2,8])
|
83
|
+
assert c.include?([3,4,5,7])
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2006 Shawn Patrick Garbett
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
5
|
+
# are permitted provided that the following conditions are met:
|
6
|
+
#
|
7
|
+
# * Redistributions of source code must retain the above copyright notice(s),
|
8
|
+
# this list of conditions and the following disclaimer.
|
9
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
# this list of conditions and the following disclaimer in the documentation
|
11
|
+
# and/or other materials provided with the distribution.
|
12
|
+
# * Neither the name of the Shawn Garbett nor the names of its contributors
|
13
|
+
# may be used to endorse or promote products derived from this software
|
14
|
+
# without specific prior written permission.
|
15
|
+
#
|
16
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
17
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
19
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
20
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
21
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
22
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
23
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
24
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
25
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
26
|
+
#++
|
27
|
+
|
28
|
+
|
29
|
+
require 'test/unit'
|
30
|
+
require 'gratr/import'
|
31
|
+
|
32
|
+
class TestTriagulated < Test::Unit::TestCase #:nodoc:
|
33
|
+
|
34
|
+
def test_berge_mystery
|
35
|
+
berge_mystery = UndirectedGraph[
|
36
|
+
:abe, :eddie,
|
37
|
+
:abe, :burt,
|
38
|
+
:abe, :desmond,
|
39
|
+
:eddie, :burt,
|
40
|
+
:eddie, :ida,
|
41
|
+
:eddie, :charlotte,
|
42
|
+
:charlotte, :ida,
|
43
|
+
:charlotte, :desmond,
|
44
|
+
:burt, :ida,
|
45
|
+
:ida, :desmond]
|
46
|
+
|
47
|
+
assert !berge_mystery.triangulated?
|
48
|
+
berge_mystery.remove_vertex!(:desmond)
|
49
|
+
assert berge_mystery.triangulated?
|
50
|
+
|
51
|
+
assert 3, berge_mystery.chromatic_number
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_house
|
55
|
+
house = UndirectedGraph[
|
56
|
+
:roof, :left_gutter,
|
57
|
+
:roof, :right_gutter,
|
58
|
+
:left_gutter, :left_foundation,
|
59
|
+
:right_gutter, :right_foundation,
|
60
|
+
:left_foundation, :right_foundation
|
61
|
+
]
|
62
|
+
assert !house.triangulated?
|
63
|
+
house.remove_vertex!(:left_foundation) # Becomes a bulls head graph
|
64
|
+
assert house.triangulated?
|
65
|
+
assert 3, house.chromatic_number
|
66
|
+
end
|
67
|
+
|
68
|
+
# A triangulated, but not interval graph test
|
69
|
+
def test_non_interval
|
70
|
+
non_interval = UndirectedGraph[
|
71
|
+
:ao, :ai,
|
72
|
+
:ai, :bi,
|
73
|
+
:ai, :ci,
|
74
|
+
:bo, :bi,
|
75
|
+
:bi, :ci,
|
76
|
+
:co, :ci
|
77
|
+
]
|
78
|
+
assert non_interval.triangulated?
|
79
|
+
assert 3, non_interval.chromatic_number
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_simple
|
83
|
+
simple = UndirectedGraph[
|
84
|
+
:a, :b,
|
85
|
+
:b, :c,
|
86
|
+
:c, :d,
|
87
|
+
:d, :e,
|
88
|
+
:e, :f,
|
89
|
+
:f, :g,
|
90
|
+
:g, :a,
|
91
|
+
:g, :b,
|
92
|
+
:b, :f,
|
93
|
+
:f, :c,
|
94
|
+
]
|
95
|
+
assert !simple.triangulated?
|
96
|
+
simple.add_edge!(:c, :e)
|
97
|
+
assert simple.triangulated?
|
98
|
+
assert 3, simple.chromatic_number
|
99
|
+
assert 2, UndirectedGraph[:a, :b].chromatic_number
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_simple2
|
103
|
+
simple2 = UndirectedGraph[
|
104
|
+
:x, :p,
|
105
|
+
:p, :z,
|
106
|
+
:z, :r,
|
107
|
+
:r, :x,
|
108
|
+
:p, :y,
|
109
|
+
:y, :r,
|
110
|
+
:y, :q,
|
111
|
+
:q, :z]
|
112
|
+
assert !simple2.triangulated?
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_lexicographic_queue
|
116
|
+
q = UndirectedGraph::LexicographicQueue.new([1,2,3,4,5,6,7,8,9])
|
117
|
+
assert_equal 9, q.pop
|
118
|
+
q.add_lexeme([3,4,5,6,7,8])
|
119
|
+
assert_equal 8, q.pop
|
120
|
+
q.add_lexeme([2,6,7,9])
|
121
|
+
assert_equal 7, q.pop
|
122
|
+
q.add_lexeme([8,9])
|
123
|
+
assert_equal 6, q.pop
|
124
|
+
q.add_lexeme([1,5,8,9])
|
125
|
+
assert_equal 5, q.pop
|
126
|
+
q.add_lexeme([6,9])
|
127
|
+
assert_equal 4, q.pop
|
128
|
+
q.add_lexeme([3,9])
|
129
|
+
assert_equal 3, q.pop
|
130
|
+
q.add_lexeme([4,9])
|
131
|
+
assert_equal 2, q.pop
|
132
|
+
q.add_lexeme([8])
|
133
|
+
assert_equal 1, q.pop
|
134
|
+
assert_equal nil, q.pop
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|