gratr 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Grater.xcf +0 -0
- data/README +328 -0
- data/Rakefile +220 -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 +33 -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 +73 -0
- data/lib/gratr/comparability.rb +92 -0
- data/lib/gratr/digraph.rb +113 -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 +315 -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 +326 -0
- data/lib/gratr/search.rb +409 -0
- data/lib/gratr/strong_components.rb +127 -0
- data/lib/gratr/undirected_graph.rb +153 -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/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 +257 -0
- data/tests/TestStrongComponents.rb +85 -0
- data/tests/TestTriagulated.rb +137 -0
- data/tests/TestUndirectedGraph.rb +219 -0
- metadata +92 -0
@@ -0,0 +1,160 @@
|
|
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
|
+
require 'gratr/dot'
|
32
|
+
|
33
|
+
# This test runs the classes from Appendix F in
|
34
|
+
# _Algorithmic_Graph_Theory_and_Perfect_Graphs,
|
35
|
+
# by Martin Charles Golumbic
|
36
|
+
class TestProperties < Test::Unit::TestCase # :nodoc:
|
37
|
+
|
38
|
+
def test_g1
|
39
|
+
g1 = UndirectedGraph[ :a,:b, :a,:d, :a,:e, :a,:i, :a,:g, :a,:h,
|
40
|
+
:b,:c, :b,:f,
|
41
|
+
:c,:d, :c,:h,
|
42
|
+
:d,:h, :d,:e,
|
43
|
+
:e,:f,
|
44
|
+
:f,:g, :f,:h, :f,:i,
|
45
|
+
:h,:i ]
|
46
|
+
|
47
|
+
assert !g1.triangulated?
|
48
|
+
assert !g1.complement.triangulated? # Disagrees with Golumbic!
|
49
|
+
assert !g1.comparability?
|
50
|
+
assert !g1.complement.comparability?
|
51
|
+
assert !g1.interval?
|
52
|
+
assert !g1.complement.interval?
|
53
|
+
assert !g1.permutation?
|
54
|
+
assert !g1.split?
|
55
|
+
|
56
|
+
# g1.write_to_graphic_file('jpg','g1')
|
57
|
+
# g1.complement.write_to_graphic_file('jpg','g1_complement')
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_g2
|
61
|
+
g2 = UndirectedGraph[ :a,:b, :a,:e,
|
62
|
+
:b,:c, :b,:e, :b,:f,
|
63
|
+
:c,:d, :c,:f, :c,:g,
|
64
|
+
:d,:g,
|
65
|
+
:e,:f,
|
66
|
+
:f,:g]
|
67
|
+
|
68
|
+
assert g2.triangulated?
|
69
|
+
assert !g2.complement.triangulated?
|
70
|
+
assert !g2.comparability?
|
71
|
+
assert g2.complement.comparability?
|
72
|
+
assert g2.interval?
|
73
|
+
assert !g2.complement.interval?
|
74
|
+
assert !g2.permutation?
|
75
|
+
assert !g2.split?
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_g3
|
79
|
+
g3 = UndirectedGraph[ :a,:c,
|
80
|
+
:b,:e,
|
81
|
+
:c,:d, :c,:f,
|
82
|
+
:d,:f, :d,:g, :d,:e,
|
83
|
+
:e,:g,
|
84
|
+
:f,:g ]
|
85
|
+
assert g3.triangulated?
|
86
|
+
assert !g3.complement.triangulated?
|
87
|
+
assert !g3.comparability?
|
88
|
+
assert g3.complement.comparability?
|
89
|
+
assert g3.interval?
|
90
|
+
assert !g3.complement.interval?
|
91
|
+
assert !g3.permutation?
|
92
|
+
assert !g3.split?
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_g4
|
96
|
+
g4 = UndirectedGraph[ :a,:b,
|
97
|
+
:b,:c,
|
98
|
+
:c,:d, :c,:e,
|
99
|
+
:d,:f,
|
100
|
+
:e,:g]
|
101
|
+
assert g4.triangulated?
|
102
|
+
assert !g4.complement.triangulated?
|
103
|
+
assert g4.comparability?
|
104
|
+
assert !g4.complement.comparability?
|
105
|
+
assert !g4.interval?
|
106
|
+
assert !g4.complement.interval?
|
107
|
+
assert !g4.permutation?
|
108
|
+
assert !g4.split?
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_g5
|
112
|
+
g5 = UndirectedGraph[ :a,:b, :a,:c,
|
113
|
+
:b,:c, :b,:d, :b,:f, :b,:g,
|
114
|
+
:c,:e, :c,:f, :c,:g,
|
115
|
+
:d,:f,
|
116
|
+
:e,:g,
|
117
|
+
:f,:g]
|
118
|
+
assert g5.triangulated?
|
119
|
+
assert g5.complement.triangulated?
|
120
|
+
assert g5.comparability?
|
121
|
+
assert !g5.complement.comparability?
|
122
|
+
assert !g5.interval?
|
123
|
+
assert g5.complement.interval?
|
124
|
+
assert !g5.permutation?
|
125
|
+
assert g5.split?
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_g6
|
129
|
+
g6 = UndirectedGraph[ :a,:c, :a,:d,
|
130
|
+
:b,:c,
|
131
|
+
:c,:f,
|
132
|
+
:d,:e, :d,:f]
|
133
|
+
assert !g6.triangulated?
|
134
|
+
assert !g6.complement.triangulated?
|
135
|
+
assert g6.comparability?
|
136
|
+
assert g6.complement.comparability?
|
137
|
+
assert !g6.interval?
|
138
|
+
assert !g6.complement.interval?
|
139
|
+
assert g6.permutation?
|
140
|
+
assert !g6.split?
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_g7
|
144
|
+
g7 = UndirectedGraph[ :a,:b, :a,:c,
|
145
|
+
:b,:c, :b,:d, :b,:e,
|
146
|
+
:c,:e, :c,:f,
|
147
|
+
:d,:e,
|
148
|
+
:e,:f]
|
149
|
+
assert g7.triangulated?
|
150
|
+
assert g7.complement.triangulated?
|
151
|
+
assert !g7.comparability?
|
152
|
+
assert !g7.complement.comparability?
|
153
|
+
assert !g7.interval?
|
154
|
+
assert !g7.complement.interval?
|
155
|
+
assert !g7.permutation?
|
156
|
+
assert g7.split?
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
data/tests/TestSearch.rb
ADDED
@@ -0,0 +1,257 @@
|
|
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", "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", "er (Arad=Sibiu)", "dv Sibiu",
|
216
|
+
"er (Arad=Timisoara)", "dv Timisoara", "er (Arad=Zerind)", "dv Zerind",
|
217
|
+
"fv Arad", "ev Zerind", "er (Oradea=Zerind)", "dv Oradea",
|
218
|
+
"enr (Arad=Zerind)", "fv Zerind", "ev Oradea", "enr (Oradea=Sibiu)",
|
219
|
+
"enr (Oradea=Zerind)", "fv Oradea", "ev Timisoara",
|
220
|
+
"er (Lugoj=Timisoara)", "dv Lugoj", "enr (Arad=Timisoara)",
|
221
|
+
"fv Timisoara", "ev Lugoj", "enr (Lugoj=Timisoara)",
|
222
|
+
"er (Lugoj=Mehadia)", "dv Mehadia", "fv Lugoj", "ev Mehadia",
|
223
|
+
"er (Dobreta=Mehadia)", "dv Dobreta", "enr (Lugoj=Mehadia)",
|
224
|
+
"fv Mehadia", "ev Dobreta", "enr (Dobreta=Mehadia)",
|
225
|
+
"er (Craiova=Dobreta)", "dv Craiova", "fv Dobreta", "ev Craiova",
|
226
|
+
"enr (Craiova=Dobreta)", "er (Craiova=Rimnicu Vilcea)",
|
227
|
+
"dv Rimnicu Vilcea", "er (Craiova=Pitesti)", "dv Pitesti",
|
228
|
+
"fv Craiova", "ev Pitesti", "enr (Pitesti=Rimnicu Vilcea)",
|
229
|
+
"er (Bucharest=Pitesti)", "dv Bucharest"], list
|
230
|
+
end
|
231
|
+
|
232
|
+
def test_bfs_spanning_forest
|
233
|
+
predecessor, roots = @tree.bfs_spanning_forest(1)
|
234
|
+
assert_equal({2=>1, 3=>1, 4=>1, 5=>2, 6=>2, 7=>6, 24=>23}, predecessor)
|
235
|
+
assert_equal [1,23], roots.sort
|
236
|
+
predecessor, roots = @tree.bfs_spanning_forest(3)
|
237
|
+
assert_equal({7=>6, 24=>23, 2=>1, 4=>1}, predecessor)
|
238
|
+
assert_equal [1,3,5,6,23], roots.sort
|
239
|
+
end
|
240
|
+
|
241
|
+
def test_dfs_spanning_forest
|
242
|
+
predecessor, roots = @tree.dfs_spanning_forest(1)
|
243
|
+
assert_equal({5=>2, 6=>2, 7=>6, 24=>23, 2=>1, 3=>1, 4=>2}, predecessor)
|
244
|
+
assert_equal [1,23], roots.sort
|
245
|
+
predecessor, roots = @tree.dfs_spanning_forest(3)
|
246
|
+
assert_equal({7=>6, 24=>23, 2=>1, 4=>2}, predecessor)
|
247
|
+
assert_equal [1,3,5,6,23], roots.sort
|
248
|
+
end
|
249
|
+
|
250
|
+
def test_tree_from_vertex
|
251
|
+
assert_equal({5=>2, 6=>2, 7=>6, 2=>1, 3=>1, 4=>1}, @tree.bfs_tree_from_vertex(1))
|
252
|
+
assert_equal({}, @tree.bfs_tree_from_vertex(3))
|
253
|
+
assert_equal({5=>2, 6=>2, 7=>6, 2=>1, 3=>1, 4=>2}, @tree.dfs_tree_from_vertex(1))
|
254
|
+
assert_equal({}, @tree.dfs_tree_from_vertex(3))
|
255
|
+
end
|
256
|
+
|
257
|
+
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
|