rgl 0.5.1 → 0.5.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -77,7 +77,7 @@ def bfs_example(g = cycle(5), start = g.detect { |x| true })
77
77
  end
78
78
 
79
79
  # Would like to have GraphXML here
80
- def graph_from_dotfile (file)
80
+ def graph_from_dotfile(file)
81
81
  g = RGL::AdjacencyGraph.new
82
82
  pattern = /\s*([^\"]+)[\"\s]*--[\"\s]*([^\"\[\;]+)/ # ugly but works
83
83
  IO.foreach(file) { |line|
@@ -94,21 +94,23 @@ def graph_from_dotfile (file)
94
94
  g
95
95
  end
96
96
 
97
- # ruby -Ilib -r examples/examples.rb -rrgl/dot -e'bfs_example(module_graph,RGL::AdjacencyGraph).dotty'
98
-
97
+ # ruby -Ilib examples/examples.rb
99
98
  if $0 == __FILE__
100
99
  require 'rgl/dot'
101
100
 
102
101
  dg = RGL::DirectedAdjacencyGraph[1,2, 2,3, 2,4, 4,5, 6,4, 1,6]
103
- dg.dotty
104
102
  dg.write_to_graphic_file
105
- bfs_example(dg, 1).dotty
106
- bfs_example(graph_from_dotfile('dot/unix.dot'), 'Interdata').dotty({ 'label' => 'Interdata Nachfolger', 'fontsize' => 12 })
107
103
 
104
+ # BFS tree from 1 of dg:
105
+ bfs_example(dg, 1).write_to_graphic_file('png', 'bfs_example')
106
+
107
+ # Unix history as a graph:
108
+ g = bfs_example(graph_from_dotfile('examples/unix.dot'), 'Interdata')
109
+ g.write_to_graphic_file('png', 'unix', { 'label' => 'Interdata Nachfolger', 'fontsize' => 12 })
110
+
111
+ # Modules included by AdjacencyGraph:
108
112
  g = module_graph
109
113
  tree = bfs_example(module_graph, RGL::AdjacencyGraph)
110
114
  g = g.vertices_filtered_by { |v| tree.has_vertex? v }
111
- g.write_to_graphic_file
112
- g.dotty
115
+ g.write_to_graphic_file('png', 'module_graph')
113
116
  end
114
-
@@ -0,0 +1,53 @@
1
+ /* courtesy Ian Darwin and Geoff Collyer, Softquad Inc. */
2
+ digraph unix {
3
+ size="6,6";
4
+ "5th Edition" -> "6th Edition";
5
+ "5th Edition" -> "PWB 1.0";
6
+ "6th Edition" -> "LSX";
7
+ "6th Edition" -> "1 BSD";
8
+ "6th Edition" -> "Mini Unix";
9
+ "6th Edition" -> "Wollongong";
10
+ "6th Edition" -> "Interdata";
11
+ "Interdata" -> "Unix/TS 3.0";
12
+ "Interdata" -> "PWB 2.0";
13
+ "Interdata" -> "7th Edition";
14
+ "7th Edition" -> "8th Edition";
15
+ "7th Edition" -> "32V";
16
+ "7th Edition" -> "V7M";
17
+ "7th Edition" -> "Ultrix-11";
18
+ "7th Edition" -> "Xenix";
19
+ "7th Edition" -> "UniPlus+";
20
+ "V7M" -> "Ultrix-11";
21
+ "8th Edition" -> "9th Edition";
22
+ "1 BSD" -> "2 BSD";
23
+ "2 BSD" -> "2.8 BSD";
24
+ "2.8 BSD" -> "Ultrix-11";
25
+ "2.8 BSD" -> "2.9 BSD";
26
+ "32V" -> "3 BSD";
27
+ "3 BSD" -> "4 BSD";
28
+ "4 BSD" -> "4.1 BSD";
29
+ "4.1 BSD" -> "4.2 BSD";
30
+ "4.1 BSD" -> "2.8 BSD";
31
+ "4.1 BSD" -> "8th Edition";
32
+ "4.2 BSD" -> "4.3 BSD";
33
+ "4.2 BSD" -> "Ultrix-32";
34
+ "PWB 1.0" -> "PWB 1.2";
35
+ "PWB 1.0" -> "USG 1.0";
36
+ "PWB 1.2" -> "PWB 2.0";
37
+ "USG 1.0" -> "CB Unix 1";
38
+ "USG 1.0" -> "USG 2.0";
39
+ "CB Unix 1" -> "CB Unix 2";
40
+ "CB Unix 2" -> "CB Unix 3";
41
+ "CB Unix 3" -> "Unix/TS++";
42
+ "CB Unix 3" -> "PDP-11 Sys V";
43
+ "USG 2.0" -> "USG 3.0";
44
+ "USG 3.0" -> "Unix/TS 3.0";
45
+ "PWB 2.0" -> "Unix/TS 3.0";
46
+ "Unix/TS 1.0" -> "Unix/TS 3.0";
47
+ "Unix/TS 3.0" -> "TS 4.0";
48
+ "Unix/TS++" -> "TS 4.0";
49
+ "CB Unix 3" -> "TS 4.0";
50
+ "TS 4.0" -> "System V.0";
51
+ "System V.0" -> "System V.2";
52
+ "System V.2" -> "System V.3";
53
+ }
@@ -77,7 +77,7 @@ module RGL
77
77
  # Complexity is O(1), because the vertices are kept in a Hash containing
78
78
  # as values the lists of adjacent vertices of _v_.
79
79
  #
80
- def has_vertex? (v)
80
+ def has_vertex?(v)
81
81
  @vertices_dict.has_key?(v)
82
82
  end
83
83
 
@@ -87,7 +87,7 @@ module RGL
87
87
  # ---
88
88
  # MutableGraph interface.
89
89
  #
90
- def has_edge? (u, v)
90
+ def has_edge?(u, v)
91
91
  has_vertex?(u) && @vertices_dict[u].include?(v)
92
92
  end
93
93
 
@@ -4,9 +4,7 @@
4
4
  # library. The main module is RGL::Graph which defines the abstract behavior of
5
5
  # all graphs in the library.
6
6
 
7
- require 'rgl/enumerable_ext'
8
-
9
- RGL_VERSION = "0.5.1"
7
+ RGL_VERSION = "0.5.7"
10
8
 
11
9
  module RGL
12
10
  class NotDirectedError < RuntimeError; end
@@ -77,6 +75,9 @@ module RGL
77
75
  "(#{source}-#{target})"
78
76
  end
79
77
 
78
+ # Since Ruby 2.0 #inspect no longer calls #to_s. So we alias it to to_s (fixes #22)
79
+ alias inspect to_s
80
+
80
81
  # Returns the array [source,target].
81
82
  #
82
83
  def to_a
@@ -2,8 +2,7 @@ require 'rgl/dijkstra_visitor'
2
2
  require 'rgl/edge_properties_map'
3
3
  require 'rgl/path_builder'
4
4
 
5
- require 'delegate'
6
- require 'algorithms'
5
+ require 'lazy_priority_queue'
7
6
 
8
7
  module RGL
9
8
 
@@ -22,7 +22,7 @@ module RGL
22
22
  next if bfs.finished_vertex?(u)
23
23
 
24
24
  bfs.reset_start(u)
25
- bfs.move_forward_until { @found_odd_cycle }
25
+ bfs.move_forward_until { bfs.found_odd_cycle }
26
26
 
27
27
  return if bfs.found_odd_cycle
28
28
  end
@@ -84,4 +84,4 @@ module RGL
84
84
 
85
85
  end # class BipartiteBFSIterator
86
86
 
87
- end # module RGL
87
+ end # module RGL
@@ -2,8 +2,7 @@ require 'rgl/dijkstra_visitor'
2
2
  require 'rgl/edge_properties_map'
3
3
  require 'rgl/path_builder'
4
4
 
5
- require 'delegate'
6
- require 'algorithms'
5
+ require 'lazy_priority_queue'
7
6
 
8
7
  module RGL
9
8
 
@@ -55,7 +54,7 @@ module RGL
55
54
  def init(source)
56
55
  @visitor.set_source(source)
57
56
 
58
- @queue = Queue.new
57
+ @queue = MinPriorityQueue.new
59
58
  @queue.push(source, 0)
60
59
  end
61
60
 
@@ -82,8 +81,6 @@ module RGL
82
81
  new_v_distance = @distance_combinator.call(@visitor.distance_map[u], @edge_weights_map.edge_property(u, v))
83
82
 
84
83
  if new_v_distance < @visitor.distance_map[v]
85
- old_v_distance = @visitor.distance_map[v]
86
-
87
84
  @visitor.distance_map[v] = new_v_distance
88
85
  @visitor.parents_map[v] = u
89
86
 
@@ -91,7 +88,7 @@ module RGL
91
88
  @visitor.color_map[v] = :GRAY
92
89
  @queue.push(v, new_v_distance)
93
90
  elsif @visitor.color_map[v] == :GRAY
94
- @queue.decrease_key(v, old_v_distance, new_v_distance)
91
+ @queue.decrease_key(v, new_v_distance)
95
92
  end
96
93
 
97
94
  @visitor.handle_edge_relaxed(u, v)
@@ -104,29 +101,6 @@ module RGL
104
101
  edge_weights_map.is_a?(EdgePropertiesMap) ? edge_weights_map : NonNegativeEdgePropertiesMap.new(edge_weights_map, @graph.directed?)
105
102
  end
106
103
 
107
- class Queue < SimpleDelegator # :nodoc:
108
-
109
- def initialize
110
- @heap = Containers::Heap.new { |a, b| a.distance < b.distance }
111
- super(@heap)
112
- end
113
-
114
- def push(vertex, distance)
115
- @heap.push(vertex_key(vertex, distance), vertex)
116
- end
117
-
118
- def decrease_key(vertex, old_distance, new_distance)
119
- @heap.change_key(vertex_key(vertex, old_distance), vertex_key(vertex, new_distance))
120
- end
121
-
122
- def vertex_key(vertex, distance)
123
- VertexKey.new(vertex, distance)
124
- end
125
-
126
- VertexKey = Struct.new(:vertex, :distance)
127
-
128
- end
129
-
130
104
  end # class DijkstraAlgorithm
131
105
 
132
106
  module Graph
@@ -5,6 +5,9 @@
5
5
  # Minimal Dot support, based on Dave Thomas's dot module (included in rdoc).
6
6
  # rdot.rb is a modified version which also contains support for undirected
7
7
  # graphs.
8
+ #
9
+ # You need to have [GraphViz](http://www.graphviz.org) installed, because the
10
+ # functions in this modul execute the GraphViz executables _dot_ or _dotty_.
8
11
 
9
12
  require 'rgl/rdot'
10
13
 
@@ -17,6 +20,10 @@ module RGL
17
20
  v.to_s
18
21
  end
19
22
 
23
+ def vertex_id(v)
24
+ v
25
+ end
26
+
20
27
  # Return a RGL::DOT::Digraph for directed graphs or a DOT::Graph for an
21
28
  # undirected Graph. _params_ can contain any graph property specified in
22
29
  # rdot.rb.
@@ -26,21 +33,29 @@ module RGL
26
33
  fontsize = params['fontsize'] ? params['fontsize'] : '8'
27
34
  graph = (directed? ? DOT::Digraph : DOT::Graph).new(params)
28
35
  edge_class = directed? ? DOT::DirectedEdge : DOT::Edge
36
+ vertex_options = params['vertex'] || {}
37
+ edge_options = params['edge'] || {}
29
38
 
30
39
  each_vertex do |v|
31
- graph << DOT::Node.new(
32
- 'name' => v.object_id,
33
- 'fontsize' => fontsize,
34
- 'label' => vertex_label(v)
35
- )
40
+ default_vertex_options = {
41
+ 'name' => vertex_id(v),
42
+ 'fontsize' => fontsize,
43
+ 'label' => vertex_label(v)
44
+ }
45
+ each_vertex_options = default_vertex_options.merge(vertex_options)
46
+ vertex_options.each{|option, val| each_vertex_options[option] = val.call(v) if val.is_a?(Proc)}
47
+ graph << DOT::Node.new(each_vertex_options)
36
48
  end
37
49
 
38
50
  each_edge do |u, v|
39
- graph << edge_class.new(
40
- 'from' => u.object_id,
41
- 'to' => v.object_id,
42
- 'fontsize' => fontsize
43
- )
51
+ default_edge_options = {
52
+ 'from' => vertex_id(u),
53
+ 'to' => vertex_id(v),
54
+ 'fontsize' => fontsize
55
+ }
56
+ each_edge_options = default_edge_options.merge(edge_options)
57
+ edge_options.each{|option, val| each_edge_options[option] = val.call(u, v) if val.is_a?(Proc)}
58
+ graph << edge_class.new(each_edge_options)
44
59
  end
45
60
 
46
61
  graph
@@ -60,21 +75,25 @@ module RGL
60
75
  File.open(dotfile, "w") do |f|
61
76
  print_dotted_on(params, f)
62
77
  end
63
- system("dotty", dotfile)
78
+ unless system("dotty", dotfile)
79
+ raise "Error executing dotty. Did you install GraphViz?"
80
+ end
64
81
  end
65
82
 
66
83
  # Use dot[http://www.graphviz.org] to create a graphical representation of
67
84
  # the graph. Returns the filename of the graphics file.
68
85
  #
69
- def write_to_graphic_file(fmt='png', dotfile="graph")
86
+ def write_to_graphic_file(fmt='png', dotfile="graph", options={})
70
87
  src = dotfile + ".dot"
71
88
  dot = dotfile + "." + fmt
72
89
 
73
90
  File.open(src, 'w') do |f|
74
- f << self.to_dot_graph.to_s << "\n"
91
+ f << self.to_dot_graph(options).to_s << "\n"
75
92
  end
76
93
 
77
- system("dot -T#{fmt} #{src} -o #{dot}")
94
+ unless system("dot -T#{fmt} #{src} -o #{dot}")
95
+ raise "Error executing dot. Did you install GraphViz?"
96
+ end
78
97
  dot
79
98
  end
80
99
 
@@ -46,9 +46,9 @@ module RGL
46
46
  min_residual_capacity = [min_residual_capacity, @residual_capacity_map[u, v]].min
47
47
  end
48
48
 
49
- augmenting_path.each_cons(2) do |(u, v)|
50
- @flow_map[[u, v]] += min_residual_capacity
51
- @flow_map[[v, u]] -= min_residual_capacity
49
+ augmenting_path.each_cons(2) do |(uu, vv)|
50
+ @flow_map[[uu, vv]] += min_residual_capacity
51
+ @flow_map[[vv, uu]] -= min_residual_capacity
52
52
  end
53
53
  end
54
54
  end
@@ -133,4 +133,4 @@ module RGL
133
133
 
134
134
  end # module Graph
135
135
 
136
- end
136
+ end
@@ -10,6 +10,10 @@ module RGL
10
10
  module GraphIterator
11
11
  include Stream
12
12
  include GraphWrapper
13
+
14
+ def length
15
+ inject(0) { |sum| sum + 1 }
16
+ end
13
17
  end
14
18
 
15
19
  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://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
@@ -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 http://www.graphdrawing.org/graphml).
51
+ # +source+ (see http://graphml.graphdrawing.org/).
52
52
  #
53
53
  def from_graphxml(source)
54
54
  listener = MutableGraphParser.new(self)
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rgl/traversal'
4
+
5
+ module RGL
6
+ module Graph
7
+ # Checks whether a path exists between _source_ and _target_ vertices
8
+ # in the graph.
9
+ #
10
+ def path?(source, target)
11
+ return false unless has_vertex?(source)
12
+
13
+ bfs_iterator = bfs_iterator(source)
14
+ bfs_iterator.include?(target)
15
+ end
16
+ end
17
+ end
@@ -328,7 +328,7 @@ module RGL
328
328
  # :call-seq:
329
329
  # graph << element -> graph
330
330
  #
331
- def << (element)
331
+ def <<(element)
332
332
  @elements << element
333
333
  self
334
334
  end
@@ -58,9 +58,12 @@ module RGL
58
58
  # Reset the iterator to the initial state (i.e. at_beginning? == true).
59
59
  #
60
60
  def set_to_begin
61
+ # Reset color_map
62
+ @color_map = Hash.new(:WHITE)
61
63
  color_map[@start_vertex] = :GRAY
62
- @waiting = [@start_vertex] # a queue
64
+ @waiting = [@start_vertex] # a queue
63
65
  handle_tree_edge(nil, @start_vertex) # discovers start vertex
66
+ self
64
67
  end
65
68
 
66
69
  def basic_forward # :nodoc:
@@ -169,6 +172,10 @@ module RGL
169
172
  # it is called on each _finish_vertex_ event. See
170
173
  # strongly_connected_components for an example usage.
171
174
  #
175
+ # Note that this traversal does not garantee, that roots are at the top of
176
+ # each spanning subtree induced by the DFS search on a directed graph (see
177
+ # also the discussion in issue #20[https://github.com/monora/rgl/issues/20]).
178
+ #
172
179
  def depth_first_search(vis = DFSVisitor.new(self), &b)
173
180
  each_vertex do |u|
174
181
  unless vis.finished_vertex?(u)
@@ -61,7 +61,7 @@ i -> h j e c
61
61
 
62
62
  assert_equal(4, vis.num_comp)
63
63
 
64
- res = vis.comp_map.to_a.sort.reduce({}) { |res, a|
64
+ result = vis.comp_map.to_a.sort.reduce({}) { |res, a|
65
65
  if res.key?(a[1])
66
66
  res[a[1]] << a[0]
67
67
  else
@@ -70,7 +70,7 @@ i -> h j e c
70
70
  res
71
71
  }
72
72
 
73
- std_res = res.to_a.map {
73
+ std_res = result.to_a.map {
74
74
  |a|
75
75
  [a[1][0], a[1]]
76
76
  }.sort
@@ -0,0 +1,23 @@
1
+ require 'test_helper'
2
+
3
+ require 'rgl/dijkstra'
4
+ require 'rgl/adjacency'
5
+
6
+ include RGL
7
+
8
+ class TestDijkstraIssue24 < Test::Unit::TestCase
9
+
10
+ def setup
11
+ @graph = RGL::AdjacencyGraph[2,53, 2,3, 3,8, 3,28, 3,39, 29,58, 8,35, 12,39, 10,29, 62,15, 15,32, 32,58, 58,44, 44,53]
12
+
13
+ end
14
+
15
+ def test_shortest_path_search
16
+ assert_equal([53, 44, 58, 32, 15, 62], shortest_path(53, 62))
17
+ end
18
+
19
+ def shortest_path(v,w)
20
+ @graph.dijkstra_shortest_path(Hash.new(1), v, w)
21
+ end
22
+
23
+ end