rgl 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/ChangeLog +19 -10
  2. data/Gemfile +3 -0
  3. data/{README → README.rdoc} +70 -98
  4. data/Rakefile +44 -150
  5. data/examples/canvas.rb +63 -64
  6. data/examples/examples.rb +42 -42
  7. data/examples/graph.dot +46 -0
  8. data/examples/images/example.jpg +0 -0
  9. data/examples/images/module_graph.jpg +0 -0
  10. data/examples/images/rgl_modules.png +0 -0
  11. data/examples/{insel-der-tausend-gefahren.rb → insel_der_tausend_gefahren.rb} +18 -19
  12. data/examples/north.rb +2 -2
  13. data/examples/north2.rb +11 -11
  14. data/examples/rdep-rgl.rb +218 -222
  15. data/lib/rgl/adjacency.rb +78 -74
  16. data/lib/rgl/base.rb +160 -78
  17. data/lib/rgl/bellman_ford.rb +115 -0
  18. data/lib/rgl/bidirectional.rb +17 -10
  19. data/lib/rgl/bipartite.rb +87 -0
  20. data/lib/rgl/condensation.rb +13 -4
  21. data/lib/rgl/connected_components.rb +38 -30
  22. data/lib/rgl/dijkstra.rb +158 -0
  23. data/lib/rgl/dijkstra_visitor.rb +42 -0
  24. data/lib/rgl/dot.rb +40 -32
  25. data/lib/rgl/edge_properties_map.rb +55 -0
  26. data/lib/rgl/edmonds_karp.rb +136 -0
  27. data/lib/rgl/enumerable_ext.rb +4 -1
  28. data/lib/rgl/graph_iterator.rb +15 -0
  29. data/lib/rgl/graph_visitor.rb +138 -0
  30. data/lib/rgl/graph_wrapper.rb +15 -0
  31. data/lib/rgl/graphxml.rb +20 -10
  32. data/lib/rgl/implicit.rb +68 -66
  33. data/lib/rgl/mutable.rb +37 -31
  34. data/lib/rgl/path_builder.rb +40 -0
  35. data/lib/rgl/prim.rb +52 -0
  36. data/lib/rgl/rdot.rb +411 -374
  37. data/lib/rgl/topsort.rb +23 -16
  38. data/lib/rgl/transitivity.rb +29 -27
  39. data/lib/rgl/traversal.rb +67 -205
  40. data/rakelib/dep_graph.rake +4 -3
  41. data/test/bellman_ford_test.rb +187 -0
  42. data/test/bipartite_test.rb +47 -0
  43. data/test/components_test.rb +80 -0
  44. data/test/cycles_test.rb +60 -0
  45. data/test/dijkstra_test.rb +148 -0
  46. data/test/directed_graph_test.rb +118 -0
  47. data/test/dot_test.rb +26 -0
  48. data/test/edge_properties_map_test.rb +63 -0
  49. data/test/edge_test.rb +35 -0
  50. data/test/edmonds_karp_test.rb +105 -0
  51. data/{tests/TestGraph.rb → test/graph_test.rb} +6 -6
  52. data/test/graph_xml_test.rb +57 -0
  53. data/test/implicit_test.rb +53 -0
  54. data/test/prim_test.rb +98 -0
  55. data/{tests/TestRdot.rb → test/rdot_test.rb} +309 -308
  56. data/{tests → test}/test_helper.rb +4 -1
  57. data/{tests/TestTransitivity.rb → test/transitivity_test.rb} +43 -43
  58. data/test/traversal_test.rb +221 -0
  59. data/test/undirected_graph_test.rb +103 -0
  60. metadata +226 -145
  61. data/examples/example.jpg +0 -0
  62. data/examples/module_graph.jpg +0 -0
  63. data/install.rb +0 -49
  64. data/tests/TestComponents.rb +0 -65
  65. data/tests/TestCycles.rb +0 -61
  66. data/tests/TestDirectedGraph.rb +0 -125
  67. data/tests/TestDot.rb +0 -18
  68. data/tests/TestEdge.rb +0 -34
  69. data/tests/TestGraphXML.rb +0 -57
  70. data/tests/TestImplicit.rb +0 -52
  71. data/tests/TestTraversal.rb +0 -220
  72. data/tests/TestUnDirectedGraph.rb +0 -102
@@ -1,13 +1,16 @@
1
1
  module Enumerable
2
+
2
3
  # Fixnum()
3
4
  #
4
5
  # Return the number of elements of the Enumerable. Same as _size_ but not all
5
6
  # Enumerables implement size.
6
7
  #--
7
8
  # Should we call the methods _size_?
9
+ #
8
10
  def length
9
- inject(0) do |sum,v|
11
+ inject(0) do |sum, v|
10
12
  sum + 1
11
13
  end
12
14
  end
15
+
13
16
  end
@@ -0,0 +1,15 @@
1
+ require 'stream'
2
+
3
+ require 'rgl/graph_wrapper'
4
+
5
+ module RGL
6
+
7
+ # A GraphIterator is the abstract basis for all Iterators on graphs.
8
+ # Each graph iterator should implement the protocol defined in module Stream.
9
+ #
10
+ module GraphIterator
11
+ include Stream
12
+ include GraphWrapper
13
+ end
14
+
15
+ end # RGL
@@ -0,0 +1,138 @@
1
+ require 'rgl/graph_wrapper'
2
+
3
+ module RGL
4
+
5
+ # Module GraphVisitor defines the BGL
6
+ # BFS[http://www.boost.org/libs/graph/doc/BFSVisitor.html] Visitor Concept).
7
+ #
8
+ # Visitors provide a mechanism for extending an algorithm (i.e., for
9
+ # customizing what is done at each step of the algorithm). They allow users
10
+ # to insert their own operations at various steps within a graph algorithm.
11
+ #
12
+ # Graph algorithms typically have multiple event points where one may want to
13
+ # insert a call-back. Therefore, visitors have several methods that
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.
16
+ #
17
+ # * examine_vertex
18
+ # * examine_edge
19
+ # * tree_edge
20
+ # * back_edge
21
+ # * forward_edge
22
+ # * finish_vertex
23
+ #
24
+ # These methods are all called handle_* and can be set to appropriate blocks,
25
+ # using the methods set_*_event_handler, which are defined for each event
26
+ # mentioned above.
27
+ #
28
+ # As an alternative, you can also override the handle_* methods in a
29
+ # subclass, to configure the algorithm (as an example, see TarjanSccVisitor).
30
+ #
31
+ # During a graph traversal, vertices are *colored* using the colors :GRAY
32
+ # (when waiting) and :BLACK when finished. All other vertices are :WHITE.
33
+ # The color_map is also maintained in the visitor.
34
+ #
35
+ module GraphVisitor
36
+
37
+ include GraphWrapper
38
+
39
+ attr_reader :color_map
40
+
41
+ # Create a new GraphVisitor on _graph_.
42
+ #
43
+ def initialize(graph)
44
+ super(graph)
45
+ reset
46
+ end
47
+
48
+ # Mark each vertex unvisited (i.e. :WHITE)
49
+ #
50
+ def reset
51
+ @color_map = Hash.new(:WHITE)
52
+ end
53
+
54
+ # Returns true if vertex _v_ is colored :BLACK (i.e. finished).
55
+ #
56
+ def finished_vertex?(v)
57
+ @color_map[v] == :BLACK
58
+ end
59
+
60
+ # Shall we follow the edge (u,v); i.e. v has color :WHITE
61
+ #
62
+ def follow_edge?(u, v) # :nodoc:
63
+ @color_map[v] == :WHITE
64
+ end
65
+
66
+ # Attach a map to the visitor which records the distance of a visited
67
+ # vertex to the start vertex.
68
+ #
69
+ # This is similar to BGLs
70
+ # distance_recorder[http://www.boost.org/libs/graph/doc/distance_recorder.html].
71
+ #
72
+ # After the distance_map is attached, the visitor has a new method
73
+ # distance_to_root, which answers the distance to the start vertex.
74
+ #
75
+ def attach_distance_map(map = Hash.new(0))
76
+ @distance_map = map
77
+
78
+ # add distance map support to the current visitor instance
79
+ extend(DistanceMapSupport)
80
+ end
81
+
82
+ module DistanceMapSupport
83
+
84
+ def handle_tree_edge(u, v)
85
+ super
86
+ @distance_map[v] = @distance_map[u] + 1
87
+ end
88
+
89
+ # Answer the distance to the start vertex.
90
+
91
+ def distance_to_root(v)
92
+ @distance_map[v]
93
+ end
94
+
95
+ end # module DistanceMapSupport
96
+
97
+ module ClassMethods
98
+
99
+ # Defines an event handler.
100
+ #
101
+ def def_event_handlers(*events)
102
+ events.each do |event|
103
+ params = event.to_s.include?('edge') ? 'u, v' : 'u'
104
+
105
+ handler = "@#{event}_event_handler"
106
+
107
+ class_eval <<-END
108
+ def handle_#{event}(#{params})
109
+ #{handler}.call(#{params}) if defined? #{handler}
110
+ end
111
+
112
+ def set_#{event}_event_handler(&block)
113
+ #{handler} = block
114
+ end
115
+ END
116
+ end
117
+ end
118
+
119
+ alias def_event_handler def_event_handlers
120
+
121
+ end # module ClassMethods
122
+
123
+ extend ClassMethods # add class methods to GraphVisitor class itself
124
+
125
+ def self.included(base)
126
+ base.extend ClassMethods # when GraphVisitor is included into a class/module, add class methods as well
127
+ end
128
+
129
+ def_event_handlers :examine_vertex,
130
+ :examine_edge,
131
+ :tree_edge,
132
+ :back_edge,
133
+ :forward_edge,
134
+ :finish_vertex
135
+
136
+ end # module GraphVisitor
137
+
138
+ end # module RGL
@@ -0,0 +1,15 @@
1
+ module RGL
2
+
3
+ module GraphWrapper # :nodoc:
4
+
5
+ attr_accessor :graph
6
+
7
+ # Creates a new GraphWrapper on _graph_.
8
+ #
9
+ def initialize(graph)
10
+ @graph = graph
11
+ end
12
+
13
+ end # module GraphWrapper
14
+
15
+ end # RGL
@@ -1,7 +1,7 @@
1
1
  # graphxml.rb
2
2
  #
3
3
  # This file contains minimal support for creating RGL graphs from the GraphML
4
- # format (see http://www.graphdrawing.org/graphml). The main purpose is to
4
+ # format (see http://www.graphdrawing.org/graphml). 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
@@ -16,36 +16,46 @@ require 'rexml/document'
16
16
  require 'rexml/streamlistener'
17
17
 
18
18
  module RGL
19
+
19
20
  module MutableGraph
21
+
20
22
  # Used to parse a subset of GraphML into an RGL graph implementation.
23
+ #
21
24
  class MutableGraphParser
25
+
22
26
  include REXML::StreamListener
23
27
 
24
28
  # First resets +graph+ to be empty and stores a reference for use with
25
29
  # #tag_start.
26
- def initialize (graph)
30
+ #
31
+ def initialize(graph)
27
32
  @graph = graph
28
33
  @graph.remove_vertices(@graph.vertices)
29
34
  end
30
35
 
31
36
  # Processes incoming edge and node elements from GraphML in order to
32
37
  # populate the graph given to #new.
33
- def tag_start (name, attrs)
38
+ #
39
+ def tag_start(name, attrs)
34
40
  case name
35
- when 'edge'
36
- @graph.add_edge(attrs['source'], attrs['target'])
37
- when 'node'
38
- @graph.add_vertex(attrs['id'])
41
+ when 'edge'
42
+ @graph.add_edge(attrs['source'], attrs['target'])
43
+ when 'node'
44
+ @graph.add_vertex(attrs['id'])
39
45
  end
40
46
  end
41
- end # class MutableGraphParser
47
+
48
+ end # class MutableGraphParser
42
49
 
43
50
  # Initializes an RGL graph from a subset of the GraphML format given in
44
51
  # +source+ (see http://www.graphdrawing.org/graphml).
52
+ #
45
53
  def from_graphxml(source)
46
54
  listener = MutableGraphParser.new(self)
47
55
  REXML::Document.parse_stream(source, listener)
48
56
  self
49
57
  end
50
- end # module MutableGraph
51
- end # module RGL
58
+
59
+ end # module MutableGraph
60
+
61
+ end # module RGL
@@ -1,19 +1,19 @@
1
- # implicit.rb
1
+ # implicit.rb
2
2
  #
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
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,
7
+ # blocks for the two iterators defining a graph. A directed cyclic graph,
8
8
  # with five vertices can be created as follows:
9
9
  #
10
- # g = RGL::ImplicitGraph.new { |g|
10
+ # g = RGL::ImplicitGraph.new do |g|
11
11
  # g.vertex_iterator { |b| 0.upto(4,&b) }
12
12
  # g.adjacent_iterator { |x, b| b.call((x+1)%5) }
13
13
  # g.directed = true
14
- # }
14
+ # end
15
15
  #
16
- # g.to_s => "(0-1)(1-2)(2-3)(3-4)(4-0)"
16
+ # g.to_s # => "(0-1)(1-2)(2-3)(3-4)(4-0)"
17
17
  #
18
18
  # Other examples are given by the methods vertices_filtered_by and
19
19
  # edges_filtered_by, which can be applied to any graph.
@@ -28,110 +28,109 @@ module RGL
28
28
 
29
29
  attr_writer :directed
30
30
 
31
- EMPTY_VERTEX_ITERATOR = proc { |b| }
31
+ EMPTY_VERTEX_ITERATOR = proc { |b| }
32
32
  EMPTY_NEIGHBOR_ITERATOR = proc { |x, b| }
33
-
34
- # Create a new ImplicitGraph, which is empty by default. The caller should
35
- # configure the graph using vertex and neighbor iterators. If the graph is
36
- # directed, the client should set _directed_ to true. The default value
37
- # for _directed_ is false.
38
33
 
34
+ # Create a new ImplicitGraph, which is empty by default. The caller should
35
+ # configure the graph using vertex and neighbor iterators. If the graph is
36
+ # directed, the client should set _directed_ to true. The default value
37
+ # for _directed_ is false.
38
+ #
39
39
  def initialize
40
- @directed = false
40
+ @directed = false
41
41
  @vertex_iterator = EMPTY_VERTEX_ITERATOR
42
42
  @adjacent_iterator = EMPTY_NEIGHBOR_ITERATOR
43
- yield self if block_given? # Let client overwrite defaults.
43
+ yield self if block_given? # Let client overwrite defaults.
44
44
  end
45
45
 
46
46
  # Returns the value of @directed.
47
-
47
+ #
48
48
  def directed?
49
49
  @directed
50
50
  end
51
-
52
- def each_vertex (&block) # :nodoc:
51
+
52
+ def each_vertex(&block) # :nodoc:
53
53
  @vertex_iterator.call(block)
54
54
  end
55
55
 
56
- def each_adjacent (v, &block) # :nodoc:
56
+ def each_adjacent(v, &block) # :nodoc:
57
57
  @adjacent_iterator.call(v, block)
58
58
  end
59
59
 
60
- def each_edge (&block) # :nodoc:
60
+ def each_edge(&block) # :nodoc:
61
61
  if defined? @edge_iterator
62
62
  @edge_iterator.call(block)
63
63
  else
64
- super # use default implementation
64
+ super # use default implementation
65
65
  end
66
66
  end
67
67
 
68
68
  # Sets the vertex_iterator to _block_,
69
69
  # which must be a block of one parameter
70
70
  # which again is the block called by each_vertex.
71
-
72
- def vertex_iterator (&block)
71
+ #
72
+ def vertex_iterator(&block)
73
73
  @vertex_iterator = block
74
74
  end
75
75
 
76
76
  # Sets the adjacent_iterator to _block_,
77
- # which must be a block of two parameters:
77
+ # which must be a block of two parameters:
78
78
  #
79
79
  # The first parameter is the vertex the neighbors of which are to be
80
80
  # traversed.
81
81
  #
82
82
  # The second is the block which will be called for each neighbor
83
83
  # of this vertex.
84
-
85
- def adjacent_iterator (&block)
84
+ #
85
+ def adjacent_iterator(&block)
86
86
  @adjacent_iterator = block
87
87
  end
88
88
 
89
89
  # Sets the edge_iterator to _block_, which must be a block of two
90
90
  # parameters: The first parameter is the source of the edges; the
91
91
  # second is the target of the edge.
92
-
93
- def edge_iterator (&block)
92
+ #
93
+ def edge_iterator(&block)
94
94
  @edge_iterator = block
95
95
  end
96
96
 
97
- end # class ImplicitGraph
98
-
97
+ end # class ImplicitGraph
99
98
 
100
99
  module Graph
101
100
 
102
- # ---
103
101
  # === Graph adaptors
104
102
  #
105
103
  # Return a new ImplicitGraph which has as vertices all vertices of the
106
104
  # receiver which satisfy the predicate _filter_.
107
105
  #
108
- # The methods provides similar functionaty as the BGL graph adapter
109
- # filtered_graph (see BOOST_DOC/filtered_graph.html).
106
+ # The methods provides similar functionality as the BGL graph adapter
107
+ # filtered_graph (see BOOST_DOC/filtered_graph.html).
110
108
  #
111
109
  # ==== Example
112
110
  #
113
111
  # def complete (n)
114
112
  # set = n.integer? ? (1..n) : n
115
- # RGL::ImplicitGraph.new { |g|
116
- # g.vertex_iterator { |b| set.each(&b) }
117
- # g.adjacent_iterator { |x, b|
118
- # set.each { |y| b.call(y) unless x == y }
119
- # }
120
- # }
113
+ # RGL::ImplicitGraph.new do |g|
114
+ # g.vertex_iterator { |b| set.each(&b) }
115
+ # g.adjacent_iterator do |x, b|
116
+ # set.each { |y| b.call(y) unless x == y }
117
+ # end
118
+ # end
121
119
  # end
122
120
  #
123
- # complete(4).to_s => "(1=2)(1=3)(1=4)(2=3)(2=4)(3=4)"
124
- # complete(4).vertices_filtered_by {|v| v != 4}.to_s => "(1=2)(1=3)(2=3)"
125
-
126
- def vertices_filtered_by (&filter)
127
- implicit_graph { |g|
128
- g.vertex_iterator { |b|
121
+ # complete(4).to_s # => "(1=2)(1=3)(1=4)(2=3)(2=4)(3=4)"
122
+ # complete(4).vertices_filtered_by { |v| v != 4 }.to_s # => "(1=2)(1=3)(2=3)"
123
+ #
124
+ def vertices_filtered_by(&filter)
125
+ implicit_graph do |g|
126
+ g.vertex_iterator do |b|
129
127
  self.each_vertex { |v| b.call(v) if filter.call(v) }
130
- }
131
- g.adjacent_iterator { |v, b|
128
+ end
129
+
130
+ g.adjacent_iterator do |v, b|
132
131
  self.each_adjacent(v) { |u| b.call(u) if filter.call(u) }
133
- }
134
- }
132
+ end
133
+ end
135
134
  end
136
135
 
137
136
  # Return a new ImplicitGraph which has as edges all edges of the receiver
@@ -139,36 +138,39 @@ module RGL
139
138
  #
140
139
  # ==== Example
141
140
  #
142
- # g = complete(7).edges_filtered_by {|u,v| u+v == 7}
141
+ # g = complete(7).edges_filtered_by { |u,v| u+v == 7 }
143
142
  # g.to_s => "(1=6)(2=5)(3=4)"
144
143
  # g.vertices => [1, 2, 3, 4, 5, 6, 7]
145
-
146
- def edges_filtered_by (&filter)
147
- implicit_graph { |g|
148
- g.adjacent_iterator { |v, b|
149
- self.each_adjacent(v) { |u|
144
+ #
145
+ def edges_filtered_by(&filter)
146
+ implicit_graph do |g|
147
+ g.adjacent_iterator do |v, b|
148
+ self.each_adjacent(v) do |u|
150
149
  b.call(u) if filter.call(v, u)
151
- }
152
- }
153
- g.edge_iterator { |b|
154
- self.each_edge { |u,v| b.call(u, v) if filter.call(u, v) }
155
- }
156
- }
150
+ end
151
+ end
152
+
153
+ g.edge_iterator do |b|
154
+ self.each_edge { |u, v| b.call(u, v) if filter.call(u, v) }
155
+ end
156
+ end
157
157
  end
158
158
 
159
159
  # Return a new ImplicitGraph which is isomorphic (i.e. has same edges and
160
- # vertices) to the receiver. It is a shortcut, also used by
160
+ # vertices) to the receiver. It is a shortcut, also used by
161
161
  # edges_filtered_by and vertices_filtered_by.
162
-
162
+ #
163
163
  def implicit_graph
164
- result = ImplicitGraph.new { |g|
164
+ result = ImplicitGraph.new do |g|
165
165
  g.vertex_iterator { |b| self.each_vertex(&b) }
166
166
  g.adjacent_iterator { |v, b| self.each_adjacent(v, &b) }
167
167
  g.directed = self.directed?
168
- }
168
+ end
169
+
169
170
  yield result if block_given? # let client overwrite defaults
170
171
  result
171
172
  end
172
173
 
173
- end # module Graph
174
- end # module RGL
174
+ end # module Graph
175
+
176
+ end # module RGL