gratr 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/Grater.xcf +0 -0
  2. data/README +328 -0
  3. data/Rakefile +220 -0
  4. data/examples/graph_self.rb +54 -0
  5. data/examples/module_graph.jpg +0 -0
  6. data/examples/module_graph.rb +12 -0
  7. data/examples/self_graph.jpg +0 -0
  8. data/examples/visualize.jpg +0 -0
  9. data/examples/visualize.rb +8 -0
  10. data/install.rb +49 -0
  11. data/lib/gratr.rb +33 -0
  12. data/lib/gratr/adjacency_graph.rb +230 -0
  13. data/lib/gratr/base.rb +34 -0
  14. data/lib/gratr/biconnected.rb +116 -0
  15. data/lib/gratr/chinese_postman.rb +123 -0
  16. data/lib/gratr/common.rb +73 -0
  17. data/lib/gratr/comparability.rb +92 -0
  18. data/lib/gratr/digraph.rb +113 -0
  19. data/lib/gratr/digraph_distance.rb +185 -0
  20. data/lib/gratr/dot.rb +90 -0
  21. data/lib/gratr/edge.rb +145 -0
  22. data/lib/gratr/graph.rb +315 -0
  23. data/lib/gratr/graph_api.rb +82 -0
  24. data/lib/gratr/import.rb +44 -0
  25. data/lib/gratr/labels.rb +103 -0
  26. data/lib/gratr/maximum_flow.rb +107 -0
  27. data/lib/gratr/rdot.rb +326 -0
  28. data/lib/gratr/search.rb +409 -0
  29. data/lib/gratr/strong_components.rb +127 -0
  30. data/lib/gratr/undirected_graph.rb +153 -0
  31. data/tests/TestBiconnected.rb +53 -0
  32. data/tests/TestChinesePostman.rb +53 -0
  33. data/tests/TestComplement.rb +54 -0
  34. data/tests/TestDigraph.rb +333 -0
  35. data/tests/TestDigraphDistance.rb +138 -0
  36. data/tests/TestEdge.rb +171 -0
  37. data/tests/TestInspection.rb +57 -0
  38. data/tests/TestMultiEdge.rb +57 -0
  39. data/tests/TestNeighborhood.rb +64 -0
  40. data/tests/TestProperties.rb +160 -0
  41. data/tests/TestSearch.rb +257 -0
  42. data/tests/TestStrongComponents.rb +85 -0
  43. data/tests/TestTriagulated.rb +137 -0
  44. data/tests/TestUndirectedGraph.rb +219 -0
  45. metadata +92 -0
@@ -0,0 +1,153 @@
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 'gratr/adjacency_graph'
31
+ require 'gratr/search'
32
+ require 'gratr/biconnected'
33
+ require 'gratr/comparability'
34
+ require 'set'
35
+
36
+ module GRATR
37
+ class UndirectedGraph
38
+ include AdjacencyGraph
39
+ include Graph::Search
40
+ include Graph::Biconnected
41
+ include Graph::Comparability
42
+
43
+ def initialize(*params)
44
+ raise ArgumentError if params.any? do |p|
45
+ !(p.kind_of? GRATR::Graph or p.kind_of? Array)
46
+ end if self.class == GRATR::UndirectedGraph
47
+ super(*params)
48
+ end
49
+
50
+ # UndirectedGraph is by definition undirected, always returns false
51
+ def directed?() false; end
52
+
53
+ # Redefine degree (default was sum)
54
+ def degree(v) in_degree(v); end
55
+
56
+ # A vertex of an undirected graph is balanced by definition
57
+ def balanced?(v) true; end
58
+
59
+ # UndirectedGraph uses Edge for the edge class.
60
+ def edge_class() @parallel_edges ? GRATR::MultiEdge : GRATR::Edge; end
61
+
62
+ def remove_edge!(u, v=nil)
63
+ unless u.kind_of? GRATR::Arc
64
+ raise ArgumentError if @parallel_edges
65
+ u = edge_class[u,v]
66
+ end
67
+ super(u.reverse) unless u.source == u.target
68
+ super(u)
69
+ end
70
+
71
+ # A triangulated graph is an undirected perfect graph that every cycle of length greater than
72
+ # three possesses a chord. They have also been called chordal, rigid circuit, monotone transitive,
73
+ # and perfect elimination graphs.
74
+ #
75
+ # Implementation taken from Golumbic's, "Algorithmic Graph Theory and
76
+ # Perfect Graphs" pg. 90
77
+ def triangulated?
78
+ a = Hash.new {|h,k| h[k]=Set.new}; sigma=lexicograph_bfs
79
+ inv_sigma = sigma.inject({}) {|acc,val| acc[val] = sigma.index(val); acc}
80
+ sigma[0..-2].each do |v|
81
+ x = adjacent(v).select {|w| inv_sigma[v] < inv_sigma[w] }
82
+ unless x.empty?
83
+ u = sigma[x.map {|y| inv_sigma[y]}.min]
84
+ a[u].merge(x - [u])
85
+ end
86
+ return false unless a[v].all? {|z| adjacent?(v,z)}
87
+ end
88
+ true
89
+ end
90
+
91
+ def chromatic_number
92
+ return triangulated_chromatic_number if triangulated?
93
+ raise NotImplementedError
94
+ end
95
+
96
+ # An interval graph can have its vertices into one-to-one
97
+ # correspondence with a set of intervals F of a linearly ordered
98
+ # set (like the real line) such that two vertices are connected
99
+ # by an edge of G if and only if their corresponding intervals
100
+ # have nonempty intersection.
101
+ def interval?() triangulated? and complement.comparability?; end
102
+
103
+ # A permutation diagram consists of n points on each of two parallel
104
+ # lines and n straight line segments matchin the points. The intersection
105
+ # graph of the line segments is called a permutation graph.
106
+ def permutation?() comparability? and complement.comparability?; end
107
+
108
+ # An undirected graph is defined to be split if there is a partition
109
+ # V = S + K of its vertex set into a stable set S and a complete set K.
110
+ def split?() triangulated? and complement.triangulated?; end
111
+
112
+ private
113
+ # Implementation taken from Golumbic's, "Algorithmic Graph Theory and
114
+ # Perfect Graphs" pg. 99
115
+ def triangulated_chromatic_number
116
+ chi = 1; s= Hash.new {|h,k| h[k]=0}
117
+ sigma=lexicograph_bfs
118
+ inv_sigma = sigma.inject({}) {|acc,val| acc[val] = sigma.index(val); acc}
119
+ sigma.each do |v|
120
+ x = adjacent(v).select {|w| inv_sigma[v] < inv_sigma[w] }
121
+ unless x.empty?
122
+ u = sigma[x.map {|y| inv_sigma[y]}.min]
123
+ s[u] = [s[u], x.size-1].max
124
+ chi = [chi, x.size+1].max if s[v] < x.size
125
+ end
126
+ end; chi
127
+ end
128
+
129
+ end # UndirectedGraph
130
+
131
+ # This is a UndirectedGraph that allows for parallel edges, but does not
132
+ # allow loops
133
+ class UndirectedPseudoGraph < UndirectedGraph
134
+ def initialize(*params)
135
+ raise ArgumentError if params.any? do |p|
136
+ !(p.kind_of? Graph or p.kind_of? Array)
137
+ end
138
+ super(:parallel_edges, *params)
139
+ end
140
+ end
141
+
142
+ # This is a UndirectedGraph that allows for parallel edges and loops
143
+ class UndirectedMultiGraph < UndirectedGraph
144
+ def initialize(*params)
145
+ raise ArgumentError if params.any? do |p|
146
+ !(p.kind_of? Graph or p.kind_of? Array)
147
+ end
148
+ super(:parallel_edges, :loops, *params)
149
+ end
150
+ end
151
+
152
+
153
+ end # GRATR
@@ -0,0 +1,53 @@
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
+ require 'test/unit'
29
+ require 'gratr/import'
30
+
31
+ class TestBiconnected < Test::Unit::TestCase # :nodoc:
32
+ def test_tarjan
33
+ tarjan = UndirectedGraph[ 1, 2,
34
+ 1, 5,
35
+ 1, 6,
36
+ 1, 7,
37
+ 2, 3,
38
+ 2, 4,
39
+ 3, 4,
40
+ 2, 5,
41
+ 5, 6,
42
+ 7, 8,
43
+ 7, 9,
44
+ 8, 9 ]
45
+ graphs, articulations = tarjan.biconnected
46
+ assert_equal [1,2,7], articulations.sort
47
+ assert_equal 4, graphs.size
48
+ assert_equal [1,7], graphs.find {|g| g.size == 2}.vertices.sort
49
+ assert_equal [1,2,5,6], graphs.find {|g| g.size == 4}.vertices.sort
50
+ assert_equal [2,3,4], graphs.find {|g| g.size == 3 && g.vertex?(2)}.vertices.sort
51
+ assert_equal [7,8,9], graphs.find {|g| g.size == 3 && g.vertex?(7)}.vertices.sort
52
+ end
53
+ end
@@ -0,0 +1,53 @@
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 TestChinesePostman < Test::Unit::TestCase # :nodoc:
33
+
34
+ def setup
35
+ @simple=Digraph[ 0,1, 0,2, 1,2, 1,3, 2,3, 3,0 ]
36
+ @weight = Proc.new {|e| 1}
37
+ end
38
+
39
+ def test_closed_simple_tour
40
+ tour = @simple.closed_chinese_postman_tour(0, @weight)
41
+ assert_equal 11, tour.size
42
+ assert_equal 0, tour[0]
43
+ assert_equal 0, tour[10]
44
+ edges = Set.new
45
+ 0.upto(9) do |n|
46
+ edges << Arc[tour[n],tour[n+1]]
47
+ assert(@simple.edge?(tour[n],tour[n+1]), "Arc(#{tour[n]},#{tour[n+1]}) from tour not in graph")
48
+ end
49
+ assert_equal @simple.edges.size, edges.size, "Not all arcs traversed!"
50
+ end
51
+
52
+
53
+ end
@@ -0,0 +1,54 @@
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 TestComplement < Test::Unit::TestCase # :nodoc:
34
+
35
+ def test_square
36
+ x = UndirectedGraph[:a,:b, :b,:c, :c,:d, :d,:a].complement
37
+ assert_equal 2, x.edges.size
38
+ assert x.edges.include?(Edge[:a,:c])
39
+ assert x.edges.include?(Edge[:b,:d])
40
+ end
41
+
42
+ def test_g1
43
+ g1 = UndirectedGraph[ :a,:b, :a,:d, :a,:e, :a,:i, :a,:g, :a,:h,
44
+ :b,:c, :b,:f,
45
+ :c,:d, :c,:h,
46
+ :d,:h, :d,:e,
47
+ :e,:f,
48
+ :f,:g, :f,:h, :f,:i,
49
+ :h,:i ].complement
50
+ assert_equal 19, g1.edges.size
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,333 @@
1
+ #--
2
+ # Copyright (c) 2006 Shawn Patrick Garbett
3
+ # Copyright (c) 2002,2004,2005 by Horst Duchene
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ #++
24
+
25
+ require 'test/unit'
26
+ require 'gratr/import'
27
+
28
+ class TestDigraph < Test::Unit::TestCase # :nodoc:
29
+
30
+ def setup
31
+ @single = Digraph[1,2, 2,3, 3,4, 1,2, 2,3, 4,4]
32
+ @dups = DirectedPseudoGraph[1,2, 2,3, 3,4, 1,2, 2,3, 4,4]
33
+ @loops = DirectedMultiGraph[1,2, 2,3, 3,4, 4,4, 1,2, 2,3]
34
+ end
35
+
36
+ def test_new
37
+ assert_equal Digraph[1,2, 2,3, 3,4], @single
38
+ assert_equal DirectedPseudoGraph.new([1,2, 2,3, 3,4, 1,2, 2,3]), @dups
39
+ assert_equal DirectedMultiGraph.new([1,2, 2,3, 3,4, 4,4, 1,2, 2,3]), @loops
40
+ assert_raise(ArgumentError) {Digraph.new(:loops)}
41
+ assert_raise(ArgumentError) {Digraph.new(:parallel_edges)}
42
+ assert_raise(ArgumentError) {DirectedMultiGraph.new(:loops)}
43
+ assert_raise(ArgumentError) {DirectedMultiGraph.new(:parallel_edges)}
44
+ assert_raise(ArgumentError) {DirectedPseudoGraph.new(:loops)}
45
+ assert_raise(ArgumentError) {DirectedPseudoGraph.new(:parallel_edges)}
46
+ assert_raise(ArgumentError) {Digraph.new(1)}
47
+ assert_equal @single, Digraph.new(@single)
48
+ assert_equal @dups, DirectedPseudoGraph.new(@dups)
49
+ assert_equal @loops, DirectedMultiGraph.new(@loops)
50
+ assert_equal Digraph[1,2, 2,3, 3,4], Digraph.new(@loops)
51
+ end
52
+
53
+ def test_edges
54
+ assert_equal 3,@single.edges.size
55
+ assert @single.edges.include?(Arc[1,2])
56
+ assert @single.edges.include?(Arc[2,3])
57
+ assert @single.edges.include?(Arc[3,4])
58
+ assert !@single.edges.include?(Arc[4,4])
59
+ assert @single.edges.include?(Arc[1,2])
60
+ assert @single.edges.include?(Arc[2,3])
61
+ assert !@single.edges.include?(Arc[1,3])
62
+ assert @single.edge?(2,3)
63
+ assert !@single.edge?(1,4)
64
+ assert @single.edge?(Arc[1,2])
65
+ assert !@single.add_edge!(5,5).edge?(5,5)
66
+ assert !@single.remove_edge!(5,5).edge?(5,5)
67
+
68
+ assert_equal 5,@dups.edges.size
69
+ assert @dups.edges.include?(MultiArc[1,2])
70
+ assert @dups.edges.include?(MultiArc[2,3])
71
+ assert @dups.edges.include?(MultiArc[3,4])
72
+ assert !@dups.edges.include?(MultiArc[4,4])
73
+ assert @dups.edges.include?(MultiArc[1,2])
74
+ assert @dups.edges.include?(MultiArc[2,3])
75
+ assert !@dups.edges.include?(MultiArc[1,3])
76
+ assert @dups.edge?(2,3)
77
+ assert !@dups.edge?(1,4)
78
+ assert @dups.edge?(MultiArc[1,2])
79
+ assert !@dups.add_edge!(5,5).edge?(5,5)
80
+ assert_raise(ArgumentError) { @dups.remove_edge!(5,5) }
81
+
82
+ assert_equal 5,@dups.edges.size
83
+ assert @loops.edges.include?(MultiArc[1,2])
84
+ assert @loops.edges.include?(MultiArc[2,3])
85
+ assert @loops.edges.include?(MultiArc[3,4])
86
+ assert @loops.edges.include?(MultiArc[4,4])
87
+ assert @loops.edges.include?(MultiArc[1,2])
88
+ assert @loops.edges.include?(MultiArc[2,3])
89
+ assert !@loops.edges.include?(MultiArc[1,3])
90
+ assert @loops.edge?(2,3)
91
+ assert !@loops.edge?(1,4)
92
+ assert @loops.edge?(MultiArc[1,2])
93
+ assert @loops.add_edge!(5,5).edge?(5,5)
94
+ assert_raise(ArgumentError) { @loops.remove_edge!(5,5) }
95
+
96
+ end
97
+
98
+ def test_vertices
99
+ assert_equal [1,2,3,4], @single.vertices.sort
100
+ assert_equal [1,2,3,4,5], @single.add_vertex!(5).sort
101
+ assert_equal [1,2,4,5], @single.remove_vertex!(3).sort
102
+ assert !@single.vertex?(3)
103
+ assert !@single.edge?(2,3)
104
+ assert !@single.edge?(3,4)
105
+ assert @single.add_vertex(:bogus).vertex?(:bogus)
106
+ assert !@single.add_vertex(:bogus).vertex?(nil)
107
+ assert !@single.vertex?(:bogus)
108
+ @single.add_vertex!(:real)
109
+ assert @single.vertex?(:real)
110
+ assert @single.add_edge(:here, :there).edge?(Arc[:here, :there])
111
+ assert !@single.edge?(Arc[:here, :there])
112
+ assert !@single.vertex?(:here)
113
+ assert !@single.vertex?(:there)
114
+ @single.add_edge!(:here, :there)
115
+ assert @single.edge?(Arc[:here, :there])
116
+ assert @single.vertex?(:here)
117
+ assert @single.vertex?(:there)
118
+ end
119
+
120
+ def test_properties
121
+ assert @single.directed?
122
+ assert @single.empty? == false
123
+ assert Digraph.new.empty? == true
124
+ assert_equal 4, @single.size
125
+ assert_equal 4, @dups.size
126
+ assert_equal 4, @loops.size
127
+ assert_equal 4, @single.num_vertices
128
+ assert_equal 4, @dups.num_vertices
129
+ assert_equal 3, @single.num_edges
130
+ assert_equal 5, @dups.num_edges
131
+ assert_equal 6, @loops.num_edges
132
+ assert @single.oriented?
133
+ @single.remove_vertex!(4)
134
+ assert @single.oriented?
135
+ assert !@loops.oriented?
136
+ @loops.remove_vertex!(4)
137
+ assert @loops.oriented?
138
+ end
139
+
140
+ def test_merge
141
+ @dups.merge(@single)
142
+ assert_equal 8, @dups.num_edges
143
+ assert_equal [1,2,3,4], @dups.vertices.sort
144
+ end
145
+
146
+ def test_operators
147
+ result = @single + Arc[3,2]
148
+ assert_equal 4, @single.size
149
+ assert_equal 3, @single.num_edges
150
+ assert_equal 4, result.size
151
+ assert_equal 4, result.num_edges
152
+
153
+ result = @single + 5
154
+ assert_equal 4, @single.size
155
+ assert_equal 3, @single.num_edges
156
+ assert_equal 5, result.size
157
+ assert_equal 3, result.num_edges
158
+
159
+ result = @single - Arc[4,4]
160
+ assert_equal 4, @single.size
161
+ assert_equal 3, @single.num_edges
162
+ assert_equal 4, result.size
163
+ assert_equal 3, result.num_edges
164
+
165
+ e = @loops.edges.detect{|e| e.source == 4 and e.target == 4}
166
+ result = @loops - e
167
+ assert_equal 4, @single.size
168
+ assert_equal 3, @single.num_edges
169
+ assert_equal 4, result.size
170
+ assert_equal 5, result.num_edges
171
+
172
+ result = @single - 4
173
+ assert_equal 4, @single.size
174
+ assert_equal 3, @single.num_edges
175
+ assert_equal 3, result.size
176
+ assert_equal 2, result.num_edges
177
+
178
+ @single << Arc[6,1]
179
+ assert_equal 5, @single.size
180
+ assert_equal 4, @single.num_edges
181
+ assert @single.edge?(6,1)
182
+ end
183
+
184
+ def test_reversal
185
+ reverse = @single.reversal
186
+ assert [1,2,3,4], reverse.vertices.sort
187
+ assert reverse.edge?(2,1)
188
+ assert reverse.edge?(3,2)
189
+ assert reverse.edge?(4,3)
190
+ assert !reverse.edge?(4,4)
191
+ assert 3, reverse.num_edges
192
+ reverse = @loops.reversal
193
+ assert reverse.edge?(4,4)
194
+ end
195
+
196
+ def test_complement
197
+ complement = @single.complement
198
+ assert_equal [1,2,3,4], complement.vertices.sort
199
+ assert !complement.edge?(1,1)
200
+ assert complement.edge?(1,3)
201
+ assert complement.edge?(1,4)
202
+ assert complement.edge?(2,1)
203
+ assert complement.edge?(2,4)
204
+ assert complement.edge?(3,1)
205
+ assert complement.edge?(3,2)
206
+ assert complement.edge?(4,1)
207
+ assert complement.edge?(4,2)
208
+ assert complement.edge?(4,3)
209
+ assert 9, complement.num_edges
210
+
211
+ complement = @loops.complement
212
+ assert_equal [1,2,3,4], complement.vertices.sort
213
+ assert complement.edge?(1,1)
214
+ assert complement.edge?(1,3)
215
+ assert complement.edge?(1,4)
216
+ assert complement.edge?(2,1)
217
+ assert complement.edge?(2,2)
218
+ assert complement.edge?(2,4)
219
+ assert complement.edge?(3,1)
220
+ assert complement.edge?(3,2)
221
+ assert complement.edge?(3,3)
222
+ assert complement.edge?(4,1)
223
+ assert complement.edge?(4,2)
224
+ assert complement.edge?(4,3)
225
+ assert 12, complement.num_edges
226
+ end
227
+
228
+ def test_induced_subgraph
229
+ induced = @single.induced_subgraph([1,2])
230
+ assert [1,2], induced.vertices.sort
231
+ assert induced.edge?(1,2)
232
+ assert 1, induced.num_edges
233
+ end
234
+
235
+ def test_include
236
+ assert @single.include?(4)
237
+ assert @dups.include?(4)
238
+ assert !@dups.include?(5)
239
+ assert !@single.include?(5)
240
+ assert @single.include?(Arc[1,2])
241
+ assert @dups.include?(Arc[1,2])
242
+ end
243
+
244
+ def test_adjacent
245
+
246
+ assert @single.adjacent?(2, Arc[1,2])
247
+ assert_equal [2], @single.adjacent(1)
248
+
249
+ assert_equal [Arc[1,2]], @single.adjacent(1, :type=>:edges)
250
+ assert_equal [Arc[1,2]], @single.adjacent(1, :type=>:edges, :direction=> :out)
251
+ assert_equal [Arc[1,2]], @single.adjacent(2, :type=>:edges, :direction=> :in)
252
+ assert_equal [Arc[1,2],Arc[2,3]], @single.adjacent(2, :type=>:edges, :direction=> :all).sort
253
+
254
+ [[{},1], [{:direction => :out},1], [{:direction => :in},2]].each do |h,v|
255
+ adj = @dups.adjacent(v, h.merge(:type=>:edges))
256
+ assert_equal 2, adj.size
257
+ adj.each {|e| assert e.source == 1; assert e.target == 2}
258
+ end
259
+
260
+ adj = @dups.adjacent(2, {:type=>:edges,:direction=>:all})
261
+ assert_equal 4, adj.size
262
+ adj.each do |e|
263
+ assert((e.source==1 and e.target==2) ||
264
+ (e.source==2 and e.target==3))
265
+ end
266
+
267
+ assert_equal [2], @single.adjacent(1, :type=>:vertices)
268
+ assert_equal [2], @single.adjacent(1, :type=>:vertices, :direction=> :out)
269
+ assert_equal [1], @single.adjacent(2, :type=>:vertices, :direction=> :in)
270
+ assert_equal [1,3], @single.adjacent(2, :type=>:vertices, :direction=> :all)
271
+
272
+ assert_equal [3], @single.adjacent(Arc[2,3], :type=>:vertices)
273
+ assert_equal [3], @single.adjacent(Arc[2,3], :type=>:vertices, :direction=> :out)
274
+ assert_equal [2], @single.adjacent(Arc[2,3], :type=>:vertices, :direction=> :in)
275
+ assert_equal [2,3], @single.adjacent(Arc[2,3], :type=>:vertices, :direction=> :all)
276
+
277
+ assert_equal [Arc[3,4]], @single.adjacent(Arc[2,3], :type=>:edges)
278
+ assert_equal [Arc[3,4]], @single.adjacent(Arc[2,3], :type=>:edges, :direction=> :out)
279
+ assert_equal [Arc[1,2]], @single.adjacent(Arc[2,3], :type=>:edges, :direction=> :in)
280
+ assert_equal [Arc[1,2],Arc[3,4]], @single.adjacent(Arc[2,3], :type=>:edges, :direction=> :all).sort
281
+
282
+ assert_equal [MultiArc[3,4]], @dups.adjacent(MultiArc[2,3], :type=>:edges)
283
+ assert_equal [MultiArc[3,4]], @dups.adjacent(MultiArc[2,3], :type=>:edges, :direction=> :out)
284
+ assert_equal [MultiArc[1,2]]*2, @dups.adjacent(MultiArc[2,3], :type=>:edges, :direction=> :in)
285
+ assert_equal ([MultiArc[1,2]]*2+[MultiArc[3,4]]), @dups.adjacent(MultiArc[2,3], :type=>:edges, :direction=> :all).sort
286
+ end
287
+
288
+ def test_neighborhood
289
+ assert_equal [2], @single.neighborhood(1).sort
290
+ assert_equal [1,3], @single.neighborhood(2).sort
291
+ assert_equal [Arc[1,2], Arc[3,4]], @single.neighborhood(Arc[2,3]).sort
292
+ end
293
+
294
+ def test_degree
295
+ assert_equal 0, @single.in_degree(1)
296
+ assert_equal 1, @single.in_degree(2)
297
+ assert_equal 1, @single.in_degree(4)
298
+ assert_equal 3, @loops.degree(4)
299
+ assert_equal 2, @loops.in_degree(4)
300
+ assert_equal 1, @single.out_degree(1)
301
+ assert_equal 1, @single.out_degree(2)
302
+ assert_equal 0, @single.out_degree(4)
303
+ assert_equal 1, @loops.out_degree(4)
304
+ assert_equal 0, @single.add_vertex!(6).out_degree(6)
305
+ assert_equal 0, @single.add_vertex!(7).in_degree(7)
306
+ assert_equal 1, @single.add_edge!(4,2).out_degree(4)
307
+ assert_equal 2, @loops.add_edge!(4,2).out_degree(4)
308
+ assert_equal 2, @single.in_degree(2)
309
+
310
+ assert_equal 0, @single.min_in_degree
311
+ assert_equal 2, @single.max_in_degree
312
+ assert_equal 0, @single.min_out_degree
313
+ assert_equal 1, @single.max_out_degree
314
+
315
+ assert_equal 0, @loops.min_in_degree
316
+ assert_equal 2, @loops.max_in_degree
317
+ assert_equal 1, @loops.min_out_degree
318
+ assert_equal 2, @loops.max_out_degree
319
+ assert_equal 4, @loops.degree(2)
320
+ assert_equal 1, @single.degree(1)
321
+ assert !@loops.regular?
322
+ assert !@single.regular?
323
+ assert !@dups.regular?
324
+ end
325
+
326
+ def test_include
327
+ assert @single.include?(2)
328
+ assert !@single.include?(23)
329
+ assert @single.include?(Arc[1,2])
330
+ assert !@single.include?(Arc[1,4])
331
+ end
332
+
333
+ end