plexus 0.5.4 → 0.5.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/Gemfile +3 -0
  2. data/LICENSE +37 -0
  3. data/README.md +208 -0
  4. data/Rakefile +25 -0
  5. data/lib/plexus.rb +90 -0
  6. data/lib/plexus/adjacency_graph.rb +225 -0
  7. data/lib/plexus/arc.rb +60 -0
  8. data/lib/plexus/arc_number.rb +50 -0
  9. data/lib/plexus/biconnected.rb +84 -0
  10. data/lib/plexus/chinese_postman.rb +91 -0
  11. data/lib/plexus/classes/graph_classes.rb +28 -0
  12. data/lib/plexus/common.rb +63 -0
  13. data/lib/plexus/comparability.rb +63 -0
  14. data/lib/plexus/directed_graph.rb +78 -0
  15. data/lib/plexus/directed_graph/algorithms.rb +95 -0
  16. data/lib/plexus/directed_graph/distance.rb +167 -0
  17. data/lib/plexus/dot.rb +94 -0
  18. data/lib/plexus/edge.rb +38 -0
  19. data/lib/plexus/ext.rb +79 -0
  20. data/lib/plexus/graph.rb +628 -0
  21. data/lib/plexus/graph_api.rb +35 -0
  22. data/lib/plexus/labels.rb +112 -0
  23. data/lib/plexus/maximum_flow.rb +77 -0
  24. data/lib/plexus/ruby_compatibility.rb +17 -0
  25. data/lib/plexus/search.rb +510 -0
  26. data/lib/plexus/strong_components.rb +93 -0
  27. data/lib/plexus/support/support.rb +9 -0
  28. data/lib/plexus/undirected_graph.rb +56 -0
  29. data/lib/plexus/undirected_graph/algorithms.rb +90 -0
  30. data/lib/plexus/version.rb +6 -0
  31. data/spec/biconnected_spec.rb +27 -0
  32. data/spec/chinese_postman_spec.rb +27 -0
  33. data/spec/community_spec.rb +44 -0
  34. data/spec/complement_spec.rb +27 -0
  35. data/spec/digraph_distance_spec.rb +121 -0
  36. data/spec/digraph_spec.rb +339 -0
  37. data/spec/dot_spec.rb +48 -0
  38. data/spec/edge_spec.rb +158 -0
  39. data/spec/inspection_spec.rb +38 -0
  40. data/spec/multi_edge_spec.rb +32 -0
  41. data/spec/neighborhood_spec.rb +36 -0
  42. data/spec/properties_spec.rb +146 -0
  43. data/spec/search_spec.rb +227 -0
  44. data/spec/spec.opts +4 -0
  45. data/spec/spec_helper.rb +59 -0
  46. data/spec/strong_components_spec.rb +61 -0
  47. data/spec/triangulated_spec.rb +125 -0
  48. data/spec/undirected_graph_spec.rb +220 -0
  49. data/vendor/priority-queue/CHANGELOG +33 -0
  50. data/vendor/priority-queue/Makefile +140 -0
  51. data/vendor/priority-queue/README +133 -0
  52. data/vendor/priority-queue/benchmark/dijkstra.rb +171 -0
  53. data/vendor/priority-queue/compare_comments.rb +49 -0
  54. data/vendor/priority-queue/doc/c-vs-rb.png +0 -0
  55. data/vendor/priority-queue/doc/compare_big.gp +14 -0
  56. data/vendor/priority-queue/doc/compare_big.png +0 -0
  57. data/vendor/priority-queue/doc/compare_small.gp +15 -0
  58. data/vendor/priority-queue/doc/compare_small.png +0 -0
  59. data/vendor/priority-queue/doc/results.csv +37 -0
  60. data/vendor/priority-queue/ext/priority_queue/CPriorityQueue/extconf.rb +2 -0
  61. data/vendor/priority-queue/ext/priority_queue/CPriorityQueue/priority_queue.c +947 -0
  62. data/vendor/priority-queue/lib/priority_queue.rb +14 -0
  63. data/vendor/priority-queue/lib/priority_queue/c_priority_queue.rb +1 -0
  64. data/vendor/priority-queue/lib/priority_queue/poor_priority_queue.rb +46 -0
  65. data/vendor/priority-queue/lib/priority_queue/ruby_priority_queue.rb +526 -0
  66. data/vendor/priority-queue/priority_queue.so +0 -0
  67. data/vendor/priority-queue/setup.rb +1551 -0
  68. data/vendor/priority-queue/test/priority_queue_test.rb +371 -0
  69. data/vendor/rdot.rb +360 -0
  70. metadata +100 -10
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,37 @@
1
+ Copyright (c) 2010 Jean-Denis Vauguet <jd@vauguet.fr>
2
+
3
+ Copyright (c) 2009 Bruce Williams
4
+
5
+ Copyright (c) 2007,2006 Shawn Patrick Garbett
6
+
7
+ Copyright (c) 2002,2004,2005 by Horst Duchene
8
+
9
+ Copyright (c) 2000,2001 Jeremy Siek, Indiana University (jsiek@osl.iu.edu)
10
+
11
+ All rights reserved.
12
+
13
+ Jeremy Siek was one of the principal developers of the Boost Graph library.
14
+ Since this work is derivative, his name is included in the copyright list.
15
+
16
+ Redistribution and use in source and binary forms, with or without modification,
17
+ are permitted provided that the following conditions are met:
18
+
19
+ * Redistributions of source code must retain the above copyright notice(s),
20
+ this list of conditions and the following disclaimer.
21
+ * Redistributions in binary form must reproduce the above copyright notice,
22
+ this list of conditions and the following disclaimer in the documentation
23
+ and/or other materials provided with the distribution.
24
+ * Neither the name of the Bruce Williams nor the names of its contributors
25
+ may be used to endorse or promote products derived from this software
26
+ without specific prior written permission.
27
+
28
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
29
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
32
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
34
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
35
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
36
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,208 @@
1
+ # Plexus (was Graphy). A framework for graph theory, graph data structures and associated algorithms.
2
+
3
+ Graph algorithms currently provided are:
4
+
5
+ * Topological Sort
6
+ * Strongly Connected Components
7
+ * Transitive Closure
8
+ * Rural Chinese Postman
9
+ * Biconnected
10
+
11
+ These are based on more general algorithm patterns:
12
+
13
+ * Breadth First Search
14
+ * Depth First Search
15
+ * A* Search
16
+ * Floyd-Warshall
17
+ * Best First Search
18
+ * Djikstra's Algorithm
19
+ * Lexicographic Search
20
+
21
+ ## A quick Tour
22
+
23
+ ### Arcs
24
+
25
+ There are two vertices bound classes, `Plexus::Arc` and `Plexus::Edge`. The
26
+ former defines directional edges, the latter undirected edges.
27
+
28
+ ### Vertices
29
+
30
+ Vertices can be any `Object`.
31
+
32
+ ### Graph Types
33
+
34
+ There are a number of different graph types, each of which provide
35
+ different features and constraints:
36
+
37
+ `Plexus::Digraph` and its alias `Plexus::DirectedGraph`:
38
+
39
+ * Single directed edges (arcs) between vertices
40
+ * Loops are forbidden
41
+
42
+ `Plexus::DirectedPseudoGraph`:
43
+
44
+ * Multiple directed edges (arcs) between vertices
45
+ * Loops are forbidden
46
+
47
+ `Plexus::DirectedMultiGraph`:
48
+
49
+ * Multiple directed edges (arcs) between vertices
50
+ * Loops on vertices
51
+
52
+ `Plexus::UndirectedGraph`, `Plexus::UndirectedPseudoGraph`, and
53
+ `Graph::UndirectedMultiGraph` are similar but all edges are undirected.
54
+
55
+ ### Data Structures
56
+
57
+ In order to modelize data structures, make use of the `Plexus::AdjacencyGraph`
58
+ module which provides a generalized adjacency list and an edge list adaptor.
59
+
60
+ The `Plexus::Digraph` class is the general purpose "swiss army knife" of graph
61
+ classes, most of the other classes are just modifications to this class.
62
+ It is optimized for efficient access to just the out-edges, fast vertex
63
+ insertion and removal at the cost of extra space overhead, etc.
64
+
65
+ ## Example Usage
66
+
67
+ Using IRB, first require the library:
68
+
69
+ ``` bash
70
+ require 'rubygems' # only if you are using ruby 1.8.x
71
+ require 'plexus'
72
+ ```
73
+
74
+ If you'd like to include all the classes in the current scope (so you
75
+ don't have to prefix with `Plexus::`), just:
76
+
77
+ ``` bash
78
+ include Plexus
79
+ ```
80
+
81
+ Let's play with the library a bit in IRB:
82
+
83
+ ``` bash
84
+ >> dg = Digraph[1,2, 2,3, 2,4, 4,5, 6,4, 1,6]
85
+ => Plexus::Digraph[[2, 3], [1, 6], [2, 4], [4, 5], [1, 2], [6, 4]]
86
+ ```
87
+
88
+ A few properties of the graph we just created:
89
+
90
+ ``` bash
91
+ >> dg.directed?
92
+ => true
93
+ >> dg.vertex?(4)
94
+ => true
95
+ >> dg.edge?(2,4)
96
+ => true
97
+ >> dg.edge?(4,2)
98
+ => false
99
+ >> dg.vertices
100
+ => [1, 2, 3, 4, 5, 6]
101
+ ```
102
+
103
+ Every object could be a vertex, even the class object `Object`:
104
+
105
+ ``` bash
106
+ >> dg.vertex?(Object)
107
+ => false
108
+
109
+ >> UndirectedGraph.new(dg).edges.sort.to_s
110
+ => "[Plexus::Edge[1,2,nil], Plexus::Edge[2,3,nil], Plexus::Edge[2,4,nil],
111
+ Plexus::Edge[4,5,nil], Plexus::Edge[1,6,nil], Plexus::Edge[6,4,nil]]"
112
+ ```
113
+
114
+ Add inverse edge `(4-2)` to directed graph:
115
+
116
+ ``` bash
117
+ >> dg.add_edge!(4,2)
118
+ => Plexus::DirectedGraph[Plexus::Arc[1,2,nil], Plexus::Arc[1,6,nil], Plexus::Arc[2,3,nil],
119
+ Plexus::Arc[2,4,nil], Plexus::Arc[4,5,nil], Plexus::Arc[4,2,nil],
120
+ Plexus::Arc[6,4,nil]]
121
+ ```
122
+
123
+ `(4-2) == (2-4)` in the undirected graph (4-2 doesn't show up):
124
+
125
+ ``` bash
126
+ >> UndirectedGraph.new(dg).edges.sort.to_s
127
+ => "[Plexus::Edge[1,2,nil], Plexus::Edge[2,3,nil], Plexus::Edge[2,4,nil],
128
+ Plexus::Edge[4,5,nil], Plexus::Edge[1,6,nil], Plexus::Edge[6,4,nil]]"
129
+ ```
130
+
131
+ `(4-2) != (2-4)` in directed graphs (both show up):
132
+
133
+ ``` bash
134
+ >> dg.edges.sort.to_s
135
+ => "[Plexus::Arc[1,2,nil], Plexus::Arc[1,6,nil], Plexus::Arc[2,3,nil],
136
+ Plexus::Arc[2,4,nil], Plexus::Arc[4,2,nil], Plexus::Arc[4,5,nil],
137
+ Plexus::Arc[6,4,nil]]"
138
+
139
+ >> dg.remove_edge! 4,2
140
+ => Plexus::DirectedGraph[Plexus::Arc[1,2,nil], Plexus::Arc[1,6,nil], Plexus::Arc[2,3,nil],
141
+ Plexus::Arc[2,4,nil], Plexus::Arc[4,5,nil], Plexus::Arc[6,4,nil]]
142
+ ```
143
+
144
+ Topological sorting is realized with an iterator:
145
+
146
+ ``` bash
147
+ >> dg.topsort
148
+ => [1, 6, 2, 4, 5, 3]
149
+ >> y = 0; dg.topsort { |v| y += v }; y
150
+ => 21
151
+ ```
152
+
153
+ You can use DOT to visualize the graph:
154
+
155
+ ``` bash
156
+ >> require 'plexus/dot'
157
+ >> dg.write_to_graphic_file('jpg','visualize')
158
+ ```
159
+
160
+ Here's an example showing the module inheritance hierarchy:
161
+
162
+ ``` bash
163
+ >> module_graph = Digraph.new
164
+ >> ObjectSpace.each_object(Module) do |m|
165
+ >> m.ancestors.each {|a| module_graph.add_edge!(m,a) if m != a}
166
+ >> end
167
+ >> gv = module_graph.vertices.select {|v| v.to_s.match(/Plexus/) }
168
+ >> module_graph.induced_subgraph(gv).write_to_graphic_file('jpg','module_graph')
169
+ ```
170
+
171
+ Look for more in the examples directory.
172
+
173
+ ## History
174
+
175
+ This library is based on [GRATR][1] by Shawn Garbett (itself a fork of
176
+ Horst Duchene's [RGL][2] library) which is heavily influenced by the [Boost][3]
177
+ Graph Library (BGL).
178
+
179
+ This fork attempts to modernize and extend the API and tests.
180
+
181
+ ## References
182
+
183
+ For more information on Graph Theory, you may want to read:
184
+
185
+ * the [documentation][3] for the Boost Graph Library
186
+ * [the Dictionary of Algorithms and Data Structures][4]
187
+
188
+ ## Credits
189
+
190
+ See CREDITS.markdown
191
+
192
+ ## TODO
193
+
194
+ See TODO.markdown
195
+
196
+ ## CHANGELOG
197
+
198
+ See CHANGELOG.markdown
199
+
200
+ ## License
201
+
202
+ [MIT License](http://en.wikipedia.org/wiki/MIT_License). See the LICENSE file.
203
+
204
+ [1]: http://gratr.rubyforge.org
205
+ [2]: http://rgl.rubyforge.org
206
+ [3]: http://www.boost.org/libs/graph/doc
207
+ [4]: http://www.nist.gov/dads/HTML/graph.html
208
+
@@ -0,0 +1,25 @@
1
+ # encoding: UTF-8
2
+ require 'rubygems'
3
+ begin
4
+ require 'bundler/setup'
5
+ rescue LoadError
6
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
+ end
8
+
9
+ require 'rake'
10
+ require 'rake/rdoctask'
11
+
12
+ require 'rspec/core'
13
+ require 'rspec/core/rake_task'
14
+
15
+ RSpec::Core::RakeTask.new(:spec)
16
+
17
+ task :default => :spec
18
+
19
+ Rake::RDocTask.new(:rdoc) do |rdoc|
20
+ rdoc.rdoc_dir = 'rdoc'
21
+ rdoc.title = 'Plexus'
22
+ rdoc.options << '--line-numbers' << '--inline-source'
23
+ rdoc.rdoc_files.include('README.rdoc')
24
+ rdoc.rdoc_files.include('lib/**/*.rb')
25
+ end
@@ -0,0 +1,90 @@
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
+ require 'set'
30
+
31
+ module Plexus
32
+ # Plexus internals: graph builders and additionnal behaviors
33
+ autoload :GraphAPI, 'plexus/graph_api'
34
+
35
+ autoload :GraphBuilder, 'plexus/graph'
36
+ autoload :AdjacencyGraphBuilder, 'plexus/adjacency_graph'
37
+
38
+ autoload :DirectedGraphBuilder, 'plexus/directed_graph'
39
+ autoload :DigraphBuilder, 'plexus/directed_graph'
40
+ autoload :DirectedPseudoGraphBuilder, 'plexus/directed_graph'
41
+ autoload :DirectedMultiGraphBuilder, 'plexus/directed_graph'
42
+
43
+ autoload :UndirectedGraphBuilder, 'plexus/undirected_graph'
44
+ autoload :UndirectedPseudoGraphBuilder, 'plexus/undirected_graph'
45
+ autoload :UndirectedMultiGraphBuilder, 'plexus/undirected_graph'
46
+
47
+ autoload :Arc, 'plexus/arc'
48
+ autoload :ArcNumber, 'plexus/arc_number'
49
+ autoload :Biconnected, 'plexus/biconnected'
50
+ autoload :ChinesePostman, 'plexus/chinese_postman'
51
+ autoload :Common, 'plexus/common'
52
+ autoload :Comparability, 'plexus/comparability'
53
+
54
+ autoload :Dot, 'plexus/dot'
55
+ autoload :Edge, 'plexus/edge'
56
+ autoload :Labels, 'plexus/labels'
57
+ autoload :MaximumFlow, 'plexus/maximum_flow'
58
+ #autoload :Rdot, 'plexus/dot'
59
+ autoload :Search, 'plexus/search'
60
+ autoload :StrongComponents, 'plexus/strong_components'
61
+
62
+ # Plexus classes
63
+ autoload :AdjacencyGraph, 'plexus/classes/graph_classes'
64
+ autoload :DirectedGraph, 'plexus/classes/graph_classes'
65
+ autoload :Digraph, 'plexus/classes/graph_classes'
66
+ autoload :DirectedPseudoGraph, 'plexus/classes/graph_classes'
67
+ autoload :DirectedMultiGraph, 'plexus/classes/graph_classes'
68
+ autoload :UndirectedGraph, 'plexus/classes/graph_classes'
69
+ autoload :UndirectedPseudoGraph, 'plexus/classes/graph_classes'
70
+ autoload :UndirectedMultiGraph, 'plexus/classes/graph_classes'
71
+
72
+ # ruby stdlib extensions
73
+ require 'plexus/ext'
74
+ # ruby 1.8.x/1.9.x compatibility
75
+ require 'plexus/ruby_compatibility'
76
+ end
77
+
78
+ # Vendored libraries
79
+
80
+ require 'pathname'
81
+ path = Pathname.new(__FILE__)
82
+ $LOAD_PATH.unshift(path + '../../vendor') # http://ruby.brian-amberg.de/priority-queue/
83
+ $LOAD_PATH.unshift(path + '../../vendor/priority-queue/lib')
84
+
85
+ require 'rdot'
86
+ require 'facets/hash'
87
+
88
+ require 'priority_queue/ruby_priority_queue'
89
+ PriorityQueue = RubyPriorityQueue
90
+
@@ -0,0 +1,225 @@
1
+ module Plexus
2
+
3
+ # This module provides the basic routines needed to implement the specialized builders:
4
+ # {DigraphBuilder}, {UndirectedGraphBuilder}, {DirectedPseudoGraphBuilder},
5
+ # {UndirectedPseudoGraphBuilder}, {DirectedMultiGraphBuilder} and {UndirectedMultiGraphBuilder}
6
+ # modules, each of them streamlining {AdjacencyGraphBuilder}'s behavior. Those
7
+ # implementations rely on the {GraphBuilder}, under the control of the {GraphAPI}.
8
+ module AdjacencyGraphBuilder
9
+
10
+ # Defines a useful `push` -> `add` alias for arrays.
11
+ class ArrayWithAdd < Array
12
+ alias add push
13
+ end
14
+
15
+ # This method is called by the specialized implementations
16
+ # upon graph creation.
17
+ #
18
+ # Initialization parameters can include:
19
+ #
20
+ # * an array of edges to add
21
+ # * one or several graphs to copy (will be merged if multiple)
22
+ # * `:parallel_edges` denotes that duplicate edges are allowed
23
+ # * `:loops denotes` that loops are allowed
24
+ #
25
+ # @param *params [Hash] the initialization parameters
26
+ #
27
+ def implementation_initialize(*params)
28
+ @vertex_dict = Hash.new
29
+ clear_all_labels
30
+
31
+ # FIXME: could definitely make use of the activesupport helper
32
+ # extract_options! and facets' reverse_merge! technique
33
+ # to handle parameters
34
+ args = (params.pop if params.last.is_a? Hash) || {}
35
+
36
+ # Basic configuration of adjacency.
37
+ @allow_loops = args[:loops] || false
38
+ @parallel_edges = args[:parallel_edges] || false
39
+ @edgelist_class = @parallel_edges ? ArrayWithAdd : Set
40
+ if @parallel_edges
41
+ @edge_number = Hash.new
42
+ @next_edge_number = 0
43
+ end
44
+
45
+ # Copy any given graph into this graph.
46
+ params.select { |p| p.is_a? Plexus::GraphBuilder }.each do |g|
47
+ g.edges.each do |e|
48
+ add_edge!(e)
49
+ edge_label_set(e, edge_label(e)) if edge_label(e)
50
+ end
51
+ g.vertices.each do |v|
52
+ add_vertex!(v)
53
+ vertex_label_set(v, vertex_label(v)) if vertex_label(v)
54
+ end
55
+ end
56
+
57
+ # Add all array edges specified.
58
+ params.select { |p| p.is_a? Array }.each do |a|
59
+ 0.step(a.size-1, 2) { |i| add_edge!(a[i], a[i+1]) }
60
+ end
61
+ end
62
+
63
+ # Returns true if v is a vertex of this Graph
64
+ # (an "O(1)" implementation of `vertex?`).
65
+ #
66
+ # @param [vertex] v
67
+ # @return [Boolean]
68
+ def vertex?(v)
69
+ @vertex_dict.has_key?(v)
70
+ end
71
+
72
+ # Returns true if [u,v] or u is an {Arc}
73
+ # (an "O(1)" implementation of `edge?`).
74
+ #
75
+ # @param [vertex] u
76
+ # @param [vertex] v (nil)
77
+ # @return [Boolean]
78
+ def edge?(u, v = nil)
79
+ u, v = u.source, u.target if u.is_a? Plexus::Arc
80
+ vertex?(u) and @vertex_dict[u].include?(v)
81
+ end
82
+
83
+ # Adds a vertex to the graph with an optional label.
84
+ #
85
+ # @param [vertex(Object)] vertex any kind of Object can act as a vertex
86
+ # @param [#to_s] label (nil)
87
+ def add_vertex!(vertex, label = nil)
88
+ @vertex_dict[vertex] ||= @edgelist_class.new
89
+ self[vertex] = label if label
90
+ self
91
+ end
92
+
93
+ # Adds an edge to the graph.
94
+ #
95
+ # Can be called in two basic ways, label is optional:
96
+ # @overload add_edge!(arc)
97
+ # Using an explicit {Arc}
98
+ # @param [Arc] arc an {Arc}[source, target, label = nil] object
99
+ # @return [AdjacencyGraph] `self`
100
+ # @overload add_edge!(source, target, label = nil)
101
+ # Using vertices to define an arc implicitly
102
+ # @param [vertex] u
103
+ # @param [vertex] v (nil)
104
+ # @param [Label] l (nil)
105
+ # @param [Integer] n (nil) {Arc arc} number of `(u, v)` (if `nil` and if `u`
106
+ # has an {ArcNumber}, then it will be used)
107
+ # @return [AdjacencyGraph] `self`
108
+ #
109
+ def add_edge!(u, v = nil, l = nil, n = nil)
110
+ n = u.number if u.class.include? ArcNumber and n.nil?
111
+ u, v, l = u.source, u.target, u.label if u.is_a? Plexus::Arc
112
+
113
+ return self if not @allow_loops and u == v
114
+
115
+ n = (@next_edge_number += 1) unless n if @parallel_edges
116
+ add_vertex!(u)
117
+ add_vertex!(v)
118
+ @vertex_dict[u].add(v)
119
+ (@edge_number[u] ||= @edgelist_class.new).add(n) if @parallel_edges
120
+
121
+ unless directed?
122
+ @vertex_dict[v].add(u)
123
+ (@edge_number[v] ||= @edgelist_class.new).add(n) if @parallel_edges
124
+ end
125
+
126
+ self[n ? edge_class[u,v,n] : edge_class[u,v]] = l if l
127
+ self
128
+ end
129
+
130
+ # Removes a given vertex from the graph.
131
+ #
132
+ # @param [vertex] v
133
+ # @return [AdjacencyGraph] `self`
134
+ def remove_vertex!(v)
135
+ # FIXME This is broken for multi graphs
136
+ @vertex_dict.delete(v)
137
+ @vertex_dict.each_value { |adjList| adjList.delete(v) }
138
+ @vertex_dict.keys.each do |u|
139
+ delete_label(edge_class[u,v])
140
+ delete_label(edge_class[v,u])
141
+ end
142
+ delete_label(v)
143
+ self
144
+ end
145
+
146
+ # Removes an edge from the graph.
147
+ #
148
+ # Can be called with both source and target as vertex,
149
+ # or with source and object of {Plexus::Arc} derivation.
150
+ #
151
+ # @overload remove_edge!(a)
152
+ # @param [Plexus::Arc] a
153
+ # @return [AdjacencyGraph] `self`
154
+ # @raise [ArgumentError] if parallel edges are enabled
155
+ # @overload remove_edge!(u, v)
156
+ # @param [vertex] u
157
+ # @param [vertex] v
158
+ # @return [AdjacencyGraph] `self`
159
+ # @raise [ArgumentError] if parallel edges are enabled and the {ArcNumber} of `u` is zero
160
+ def remove_edge!(u, v = nil)
161
+ unless u.is_a? Plexus::Arc
162
+ raise ArgumentError if @parallel_edges
163
+ u = edge_class[u,v]
164
+ end
165
+ raise ArgumentError if @parallel_edges and (u.number || 0) == 0
166
+ return self unless @vertex_dict[u.source] # It doesn't exist
167
+ delete_label(u) # Get rid of label
168
+ if @parallel_edges
169
+ index = @edge_number[u.source].index(u.number)
170
+ raise NoArcError unless index
171
+ @vertex_dict[u.source].delete_at(index)
172
+ @edge_number[u.source].delete_at(index)
173
+ else
174
+ @vertex_dict[u.source].delete(u.target)
175
+ end
176
+ self
177
+ end
178
+
179
+ # Returns an array of vertices that the graph has.
180
+ #
181
+ # @return [Array] graph's vertices
182
+ def vertices
183
+ @vertex_dict.keys
184
+ end
185
+
186
+ # Returns an array of edges, most likely of class {Arc} or {Edge} depending
187
+ # upon the type of graph.
188
+ #
189
+ # @return [Array]
190
+ def edges
191
+ @vertex_dict.keys.inject(Set.new) do |a,v|
192
+ if @parallel_edges and @edge_number[v]
193
+ @vertex_dict[v].zip(@edge_number[v]).each do |w|
194
+ s, t, n = v, w[0], w[1]
195
+ a.add(edge_class[s, t, n, edge_label(s, t, n)])
196
+ end
197
+ else
198
+ @vertex_dict[v].each do |w|
199
+ a.add(edge_class[v, w, edge_label(v, w)])
200
+ end
201
+ end
202
+ a
203
+ end.to_a
204
+ end
205
+
206
+ # FIXME, EFFED UP (but why?)
207
+ #
208
+ # @fixme
209
+ def adjacent(x, options = {})
210
+ options[:direction] ||= :out
211
+ if !x.is_a?(Plexus::Arc) and (options[:direction] == :out || !directed?)
212
+ if options[:type] == :edges
213
+ i = -1
214
+ @parallel_edges ?
215
+ @vertex_dict[x].map { |v| e = edge_class[x, v, @edge_number[x][i+=1]]; e.label = self[e]; e } :
216
+ @vertex_dict[x].map { |v| e = edge_class[x, v]; e.label = self[e]; e }
217
+ else
218
+ @vertex_dict[x].to_a
219
+ end
220
+ else
221
+ graph_adjacent(x,options)
222
+ end
223
+ end
224
+ end
225
+ end