gratr19 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/README +335 -0
  2. data/examples/graph_self.rb +54 -0
  3. data/examples/module_graph.jpg +0 -0
  4. data/examples/module_graph.rb +12 -0
  5. data/examples/self_graph.jpg +0 -0
  6. data/examples/visualize.jpg +0 -0
  7. data/examples/visualize.rb +8 -0
  8. data/install.rb +49 -0
  9. data/lib/gratr.rb +42 -0
  10. data/lib/gratr/adjacency_graph.rb +230 -0
  11. data/lib/gratr/base.rb +34 -0
  12. data/lib/gratr/biconnected.rb +116 -0
  13. data/lib/gratr/chinese_postman.rb +123 -0
  14. data/lib/gratr/common.rb +74 -0
  15. data/lib/gratr/comparability.rb +92 -0
  16. data/lib/gratr/digraph.rb +115 -0
  17. data/lib/gratr/digraph_distance.rb +185 -0
  18. data/lib/gratr/dot.rb +90 -0
  19. data/lib/gratr/edge.rb +145 -0
  20. data/lib/gratr/graph.rb +314 -0
  21. data/lib/gratr/graph_api.rb +82 -0
  22. data/lib/gratr/import.rb +44 -0
  23. data/lib/gratr/labels.rb +103 -0
  24. data/lib/gratr/maximum_flow.rb +107 -0
  25. data/lib/gratr/rdot.rb +332 -0
  26. data/lib/gratr/search.rb +422 -0
  27. data/lib/gratr/strong_components.rb +127 -0
  28. data/lib/gratr/undirected_graph.rb +153 -0
  29. data/lib/gratr/version.rb +6 -0
  30. data/lib/priority-queue/benchmark/dijkstra.rb +171 -0
  31. data/lib/priority-queue/compare_comments.rb +49 -0
  32. data/lib/priority-queue/ext/priority_queue/CPriorityQueue/extconf.rb +2 -0
  33. data/lib/priority-queue/lib/priority_queue.rb +14 -0
  34. data/lib/priority-queue/lib/priority_queue/c_priority_queue.rb +1 -0
  35. data/lib/priority-queue/lib/priority_queue/poor_priority_queue.rb +46 -0
  36. data/lib/priority-queue/lib/priority_queue/ruby_priority_queue.rb +525 -0
  37. data/lib/priority-queue/setup.rb +1551 -0
  38. data/lib/priority-queue/test/priority_queue_test.rb +371 -0
  39. data/tests/TestBiconnected.rb +53 -0
  40. data/tests/TestChinesePostman.rb +53 -0
  41. data/tests/TestComplement.rb +54 -0
  42. data/tests/TestDigraph.rb +333 -0
  43. data/tests/TestDigraphDistance.rb +138 -0
  44. data/tests/TestDot.rb +75 -0
  45. data/tests/TestEdge.rb +171 -0
  46. data/tests/TestInspection.rb +57 -0
  47. data/tests/TestMultiEdge.rb +57 -0
  48. data/tests/TestNeighborhood.rb +64 -0
  49. data/tests/TestProperties.rb +160 -0
  50. data/tests/TestSearch.rb +277 -0
  51. data/tests/TestStrongComponents.rb +85 -0
  52. data/tests/TestTriagulated.rb +137 -0
  53. data/tests/TestUndirectedGraph.rb +219 -0
  54. metadata +152 -0
@@ -0,0 +1,82 @@
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 AREf
20
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+ #++
27
+
28
+
29
+ module GRATR
30
+
31
+ # This defines the minimum set of functions required to make a graph class that can
32
+ # use the algorithms defined by this library
33
+ module GraphAPI
34
+
35
+ # Is the graph directed?
36
+ #
37
+ # This method must be implemented by the specific graph class
38
+ def directed?() raise NotImplementedError; end
39
+
40
+ # Add a vertex to the Graph and return the Graph
41
+ # An additional label l can be specified as well
42
+ #
43
+ # This method must be implemented by the specific graph class
44
+ def add_vertex!(v,l=nil) raise NotImplementedError; end
45
+
46
+ # Add an edge to the Graph and return the Graph
47
+ # u can be an object of type GRATR::Arc or u,v specifies
48
+ # a source, target pair. The last parameter is an optional label
49
+ #
50
+ # This method must be implemented by the specific graph class
51
+ def add_edge!(u,v=nil,l=nil) raise NotImplementedError; end
52
+
53
+ # Remove a vertex to the Graph and return the Graph
54
+ #
55
+ # This method must be implemented by the specific graph class
56
+ def remove_vertex!(v) raise NotImplementedError; end
57
+
58
+ # Remove an edge from the Graph and return the Graph
59
+ #
60
+ # Can be a type of GRATR::Arc or a source and target
61
+ # This method must be implemented by the specific graph class
62
+ def remove_edge!(u,v=nil) raise NotImplementedError; end
63
+
64
+ # Return the array of vertices.
65
+ #
66
+ # This method must be implemented by the specific graph class
67
+ def vertices() raise NotImplementedError; end
68
+
69
+ # Return the array of edges.
70
+ #
71
+ # This method must be implemented by the specific graph class
72
+ def edges() raise NotImplementedError; end
73
+
74
+ # Returns the edge class
75
+ def edge_class() raise NotImplementedError; end
76
+
77
+ # Return the chromatic number for this graph
78
+ # This is currently incomplete and in some cases will be NP-complete
79
+ # FIXME: Should this even be here? My gut feeling is no...
80
+ def chromatic_number() raise NotImplementedError; end
81
+ end
82
+ end
@@ -0,0 +1,44 @@
1
+ #--
2
+ # Copyright (c) 2006 Shawn Patrick Garbett
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without modification,
5
+ # are permitted provided that the following conditions are met:
6
+ #
7
+ # * Redistributions of source code must retain the above copyright notice(s),
8
+ # this list of conditions and the following disclaimer.
9
+ # * Redistributions in binary form must reproduce the above copyright notice,
10
+ # this list of conditions and the following disclaimer in the documentation
11
+ # and/or other materials provided with the distribution.
12
+ # * Neither the name of the Shawn Garbett nor the names of its contributors
13
+ # may be used to endorse or promote products derived from this software
14
+ # without specific prior written permission.
15
+ #
16
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+ #++
27
+
28
+
29
+ require 'gratr'
30
+
31
+ # Pull all GRATR classes up into the current namespace
32
+ Arc = GRATR::Arc
33
+ Edge = GRATR::Edge
34
+ MultiArc = GRATR::MultiArc
35
+ MultiEdge = GRATR::MultiEdge
36
+ Graph = GRATR::Graph
37
+ Digraph = GRATR::Digraph
38
+ DirectedGraph = GRATR::DirectedGraph
39
+ DirectedPseudoGraph = GRATR::DirectedPseudoGraph
40
+ DirectedMultiGraph = GRATR::DirectedMultiGraph
41
+ UndirectedGraph = GRATR::UndirectedGraph
42
+ UndirectedPseudoGraph = GRATR::UndirectedPseudoGraph
43
+ UndirectedMultiGraph = GRATR::UndirectedMultiGraph
44
+ Complete = GRATR::Complete
@@ -0,0 +1,103 @@
1
+ #--
2
+ # Copyright (c) 2006 Shawn Patrick Garbett
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without modification,
5
+ # are permitted provided that the following conditions are met:
6
+ #
7
+ # * Redistributions of source code must retain the above copyright notice(s),
8
+ # this list of conditions and the following disclaimer.
9
+ # * Redistributions in binary form must reproduce the above copyright notice,
10
+ # this list of conditions and the following disclaimer in the documentation
11
+ # and/or other materials provided with the distribution.
12
+ # * Neither the name of the Shawn Garbett nor the names of its contributors
13
+ # may be used to endorse or promote products derived from this software
14
+ # without specific prior written permission.
15
+ #
16
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+ #++
27
+
28
+ module GRATR
29
+ module Labels
30
+ # Return a label for an edge or vertex
31
+ def [](u) (u.kind_of? GRATR::Arc) ? edge_label(u) : vertex_label(u); end
32
+
33
+ # Set a label for an edge or vertex
34
+ def []= (u, value) (u.kind_of? GRATR::Arc) ? edge_label_set(u,value) : vertex_label_set(u, value); end
35
+
36
+ # Delete a label entirely
37
+ def delete_label(u) (u.kind_of? GRATR::Arc) ? edge_label_delete(u) : vertex_label_delete(u); end
38
+
39
+ # Get the label for an edge
40
+ def vertex_label(v) vertex_label_dict[v]; end
41
+
42
+ # Set the label for an edge
43
+ def vertex_label_set(v, l) vertex_label_dict[v] = l; self; end
44
+
45
+ # Get the label for an edge
46
+ def edge_label(u,v=nil,n=nil)
47
+ u = edge_convert(u,v,n)
48
+ edge_label_dict[u]
49
+ end
50
+
51
+ # Set the label for an edge
52
+ def edge_label_set(u, v=nil, l=nil, n=nil)
53
+ u.kind_of?(GRATR::Arc) ? l = v : u = edge_convert(u,v,n)
54
+ edge_label_dict[u] = l; self
55
+ end
56
+
57
+ # Delete all graph labels
58
+ def clear_all_labels() @vertex_labels = {}; @edge_labels = {}; end
59
+
60
+ # Delete an edge label
61
+ def edge_label_delete(u, v=nil, n=nil)
62
+ u = edge_convert(u,v,n)
63
+ edge_label_dict.delete(u)
64
+ end
65
+
66
+ # Delete a vertex label
67
+ def vertex_label_delete(v) vertex_label_dict.delete(v); end
68
+
69
+ protected
70
+
71
+ def vertex_label_dict() @vertex_labels ||= {}; end
72
+ def edge_label_dict() @edge_labels ||= {}; end
73
+
74
+ # A generic cost function. It either calls the weight function with and edge
75
+ # constructed from the two nodes, or calls the [] operator of the label
76
+ # when given a value. If no weight value is specified, the label itself is
77
+ # treated as the cost value.
78
+ #
79
+ # Note: This function will not work for Pseudo or Multi graphs at present.
80
+ # FIXME: Remove u,v interface to fix Pseudo Multi graph problems.
81
+ def cost(u,v=nil,weight=nil)
82
+ u.kind_of?(Arc) ? weight = v : u = edge_class[u,v]
83
+ case weight
84
+ when Proc : weight.call(u)
85
+ when nil : self[u]
86
+ else self[u][weight]
87
+ end
88
+ end
89
+
90
+ # An alias of cost for property retrieval in general
91
+ alias property cost
92
+
93
+ # A function to set properties specified by the user.
94
+ def property_set(u,name,value)
95
+ case name
96
+ when Proc : name.call(value)
97
+ when nil : self[u] = value
98
+ else self[u][name] = value
99
+ end
100
+ end
101
+
102
+ end
103
+ end
@@ -0,0 +1,107 @@
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 'gratr/digraph'
30
+
31
+ module GRATR
32
+
33
+ class Network < Digraph
34
+ attr_accessor :lower, :upper, :cost, :flow
35
+
36
+ def residual(residual_capacity, cost_property, zero = 0)
37
+ r = Digraph.new
38
+ edges.each do |e1|
39
+ [e1,e1.reverse].each do |e|
40
+ rij = property(e,self.upper) - property(e,self.flow) if edge? e
41
+ rij += property(e.reverse,self.flow) - property(e.reverse,self.lower) if edge? e.reverse
42
+ r.add_edge!(e) if rij > zero
43
+ r.property_set(e,residual_capacity, rij)
44
+ r.property_set(e,cost, cost(e,cost_property))
45
+ end
46
+ end
47
+ r
48
+ end
49
+
50
+ def maximum_flow() eliminate_lower_bounds.maximum_flow_prime.restore_lower_bounds(self); end
51
+
52
+ private:
53
+
54
+ def eliminate_lower_bounds
55
+ no_lower_bounds = Digraph.new(self)
56
+ if self.upper.kind_of? Proc then
57
+ no_lower_bounds.upper = Proc.new {|e| self.upper.call(e) - property(e,self.lower) }
58
+ else
59
+ no_lower_bounds.edges.each {|e| no_lower_bounds[e][self.upper] -= property(e,self.lower)}
60
+ end
61
+ no_lower_bounds
62
+ end
63
+
64
+ def restore_lower_bounds(src)
65
+ src.edges.each do {|e| (src.flow ? src[e][src.flow] : src[e]) = property(e,self.flow) + src.property(e,self.lower) }
66
+ src
67
+ end
68
+
69
+ def maximum_flow_prime
70
+ end
71
+
72
+ end
73
+
74
+ module Graph
75
+
76
+ module MaximumFlow
77
+
78
+ # Maximum flow, it returns an array with the maximum flow and a hash of flow per edge
79
+ # Currently a highly inefficient implementation, FIXME, This should use Goldberg and Tarjan's method.
80
+ def maximum_flow(s, t, capacity = nil, zero = 0)
81
+ flow = Hash.new(zero)
82
+ available = Hash.new(zero)
83
+ total = zero
84
+ edges.each {|e| available[e] = cost(e,capacity)}
85
+ adj_positive = Proc.new do |u|
86
+ adjacent(u).select {|r| available[edge_class[u,r]] > zero}
87
+ end
88
+ while (tree = bfs_tree_from_vertex(start))[t]
89
+ route = [t]
90
+ while route[-1] != s
91
+ route << tree[route[route[-1]]]
92
+ raise ArgumentError, "No route from #{s} to #{t} possible"
93
+ end; route.reverse
94
+ amt = route.map {|e| available[e]}.min
95
+ route.each do |e|
96
+ flow[e] += amt
97
+ available[e] -= amt
98
+ end
99
+ total += amt
100
+ end
101
+
102
+ [total, flow]
103
+ end
104
+
105
+ end # MaximumFlow
106
+ end # Graph
107
+ end # GRATR
@@ -0,0 +1,332 @@
1
+ # rdot.rb
2
+ #
3
+ # $Id: rdot.rb,v 1.4 2005/03/26 15:06:36 wsdng Exp $
4
+ #
5
+ # This is a modified version of dot.rb from Dave Thomas's rdoc project. I [Horst Duchene]
6
+ # renamed it to rdot.rb to avoid collision with an installed rdoc/dot.
7
+ #
8
+ # It also supports undirected edges.
9
+
10
+ class Hash
11
+ def stringify_keys
12
+ inject({}) {|options, (key, value)| options[key.to_s] = value; options}
13
+ end
14
+ end unless Hash.respond_to? :stringify_keys
15
+
16
+ module DOT
17
+
18
+ # These glogal vars are used to make nice graph source.
19
+
20
+ $tab = ' '
21
+ $tab2 = $tab * 2
22
+
23
+ # if we don't like 4 spaces, we can change it any time
24
+
25
+ def change_tab (t)
26
+ $tab = t
27
+ $tab2 = t * 2
28
+ end
29
+
30
+ # options for node declaration
31
+
32
+ NODE_OPTS = [
33
+ # attributes due to
34
+ # http://www.graphviz.org/Documentation/dotguide.pdf
35
+ # March, 26, 2005
36
+ 'bottomlabel', # auxiliary label for nodes of shape M*
37
+ 'color', # default: black; node shape color
38
+ 'comment', # any string (format-dependent)
39
+ 'distortion', # default: 0.0; node distortion for shape=polygon
40
+ 'fillcolor', # default: lightgrey/black; node fill color
41
+ 'fixedsize', # default: false; label text has no affect on node size
42
+ 'fontcolor', # default: black; type face color
43
+ 'fontname', # default: Times-Roman; font family
44
+ 'fontsize', #default: 14; point size of label
45
+ 'group', # name of node�s group
46
+ 'height', # default: .5; height in inches
47
+ 'label', # default: node name; any string
48
+ 'layer', # default: overlay range; all, id or id:id
49
+ 'orientation', # dafault: 0.0; node rotation angle
50
+ 'peripheries', # shape-dependent number of node boundaries
51
+ 'regular', # default: false; force polygon to be regular
52
+ 'shape', # default: ellipse; node shape; see Section 2.1 and Appendix E
53
+ 'shapefile', # external EPSF or SVG custom shape file
54
+ 'sides', # default: 4; number of sides for shape=polygon
55
+ 'skew' , # default: 0.0; skewing of node for shape=polygon
56
+ 'style', # graphics options, e.g. bold, dotted, filled; cf. Section 2.3
57
+ 'toplabel', # auxiliary label for nodes of shape M*
58
+ 'URL', # URL associated with node (format-dependent)
59
+ 'width', # default: .75; width in inches
60
+ 'z', #default: 0.0; z coordinate for VRML output
61
+
62
+ # maintained for backward compatibility or rdot internal
63
+ 'bgcolor',
64
+ 'rank'
65
+ ]
66
+
67
+ # options for edge declaration
68
+
69
+ EDGE_OPTS = [
70
+ 'arrowhead', # default: normal; style of arrowhead at head end
71
+ 'arrowsize', # default: 1.0; scaling factor for arrowheads
72
+ 'arrowtail', # default: normal; style of arrowhead at tail end
73
+ 'color', # default: black; edge stroke color
74
+ 'comment', # any string (format-dependent)
75
+ 'constraint', # default: true use edge to affect node ranking
76
+ 'decorate', # if set, draws a line connecting labels with their edges
77
+ 'dir', # default: forward; forward, back, both, or none
78
+ 'fontcolor', # default: black type face color
79
+ 'fontname', # default: Times-Roman; font family
80
+ 'fontsize', # default: 14; point size of label
81
+ 'headlabel', # label placed near head of edge
82
+ 'headport', # n,ne,e,se,s,sw,w,nw
83
+ 'headURL', # URL attached to head label if output format is ismap
84
+ 'label', # edge label
85
+ 'labelangle', # default: -25.0; angle in degrees which head or tail label is rotated off edge
86
+ 'labeldistance', # default: 1.0; scaling factor for distance of head or tail label from node
87
+ 'labelfloat', # default: false; lessen constraints on edge label placement
88
+ 'labelfontcolor', # default: black; type face color for head and tail labels
89
+ 'labelfontname', # default: Times-Roman; font family for head and tail labels
90
+ 'labelfontsize', # default: 14 point size for head and tail labels
91
+ 'layer', # default: overlay range; all, id or id:id
92
+ 'lhead', # name of cluster to use as head of edge
93
+ 'ltail', # name of cluster to use as tail of edge
94
+ 'minlen', # default: 1 minimum rank distance between head and tail
95
+ 'samehead', # tag for head node; edge heads with the same tag are merged onto the same port
96
+ 'sametail', # tag for tail node; edge tails with the same tag are merged onto the same port
97
+ 'style', # graphics options, e.g. bold, dotted, filled; cf. Section 2.3
98
+ 'taillabel', # label placed near tail of edge
99
+ 'tailport', # n,ne,e,se,s,sw,w,nw
100
+ 'tailURL', # URL attached to tail label if output format is ismap
101
+ 'weight', # default: 1; integer cost of stretching an edge
102
+
103
+ # maintained for backward compatibility or rdot internal
104
+ 'id'
105
+ ]
106
+
107
+ # options for graph declaration
108
+
109
+ GRAPH_OPTS = [
110
+ 'bgcolor',
111
+ 'center', 'clusterrank', 'color', 'concentrate',
112
+ 'fontcolor', 'fontname', 'fontsize',
113
+ 'label', 'layerseq',
114
+ 'margin', 'mclimit',
115
+ 'nodesep', 'nslimit',
116
+ 'ordering', 'orientation',
117
+ 'page',
118
+ 'rank', 'rankdir', 'ranksep', 'ratio',
119
+ 'size'
120
+ ]
121
+
122
+ # a root class for any element in dot notation
123
+
124
+ class DOTSimpleElement
125
+
126
+ attr_accessor :name
127
+
128
+ def initialize (params = {})
129
+ @label = params['name'] ? params['name'] : ''
130
+ end
131
+
132
+ def to_s
133
+ @name
134
+ end
135
+ end
136
+
137
+ # an element that has options ( node, edge, or graph )
138
+
139
+ class DOTElement < DOTSimpleElement
140
+
141
+ # attr_reader :parent
142
+ attr_accessor :name, :options
143
+
144
+ def initialize (params = {}, option_list = [])
145
+ super(params)
146
+ @name = params['name'] ? params['name'] : nil
147
+ @parent = params['parent'] ? params['parent'] : nil
148
+ @options = {}
149
+ p = params.stringify_keys
150
+ option_list.each {|i| @options[i] = p[i] if p[i] }
151
+ @options['label'] ||= @name if @name != 'node'
152
+ end
153
+
154
+ def each_option
155
+ @options.each{ |i| yield i }
156
+ end
157
+
158
+ def each_option_pair
159
+ @options.each_pair{ |key, val| yield key, val }
160
+ end
161
+
162
+ #def parent=( thing )
163
+ # @parent.delete( self ) if defined?( @parent ) and @parent
164
+ # @parent = thing
165
+ #end
166
+
167
+ end
168
+
169
+
170
+ # This is used when we build nodes that have shape=record
171
+ # ports don't have options :)
172
+
173
+ class DOTPort < DOTSimpleElement
174
+
175
+ attr_accessor :label
176
+
177
+ def initialize (params = {})
178
+ super(params)
179
+ @name = params['label'] ? params['label'] : ''
180
+ end
181
+
182
+ def to_s
183
+ ( @name && @name != "" ? "<#{@name}>" : "" ) + "#{@label}"
184
+ end
185
+ end
186
+
187
+ # node element
188
+
189
+ class DOTNode < DOTElement
190
+
191
+ @ports
192
+
193
+ def initialize (params = {}, option_list = NODE_OPTS)
194
+ super(params, option_list)
195
+ @ports = params['ports'] ? params['ports'] : []
196
+ end
197
+
198
+ def each_port
199
+ @ports.each { |i| yield i }
200
+ end
201
+
202
+ def << (thing)
203
+ @ports << thing
204
+ end
205
+
206
+ def push (thing)
207
+ @ports.push(thing)
208
+ end
209
+
210
+ def pop
211
+ @ports.pop
212
+ end
213
+
214
+ def to_s (t = '')
215
+
216
+ # This code is totally incomprehensible; it needs to be replaced!
217
+
218
+ label = @options['shape'] != 'record' && @ports.length == 0 ?
219
+ @options['label'] ?
220
+ t + $tab + "label = \"#{@options['label']}\"\n" :
221
+ '' :
222
+ t + $tab + 'label = "' + " \\\n" +
223
+ t + $tab2 + "#{@options['label']}| \\\n" +
224
+ @ports.collect{ |i|
225
+ t + $tab2 + i.to_s
226
+ }.join( "| \\\n" ) + " \\\n" +
227
+ t + $tab + '"' + "\n"
228
+
229
+ t + "#{@name} [\n" +
230
+ @options.to_a.collect{ |i|
231
+ i[1] && i[0] != 'label' ?
232
+ t + $tab + "#{i[0]} = #{i[1]}" : nil
233
+ }.compact.join( ",\n" ) + ( label != '' ? ",\n" : "\n" ) +
234
+ label +
235
+ t + "]\n"
236
+ end
237
+
238
+ end # class DOTNode
239
+
240
+ # A subgraph element is the same to graph, but has another header in dot
241
+ # notation.
242
+
243
+ class DOTSubgraph < DOTElement
244
+
245
+ @nodes
246
+ @dot_string
247
+
248
+ def initialize (params = {}, option_list = GRAPH_OPTS)
249
+ super(params, option_list)
250
+ @nodes = params['nodes'] ? params['nodes'] : []
251
+ @dot_string = 'graph'
252
+ end
253
+
254
+ def each_node
255
+ @nodes.each{ |i| yield i }
256
+ end
257
+
258
+ def << (thing)
259
+ @nodes << thing
260
+ end
261
+
262
+ def push (thing)
263
+ @nodes.push( thing )
264
+ end
265
+
266
+ def pop
267
+ @nodes.pop
268
+ end
269
+
270
+ def to_s (t = '')
271
+ hdr = t + "#{@dot_string} #{@name} {\n"
272
+
273
+ options = @options.to_a.collect{ |name, val|
274
+ val && name != 'label' ?
275
+ t + $tab + "#{name} = #{val}" :
276
+ name ? t + $tab + "#{name} = \"#{val}\"" : nil
277
+ }.compact.join( "\n" ) + "\n"
278
+
279
+ nodes = @nodes.collect{ |i|
280
+ i.to_s( t + $tab )
281
+ }.join( "\n" ) + "\n"
282
+ hdr + options + nodes + t + "}\n"
283
+ end
284
+
285
+ end # class DOTSubgraph
286
+
287
+ # This is a graph.
288
+
289
+ class DOTDigraph < DOTSubgraph
290
+
291
+ def initialize (params = {}, option_list = GRAPH_OPTS)
292
+ super(params, option_list)
293
+ @dot_string = 'digraph'
294
+ end
295
+
296
+ end # class DOTDigraph
297
+
298
+ # This is an edge.
299
+
300
+ class DOTArc < DOTElement
301
+
302
+ attr_accessor :from, :to
303
+
304
+ def initialize (params = {}, option_list = EDGE_OPTS)
305
+ super(params, option_list)
306
+ @from = params['from'] ? params['from'] : nil
307
+ @to = params['to'] ? params['to'] : nil
308
+ end
309
+
310
+ def edge_link
311
+ '--'
312
+ end
313
+
314
+ def to_s (t = '')
315
+ t + "#{@from} #{edge_link} #{to} [\n" +
316
+ @options.to_a.collect{ |i|
317
+ i[1] && i[0] != 'label' ?
318
+ t + $tab + "#{i[0]} = #{i[1]}" :
319
+ i[1] ? t + $tab + "#{i[0]} = \"#{i[1]}\"" : nil
320
+ }.compact.join( "\n" ) + "\n" + t + "]\n"
321
+ end
322
+
323
+ end # class DOTArc
324
+
325
+ class DOTDirectedArc < DOTArc
326
+
327
+ def edge_link
328
+ '->'
329
+ end
330
+
331
+ end # class DOTDirectedArc
332
+ end # module DOT