gratr19 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,525 @@
1
+ # Pure ruby Priority Queue
2
+ class RubyPriorityQueue
3
+
4
+ include Enumerable
5
+
6
+ private
7
+
8
+ #
9
+ def link_nodes(b1, b2)
10
+ return link_nodes(b2, b1) if b2.priority < b1.priority
11
+
12
+ b2.parent = b1
13
+ child = b1.child
14
+ b1.child = b2
15
+ if child
16
+ b2.left = child.left
17
+ b2.left.right = b2
18
+ b2.right = child
19
+ child.left = b2
20
+ else
21
+ b2.left = b2
22
+ b2.right = b2
23
+ end
24
+ b1.degree += 1
25
+ b2.mark = false # TODO: Check if this is correct, or if b1 should be marked as false
26
+ return b1
27
+ end
28
+
29
+ # Does not change length
30
+ def delete_first
31
+ return nil unless @rootlist
32
+
33
+ result = @rootlist
34
+ if result == result.right
35
+ @min = @rootlist = nil
36
+ else
37
+ @rootlist = result.right
38
+ @rootlist.left = result.left
39
+ @rootlist.left.right = @rootlist
40
+
41
+ result.right = result.left = result
42
+ end
43
+ return result;
44
+ end
45
+
46
+ def cut_node(n)
47
+ return self unless n.parent
48
+ n.parent.degree -= 1
49
+ if n.parent.child == n
50
+ if n.right == n
51
+ n.parent.child = nil
52
+ else
53
+ n.parent.child = n.right;
54
+ end
55
+ end
56
+ n.parent = nil
57
+ n.right.left = n.left
58
+ n.left.right = n.right
59
+
60
+ n.right = @rootlist
61
+ n.left = @rootlist.left
62
+ @rootlist.left.right = n
63
+ @rootlist.left = n
64
+
65
+ n.mark = false
66
+
67
+ return self
68
+ end
69
+
70
+ # Does not change length
71
+ def insert_tree(tree)
72
+ if @rootlist == nil
73
+ @rootlist = @min = tree
74
+ else
75
+ l = @rootlist.left
76
+ l.right = tree
77
+ @rootlist.left = tree
78
+ tree.left = l
79
+ tree.right = @rootlist
80
+ @min = tree if tree.priority < @min.priority
81
+ end
82
+ self
83
+ end
84
+
85
+ def consolidate
86
+ return self if self.empty?
87
+ array_size = (2.0 * Math.log(self.length) / Math.log(2) + 1.0).ceil
88
+ tree_by_degree = Array.new(array_size)
89
+
90
+ while n = delete_first
91
+ while n1 = tree_by_degree[n.degree]
92
+ tree_by_degree[n.degree] = nil;
93
+ n = link_nodes(n, n1);
94
+ end
95
+ tree_by_degree[n.degree] = n;
96
+ end
97
+
98
+ @rootlist = @min = nil;
99
+ tree_by_degree.each do | tree |
100
+ next unless tree
101
+ insert_tree(tree)
102
+ end
103
+ self
104
+ end
105
+
106
+ # Node class used internally
107
+ class Node # :nodoc:
108
+ attr_accessor :parent, :child, :left, :right, :key, :priority, :degree, :mark
109
+
110
+ def child=(c)
111
+ raise "Circular Child" if c == self
112
+ raise "Child is neighbour" if c == self.right
113
+ raise "Child is neighbour" if c == self.left
114
+ @child = c
115
+ end
116
+
117
+ def to_dot(only_down = false, known_nodes = [])
118
+ p known_nodes.map { | n | n.dot_id }
119
+ p self.dot_id
120
+ result = []
121
+ if only_down
122
+ raise "Circular #{caller.inspect}" if known_nodes.include?(self)
123
+ known_nodes << self
124
+
125
+ result << "#{dot_id} [label=\"#{@key}: #{@priority}\"];"
126
+ l = " "
127
+ #l << "#{@left.dot_id} <- #{dot_id}; " if @left
128
+ l << "#{dot_id} -> #{@left.dot_id} [constraint=false]; " if @left and @left.dot_id < self.dot_id
129
+ l << "#{dot_id} -> #{@right.dot_id} [constraint=false];\t\t\t\t/*neighbours*/" if @right and @right.dot_id <= self.dot_id
130
+ result << l
131
+ result << " #{dot_id} -> #{@child.dot_id}; //child" if @child
132
+ result << @child.to_dot(false, known_nodes) if @child
133
+ else
134
+ n = self
135
+ begin
136
+ result.concat(n.to_dot(true, known_nodes))
137
+ n = n.right
138
+ end while n != self
139
+ end
140
+ result.flatten.map{|r| " " << r}
141
+ end
142
+
143
+ def dot_id
144
+ "N#{@key}"
145
+ end
146
+
147
+ def initialize(key, priority)
148
+ @key = key; @priority = priority; @degree = 0
149
+ end
150
+ end
151
+
152
+ public
153
+
154
+ # Returns the number of elements of the queue.
155
+ #
156
+ # q = PriorityQueue.new
157
+ # q.length #=> 0
158
+ # q[0] = 1
159
+ # q.length #=> 1
160
+ attr_reader :length
161
+
162
+ # Create a new, empty PriorityQueue
163
+ def initialize
164
+ @nodes = Hash.new
165
+ @rootlist = nil
166
+ @min = nil
167
+ @length = 0
168
+ end
169
+
170
+ # Print a priority queue as a dot-graph. The output can be fed to dot from the
171
+ # vizgraph suite to create a tree depicting the internal datastructure.
172
+ def to_dot
173
+ r = ["digraph fibheap {"]
174
+ #r << @rootlist.to_dot.join("\n") if @rootlist
175
+ r << "ROOT -> #{@rootlist.dot_id};" if @rootlist
176
+ @nodes.to_a.sort.each do | (_, n) |
177
+ r << " #{n.dot_id} [label=\"#{n.key}: #{n.priority}\"];"
178
+ r << " #{n.dot_id} -> #{n.right.dot_id} [constraint=false];" if n.right# and n.dot_id < n.right.dot_id
179
+ r << " #{n.dot_id} -> #{n.left.dot_id} [constraint=false];" if n.left #and n.dot_id < n.left.dot_id
180
+ r << " #{n.dot_id} -> #{n.child.dot_id}" if n.child
181
+ end
182
+ r << "}"
183
+ r.join("\n")
184
+ r
185
+ end
186
+
187
+ # Call dot and gv displaying the datstructure
188
+ def display_dot
189
+ puts to_dot
190
+ system "echo '#{to_dot}' | twopi -Tps -Groot=ROOT -Goverlap=false> /tmp/dotfile.ps; gv /tmp/dotfile.ps"
191
+ end
192
+
193
+ # call-seq:
194
+ # [key] = priority
195
+ # change_priority(key, priority)
196
+ # push(key, priority)
197
+ #
198
+ # Set the priority of a key.
199
+ #
200
+ # q = PriorityQueue.new
201
+ # q["car"] = 50
202
+ # q["train"] = 50
203
+ # q["bike"] = 10
204
+ # q.min #=> ["bike", 10]
205
+ # q["car"] = 0
206
+ # q.min #=> ["car", 0]
207
+ def change_priority(key, priority)
208
+ return push(key, priority) unless @nodes[key]
209
+
210
+ n = @nodes[key]
211
+ if n.priority < priority # Priority was increased. Remove the node and reinsert.
212
+ self.delete(key)
213
+ self.push(key, priority);
214
+ return self
215
+ end
216
+ n.priority = priority;
217
+ @min = n if n.priority < @min.priority
218
+
219
+ return self if !n.parent or n.parent.priority <= n.priority # Already in rootlist or bigger than parent
220
+ begin # Cascading Cuts
221
+ p = n.parent
222
+ cut_node(n)
223
+ n = p
224
+ end while n.mark and n.parent
225
+ n.mark = true if n.parent
226
+
227
+ self
228
+ end
229
+
230
+ # Add an object to the queue.
231
+ def push(key, priority)
232
+ return change_priority(key, priority) if @nodes[key]
233
+ @nodes[key] = node = Node.new(key, priority)
234
+ @min = node if !@min or priority < @min.priority
235
+ if not @rootlist
236
+ @rootlist = node
237
+ node.left = node.right = node
238
+ else
239
+ node.left = @rootlist.left
240
+ node.right = @rootlist
241
+ @rootlist.left.right = node
242
+ @rootlist.left = node
243
+ end
244
+ @length += 1
245
+ self
246
+ end
247
+
248
+ # Returns true if the array is empty, false otherwise.
249
+ def empty?
250
+ @rootlist.nil?
251
+ end
252
+
253
+ # call-seq:
254
+ # [key] -> priority
255
+ #
256
+ # Return the priority of a key or nil if the key is not in the queue.
257
+ #
258
+ # q = PriorityQueue.new
259
+ # (0..10).each do | i | q[i.to_s] = i end
260
+ # q["5"] #=> 5
261
+ # q[5] #=> nil
262
+ def [](key)
263
+ @nodes[key] and @nodes[key].priority
264
+ end
265
+
266
+ # call-seq:
267
+ # has_key? key -> boolean
268
+ #
269
+ # Return false if the key is not in the queue, true otherwise.
270
+ #
271
+ # q = PriorityQueue.new
272
+ # (0..10).each do | i | q[i.to_s] = i end
273
+ # q.has_key("5") #=> true
274
+ # q.has_key(5) #=> false
275
+ def has_key?(key)
276
+ @nodes.has_key?(key)
277
+ end
278
+
279
+ alias :[]= :push
280
+
281
+ # Call the given block with each [key, priority] pair in the queue
282
+ #
283
+ # Beware: Changing the queue in the block may lead to unwanted behaviour and
284
+ # even infinite loops.
285
+ def each
286
+ @nodes.each do | key, node |
287
+ yield(key, node.priority)
288
+ end
289
+ end
290
+
291
+ # call-seq:
292
+ # min -> [object, priority]
293
+ #
294
+ # Return the pair [object, priority] with minimal priority or nil when the
295
+ # queue is empty.
296
+ #
297
+ # q = PriorityQueue.new
298
+ # q["a"] = 10
299
+ # q["b"] = 20
300
+ # q.min #=> ["a", 10]
301
+ # q.delete_min #=> ["a", 10]
302
+ # q.min #=> ["b", 20]
303
+ # q.delete_min #=> ["b", 20]
304
+ # q.min #=> nil
305
+ def min
306
+ [@min.key, @min.priority] rescue nil
307
+ end
308
+
309
+ # call-seq:
310
+ # min_key -> object
311
+ #
312
+ # Return the key that has the minimal priority or nil when the queue is empty.
313
+ #
314
+ # q = PriorityQueue.new
315
+ # q["a"] = 10
316
+ # q["b"] = 20
317
+ # q.min_key #=> "a"
318
+ # q.delete_min #=> ["a", 10]
319
+ # q.min_key #=> "b"
320
+ # q.delete_min #=> ["b", 20]
321
+ # q.min_key #=> nil
322
+ def min_key
323
+ @min.key rescue nil
324
+ end
325
+
326
+ # call-seq:
327
+ # min_priority -> priority
328
+ #
329
+ # Return the minimal priority or nil when the queue is empty.
330
+ #
331
+ # q = PriorityQueue.new
332
+ # q["a"] = 10
333
+ # q["b"] = 20
334
+ # q.min_priority #=> 10
335
+ # q.delete_min #=> ["a", 10]
336
+ # q.min_priority #=> 20
337
+ # q.delete_min #=> ["b", 20]
338
+ # q.min_priority #=> nil
339
+ def min_priority
340
+ @min.priority rescue nil
341
+ end
342
+
343
+ # call-seq:
344
+ # delete(key) -> [key, priority]
345
+ # delete(key) -> nil
346
+ #
347
+ # Delete a key from the priority queue. Returns nil when the key was not in
348
+ # the queue and [key, priority] otherwise.
349
+ #
350
+ # q = PriorityQueue.new
351
+ # (0..10).each do | i | q[i.to_s] = i end
352
+ # q.delete(5) #=> ["5", 5]
353
+ # q.delete(5) #=> nil
354
+ def delete(key)
355
+ return nil unless n = @nodes.delete(key)
356
+
357
+ if n.child
358
+ c = n.child
359
+ e = n.child
360
+ begin
361
+ r = c.right
362
+ cut_node(c)
363
+ c = r
364
+ end while c != e
365
+ end
366
+ cut_node(n) if n.parent
367
+
368
+ if n == n.right
369
+ @min = nil;
370
+ @rootlist = nil;
371
+ else
372
+ @rootlist = n.right if @rootlist == n
373
+ if @min == n
374
+ n1 = n.right
375
+ @min = n1
376
+ begin
377
+ @min = n1 if n1.priority < @min.priority
378
+ n1 = n1.right
379
+ end while(n1 != n);
380
+ end
381
+ n.right.left = n.left
382
+ n.left.right = n.right
383
+ n.left = n
384
+ n.right = n
385
+ end
386
+ @length -= 1
387
+ return [n.key, n.priority]
388
+ end
389
+
390
+ # call-seq:
391
+ # delete_min_return_key -> key
392
+ #
393
+ # Delete key with minimal priority and return the key
394
+ #
395
+ # q = PriorityQueue.new
396
+ # q["a"] = 1
397
+ # q["b"] = 0
398
+ # q.delete_min_return_key #=> "b"
399
+ # q.delete_min_return_key #=> "a"
400
+ # q.delete_min_return_key #=> nil
401
+ def delete_min_return_key
402
+ delete_min[0] rescue nil
403
+ end
404
+
405
+ # call-seq:
406
+ # delete_min_return_priority -> priority
407
+ #
408
+ # Delete key with minimal priority and return the priority value
409
+ #
410
+ # q = PriorityQueue.new
411
+ # q["a"] = 1
412
+ # q["b"] = 0
413
+ # q.delete_min_return_priority #=> 0
414
+ # q.delete_min_return_priority #=> 1
415
+ # q.delete_min_return_priority #=> nil
416
+ def delete_min_return_priority
417
+ delete_min[1] rescue nil
418
+ end
419
+
420
+ # call-seq:
421
+ # delete_min -> [key, priority]
422
+ #
423
+ # Delete key with minimal priority and return [key, priority]
424
+ #
425
+ # q = PriorityQueue.new
426
+ # q["a"] = 1
427
+ # q["b"] = 0
428
+ # q.delete_min #=> ["b", 0]
429
+ # q.delete_min #=> ["a", 1]
430
+ # q.delete_min #=> nil
431
+ def delete_min
432
+ return nil if self.empty?
433
+ result = self.min
434
+
435
+ @nodes.delete(@min.key)
436
+
437
+ if @length == 1
438
+ @rootlist = @min = nil
439
+ @length = 0
440
+ else
441
+ min = @min
442
+ if @min == @rootlist # If the rootlist is anchored at the minimum, shift to the right
443
+ if @rootlist == @rootlist.right
444
+ @rootlist = @min = nil
445
+ else
446
+ @rootlist = @min = @min.right
447
+ end
448
+ end
449
+ min.left.right = min.right;
450
+ min.right.left = min.left;
451
+ min.left = min.right = min;
452
+ if min.child
453
+ # Kinder und Eltern trennen, Markierung aufheben
454
+ n = min.child;
455
+ begin
456
+ n.parent = nil;
457
+ n.mark = false;
458
+ n = n.right;
459
+ end while n != min.child
460
+
461
+ # Kinder einf�gen
462
+ if @rootlist
463
+ l1 = @rootlist.left
464
+ l2 = n.left
465
+
466
+ l1.right = n
467
+ n.left = l1
468
+ l2.right = @rootlist
469
+ @rootlist.left = l2
470
+ else
471
+ @rootlist = n
472
+ end
473
+ end
474
+
475
+ # Gr��e anpassen
476
+ @length -= 1
477
+
478
+ # Wieder aufh�bschen
479
+ consolidate
480
+ end
481
+
482
+ result
483
+ end
484
+
485
+ # Returns a string representation of the priority queue.
486
+ def inspect
487
+ "<PriorityQueue: #{@nodes.map{|(_, n)| [n.key, n.priority]}.sort_by{|(_,p)|p}.inspect}>"
488
+ end
489
+
490
+ def initialize_copy(copy)
491
+ copy_nodes = @nodes
492
+ @nodes = {}
493
+
494
+ copy_nodes.each do | (_, cn) |
495
+ n = @nodes[cn.key] = Node.new(cn.key, cn.priority)
496
+ n.mark = cn.mark
497
+ n.degree = cn.degree
498
+ end
499
+
500
+ copy_nodes.each do | (_, cn) |
501
+ n = @nodes[cn.key]
502
+ n.left = @nodes[cn.left.key] if cn.left
503
+ n.right = @nodes[cn.right.key] if cn.right
504
+ n.parent = @nodes[cn.parent.key] if cn.parent
505
+ n.child = @nodes[cn.child.key] if cn.child
506
+ end
507
+ @rootlist = @nodes[@rootlist.key] if @rootlist
508
+ @min = @nodes[@min.key] if @min
509
+ self
510
+ end
511
+ end
512
+
513
+ if __FILE__ == $0
514
+ q = RubyPriorityQueue.new
515
+
516
+ ('a'..'z').each do | n |
517
+ q[n] = n[0]
518
+ end
519
+ q.delete_min
520
+ q.delete_min
521
+ q.delete_min
522
+ q.delete_min
523
+ q.display_dot
524
+ q.delete_min
525
+ end