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