plexus 0.5.4 → 0.5.5
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/Gemfile +3 -0
- data/LICENSE +37 -0
- data/README.md +208 -0
- data/Rakefile +25 -0
- data/lib/plexus.rb +90 -0
- data/lib/plexus/adjacency_graph.rb +225 -0
- data/lib/plexus/arc.rb +60 -0
- data/lib/plexus/arc_number.rb +50 -0
- data/lib/plexus/biconnected.rb +84 -0
- data/lib/plexus/chinese_postman.rb +91 -0
- data/lib/plexus/classes/graph_classes.rb +28 -0
- data/lib/plexus/common.rb +63 -0
- data/lib/plexus/comparability.rb +63 -0
- data/lib/plexus/directed_graph.rb +78 -0
- data/lib/plexus/directed_graph/algorithms.rb +95 -0
- data/lib/plexus/directed_graph/distance.rb +167 -0
- data/lib/plexus/dot.rb +94 -0
- data/lib/plexus/edge.rb +38 -0
- data/lib/plexus/ext.rb +79 -0
- data/lib/plexus/graph.rb +628 -0
- data/lib/plexus/graph_api.rb +35 -0
- data/lib/plexus/labels.rb +112 -0
- data/lib/plexus/maximum_flow.rb +77 -0
- data/lib/plexus/ruby_compatibility.rb +17 -0
- data/lib/plexus/search.rb +510 -0
- data/lib/plexus/strong_components.rb +93 -0
- data/lib/plexus/support/support.rb +9 -0
- data/lib/plexus/undirected_graph.rb +56 -0
- data/lib/plexus/undirected_graph/algorithms.rb +90 -0
- data/lib/plexus/version.rb +6 -0
- data/spec/biconnected_spec.rb +27 -0
- data/spec/chinese_postman_spec.rb +27 -0
- data/spec/community_spec.rb +44 -0
- data/spec/complement_spec.rb +27 -0
- data/spec/digraph_distance_spec.rb +121 -0
- data/spec/digraph_spec.rb +339 -0
- data/spec/dot_spec.rb +48 -0
- data/spec/edge_spec.rb +158 -0
- data/spec/inspection_spec.rb +38 -0
- data/spec/multi_edge_spec.rb +32 -0
- data/spec/neighborhood_spec.rb +36 -0
- data/spec/properties_spec.rb +146 -0
- data/spec/search_spec.rb +227 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +59 -0
- data/spec/strong_components_spec.rb +61 -0
- data/spec/triangulated_spec.rb +125 -0
- data/spec/undirected_graph_spec.rb +220 -0
- data/vendor/priority-queue/CHANGELOG +33 -0
- data/vendor/priority-queue/Makefile +140 -0
- data/vendor/priority-queue/README +133 -0
- data/vendor/priority-queue/benchmark/dijkstra.rb +171 -0
- data/vendor/priority-queue/compare_comments.rb +49 -0
- data/vendor/priority-queue/doc/c-vs-rb.png +0 -0
- data/vendor/priority-queue/doc/compare_big.gp +14 -0
- data/vendor/priority-queue/doc/compare_big.png +0 -0
- data/vendor/priority-queue/doc/compare_small.gp +15 -0
- data/vendor/priority-queue/doc/compare_small.png +0 -0
- data/vendor/priority-queue/doc/results.csv +37 -0
- data/vendor/priority-queue/ext/priority_queue/CPriorityQueue/extconf.rb +2 -0
- data/vendor/priority-queue/ext/priority_queue/CPriorityQueue/priority_queue.c +947 -0
- data/vendor/priority-queue/lib/priority_queue.rb +14 -0
- data/vendor/priority-queue/lib/priority_queue/c_priority_queue.rb +1 -0
- data/vendor/priority-queue/lib/priority_queue/poor_priority_queue.rb +46 -0
- data/vendor/priority-queue/lib/priority_queue/ruby_priority_queue.rb +526 -0
- data/vendor/priority-queue/priority_queue.so +0 -0
- data/vendor/priority-queue/setup.rb +1551 -0
- data/vendor/priority-queue/test/priority_queue_test.rb +371 -0
- data/vendor/rdot.rb +360 -0
- metadata +100 -10
data/Gemfile
ADDED
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.
|
data/README.md
ADDED
@@ -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
|
+
|
data/Rakefile
ADDED
@@ -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
|
data/lib/plexus.rb
ADDED
@@ -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
|