fsm 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,70 @@
1
+ class Array
2
+ def equality_uniq
3
+ uniq_elements = []
4
+ self.each {|e| uniq_elements.push(e) unless uniq_elements.index(e)}
5
+ uniq_elements
6
+ end
7
+
8
+ def delete_at_indices(indices = [])
9
+ not_deleted = Array.new
10
+ self.each_with_index {|e,i| not_deleted.push(e) if !indices.include?(i)}
11
+ not_deleted
12
+ end
13
+ end
14
+
15
+ class DefaultInitArray < Array
16
+ def initialize(*args, &initblock)
17
+ super(*args)
18
+ @initblock = initblock
19
+ end
20
+
21
+ def [](index)
22
+ super(index) || (self[index] = @initblock.call(index))
23
+ end
24
+ end
25
+
26
+ class ArrayOfArrays < DefaultInitArray
27
+ @@create_array = proc{|i| Array.new}
28
+ def initialize(*args)
29
+ super(*args, &@@create_array)
30
+ end
31
+ end
32
+
33
+ class ArrayOfHashes < DefaultInitArray
34
+ @@create_hash = proc{|i| Hash.new}
35
+ def initialize(*args)
36
+ super(*args, &@@create_hash)
37
+ end
38
+ end
39
+
40
+ # Hash which takes a block that is called to give a default value when a key
41
+ # has the value nil in the hash.
42
+ class DefaultInitHash < Hash
43
+ def initialize(*args, &initblock)
44
+ super(*args)
45
+ @initblock = initblock
46
+ end
47
+
48
+ def [](key)
49
+ super(key) || (self[key] = @initblock.call(key))
50
+ end
51
+ end
52
+
53
+ unless Object.constants.include?("TimesClass")
54
+ TimesClass = (RUBY_VERSION < "1.7") ? Time : Process
55
+ end
56
+
57
+ def time_and_puts(string, &block)
58
+ if $TIME_AND_PUTS_VERBOSE
59
+ print string; STDOUT.flush
60
+ end
61
+ starttime = [Time.new, TimesClass.times]
62
+ block.call
63
+ endtime = [Time.new, TimesClass.times]
64
+ duration = endtime[0] - starttime[0]
65
+ begin
66
+ load = [((endtime[1].utime+endtime[1].stime)-(starttime[1].utime+starttime[1].stime))/duration*100.0, 100.0].min
67
+ puts " (%.2f s %.2f%%)" % [duration, load] if $TIME_AND_PUTS_VERBOSE
68
+ rescue FloatDomainError
69
+ end
70
+ end
@@ -0,0 +1,481 @@
1
+ require 'graph/base_extensions'
2
+ require 'graph/graphviz_dot'
3
+
4
+ class HashOfHash < DefaultInitHash
5
+ def initialize(&initBlock)
6
+ super do
7
+ if initBlock
8
+ DefaultInitHash.new(&initBlock)
9
+ else
10
+ Hash.new
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ GraphLink = Struct.new("GraphLink", :from, :to, :info)
17
+ class GraphLink
18
+ def inspect
19
+ info_str = info ? info.inspect + "-" : ""
20
+ "#{from.inspect}-#{info_str}>#{to.inspect}"
21
+ end
22
+ end
23
+
24
+ class GraphTraversalException < Exception
25
+ attr_reader :node, :links, :link_info
26
+ def initialize(node, links, linkInfo)
27
+ @node, @links, @link_info = node, links, linkInfo
28
+ super(message)
29
+ end
30
+
31
+ def message
32
+ "There is no link from #{@node.inspect} having info #{@link_info.inspect} (valid links are #{@links.inspect})"
33
+ end
34
+ alias inspect message
35
+ end
36
+
37
+ class DirectedGraph
38
+ # This is a memory expensive variant that manages several additional
39
+ # information data structures to cut down on processing when the graph
40
+ # has been built.
41
+
42
+ attr_reader :links
43
+ attr_reader :link_map
44
+ attr_reader :is_root
45
+ attr_reader :is_leaf
46
+
47
+ def initialize
48
+ @link_map = HashOfHash.new {Array.new} # [from][to] -> array of links
49
+ @link_map = Hash.new{|h,from| h[from] = Hash.new{|h2,to| h2[to] = []}}
50
+ @links = Array.new # All links in one array
51
+ @is_root = Hash.new # true iff root node
52
+ @is_leaf = Hash.new # true iff leaf node
53
+ end
54
+
55
+ def nodes
56
+ @is_root.keys
57
+ end
58
+
59
+ def add_node(node)
60
+ unless include_node?(node)
61
+ @is_root[node] = @is_leaf[node] = true
62
+ end
63
+ end
64
+
65
+ def root?(node)
66
+ @is_root[node]
67
+ end
68
+
69
+ def leaf?(node)
70
+ @is_leaf[node]
71
+ end
72
+
73
+ def include_node?(node)
74
+ @is_root.has_key?(node)
75
+ end
76
+
77
+ def links_from_to(from, to)
78
+ @link_map[from][to]
79
+ end
80
+
81
+ def links_from(node)
82
+ @link_map[node].map {|to, links| links}.flatten
83
+ end
84
+
85
+ def children(node)
86
+ @link_map[node].keys.select {|k| @link_map[node][k].length > 0}
87
+ end
88
+
89
+ # (Forced) add link will always add link even if there are already links
90
+ # between the nodes.
91
+ def add_link(from, to, informationOnLink = nil)
92
+ add_link_nodes(from, to)
93
+ link = GraphLink.new(from, to, informationOnLink)
94
+ links_from_to(from, to).push link
95
+ #@link_map[from][to].push link
96
+ add_to_links(link)
97
+ link
98
+ end
99
+
100
+ def add_link_nodes(from, to)
101
+ add_node(from)
102
+ add_node(to)
103
+ @is_leaf[from] = @is_root[to] = false
104
+ end
105
+
106
+ # Add link if not already linked
107
+ def link_nodes(from, to, info = nil)
108
+ links_from_to?(from, to) ? nil : add_link(from, to, info)
109
+ end
110
+
111
+ def links_from_to?(from, to)
112
+ not links_from_to(from, to).empty?
113
+ end
114
+ alias linked? links_from_to?
115
+
116
+ def add_to_links(link)
117
+ @links.push link
118
+ end
119
+ private :add_to_links
120
+
121
+ def each_reachable_node_once_depth_first(node, inclusive = true, &block)
122
+ children(node).each do |c|
123
+ recurse_each_reachable_depth_first_visited(c, Hash.new, &block)
124
+ end
125
+ block.call(node) if inclusive
126
+ end
127
+ alias each_reachable_node each_reachable_node_once_depth_first
128
+
129
+ def recurse_each_reachable_depth_first_visited(node, visited, &block)
130
+ visited[node] = true
131
+ children(node).each do |c|
132
+ unless visited[c]
133
+ recurse_each_reachable_depth_first_visited(c, visited, &block)
134
+ end
135
+ end
136
+ block.call(node)
137
+ end
138
+
139
+ def each_reachable_node_once_breadth_first(node, inclusive = true, &block)
140
+ block.call(node) if inclusive
141
+ children(node).each do |c|
142
+ recurse_each_reachable_breadth_first_visited(c, Hash.new, &block)
143
+ end
144
+ end
145
+ alias each_reachable_node each_reachable_node_once_depth_first
146
+
147
+ def recurse_each_reachable_breadth_first_visited(node, visited, &block)
148
+ visited[node] = true
149
+ block.call(node)
150
+ children(node).each do |c|
151
+ unless visited[c]
152
+ recurse_each_reachable_breadth_first_visited(c, visited, &block)
153
+ end
154
+ end
155
+ end
156
+
157
+ def root_nodes
158
+ @is_root.reject {|key,val| val == false}.keys
159
+ end
160
+ alias_method :roots, :root_nodes
161
+
162
+ def leaf_nodes
163
+ @is_leaf.reject {|key,val| val == false}.keys
164
+ end
165
+ alias_method :leafs, :leaf_nodes
166
+
167
+ def internal_node?(node)
168
+ !root?(node) and !leaf?(node)
169
+ end
170
+
171
+ def internal_nodes
172
+ nodes.reject {|n| root?(n) or leaf?(n)}
173
+ end
174
+
175
+ def recurse_cyclic?(node, visited)
176
+ visited[node] = true
177
+ children(node).each do |c|
178
+ return true if visited[c] || recurse_cyclic?(c, visited)
179
+ end
180
+ false
181
+ end
182
+
183
+ def cyclic?
184
+ visited = Hash.new
185
+ root_nodes.each {|root| return true if recurse_cyclic?(root, visited)}
186
+ false
187
+ end
188
+
189
+ def acyclic?
190
+ not cyclic?
191
+ end
192
+
193
+ def transition(state, linkInfo)
194
+ link = links_from(state).detect {|l| l.info == linkInfo}
195
+ begin
196
+ link.to
197
+ rescue Exception
198
+ raise GraphTraversalException.new(state, links_from(state), linkInfo)
199
+ end
200
+ end
201
+
202
+ def traverse(fromState, alongLinksWithInfo = [])
203
+ state, len = fromState, alongLinksWithInfo.length
204
+ alongLinksWithInfo = alongLinksWithInfo.clone
205
+ while len > 0
206
+ state = transition(state, alongLinksWithInfo.shift)
207
+ len -= 1
208
+ end
209
+ state
210
+ end
211
+
212
+ def to_dot(nodeShaper = nil, nodeLabeler = nil, linkLabeler = nil)
213
+ dgp = DotGraphPrinter.new(links, nodes)
214
+ dgp.node_shaper = nodeShaper if nodeShaper
215
+ dgp.node_labeler = nodeLabeler if nodeLabeler
216
+ dgp.link_labeler = linkLabeler if linkLabeler
217
+ dgp
218
+ end
219
+
220
+ def to_postscript_file(filename, nodeShaper = nil, nodeLabeler = nil,
221
+ linkLabeler = nil)
222
+ to_dot(nodeShaper, nodeLabeler, linkLabeler).write_to_file(filename)
223
+ end
224
+
225
+ # Floyd-Warshal algorithm which should be O(n^3) where n is the number of
226
+ # nodes. We can probably work a bit on the constant factors!
227
+ def transitive_closure_floyd_warshal
228
+ vertices = nodes
229
+ tcg = DirectedGraph.new
230
+ num_nodes = vertices.length
231
+
232
+ # Direct links
233
+ for k in (0...num_nodes)
234
+ for s in (0...num_nodes)
235
+ vk, vs = vertices[k], vertices[s]
236
+ if vk == vs
237
+ tcg.link_nodes(vk,vs)
238
+ elsif linked?(vk, vs)
239
+ tcg.link_nodes(vk,vs)
240
+ end
241
+ end
242
+ end
243
+
244
+ # Indirect links
245
+ for i in (0...num_nodes)
246
+ for j in (0...num_nodes)
247
+ for k in (0...num_nodes)
248
+ vi, vj, vk = vertices[i], vertices[j], vertices[k]
249
+ if not tcg.linked?(vi,vj)
250
+ tcg.link_nodes(vi, vj) if linked?(vi,vk) and linked?(vk,vj)
251
+ end
252
+ end
253
+ end
254
+ end
255
+ tcg
256
+ end
257
+ alias_method :transitive_closure, :transitive_closure_floyd_warshal
258
+
259
+ def num_vertices
260
+ @is_root.size
261
+ end
262
+ alias num_nodes num_vertices
263
+
264
+ # strongly_connected_components uses the algorithm described in
265
+ # following paper.
266
+ # @Article{Tarjan:1972:DFS,
267
+ # author = "R. E. Tarjan",
268
+ # key = "Tarjan",
269
+ # title = "Depth First Search and Linear Graph Algorithms",
270
+ # journal = "SIAM Journal on Computing",
271
+ # volume = "1",
272
+ # number = "2",
273
+ # pages = "146--160",
274
+ # month = jun,
275
+ # year = "1972",
276
+ # CODEN = "SMJCAT",
277
+ # ISSN = "0097-5397 (print), 1095-7111 (electronic)",
278
+ # bibdate = "Thu Jan 23 09:56:44 1997",
279
+ # bibsource = "Parallel/Multi.bib, Misc/Reverse.eng.bib",
280
+ # }
281
+ def strongly_connected_components
282
+ order_cell = [0]
283
+ order_hash = {}
284
+ node_stack = []
285
+ components = []
286
+
287
+ order_hash.default = -1
288
+
289
+ nodes.each {|node|
290
+ if order_hash[node] == -1
291
+ recurse_strongly_connected_components(node, order_cell, order_hash, node_stack, components)
292
+ end
293
+ }
294
+
295
+ components
296
+ end
297
+
298
+ def recurse_strongly_connected_components(node, order_cell, order_hash, node_stack, components)
299
+ order = (order_cell[0] += 1)
300
+ reachable_minimum_order = order
301
+ order_hash[node] = order
302
+ stack_length = node_stack.length
303
+ node_stack << node
304
+
305
+ links_from(node).each {|link|
306
+ nextnode = link.to
307
+ nextorder = order_hash[nextnode]
308
+ if nextorder != -1
309
+ if nextorder < reachable_minimum_order
310
+ reachable_minimum_order = nextorder
311
+ end
312
+ else
313
+ sub_minimum_order = recurse_strongly_connected_components(nextnode, order_cell, order_hash, node_stack, components)
314
+ if sub_minimum_order < reachable_minimum_order
315
+ reachable_minimum_order = sub_minimum_order
316
+ end
317
+ end
318
+ }
319
+
320
+ if order == reachable_minimum_order
321
+ scc = node_stack[stack_length .. -1]
322
+ node_stack[stack_length .. -1] = []
323
+ components << scc
324
+ scc.each {|n|
325
+ order_hash[n] = num_vertices
326
+ }
327
+ end
328
+ return reachable_minimum_order;
329
+ end
330
+ end
331
+
332
+ # Parallel propagation in directed acyclic graphs. Should be faster than
333
+ # traversing all links from each start node if the graph is dense so that
334
+ # many traversals can be merged.
335
+ class DagPropagator
336
+ def initialize(directedGraph, startNodes, &propagationBlock)
337
+ @graph, @block = directedGraph, propagationBlock
338
+ init_start_nodes(startNodes)
339
+ @visited = Hash.new
340
+ end
341
+
342
+ def init_start_nodes(startNodes)
343
+ @startnodes = startNodes
344
+ end
345
+
346
+ def propagate
347
+ @visited.clear
348
+ propagate_recursive
349
+ end
350
+
351
+ def propagate_recursive
352
+ next_start_nodes = Array.new
353
+ @startnodes.each do |parent|
354
+ @visited[parent] = true
355
+ @graph.children(parent).each do |child|
356
+ @block.call(parent, child)
357
+ unless @visited[child] or next_start_nodes.include?(child)
358
+ next_start_nodes.push(child)
359
+ end
360
+ end
361
+ end
362
+ if next_start_nodes.length > 0
363
+ @startnodes = next_start_nodes
364
+ propagate_recursive
365
+ end
366
+ end
367
+ end
368
+
369
+ # Directed graph with fast traversal from children to parents (back)
370
+ class BackLinkedDirectedGraph < DirectedGraph
371
+ def initialize(*args)
372
+ super
373
+ @back_link_map = HashOfHash.new {Array.new} # [to][from] -> array of links
374
+ @incoming_links_info = DefaultInitHash.new {Array.new}
375
+ end
376
+
377
+ def add_link(from, to, informationOnLink = nil)
378
+ link = super
379
+ links_to_from(to, from).push link
380
+ if informationOnLink and
381
+ !@incoming_links_info[to].include?(informationOnLink)
382
+ @incoming_links_info[to].push informationOnLink
383
+ end
384
+ link
385
+ end
386
+
387
+ def incoming_links_info(node)
388
+ @incoming_links_info[node]
389
+ end
390
+
391
+ def back_transition(node, backLinkInfo)
392
+ link = links_to(node).detect {|l| l.info == backLinkInfo}
393
+ begin
394
+ link.from
395
+ rescue Exception
396
+ raise GraphTraversalException.new(node, links_to(node), backLinkInfo)
397
+ end
398
+ end
399
+
400
+ def back_traverse(state, alongLinksWithInfo = [])
401
+ len = alongLinksWithInfo.length
402
+ alongLinksWithInfo = alongLinksWithInfo.clone
403
+ while len > 0
404
+ state = back_transition(state, alongLinksWithInfo.pop)
405
+ len -= 1
406
+ end
407
+ state
408
+ end
409
+
410
+ def links_to(node)
411
+ @back_link_map[node].map {|from, links| links}.flatten
412
+ end
413
+
414
+ protected
415
+
416
+ def links_to_from(to, from)
417
+ @back_link_map[to][from]
418
+ end
419
+ end
420
+
421
+ def calc_masks(start, stop, masks = Array.new)
422
+ mask = 1 << start
423
+ (start..stop).each {|i| masks[i] = mask; mask <<= 1}
424
+ masks
425
+ end
426
+
427
+ class BooleanMatrix
428
+ def initialize(objects)
429
+ @index, @objects, @matrix = Hash.new, objects, Array.new
430
+ cnt = 0
431
+ objects.each do |o|
432
+ @index[o] = cnt
433
+ @matrix[cnt] = 0 # Use Integers to represent the booleans
434
+ cnt += 1
435
+ end
436
+ @num_obects = cnt
437
+ end
438
+
439
+ @@masks_max = 1000
440
+ @@masks = calc_masks(0,@@masks_max)
441
+
442
+ def mask(index)
443
+ mask = @@masks[index]
444
+ unless mask
445
+ calc_masks(@@masks_max+1, index, @@masks)
446
+ mask = @masks[index]
447
+ end
448
+ mask
449
+ end
450
+
451
+ def or(index1, index2)
452
+ @matrix[index1] |= @matrix[index2]
453
+ end
454
+
455
+ def indices(anInteger)
456
+ index = 0
457
+ while anInteger > 0
458
+ yeild(index) if anInteger & 1
459
+ anInteger >>= 1
460
+ index += 1
461
+ end
462
+ end
463
+
464
+ def directed_graph
465
+ dg = Directedgraph.new
466
+ @matrix.each_with_index do |v,i|
467
+ indices(v) do |index|
468
+ dg.link_nodes(@objects[i], @objects[index])
469
+ end
470
+ end
471
+ dg
472
+ end
473
+
474
+ def transitive_closure
475
+ for i in (0..@num_obects)
476
+ for j in (0..@num_obects)
477
+
478
+ end
479
+ end
480
+ end
481
+ end