ruby-graphviz_c 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gemrc +0 -0
- data/.gitignore +9 -0
- data/.travis.yml +7 -0
- data/AUTHORS.rdoc +33 -0
- data/CHANGELOG.rdoc +287 -0
- data/COPYING.rdoc +133 -0
- data/Gemfile +4 -0
- data/README.rdoc +206 -0
- data/Rakefile +71 -0
- data/bin/dot2ruby +91 -0
- data/bin/gem2gv +165 -0
- data/bin/git2gv +167 -0
- data/bin/ruby2gv +234 -0
- data/bin/xml2gv +96 -0
- data/examples/dot/JSP.dot +52 -0
- data/examples/dot/balanced.dot +36 -0
- data/examples/dot/cluster.dot +30 -0
- data/examples/dot/dotgraph.dot +28 -0
- data/examples/dot/fsm.dot +20 -0
- data/examples/dot/genetic.dot +118 -0
- data/examples/dot/hello.dot +1 -0
- data/examples/dot/hello_test.rb +33 -0
- data/examples/dot/lion_share.dot +103 -0
- data/examples/dot/prof.dot +150 -0
- data/examples/dot/psg.dot +28 -0
- data/examples/dot/rank.dot +6 -0
- data/examples/dot/sdh.dot +284 -0
- data/examples/dot/siblings.dot +492 -0
- data/examples/dot/so-sample001.gv +30 -0
- data/examples/dot/so-sample002.gv +33 -0
- data/examples/dot/so-sample003.gv +45 -0
- data/examples/dot/test.dot +17 -0
- data/examples/dot/test_parse.rb +13 -0
- data/examples/dot/this_crach_with_dot_2.20.dot +24 -0
- data/examples/dot/unix.dot +104 -0
- data/examples/graphml/attributes.ext.graphml +12 -0
- data/examples/graphml/attributes.graphml +40 -0
- data/examples/graphml/cluster.graphml +75 -0
- data/examples/graphml/failed_graph.graphml +461 -0
- data/examples/graphml/hyper.graphml +29 -0
- data/examples/graphml/nested.graphml +54 -0
- data/examples/graphml/port.graphml +32 -0
- data/examples/graphml/simple.graphml +30 -0
- data/examples/hello.png +0 -0
- data/examples/rgv/rgv.ps +125 -0
- data/examples/rgv/test_rgv.rb +12 -0
- data/examples/sample01.rb +32 -0
- data/examples/sample02.rb +42 -0
- data/examples/sample03.rb +31 -0
- data/examples/sample04.rb +22 -0
- data/examples/sample05.rb +32 -0
- data/examples/sample06.rb +46 -0
- data/examples/sample07.rb +23 -0
- data/examples/sample08.rb +34 -0
- data/examples/sample09.rb +50 -0
- data/examples/sample10.rb +50 -0
- data/examples/sample11.rb +42 -0
- data/examples/sample12.rb +55 -0
- data/examples/sample13.rb +48 -0
- data/examples/sample14.rb +44 -0
- data/examples/sample15.rb +25 -0
- data/examples/sample16.rb +8 -0
- data/examples/sample17.rb +92 -0
- data/examples/sample18.rb +24 -0
- data/examples/sample19.rb +59 -0
- data/examples/sample20.rb +47 -0
- data/examples/sample21.rb +12 -0
- data/examples/sample22.rb +10 -0
- data/examples/sample23.rb +11 -0
- data/examples/sample24.rb +11 -0
- data/examples/sample25.rb +11 -0
- data/examples/sample26.rb +8 -0
- data/examples/sample27.rb +8 -0
- data/examples/sample28.rb +12 -0
- data/examples/sample29.rb +8 -0
- data/examples/sample30.rb +12 -0
- data/examples/sample31.rb +10 -0
- data/examples/sample32.rb +14 -0
- data/examples/sample33.rb +43 -0
- data/examples/sample34.rb +29 -0
- data/examples/sample35.rb +43 -0
- data/examples/sample36.rb +35 -0
- data/examples/sample37.rb +87 -0
- data/examples/sample38.rb +12 -0
- data/examples/sample39.rb +11 -0
- data/examples/sample40.rb +17 -0
- data/examples/sample41.rb +8 -0
- data/examples/sample42.rb +35 -0
- data/examples/sample43.rb +26 -0
- data/examples/sample44.rb +97 -0
- data/examples/sample45.rb +24 -0
- data/examples/sample46.rb +43 -0
- data/examples/sample47.rb +7 -0
- data/examples/sample48.rb +62 -0
- data/examples/sample49.rb +10 -0
- data/examples/sample50.rb +215 -0
- data/examples/sample51.rb +37 -0
- data/examples/sample52.rb +62 -0
- data/examples/sample53.rb +26 -0
- data/examples/sample54.rb +26 -0
- data/examples/sample55.rb +9 -0
- data/examples/sample56.rb +10 -0
- data/examples/sample57.rb +8 -0
- data/examples/sample58.rb +33 -0
- data/examples/sample59.rb +14 -0
- data/examples/sample60.rb +12 -0
- data/examples/sample61.rb +12 -0
- data/examples/sample62.rb +24 -0
- data/examples/sample63.rb +32 -0
- data/examples/sample64.rb +31 -0
- data/examples/sample65.rb +9 -0
- data/examples/sample66.rb +4 -0
- data/examples/sample67.rb +10 -0
- data/examples/sample68.rb +27 -0
- data/examples/sample69.rb +23 -0
- data/examples/sample70.rb +9 -0
- data/examples/sample99.rb +70 -0
- data/examples/sdlshapes/README +2 -0
- data/examples/sdlshapes/sdl.ps +655 -0
- data/examples/sdlshapes/sdlshapes.dot +78 -0
- data/examples/test.xml +26 -0
- data/examples/theory/pert.rb +47 -0
- data/examples/theory/tests.rb +87 -0
- data/lib/ext/gvpr/dot2ruby.g +185 -0
- data/lib/graphviz/attrs.rb +73 -0
- data/lib/graphviz/constants.rb +294 -0
- data/lib/graphviz/core_ext.rb +64 -0
- data/lib/graphviz/dot2ruby.rb +59 -0
- data/lib/graphviz/dot_script.rb +109 -0
- data/lib/graphviz/dsl.rb +67 -0
- data/lib/graphviz/edge.rb +197 -0
- data/lib/graphviz/elements.rb +39 -0
- data/lib/graphviz/ext.rb +17 -0
- data/lib/graphviz/family_tree/couple.rb +63 -0
- data/lib/graphviz/family_tree/generation.rb +39 -0
- data/lib/graphviz/family_tree/person.rb +120 -0
- data/lib/graphviz/family_tree/sibling.rb +13 -0
- data/lib/graphviz/family_tree.rb +118 -0
- data/lib/graphviz/graphml.rb +268 -0
- data/lib/graphviz/math/matrix.rb +221 -0
- data/lib/graphviz/node.rb +160 -0
- data/lib/graphviz/nothugly/nothugly.xsl +321 -0
- data/lib/graphviz/nothugly.rb +63 -0
- data/lib/graphviz/theory.rb +321 -0
- data/lib/graphviz/types/arrow_type.rb +32 -0
- data/lib/graphviz/types/color.rb +58 -0
- data/lib/graphviz/types/color_list.rb +24 -0
- data/lib/graphviz/types/esc_string.rb +20 -0
- data/lib/graphviz/types/gv_bool.rb +49 -0
- data/lib/graphviz/types/gv_double.rb +32 -0
- data/lib/graphviz/types/html_string.rb +18 -0
- data/lib/graphviz/types/lbl_string.rb +22 -0
- data/lib/graphviz/types/rect.rb +35 -0
- data/lib/graphviz/types/spline_type.rb +77 -0
- data/lib/graphviz/types.rb +22 -0
- data/lib/graphviz/utils/colors.rb +1018 -0
- data/lib/graphviz/utils.rb +70 -0
- data/lib/graphviz/xml.rb +119 -0
- data/lib/graphviz.rb +967 -0
- data/lib/ruby-graphviz.rb +1 -0
- data/man/dot2ruby.1 +66 -0
- data/man/dot2ruby.1.ronn +55 -0
- data/man/gem2gv.1 +60 -0
- data/man/gem2gv.1.ronn +47 -0
- data/man/git2gv.1 +48 -0
- data/man/git2gv.1.ronn +40 -0
- data/man/ruby2gv.1 +60 -0
- data/man/ruby2gv.1.ronn +47 -0
- data/man/xml2gv.1 +48 -0
- data/man/xml2gv.1.ronn +39 -0
- data/ruby-graphviz.gemspec +47 -0
- data/setup.rb +1585 -0
- data/test/helper.rb +13 -0
- data/test/support.rb +95 -0
- data/test/test_dot_script.rb +47 -0
- data/test/test_examples.rb +151 -0
- data/test/test_graph.rb +115 -0
- data/test/test_search.rb +29 -0
- data/test/test_subgraph.rb +27 -0
- data/test/test_theory.rb +98 -0
- data/test/test_types.rb +65 -0
- data/test/test_utils_colors.rb +52 -0
- metadata +301 -0
@@ -0,0 +1,63 @@
|
|
1
|
+
# This file use notugly.xsl: An XSL transform to pretty up the SVG output from Graphviz
|
2
|
+
#
|
3
|
+
# See: http://www.hokstad.com/making-graphviz-output-pretty-with-xsl.html
|
4
|
+
# And: http://www.hokstad.com/making-graphviz-output-pretty-with-xsl-updated.html
|
5
|
+
#
|
6
|
+
# By Vidar Hokstad and Ryan Shea; Contributions by Jonas Tingborn,
|
7
|
+
# Earl Cummings, Michael Kennedy (Graphviz 2.20.2 compatibility, bug fixes,
|
8
|
+
# testing, lots of gradients)
|
9
|
+
|
10
|
+
require 'rubygems'
|
11
|
+
begin
|
12
|
+
require 'xml/xslt'
|
13
|
+
XSLT_METHOD = :xml_xslt_transform
|
14
|
+
rescue LoadError => e
|
15
|
+
require 'libxml'
|
16
|
+
require 'libxslt'
|
17
|
+
XSLT_METHOD = :libxslt_transform
|
18
|
+
end
|
19
|
+
|
20
|
+
class GraphViz
|
21
|
+
# Transform to pretty up the SVG output
|
22
|
+
#
|
23
|
+
# For more information, see http://www.hokstad.com/making-graphviz-output-pretty-with-xsl.html
|
24
|
+
# and http://www.hokstad.com/making-graphviz-output-pretty-with-xsl-updated.html
|
25
|
+
#
|
26
|
+
# You can use the :nothugly option to GraphViz#output :
|
27
|
+
#
|
28
|
+
# graph.output( :svg => "myGraph.svg", :nothugly => true )
|
29
|
+
#
|
30
|
+
# Or directly on an SVG output graph :
|
31
|
+
#
|
32
|
+
# GraphViz.nothugly( "myGraph.svg" )
|
33
|
+
def self.nothugly( file, save = true )
|
34
|
+
xsl = File.join( File.dirname(File.expand_path(__FILE__)), "nothugly", "nothugly.xsl" )
|
35
|
+
out = self.send(XSLT_METHOD, file, xsl)
|
36
|
+
|
37
|
+
if save
|
38
|
+
fname = File.join( File.dirname(File.expand_path(file)), File.basename(file))
|
39
|
+
File.open( fname, "w" ) { |io|
|
40
|
+
io.print out
|
41
|
+
}
|
42
|
+
else
|
43
|
+
return out
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.xml_xslt_transform(xml, xsl)
|
48
|
+
xslt = XML::XSLT.new()
|
49
|
+
xslt.xml = xml
|
50
|
+
xslt.xsl = xsl
|
51
|
+
xslt.serve()
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.libxslt_transform(xml, xsl)
|
55
|
+
LibXML::XML.default_load_external_dtd = false
|
56
|
+
LibXML::XML.default_substitute_entities = false
|
57
|
+
|
58
|
+
stylesheet_doc = LibXML::XML::Document.file(xsl)
|
59
|
+
stylesheet = LibXSLT::XSLT::Stylesheet.new(stylesheet_doc)
|
60
|
+
xml_doc = LibXML::XML::Document.file(xml)
|
61
|
+
stylesheet.apply(xml_doc).to_s
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,321 @@
|
|
1
|
+
require 'graphviz/math/matrix'
|
2
|
+
|
3
|
+
class GraphViz
|
4
|
+
class Theory
|
5
|
+
def initialize( graph )
|
6
|
+
@graph = graph
|
7
|
+
end
|
8
|
+
|
9
|
+
# Return the adjancy matrix of the graph
|
10
|
+
def adjancy_matrix
|
11
|
+
matrix = GraphViz::Math::Matrix.new( @graph.node_count, @graph.node_count )
|
12
|
+
|
13
|
+
@graph.each_edge { |e|
|
14
|
+
x = @graph.get_node(e.node_one( false )).index
|
15
|
+
y = @graph.get_node(e.node_two( false )).index
|
16
|
+
matrix[x+1, y+1] = 1
|
17
|
+
matrix[y+1, x+1] = 1 if @graph.type == "graph"
|
18
|
+
}
|
19
|
+
|
20
|
+
return matrix
|
21
|
+
end
|
22
|
+
|
23
|
+
# Return the incidence matrix of the graph
|
24
|
+
def incidence_matrix
|
25
|
+
tail = (@graph.type == "digraph") ? -1 : 1
|
26
|
+
matrix = GraphViz::Math::Matrix.new( @graph.node_count, @graph.edge_count )
|
27
|
+
|
28
|
+
@graph.each_edge { |e|
|
29
|
+
x = e.index
|
30
|
+
|
31
|
+
nstart = @graph.get_node(e.node_one( false )).index
|
32
|
+
nend = @graph.get_node(e.node_two( false )).index
|
33
|
+
|
34
|
+
matrix[nstart+1, x+1] = 1
|
35
|
+
matrix[nend+1, x+1] = tail
|
36
|
+
matrix[nend+1, x+1] = 2 if nstart == nend
|
37
|
+
}
|
38
|
+
|
39
|
+
return matrix
|
40
|
+
end
|
41
|
+
|
42
|
+
# Return the degree of the given node
|
43
|
+
def degree( node )
|
44
|
+
degree = 0
|
45
|
+
name = node
|
46
|
+
if node.kind_of?(GraphViz::Node)
|
47
|
+
name = node.id
|
48
|
+
end
|
49
|
+
|
50
|
+
@graph.each_edge do |e|
|
51
|
+
degree += 1 if e.node_one(false) == name or e.node_two(false) == name
|
52
|
+
end
|
53
|
+
|
54
|
+
return degree
|
55
|
+
end
|
56
|
+
|
57
|
+
# Return the laplacian matrix of the graph
|
58
|
+
def laplacian_matrix
|
59
|
+
return degree_matrix - adjancy_matrix
|
60
|
+
end
|
61
|
+
|
62
|
+
# Return <tt>true</tt> if the graph if symmetric, <tt>false</tt> otherwise
|
63
|
+
def symmetric?
|
64
|
+
adjancy_matrix == adjancy_matrix.transpose
|
65
|
+
end
|
66
|
+
|
67
|
+
# moore_dijkstra(source, destination)
|
68
|
+
def moore_dijkstra( dep, arv )
|
69
|
+
dep = @graph.get_node(dep) unless dep.kind_of?(GraphViz::Node)
|
70
|
+
arv = @graph.get_node(arv) unless arv.kind_of?(GraphViz::Node)
|
71
|
+
|
72
|
+
m = distance_matrix
|
73
|
+
n = @graph.node_count
|
74
|
+
# Table des sommets à choisir
|
75
|
+
c = [dep.index]
|
76
|
+
# Table des distances
|
77
|
+
d = []
|
78
|
+
d[dep.index] = 0
|
79
|
+
|
80
|
+
# Table des predecesseurs
|
81
|
+
pred = []
|
82
|
+
|
83
|
+
@graph.each_node do |name, k|
|
84
|
+
if k != dep
|
85
|
+
d[k.index] = m[dep.index+1,k.index+1]
|
86
|
+
pred[k.index] = dep
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
while c.size < n
|
91
|
+
# trouver y tel que d[y] = min{d[k]; k sommet tel que k n'appartient pas à c}
|
92
|
+
mini = 1.0/0.0
|
93
|
+
y = nil
|
94
|
+
@graph.each_node do |name, k|
|
95
|
+
next if c.include?(k.index)
|
96
|
+
if d[k.index] < mini
|
97
|
+
mini = d[k.index]
|
98
|
+
y = k
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# si ce minimum est ∞ alors sortir de la boucle fin si
|
103
|
+
break unless mini.to_f.infinite?.nil?
|
104
|
+
|
105
|
+
c << y.index
|
106
|
+
@graph.each_node do |name, k|
|
107
|
+
next if c.include?(k.index)
|
108
|
+
if d[k.index] > d[y.index] + m[y.index+1,k.index+1]
|
109
|
+
d[k.index] = d[y.index] + m[y.index+1,k.index+1]
|
110
|
+
pred[k.index] = y
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Construction du chemin le plus court
|
116
|
+
ch = []
|
117
|
+
k = arv
|
118
|
+
while k.index != dep.index
|
119
|
+
ch.unshift(k)
|
120
|
+
k = pred[k.index]
|
121
|
+
end
|
122
|
+
ch.unshift(dep)
|
123
|
+
|
124
|
+
if d[arv.index].to_f.infinite?
|
125
|
+
return nil
|
126
|
+
else
|
127
|
+
return( {
|
128
|
+
:path => ch,
|
129
|
+
:distance => d[arv.index]
|
130
|
+
} )
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Return a liste of range
|
135
|
+
#
|
136
|
+
# If the returned array include nil values, there is one or more circuits in the graph
|
137
|
+
def range
|
138
|
+
matrix = adjancy_matrix
|
139
|
+
unseen = (1..matrix.columns).to_a
|
140
|
+
result = Array.new(matrix.columns)
|
141
|
+
r = 0
|
142
|
+
|
143
|
+
range_recursion( matrix, unseen, result, r )
|
144
|
+
end
|
145
|
+
|
146
|
+
# Return the critical path for a PERT network
|
147
|
+
#
|
148
|
+
# If the given graph is not a PERT network, return nul
|
149
|
+
def critical_path
|
150
|
+
return nil if range.include?(nil) or @graph.type != "digraph"
|
151
|
+
r = [ [0, [1]] ]
|
152
|
+
|
153
|
+
critical_path_recursion( distance_matrix, adjancy_matrix, r, [], 0 ).inject( {:distance => 0, :path => []} ) { |_r, item|
|
154
|
+
(_r[:distance] < item[0]) ? { :distance => item[0], :path => item[1] } : _r
|
155
|
+
}
|
156
|
+
end
|
157
|
+
|
158
|
+
# Return the PageRank in an directed graph.
|
159
|
+
#
|
160
|
+
# * damping_factor: PageRank dumping factor.
|
161
|
+
# * max_iterations: Maximum number of iterations.
|
162
|
+
# * min_delta: Smallest variation required to have a new iteration.
|
163
|
+
def pagerank(damping_factor = 0.85, max_iterations = 100, min_delta = 0.00001)
|
164
|
+
return nil unless @graph.directed?
|
165
|
+
|
166
|
+
min_value = (1.0-damping_factor)/@graph.node_count
|
167
|
+
|
168
|
+
pagerank = {}
|
169
|
+
@graph.each_node { |_, node|
|
170
|
+
pagerank[node] = 1.0/@graph.node_count
|
171
|
+
}
|
172
|
+
|
173
|
+
max_iterations.times { |_|
|
174
|
+
diff = 0
|
175
|
+
@graph.each_node { |_, node|
|
176
|
+
rank = min_value
|
177
|
+
incidents(node).each { |referent|
|
178
|
+
rank += damping_factor * pagerank[referent] / neighbors(referent).size
|
179
|
+
}
|
180
|
+
|
181
|
+
diff += (pagerank[node] - rank).abs
|
182
|
+
pagerank[node] = rank
|
183
|
+
}
|
184
|
+
break if diff < min_delta
|
185
|
+
}
|
186
|
+
|
187
|
+
return pagerank
|
188
|
+
end
|
189
|
+
|
190
|
+
# Return the list of nodes that are directly accessible from given node
|
191
|
+
def neighbors(node)
|
192
|
+
if node.class == String
|
193
|
+
@graph.get_node(node).neighbors
|
194
|
+
else
|
195
|
+
node.neighbors
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# Return the list of nodes that are incident to the given node (in a directed graph neighbors == incidents)
|
200
|
+
def incidents(node)
|
201
|
+
if node.class == String
|
202
|
+
@graph.get_node(node).incidents
|
203
|
+
else
|
204
|
+
node.incidents
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Breadth First Search
|
209
|
+
def bfs(node, &b)
|
210
|
+
queue = []
|
211
|
+
visited_nodes = []
|
212
|
+
node = @graph.get_node(node) if node.kind_of? String
|
213
|
+
queue << node
|
214
|
+
visited_nodes << node
|
215
|
+
|
216
|
+
while not queue.empty?
|
217
|
+
node = queue.shift
|
218
|
+
b.call(node)
|
219
|
+
neighbors(node).each do |n|
|
220
|
+
unless visited_nodes.include?(n)
|
221
|
+
visited_nodes << n
|
222
|
+
queue << n
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# Depth First Search
|
229
|
+
def dfs(node, &b)
|
230
|
+
visited_nodes = []
|
231
|
+
recursive_dfs(node, visited_nodes, &b)
|
232
|
+
end
|
233
|
+
|
234
|
+
private
|
235
|
+
def recursive_dfs(node, visited_nodes, &b)
|
236
|
+
node = @graph.get_node(node) if node.kind_of? String
|
237
|
+
b.call(node)
|
238
|
+
visited_nodes << node
|
239
|
+
neighbors(node).each do |n|
|
240
|
+
recursive_dfs(n, visited_nodes, &b) unless visited_nodes.include?(n)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def distance_matrix
|
245
|
+
type = @graph.type
|
246
|
+
matrix = GraphViz::Math::Matrix.new( @graph.node_count, @graph.node_count, (1.0/0.0) )
|
247
|
+
|
248
|
+
@graph.each_edge { |e|
|
249
|
+
x = @graph.get_node(e.node_one( false )).index
|
250
|
+
y = @graph.get_node(e.node_two( false )).index
|
251
|
+
unless x == y
|
252
|
+
weight = ((e[:weight].nil?) ? 1 : e[:weight].to_f)
|
253
|
+
matrix[x+1, y+1] = weight
|
254
|
+
matrix[y+1, x+1] = weight if type == "graph"
|
255
|
+
end
|
256
|
+
}
|
257
|
+
|
258
|
+
return matrix
|
259
|
+
end
|
260
|
+
|
261
|
+
def degree_matrix
|
262
|
+
matrix = GraphViz::Math::Matrix.new( @graph.node_count, @graph.node_count )
|
263
|
+
@graph.each_node do |name, node|
|
264
|
+
i = node.index
|
265
|
+
matrix[i+1, i+1] = degree(node)
|
266
|
+
end
|
267
|
+
return matrix
|
268
|
+
end
|
269
|
+
|
270
|
+
def range_recursion(matrix, unseen, result, r)
|
271
|
+
remove = []
|
272
|
+
matrix.columns.times do |c|
|
273
|
+
if matrix.sum_of_column(c+1) == 0
|
274
|
+
result[unseen[c]-1] = r
|
275
|
+
remove.unshift( c + 1 )
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
remove.each do |rem|
|
280
|
+
matrix = matrix.remove_line(rem).remove_column(rem)
|
281
|
+
unseen.delete_at(rem-1)
|
282
|
+
end
|
283
|
+
|
284
|
+
if matrix.columns == 1 and matrix.lines == 1
|
285
|
+
if matrix.sum_of_column(1) == 0
|
286
|
+
result[unseen[0]-1] = r+1
|
287
|
+
end
|
288
|
+
elsif remove.size > 0
|
289
|
+
range_recursion( matrix, unseen, result, r+1 )
|
290
|
+
end
|
291
|
+
|
292
|
+
return result
|
293
|
+
end
|
294
|
+
|
295
|
+
def index_of_item( array, item )
|
296
|
+
array.inject( [0,[]] ){|a,i|
|
297
|
+
a[1] << a[0] if i == item
|
298
|
+
a[0] += 1
|
299
|
+
a
|
300
|
+
}[1]
|
301
|
+
end
|
302
|
+
|
303
|
+
def critical_path_recursion( d, a, r, result, level )
|
304
|
+
r.each do |p|
|
305
|
+
node = p[1][-1]
|
306
|
+
index_of_item( a.line(node), 1 ).each do |c|
|
307
|
+
succ = c+1
|
308
|
+
|
309
|
+
cpath = [ (p[0] + d[node,succ]), (p[1].clone << succ) ]
|
310
|
+
|
311
|
+
if index_of_item( a.line(succ), 1 ).size > 0
|
312
|
+
critical_path_recursion( d, a, [cpath], result, level+1 )
|
313
|
+
else
|
314
|
+
result << cpath
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
return result
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# >> x = "hello\n\t\\l\"world\""
|
2
|
+
# => "hello\n\t\\l\"world\""
|
3
|
+
# >> puts x.inspect.gsub( "\\\\", "\\" )
|
4
|
+
# "hello\n\t\l\"world\""
|
5
|
+
#
|
6
|
+
# OR
|
7
|
+
#
|
8
|
+
# >> x = 'hello\n\t\l"world"'
|
9
|
+
# => "hello\\n\\t\\l\"world\""
|
10
|
+
# >> puts x.inspect.gsub( "\\\\", "\\" )
|
11
|
+
# "hello\n\t\l\"world\""
|
12
|
+
|
13
|
+
class GraphViz
|
14
|
+
class Types
|
15
|
+
class ArrowType < Common
|
16
|
+
def check(data)
|
17
|
+
return data
|
18
|
+
end
|
19
|
+
|
20
|
+
def output
|
21
|
+
return @data.to_s.inspect.gsub( "\\\\", "\\" )
|
22
|
+
end
|
23
|
+
|
24
|
+
alias :to_gv :output
|
25
|
+
alias :to_s :output
|
26
|
+
|
27
|
+
def to_ruby
|
28
|
+
@data
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'graphviz/utils/colors'
|
2
|
+
|
3
|
+
class ColorException < RuntimeError
|
4
|
+
end
|
5
|
+
|
6
|
+
class GraphViz
|
7
|
+
class Types
|
8
|
+
class Color < Common
|
9
|
+
HEX_FOR_COLOR = /[0-9a-fA-F]{2}/
|
10
|
+
RGBA = /^#(#{HEX_FOR_COLOR})(#{HEX_FOR_COLOR})(#{HEX_FOR_COLOR})(#{HEX_FOR_COLOR})?$/
|
11
|
+
|
12
|
+
def check(data)
|
13
|
+
data = data.to_s if data.is_a?(Symbol)
|
14
|
+
return nil if data.empty?
|
15
|
+
|
16
|
+
if data[0].chr == "#"
|
17
|
+
m = RGBA.match(data)
|
18
|
+
if m.nil?
|
19
|
+
raise ColorException, "Wrong color definition RGBA #{data}"
|
20
|
+
end
|
21
|
+
@to_ruby = GraphViz::Utils::Colors.rgb(m[1], m[2], m[3], m[4])
|
22
|
+
return data
|
23
|
+
elsif data.include?(",") or data.include?(" ")
|
24
|
+
m = data.split(/(?:\s*,\s*|\s+)/).map { |x| x.to_f }
|
25
|
+
if m.size != 3
|
26
|
+
raise ColorException, "Wrong color definition HSV #{data}"
|
27
|
+
end
|
28
|
+
@to_ruby = GraphViz::Utils::Colors.hsv(m[0], m[1], m[2])
|
29
|
+
return data
|
30
|
+
elsif data.is_a?(Array)
|
31
|
+
if data.all? { |x| x.is_a?(String) and x =~ /^#{HEX_FOR_COLOR}$/ } and [3,4].include?(data.size)
|
32
|
+
@to_ruby = GraphViz::Utils::Colors.rgb(data[0], data[1], data[2], data[3])
|
33
|
+
return data
|
34
|
+
elsif data.all? { |x| x.kind_of?(Numeric) } and data.size == 3
|
35
|
+
@to_ruby = GraphViz::Utils::Colors.hsv(data[0], data[1], data[2])
|
36
|
+
return data
|
37
|
+
end
|
38
|
+
|
39
|
+
raise ColorException, "Wrong color definition Array #{data}"
|
40
|
+
else
|
41
|
+
@to_ruby = GraphViz::Utils::Colors.name(data)
|
42
|
+
return data
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def output
|
47
|
+
return @data.to_s.inspect.gsub( "\\\\", "\\" )
|
48
|
+
end
|
49
|
+
|
50
|
+
alias :to_gv :output
|
51
|
+
alias :to_s :output
|
52
|
+
|
53
|
+
def to_ruby
|
54
|
+
@to_ruby
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|