rgl 0.5.9 → 0.5.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ChangeLog +2 -2
- data/README.md +11 -11
- data/examples/canvas.rb +1 -1
- data/examples/graph.dot +971 -0
- data/examples/insel_der_tausend_gefahren.rb +1 -1
- data/examples/north/g.10.0.graphml +1 -1
- data/examples/north/g.10.1.graphml +1 -1
- data/examples/north/g.10.11.graphml +1 -1
- data/examples/north/g.10.12.graphml +1 -1
- data/examples/north/g.10.13.graphml +1 -1
- data/examples/north/g.10.14.graphml +1 -1
- data/examples/north/g.10.15.graphml +1 -1
- data/examples/north/g.10.16.graphml +1 -1
- data/examples/north/g.10.17.graphml +1 -1
- data/examples/north/g.10.19.graphml +1 -1
- data/examples/north/g.10.2.graphml +1 -1
- data/examples/north/g.10.20.graphml +1 -1
- data/examples/north/g.10.22.graphml +1 -1
- data/examples/north/g.10.24.graphml +1 -1
- data/examples/north/g.10.25.graphml +1 -1
- data/examples/north/g.10.27.graphml +1 -1
- data/examples/north/g.10.28.graphml +1 -1
- data/examples/north/g.10.29.graphml +1 -1
- data/examples/north/g.10.3.graphml +1 -1
- data/examples/north/g.10.30.graphml +1 -1
- data/examples/north/g.10.31.graphml +1 -1
- data/examples/north/g.10.34.graphml +1 -1
- data/examples/north/g.10.37.graphml +1 -1
- data/examples/north/g.10.38.graphml +1 -1
- data/examples/north/g.10.39.graphml +1 -1
- data/examples/north/g.10.4.graphml +1 -1
- data/examples/north/g.10.40.graphml +1 -1
- data/examples/north/g.10.41.graphml +1 -1
- data/examples/north/g.10.42.graphml +1 -1
- data/examples/north/g.10.45.graphml +1 -1
- data/examples/north/g.10.46.graphml +1 -1
- data/examples/north/g.10.5.graphml +1 -1
- data/examples/north/g.10.50.graphml +1 -1
- data/examples/north/g.10.56.graphml +1 -1
- data/examples/north/g.10.57.graphml +1 -1
- data/examples/north/g.10.58.graphml +1 -1
- data/examples/north/g.10.6.graphml +1 -1
- data/examples/north/g.10.60.graphml +1 -1
- data/examples/north/g.10.61.graphml +1 -1
- data/examples/north/g.10.62.graphml +1 -1
- data/examples/north/g.10.68.graphml +1 -1
- data/examples/north/g.10.69.graphml +1 -1
- data/examples/north/g.10.7.graphml +1 -1
- data/examples/north/g.10.70.graphml +1 -1
- data/examples/north/g.10.71.graphml +1 -1
- data/examples/north/g.10.72.graphml +1 -1
- data/examples/north/g.10.74.graphml +1 -1
- data/examples/north/g.10.75.graphml +1 -1
- data/examples/north/g.10.78.graphml +1 -1
- data/examples/north/g.10.79.graphml +1 -1
- data/examples/north/g.10.8.graphml +1 -1
- data/examples/north/g.10.80.graphml +1 -1
- data/examples/north/g.10.82.graphml +1 -1
- data/examples/north/g.10.83.graphml +1 -1
- data/examples/north/g.10.85.graphml +1 -1
- data/examples/north/g.10.86.graphml +1 -1
- data/examples/north/g.10.88.graphml +1 -1
- data/examples/north/g.10.89.graphml +1 -1
- data/examples/north/g.10.9.graphml +1 -1
- data/examples/north/g.10.90.graphml +1 -1
- data/examples/north/g.10.91.graphml +1 -1
- data/examples/north/g.10.92.graphml +1 -1
- data/examples/north/g.10.93.graphml +1 -1
- data/examples/north/g.10.94.graphml +1 -1
- data/examples/north/g.12.8.graphml +1 -1
- data/examples/north/g.14.9.graphml +1 -1
- data/examples/north.rb +1 -1
- data/examples/rdep-rgl.rb +3 -3
- data/lib/rgl/adjacency.rb +43 -51
- data/lib/rgl/base.rb +71 -60
- data/lib/rgl/bellman_ford.rb +4 -3
- data/lib/rgl/bidirectional.rb +2 -2
- data/lib/rgl/bipartite.rb +1 -1
- data/lib/rgl/condensation.rb +3 -3
- data/lib/rgl/connected_components.rb +6 -6
- data/lib/rgl/dot.rb +5 -7
- data/lib/rgl/edmonds_karp.rb +7 -2
- data/lib/rgl/graph_iterator.rb +4 -2
- data/lib/rgl/graph_visitor.rb +16 -14
- data/lib/rgl/graph_wrapper.rb +3 -2
- data/lib/rgl/graphxml.rb +4 -4
- data/lib/rgl/implicit.rb +35 -35
- data/lib/rgl/mutable.rb +7 -7
- data/lib/rgl/path_builder.rb +3 -2
- data/lib/rgl/prim.rb +3 -1
- data/lib/rgl/rdot.rb +7 -7
- data/lib/rgl/topsort.rb +8 -7
- data/lib/rgl/transitivity.rb +6 -6
- data/lib/rgl/traversal.rb +47 -47
- data/test/traversal_test.rb +1 -1
- metadata +4 -3
data/lib/rgl/dot.rb
CHANGED
@@ -1,12 +1,10 @@
|
|
1
1
|
# dot.rb
|
2
2
|
#
|
3
|
-
# $Id$
|
4
|
-
#
|
5
3
|
# Minimal Dot support, based on Dave Thomas's dot module (included in rdoc).
|
6
4
|
# rdot.rb is a modified version which also contains support for undirected
|
7
5
|
# graphs.
|
8
6
|
#
|
9
|
-
# You need to have [GraphViz](
|
7
|
+
# You need to have [GraphViz](https://www.graphviz.org) installed, because the
|
10
8
|
# functions in this modul execute the GraphViz executables _dot_ or _dotty_.
|
11
9
|
|
12
10
|
require 'rgl/rdot'
|
@@ -24,8 +22,8 @@ module RGL
|
|
24
22
|
v
|
25
23
|
end
|
26
24
|
|
27
|
-
# Return a
|
28
|
-
# undirected Graph. _params_ can contain any graph property specified in
|
25
|
+
# Return a {DOT::Digraph} for directed graphs or a {DOT::Graph} for an
|
26
|
+
# undirected {Graph}. _params_ can contain any graph property specified in
|
29
27
|
# rdot.rb.
|
30
28
|
#
|
31
29
|
def to_dot_graph(params = {})
|
@@ -67,7 +65,7 @@ module RGL
|
|
67
65
|
s << to_dot_graph(params).to_s << "\n"
|
68
66
|
end
|
69
67
|
|
70
|
-
# Call dotty[
|
68
|
+
# Call dotty[https://www.graphviz.org] for the graph which is written to the
|
71
69
|
# file 'graph.dot' in the current directory.
|
72
70
|
#
|
73
71
|
def dotty(params = {})
|
@@ -80,7 +78,7 @@ module RGL
|
|
80
78
|
end
|
81
79
|
end
|
82
80
|
|
83
|
-
# Use dot[
|
81
|
+
# Use dot[https://www.graphviz.org] to create a graphical representation of
|
84
82
|
# the graph. Returns the filename of the graphics file.
|
85
83
|
#
|
86
84
|
def write_to_graphic_file(fmt='png', dotfile="graph", options={})
|
data/lib/rgl/edmonds_karp.rb
CHANGED
@@ -3,6 +3,9 @@ require 'rgl/traversal'
|
|
3
3
|
|
4
4
|
module RGL
|
5
5
|
|
6
|
+
# Implements {https://en.wikipedia.org/wiki/Edmonds%E2%80%93Karp_algorithm
|
7
|
+
# Edmonds–Karp algorithm}.
|
8
|
+
# @see Graph#maximum_flow
|
6
9
|
class EdmondsKarpAlgorithm
|
7
10
|
|
8
11
|
# Initializes Edmonds-Karp algorithm for a _graph_ with provided edges capacities map.
|
@@ -17,9 +20,10 @@ module RGL
|
|
17
20
|
|
18
21
|
# Finds the maximum flow from the _source_ to the _sink_ in the graph.
|
19
22
|
#
|
20
|
-
# Returns flows map as a hash that maps each edge of the graph to a flow
|
21
|
-
# the maximum total flow.
|
23
|
+
# Returns flows map as a hash that maps each edge of the graph to a flow
|
24
|
+
# through that edge that is required to reach the maximum total flow.
|
22
25
|
#
|
26
|
+
# @return [Hash]
|
23
27
|
def maximum_flow(source, sink)
|
24
28
|
raise ArgumentError.new("source and sink can't be equal") if source == sink
|
25
29
|
|
@@ -127,6 +131,7 @@ module RGL
|
|
127
131
|
# Raises ArgumentError if a reverse edge is missing, edge capacity is missing, an edge has negative capacity, or a
|
128
132
|
# reverse edge has positive capacity.
|
129
133
|
#
|
134
|
+
# @return [Hash]
|
130
135
|
def maximum_flow(edge_capacities_map, source, sink)
|
131
136
|
EdmondsKarpAlgorithm.new(self, edge_capacities_map).maximum_flow(source, sink)
|
132
137
|
end
|
data/lib/rgl/graph_iterator.rb
CHANGED
@@ -5,15 +5,17 @@ require 'rgl/graph_wrapper'
|
|
5
5
|
module RGL
|
6
6
|
|
7
7
|
# A GraphIterator is the abstract basis for all Iterators on graphs.
|
8
|
-
# Each graph iterator should implement the protocol defined in module
|
8
|
+
# Each graph iterator should implement the protocol defined in module
|
9
|
+
# {https://rubydoc.info/github/monora/stream Stream}.
|
9
10
|
#
|
10
11
|
module GraphIterator
|
11
12
|
include Stream
|
12
13
|
include GraphWrapper
|
13
14
|
|
15
|
+
# @return [int]
|
14
16
|
def length
|
15
17
|
inject(0) { |sum| sum + 1 }
|
16
18
|
end
|
17
19
|
end
|
18
20
|
|
19
|
-
end # RGL
|
21
|
+
end # RGL
|
data/lib/rgl/graph_visitor.rb
CHANGED
@@ -2,8 +2,8 @@ require 'rgl/graph_wrapper'
|
|
2
2
|
|
3
3
|
module RGL
|
4
4
|
|
5
|
-
# Module GraphVisitor defines the
|
6
|
-
#
|
5
|
+
# Module GraphVisitor defines the
|
6
|
+
# {https://www.boost.org/libs/graph/doc/visitor_concepts.html BGL Visitor Concepts}.
|
7
7
|
#
|
8
8
|
# Visitors provide a mechanism for extending an algorithm (i.e., for
|
9
9
|
# customizing what is done at each step of the algorithm). They allow users
|
@@ -12,7 +12,7 @@ module RGL
|
|
12
12
|
# Graph algorithms typically have multiple event points where one may want to
|
13
13
|
# insert a call-back. Therefore, visitors have several methods that
|
14
14
|
# correspond to the various event points. Each algorithm has a different
|
15
|
-
# set of event points. The following are common to both DFS and BFS search
|
15
|
+
# set of event points. The following are common to both DFS and BFS search:
|
16
16
|
#
|
17
17
|
# * examine_vertex
|
18
18
|
# * examine_edge
|
@@ -21,25 +21,26 @@ module RGL
|
|
21
21
|
# * forward_edge
|
22
22
|
# * finish_vertex
|
23
23
|
#
|
24
|
-
# These methods are all
|
25
|
-
# using the methods set_*_event_handler
|
24
|
+
# These methods are all named +handle_*+ and can be set to appropriate blocks,
|
25
|
+
# using the methods +set_*_event_handler+, which are defined for each event
|
26
26
|
# mentioned above.
|
27
27
|
#
|
28
|
-
# As an alternative, you can also override the handle_
|
28
|
+
# As an alternative, you can also override the +handle_*+ methods in a
|
29
29
|
# subclass, to configure the algorithm (as an example, see TarjanSccVisitor).
|
30
30
|
#
|
31
31
|
# During a graph traversal, vertices are *colored* using the colors :GRAY
|
32
32
|
# (when waiting) and :BLACK when finished. All other vertices are :WHITE.
|
33
|
-
# The color_map is also maintained in the visitor.
|
33
|
+
# The +color_map+ is also maintained in the visitor.
|
34
34
|
#
|
35
35
|
module GraphVisitor
|
36
36
|
|
37
37
|
include GraphWrapper
|
38
38
|
|
39
|
+
# @return [Hash] a map which store the colors for each vertex
|
39
40
|
attr_reader :color_map
|
40
41
|
|
41
42
|
# Create a new GraphVisitor on _graph_.
|
42
|
-
#
|
43
|
+
# @param [Graph] graph
|
43
44
|
def initialize(graph)
|
44
45
|
super(graph)
|
45
46
|
reset
|
@@ -59,7 +60,7 @@ module RGL
|
|
59
60
|
|
60
61
|
# Shall we follow the edge (u,v); i.e. v has color :WHITE
|
61
62
|
#
|
62
|
-
def follow_edge?(u, v)
|
63
|
+
def follow_edge?(u, v)
|
63
64
|
@color_map[v] == :WHITE
|
64
65
|
end
|
65
66
|
|
@@ -67,10 +68,10 @@ module RGL
|
|
67
68
|
# vertex to the start vertex.
|
68
69
|
#
|
69
70
|
# This is similar to BGLs
|
70
|
-
#
|
71
|
+
# {https://www.boost.org/libs/graph/doc/distance_recorder.html distance_recorder}.
|
71
72
|
#
|
72
|
-
# After the distance_map is attached, the visitor has a new method
|
73
|
-
# distance_to_root
|
73
|
+
# After the +distance_map+ is attached, the visitor has a new method
|
74
|
+
# +distance_to_root+, which answers the distance to the start vertex.
|
74
75
|
#
|
75
76
|
def attach_distance_map(map = Hash.new(0))
|
76
77
|
@distance_map = map
|
@@ -123,7 +124,8 @@ module RGL
|
|
123
124
|
extend ClassMethods # add class methods to GraphVisitor class itself
|
124
125
|
|
125
126
|
def self.included(base)
|
126
|
-
|
127
|
+
# when GraphVisitor is included into a class/module, add class methods as well
|
128
|
+
base.extend ClassMethods
|
127
129
|
end
|
128
130
|
|
129
131
|
def_event_handlers :examine_vertex,
|
@@ -135,4 +137,4 @@ module RGL
|
|
135
137
|
|
136
138
|
end # module GraphVisitor
|
137
139
|
|
138
|
-
end # module RGL
|
140
|
+
end # module RGL
|
data/lib/rgl/graph_wrapper.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
module RGL
|
2
2
|
|
3
|
-
module GraphWrapper
|
3
|
+
module GraphWrapper
|
4
4
|
|
5
|
+
# @return [Graph] the wrapped graph
|
5
6
|
attr_accessor :graph
|
6
7
|
|
7
8
|
# Creates a new GraphWrapper on _graph_.
|
@@ -12,4 +13,4 @@ module RGL
|
|
12
13
|
|
13
14
|
end # module GraphWrapper
|
14
15
|
|
15
|
-
end # RGL
|
16
|
+
end # RGL
|
data/lib/rgl/graphxml.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# graphxml.rb
|
2
2
|
#
|
3
3
|
# This file contains minimal support for creating RGL graphs from the GraphML
|
4
|
-
# format (see
|
4
|
+
# format (see https://graphml.graphdrawing.org/). The main purpose is to
|
5
5
|
# have a rich set of example graphs to have some more tests.
|
6
6
|
#
|
7
7
|
# See the examples directory, which contains a subdirectory _north_ with the
|
8
8
|
# Graph catalog GraphViz (see
|
9
|
-
#
|
9
|
+
# https://www.research.att.com/sw/tools/graphviz/refs.html).
|
10
10
|
#
|
11
11
|
# We use REXML::StreamListener from the REXML library
|
12
|
-
# (
|
12
|
+
# (https://www.germane-software.com/software/rexml) to parse the grapml files.
|
13
13
|
|
14
14
|
require 'rgl/mutable'
|
15
15
|
require 'rexml/document'
|
@@ -48,7 +48,7 @@ module RGL
|
|
48
48
|
end # class MutableGraphParser
|
49
49
|
|
50
50
|
# Initializes an RGL graph from a subset of the GraphML format given in
|
51
|
-
# +source+ (see
|
51
|
+
# +source+ (see https://graphml.graphdrawing.org/).
|
52
52
|
#
|
53
53
|
def from_graphxml(source)
|
54
54
|
listener = MutableGraphParser.new(self)
|
data/lib/rgl/implicit.rb
CHANGED
@@ -3,25 +3,26 @@
|
|
3
3
|
# This file contains the definition of the class RGL::ImplicitGraph, which
|
4
4
|
# defines vertex and edge iterators using blocks (which again call blocks).
|
5
5
|
#
|
6
|
-
# An ImplicitGraph provides a handy way to define graphs on the fly, using two
|
7
|
-
# blocks for the two iterators defining a graph. A directed cyclic graph,
|
8
|
-
# with five vertices can be created as follows:
|
9
|
-
#
|
10
|
-
# g = RGL::ImplicitGraph.new do |g|
|
11
|
-
# g.vertex_iterator { |b| 0.upto(4,&b) }
|
12
|
-
# g.adjacent_iterator { |x, b| b.call((x+1)%5) }
|
13
|
-
# g.directed = true
|
14
|
-
# end
|
15
|
-
#
|
16
|
-
# g.to_s # => "(0-1)(1-2)(2-3)(3-4)(4-0)"
|
17
|
-
#
|
18
|
-
# Other examples are given by the methods vertices_filtered_by and
|
19
|
-
# edges_filtered_by, which can be applied to any graph.
|
20
6
|
|
21
7
|
require 'rgl/base'
|
22
8
|
|
23
9
|
module RGL
|
24
10
|
|
11
|
+
# An ImplicitGraph provides a handy way to define graphs on the fly, using two
|
12
|
+
# blocks for the two iterators defining a graph. Other examples are given by the
|
13
|
+
# methods {#vertices_filtered_by} and {#edges_filtered_by}, which can be
|
14
|
+
# applied to any graph.
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
# # A directed cyclic graph, with five vertices can be created as follows:
|
18
|
+
# g = RGL::ImplicitGraph.new do |g|
|
19
|
+
# g.vertex_iterator { |b| 0.upto(4,&b) }
|
20
|
+
# g.adjacent_iterator { |x, b| b.call((x+1)%5) }
|
21
|
+
# g.directed = true
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# g.to_s # => "(0-1)(1-2)(2-3)(3-4)(4-0)"
|
25
|
+
#
|
25
26
|
class ImplicitGraph
|
26
27
|
|
27
28
|
include Graph
|
@@ -31,10 +32,10 @@ module RGL
|
|
31
32
|
EMPTY_VERTEX_ITERATOR = proc { |b| }
|
32
33
|
EMPTY_NEIGHBOR_ITERATOR = proc { |x, b| }
|
33
34
|
|
34
|
-
# Create a new ImplicitGraph, which is empty by default. The caller should
|
35
|
+
# Create a new {ImplicitGraph}, which is empty by default. The caller should
|
35
36
|
# configure the graph using vertex and neighbor iterators. If the graph is
|
36
|
-
# directed, the client should set
|
37
|
-
# for
|
37
|
+
# directed, the client should set +@directed+ to true. The default value
|
38
|
+
# for +@directed+ is false.
|
38
39
|
#
|
39
40
|
def initialize
|
40
41
|
@directed = false
|
@@ -43,21 +44,21 @@ module RGL
|
|
43
44
|
yield self if block_given? # Let client overwrite defaults.
|
44
45
|
end
|
45
46
|
|
46
|
-
# Returns the value of
|
47
|
+
# Returns the value of +@directed+.
|
47
48
|
#
|
48
49
|
def directed?
|
49
50
|
@directed
|
50
51
|
end
|
51
52
|
|
52
|
-
def each_vertex(&block)
|
53
|
+
def each_vertex(&block)
|
53
54
|
@vertex_iterator.call(block)
|
54
55
|
end
|
55
56
|
|
56
|
-
def each_adjacent(v, &block)
|
57
|
+
def each_adjacent(v, &block)
|
57
58
|
@adjacent_iterator.call(v, block)
|
58
59
|
end
|
59
60
|
|
60
|
-
def each_edge(&block)
|
61
|
+
def each_edge(&block)
|
61
62
|
if defined? @edge_iterator
|
62
63
|
@edge_iterator.call(block)
|
63
64
|
else
|
@@ -67,7 +68,7 @@ module RGL
|
|
67
68
|
|
68
69
|
# Sets the vertex_iterator to _block_,
|
69
70
|
# which must be a block of one parameter
|
70
|
-
# which again is the block called by each_vertex.
|
71
|
+
# which again is the block called by {#each_vertex}.
|
71
72
|
#
|
72
73
|
def vertex_iterator(&block)
|
73
74
|
@vertex_iterator = block
|
@@ -98,15 +99,14 @@ module RGL
|
|
98
99
|
|
99
100
|
module Graph
|
100
101
|
|
101
|
-
#
|
102
|
-
#
|
103
|
-
# Return a new ImplicitGraph which has as vertices all vertices of the
|
102
|
+
# Returns a new {ImplicitGraph} which has as vertices all vertices of the
|
104
103
|
# receiver which satisfy the predicate _filter_.
|
105
104
|
#
|
106
|
-
# The methods provides similar functionality as
|
107
|
-
#
|
105
|
+
# The methods provides similar functionality as
|
106
|
+
# {https://www.boost.org/doc/libs/1_36_0/libs/graph/doc/filtered_graph.html
|
107
|
+
# BGLs Filtered Graph}
|
108
108
|
#
|
109
|
-
#
|
109
|
+
# @example
|
110
110
|
#
|
111
111
|
# def complete (n)
|
112
112
|
# set = n.integer? ? (1..n) : n
|
@@ -120,7 +120,7 @@ module RGL
|
|
120
120
|
#
|
121
121
|
# complete(4).to_s # => "(1=2)(1=3)(1=4)(2=3)(2=4)(3=4)"
|
122
122
|
# complete(4).vertices_filtered_by { |v| v != 4 }.to_s # => "(1=2)(1=3)(2=3)"
|
123
|
-
#
|
123
|
+
# @return [ImplicitGraph]
|
124
124
|
def vertices_filtered_by(&filter)
|
125
125
|
implicit_graph do |g|
|
126
126
|
g.vertex_iterator do |b|
|
@@ -133,15 +133,15 @@ module RGL
|
|
133
133
|
end
|
134
134
|
end
|
135
135
|
|
136
|
-
#
|
136
|
+
# Returns a new {ImplicitGraph} which has as edges all edges of the receiver
|
137
137
|
# which satisfy the predicate _filter_ (a block with two parameters).
|
138
138
|
#
|
139
|
-
#
|
139
|
+
# @example
|
140
140
|
#
|
141
141
|
# g = complete(7).edges_filtered_by { |u,v| u+v == 7 }
|
142
142
|
# g.to_s => "(1=6)(2=5)(3=4)"
|
143
143
|
# g.vertices => [1, 2, 3, 4, 5, 6, 7]
|
144
|
-
#
|
144
|
+
# @return [ImplicitGraph]
|
145
145
|
def edges_filtered_by(&filter)
|
146
146
|
implicit_graph do |g|
|
147
147
|
g.adjacent_iterator do |v, b|
|
@@ -156,10 +156,10 @@ module RGL
|
|
156
156
|
end
|
157
157
|
end
|
158
158
|
|
159
|
-
# Return a new ImplicitGraph which is isomorphic (i.e. has same edges and
|
159
|
+
# Return a new {ImplicitGraph} which is isomorphic (i.e. has same edges and
|
160
160
|
# vertices) to the receiver. It is a shortcut, also used by
|
161
|
-
# edges_filtered_by and vertices_filtered_by.
|
162
|
-
#
|
161
|
+
# {#edges_filtered_by} and {#vertices_filtered_by}.
|
162
|
+
# @return [ImplicitGraph]
|
163
163
|
def implicit_graph
|
164
164
|
result = ImplicitGraph.new do |g|
|
165
165
|
g.vertex_iterator { |b| self.each_vertex(&b) }
|
data/lib/rgl/mutable.rb
CHANGED
@@ -21,7 +21,7 @@ module RGL
|
|
21
21
|
# Inserts the edge (u,v) into the graph.
|
22
22
|
#
|
23
23
|
# Note that for undirected graphs, (u,v) is the same edge as (v,u), so
|
24
|
-
# after a call to the function add_edge
|
24
|
+
# after a call to the function #add_edge, this implies that edge (u,v)
|
25
25
|
# will appear in the out-edges of u and (u,v) (or equivalently (v,u))
|
26
26
|
# will appear in the out-edges of v. Put another way, v will be adjacent
|
27
27
|
# to u and u will be adjacent to v.
|
@@ -37,8 +37,8 @@ module RGL
|
|
37
37
|
end
|
38
38
|
|
39
39
|
# Add all edges in the _edges_ array to the edge set. Elements of the
|
40
|
-
# array can be both two-element arrays or instances of DirectedEdge or
|
41
|
-
# UnDirectedEdge.
|
40
|
+
# array can be both two-element arrays or instances of {Edge::DirectedEdge} or
|
41
|
+
# {Edge::UnDirectedEdge}.
|
42
42
|
#
|
43
43
|
def add_edges(*edges)
|
44
44
|
edges.each { |edge| add_edge(edge[0], edge[1]) }
|
@@ -65,7 +65,7 @@ module RGL
|
|
65
65
|
end
|
66
66
|
|
67
67
|
# Remove all vertices specified by the array a from the graph by calling
|
68
|
-
# remove_vertex.
|
68
|
+
# {#remove_vertex}.
|
69
69
|
#
|
70
70
|
def remove_vertices(*a)
|
71
71
|
a.each { |v| remove_vertex v }
|
@@ -74,14 +74,14 @@ module RGL
|
|
74
74
|
# Returns all minimum cycles that pass through a give vertex.
|
75
75
|
# The format is an Array of cycles, with each cycle being an Array
|
76
76
|
# of vertices in the cycle.
|
77
|
-
#
|
77
|
+
# @return [Array[Array]]
|
78
78
|
def cycles_with_vertex(vertex)
|
79
79
|
cycles_with_vertex_helper(vertex, vertex, [])
|
80
80
|
end
|
81
81
|
|
82
82
|
protected
|
83
83
|
|
84
|
-
def cycles_with_vertex_helper(vertex, start, visited)
|
84
|
+
def cycles_with_vertex_helper(vertex, start, visited)
|
85
85
|
adjacent_vertices(start).reject { |x| visited.include?(x) }.inject([]) do |acc, adj|
|
86
86
|
local_visited = Array.new(visited) << adj
|
87
87
|
acc << local_visited if (adj==vertex)
|
@@ -91,7 +91,7 @@ module RGL
|
|
91
91
|
|
92
92
|
public
|
93
93
|
|
94
|
-
#
|
94
|
+
# @return [Array] of all minimum cycles in a graph
|
95
95
|
#
|
96
96
|
# This is not an efficient implementation O(n^4) and could
|
97
97
|
# be done using Minimum Spanning Trees. Hint. Hint.
|
data/lib/rgl/path_builder.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module RGL
|
2
2
|
|
3
|
-
|
3
|
+
class PathBuilder
|
4
4
|
|
5
5
|
def initialize(source, parents_map)
|
6
6
|
@source = source
|
@@ -16,6 +16,7 @@ module RGL
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
# @return [Hash]
|
19
20
|
def paths(targets)
|
20
21
|
paths_map = {}
|
21
22
|
|
@@ -37,4 +38,4 @@ module RGL
|
|
37
38
|
|
38
39
|
end
|
39
40
|
|
40
|
-
end # RGL
|
41
|
+
end # RGL
|
data/lib/rgl/prim.rb
CHANGED
@@ -3,6 +3,8 @@ require 'rgl/adjacency'
|
|
3
3
|
|
4
4
|
module RGL
|
5
5
|
|
6
|
+
# Implements {https://en.wikipedia.org/wiki/Prim%27s_algorithm Prim's algorithm}.
|
7
|
+
# @see Graph#prim_minimum_spanning_tree
|
6
8
|
class PrimAlgorithm
|
7
9
|
|
8
10
|
# Replacement for default distance combinator that is used in Dijkstra's algorithm. While building a minimum
|
@@ -36,7 +38,7 @@ module RGL
|
|
36
38
|
|
37
39
|
# Finds the minimum spanning tree of the graph.
|
38
40
|
#
|
39
|
-
# Returns an AdjacencyGraph that represents the minimum spanning tree of the graph's connectivity component that
|
41
|
+
# Returns an {AdjacencyGraph} that represents the minimum spanning tree of the graph's connectivity component that
|
40
42
|
# contains the starting vertex. The algorithm starts from an arbitrary vertex if the _start_vertex_ is not given.
|
41
43
|
# Since the implementation relies on the Dijkstra's algorithm, Prim's algorithm uses the same visitor class and emits
|
42
44
|
# the same events.
|
data/lib/rgl/rdot.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
|
-
# This is a modified version of dot.rb from Dave Thomas's rdoc project. I
|
2
|
-
# renamed it to rdot.rb to avoid collision with an installed rdoc/dot.
|
3
|
-
#
|
4
|
-
# It also supports undirected edges.
|
5
|
-
|
6
1
|
module RGL
|
7
2
|
|
3
|
+
# This is a modified version of +dot.rb+ from {https://ruby.github.io/rdoc Dave
|
4
|
+
# Thomas's rdoc project}. I renamed it to +rdot.rb+ to avoid collision with an
|
5
|
+
# installed rdoc/dot.
|
6
|
+
#
|
7
|
+
# It also supports undirected edges.
|
8
8
|
module DOT
|
9
9
|
|
10
10
|
# options for node declaration
|
11
11
|
|
12
12
|
NODE_OPTS = [
|
13
13
|
# attributes due to
|
14
|
-
#
|
14
|
+
# https://www.graphviz.org/Documentation/dotguide.pdf
|
15
15
|
# February 23, 2008
|
16
16
|
'color', # default: black; node shape color
|
17
17
|
'comment', # any string (format-dependent)
|
@@ -139,7 +139,7 @@ module RGL
|
|
139
139
|
|
140
140
|
attr_accessor :name, :options
|
141
141
|
|
142
|
-
def initialize(params = {}, option_list = [])
|
142
|
+
def initialize(params = {}, option_list = [])
|
143
143
|
@name = params['name'] ? params['name'] : nil
|
144
144
|
@options = {}
|
145
145
|
|
data/lib/rgl/topsort.rb
CHANGED
@@ -10,10 +10,11 @@ module RGL
|
|
10
10
|
# such that if edge (u,v) appears in the graph, then u comes before v in
|
11
11
|
# the ordering. The graph must be a directed acyclic graph (DAG).
|
12
12
|
#
|
13
|
-
# The iterator can also be applied to undirected graph or to a
|
13
|
+
# The iterator can also be applied to an undirected graph or to a directed graph
|
14
14
|
# which contains a cycle. In this case, the Iterator does not reach all
|
15
|
-
# vertices. The implementation of acyclic? uses this fact.
|
15
|
+
# vertices. The implementation of {Graph#acyclic?} uses this fact.
|
16
16
|
#
|
17
|
+
# @see Graph#topsort_iterator
|
17
18
|
class TopsortIterator
|
18
19
|
|
19
20
|
include GraphIterator
|
@@ -23,7 +24,7 @@ module RGL
|
|
23
24
|
set_to_begin
|
24
25
|
end
|
25
26
|
|
26
|
-
def set_to_begin
|
27
|
+
def set_to_begin
|
27
28
|
@waiting = Array.new
|
28
29
|
@inDegrees = Hash.new(0)
|
29
30
|
|
@@ -39,7 +40,8 @@ module RGL
|
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
42
|
-
|
43
|
+
# @private
|
44
|
+
def basic_forward
|
43
45
|
u = @waiting.pop
|
44
46
|
graph.each_adjacent(u) do |v|
|
45
47
|
@inDegrees[v] -= 1
|
@@ -52,16 +54,15 @@ module RGL
|
|
52
54
|
true
|
53
55
|
end
|
54
56
|
|
55
|
-
# :nodoc: FIXME
|
56
57
|
def at_end?
|
57
58
|
@waiting.empty?
|
58
|
-
end
|
59
|
+
end
|
59
60
|
|
60
61
|
end # class TopsortIterator
|
61
62
|
|
62
63
|
module Graph
|
63
64
|
|
64
|
-
#
|
65
|
+
# @return [TopsortIterator] for the graph.
|
65
66
|
#
|
66
67
|
def topsort_iterator
|
67
68
|
TopsortIterator.new(self)
|
data/lib/rgl/transitivity.rb
CHANGED
@@ -6,7 +6,7 @@ module RGL
|
|
6
6
|
|
7
7
|
module Graph
|
8
8
|
|
9
|
-
# Returns an
|
9
|
+
# Returns an {DirectedAdjacencyGraph} which is the transitive closure of
|
10
10
|
# this graph. Meaning, for each path u -> ... -> v in this graph, the path
|
11
11
|
# is copied and the edge u -> v is added. This method supports working with
|
12
12
|
# cyclic graphs by ensuring that edges are created between every pair of
|
@@ -15,8 +15,8 @@ module RGL
|
|
15
15
|
# This method should run in O(|V||E|) time, where |V| and |E| are the number
|
16
16
|
# of vertices and edges respectively.
|
17
17
|
#
|
18
|
-
# Raises
|
19
|
-
#
|
18
|
+
# Raises {NotDirectedError} if run on an undirected graph.
|
19
|
+
# @return DirectedAdjacencyGraph
|
20
20
|
def transitive_closure
|
21
21
|
raise NotDirectedError,
|
22
22
|
"transitive_closure only supported for directed graphs" unless directed?
|
@@ -86,7 +86,7 @@ module RGL
|
|
86
86
|
g
|
87
87
|
end
|
88
88
|
|
89
|
-
# Returns an
|
89
|
+
# Returns an {DirectedAdjacencyGraph} which is the transitive reduction
|
90
90
|
# of this graph. Meaning, that each edge u -> v is omitted if path
|
91
91
|
# u -> ... -> v exists. This method supports working with cyclic graphs;
|
92
92
|
# however, cycles are arbitrarily simplified which may lead to variant,
|
@@ -95,8 +95,8 @@ module RGL
|
|
95
95
|
# This method should run in O(|V||E|) time, where |V| and |E| are the number
|
96
96
|
# of vertices and edges respectively.
|
97
97
|
#
|
98
|
-
# Raises
|
99
|
-
#
|
98
|
+
# Raises {NotDirectedError} if run on an undirected graph.
|
99
|
+
# @return DirectedAdjacencyGraph
|
100
100
|
def transitive_reduction
|
101
101
|
raise NotDirectedError,
|
102
102
|
"transitive_reduction only supported for directed graphs" unless directed?
|