gratr 0.4.2
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/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
|