depq 0.5 → 0.6

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.
data/README CHANGED
@@ -21,7 +21,7 @@ depq is double-ended stable priority queue with priority update operation implem
21
21
  * ((<reference manual|URL:http://depq.rubyforge.org/rdoc/classes/Depq.html>))
22
22
  * ((<home page on rubyforge|URL:http://depq.rubyforge.org/>))
23
23
  * ((<project info on rubyforge|URL:http://rubyforge.org/projects/depq/>))
24
- * ((<depq on gemcutter|URL:http://gemcutter.org/gems/depq>))
24
+ * ((<depq on rubygems.org|URL:http://rubygems.org/gems/depq>))
25
25
  * ((<source repository on github|URL:http://github.com/akr/depq>))
26
26
  * ((<raa entry|URL:http://raa.ruby-lang.org/project/depq/>))
27
27
 
@@ -241,6 +241,11 @@ class Depq
241
241
  super value, subpriority, priority
242
242
  end
243
243
 
244
+ def initialize_in_queue(value, depq, index)
245
+ initialize(value, index, depq)
246
+ end
247
+ private :initialize_in_queue
248
+
244
249
  def inspect
245
250
  prio = self.priority
246
251
  if self.value == prio
@@ -377,10 +382,8 @@ class Depq
377
382
 
378
383
  def internal_inserted(depq, index)
379
384
  raise ArgumentError, "already inserted" if in_queue?
380
- priority = index_or_priority()
381
385
  self.depq_or_subpriority = depq
382
386
  self.index_or_priority = index
383
- priority
384
387
  end
385
388
  private :internal_inserted
386
389
 
@@ -432,7 +435,6 @@ class Depq
432
435
  @heapsize = 0
433
436
  @mode = nil
434
437
  @totalcount = 0
435
- #@subpriority_generator = nil
436
438
  end
437
439
 
438
440
  # :stopdoc:
@@ -456,12 +458,10 @@ class Depq
456
458
  end
457
459
  private :set_entry
458
460
 
459
- def delete_entry(i)
460
- locator, priority, subpriority = @ary[i*ARY_SLICE_SIZE, ARY_SLICE_SIZE]
461
- @ary[i*ARY_SLICE_SIZE, ARY_SLICE_SIZE] = []
462
- [locator, priority, subpriority]
461
+ def delete_last_entry
462
+ @ary.slice!(@ary.size-ARY_SLICE_SIZE, ARY_SLICE_SIZE)
463
463
  end
464
- private :delete_entry
464
+ private :delete_last_entry
465
465
 
466
466
  def each_entry
467
467
  0.upto(self.size-1) {|i|
@@ -479,25 +479,37 @@ class Depq
479
479
  private :mode_call
480
480
 
481
481
  def use_min
482
- if @mode == :min || @mode == :interval
482
+ case @mode
483
+ when :min, :interval
483
484
  if @heapsize < self.size
484
485
  @heapsize = mode_call(:heapify, @heapsize)
485
486
  end
486
- else
487
+ when :max
488
+ @mode = :interval
489
+ @heapsize = mode_call(:heapify)
490
+ when nil
487
491
  @mode = :min
488
492
  @heapsize = mode_call(:heapify)
493
+ else
494
+ raise "[bug] unexpected mode: #{@mode.inspect}"
489
495
  end
490
496
  end
491
497
  private :use_min
492
498
 
493
499
  def use_max
494
- if @mode == :max || @mode == :interval
500
+ case @mode
501
+ when :max, :interval
495
502
  if @heapsize < self.size
496
503
  @heapsize = mode_call(:heapify, @heapsize)
497
504
  end
498
- else
505
+ when :min
506
+ @mode = :interval
507
+ @heapsize = mode_call(:heapify)
508
+ when nil
499
509
  @mode = :max
500
510
  @heapsize = mode_call(:heapify)
511
+ else
512
+ raise "[bug] unexpected mode: #{@mode.inspect}"
501
513
  end
502
514
  end
503
515
  private :use_max
@@ -530,7 +542,6 @@ class Depq
530
542
  private :check_locator
531
543
 
532
544
  def default_subpriority
533
- #return @subpriority_generator.call if @subpriority_generator
534
545
  self.totalcount
535
546
  end
536
547
  private :default_subpriority
@@ -538,13 +549,14 @@ class Depq
538
549
  def initialize_copy(obj) # :nodoc:
539
550
  if defined? @ary
540
551
  @ary = @ary.dup
541
- 0.step(@ary.length-1, ARY_SLICE_SIZE) {|k|
542
- i = k / ARY_SLICE_SIZE
552
+ n = @ary.length / ARY_SLICE_SIZE
553
+ k = 0
554
+ n.times {|i|
543
555
  loc1 = @ary[k]
544
- priority = @ary[k+1]
545
- loc2 = Depq::Locator.new(loc1.value, priority)
546
- loc2.send(:internal_inserted, self, i)
556
+ loc2 = Depq::Locator.allocate
557
+ loc2.send(:initialize_in_queue, loc1.value, self, i)
547
558
  @ary[k] = loc2
559
+ k += ARY_SLICE_SIZE
548
560
  }
549
561
  end
550
562
  end
@@ -684,8 +696,9 @@ class Depq
684
696
 
685
697
  def internal_set_priority(loc, priority, subpriority)
686
698
  check_locator(loc)
687
- if @heapsize <= loc.send(:index)
688
- set_entry(loc.send(:index), loc, priority, subpriority)
699
+ index = loc.send(:index)
700
+ if @heapsize <= index
701
+ set_entry(index, loc, priority, subpriority)
689
702
  else
690
703
  mode_heapify
691
704
  mode_call(:update_prio, loc, priority, subpriority)
@@ -705,9 +718,10 @@ class Depq
705
718
  # p q.delete_min #=> 1
706
719
  #
707
720
  def insert_locator(loc)
721
+ priority = loc.priority
708
722
  subpriority = loc.subpriority || default_subpriority
709
723
  i = self.size
710
- priority = loc.send(:internal_inserted, self, i)
724
+ loc.send(:internal_inserted, self, i)
711
725
  set_entry(i, loc, priority, subpriority)
712
726
  @totalcount += 1
713
727
  loc
@@ -961,7 +975,7 @@ class Depq
961
975
  set_entry(index, loc2, priority2, subpriority2)
962
976
  loc2.send(:index=, index)
963
977
  end
964
- delete_entry(last)
978
+ delete_last_entry
965
979
  loc.send(:internal_deleted, priority, subpriority)
966
980
  loc
967
981
  else
@@ -1010,8 +1024,7 @@ class Depq
1010
1024
  #
1011
1025
  def delete_min_priority
1012
1026
  loc = delete_min_locator
1013
- return nil unless loc
1014
- [loc.value, loc.priority]
1027
+ loc and [loc.value, loc.priority]
1015
1028
  end
1016
1029
 
1017
1030
  # delete the minimum element in the queue and returns the value.
@@ -1075,8 +1088,7 @@ class Depq
1075
1088
  #
1076
1089
  def delete_max_priority
1077
1090
  loc = delete_max_locator
1078
- return nil unless loc
1079
- [loc.value, loc.priority]
1091
+ loc and [loc.value, loc.priority]
1080
1092
  end
1081
1093
 
1082
1094
  # delete the maximum element in the queue and returns the value.
@@ -1138,8 +1150,7 @@ class Depq
1138
1150
  #
1139
1151
  def delete_unspecified_priority
1140
1152
  loc = delete_unspecified_locator
1141
- return nil unless loc
1142
- [loc.value, loc.priority]
1153
+ loc and [loc.value, loc.priority]
1143
1154
  end
1144
1155
 
1145
1156
  # delete an element in the queue and returns the value.
@@ -1159,8 +1170,7 @@ class Depq
1159
1170
  #
1160
1171
  def delete_unspecified
1161
1172
  loc = delete_unspecified_locator
1162
- return nil unless loc
1163
- loc.value
1173
+ loc and loc.value
1164
1174
  end
1165
1175
 
1166
1176
  # replaces the minimum element.
@@ -1233,7 +1243,7 @@ class Depq
1233
1243
  # }
1234
1244
  #
1235
1245
  def each_locator # :yield: locator
1236
- each_entry {|locator, priority|
1246
+ each_entry {|locator,|
1237
1247
  yield locator
1238
1248
  }
1239
1249
  nil
@@ -1241,6 +1251,8 @@ class Depq
1241
1251
 
1242
1252
  # iterate over the values and priorities in the queue.
1243
1253
  #
1254
+ # The iteration order is unspecified.
1255
+ #
1244
1256
  # q = Depq.new
1245
1257
  # q.insert "durian", 1
1246
1258
  # q.insert "banana", 3
@@ -1295,6 +1307,8 @@ class Depq
1295
1307
  # p Depq.nlargest(3, [5, 2, 3, 1, 4, 6, 7]) {|e| -e } #=> [3, 2, 1]
1296
1308
  #
1297
1309
  def Depq.nlargest(n, iter)
1310
+ raise ArgumentError, "n is negative" if n < 0
1311
+ return [] if n == 0
1298
1312
  limit = (n * Math.log(1+n)).ceil
1299
1313
  limit = 1024 if limit < 1024
1300
1314
  q = Depq.new
@@ -1348,6 +1362,8 @@ class Depq
1348
1362
  # p Depq.nsmallest(5, [5, 2, 3, 1, 4, 6, 7]) {|e| -e } #=> [7, 6, 5, 4, 3]
1349
1363
  #
1350
1364
  def Depq.nsmallest(n, iter)
1365
+ raise ArgumentError, "n is negative" if n < 0
1366
+ return [] if n == 0
1351
1367
  limit = (n * Math.log(1+n)).ceil
1352
1368
  limit = 1024 if limit < 1024
1353
1369
  q = Depq.new
@@ -1436,6 +1452,102 @@ class Depq
1436
1452
  end
1437
1453
  end
1438
1454
 
1455
+ # search a graph using A* search algorithm.
1456
+ #
1457
+ # The graph is defined by _start_ argument and the given block.
1458
+ # _start_ specifies the start node for searching.
1459
+ # The block should takes a node and return an array of pairs.
1460
+ # The pair is an 2-element array which contains the next node and cost of the given node to the next node.
1461
+ #
1462
+ # The optional argument, _heuristics_ specifies
1463
+ # conservative estimation to goal.
1464
+ # It should be a Hash or a Proc that _heuristics_+[node]+ returns an estimated cost to goal.
1465
+ # The estimated cost must be smaller or equal to the true cost.
1466
+ # If _heuristics_ is not given, Hash.new(0) is used.
1467
+ # This means +Depq.astar_search+ behaves as Dijkstra's algorithm in that case.
1468
+ #
1469
+ # +Depq.astar_search+ returns an enumerator.
1470
+ # It yields 3 values: previous node, current node and total cost between start node to current node.
1471
+ # When current node is start node, nil is given for previous node.
1472
+ #
1473
+ # # 7 5 1
1474
+ # # A--->B--->C--->D
1475
+ # # | | | |
1476
+ # # 2| 4| 1| 3|
1477
+ # # | | | |
1478
+ # # V V V V
1479
+ # # E--->F--->G--->H
1480
+ # # 3 3 5
1481
+ # #
1482
+ # g = {
1483
+ # :A => [[:B, 7], [:E, 2]],
1484
+ # :B => [[:C, 5], [:F, 4]],
1485
+ # :C => [[:D, 1], [:G, 1]],
1486
+ # :D => [[:H, 3]],
1487
+ # :E => [[:F, 3]],
1488
+ # :F => [[:G, 3]],
1489
+ # :G => [[:H, 5]],
1490
+ # :H => []
1491
+ # }
1492
+ # # This doesn't specify _heuristics_. So This is Dijkstra's algorithm.
1493
+ # Depq.astar_search(:A) {|n| g[n] }.each {|prev, curr, cost| p [prev, curr, cost] }
1494
+ # #=> [nil, :A, 0]
1495
+ # # [:A, :E, 2]
1496
+ # # [:E, :F, 5]
1497
+ # # [:A, :B, 7]
1498
+ # # [:F, :G, 8]
1499
+ # # [:B, :C, 12]
1500
+ # # [:G, :H, 13] # H found.
1501
+ # # [:C, :D, 13]
1502
+ #
1503
+ # # heuristics using Manhattan distance assuming the goal is H.
1504
+ # h = {
1505
+ # :A => 4,
1506
+ # :B => 3,
1507
+ # :C => 2,
1508
+ # :D => 1,
1509
+ # :E => 3,
1510
+ # :F => 2,
1511
+ # :G => 1,
1512
+ # :H => 0
1513
+ # }
1514
+ # # This specify _heuristics_. So This is A* search algorithm.
1515
+ # Depq.astar_search(:A, h) {|n| g[n] }.each {|prev, curr, cost| p [prev, curr, cost] }
1516
+ # #=> [nil, :A, 0]
1517
+ # # [:A, :E, 2]
1518
+ # # [:E, :F, 5]
1519
+ # # [:F, :G, 8]
1520
+ # # [:A, :B, 7]
1521
+ # # [:G, :H, 13] # H found. Bit better than Dijkstra's algorithm.
1522
+ # # [:B, :C, 12]
1523
+ # # [:C, :D, 13]
1524
+ #
1525
+ # cf. http://en.wikipedia.org/wiki/A*_search_algorithm
1526
+ #
1527
+ def Depq.astar_search(start, heuristics=nil, &find_nexts)
1528
+ Enumerator.new {|y|
1529
+ heuristics ||= Hash.new(0)
1530
+ h = Hash.new {|_, k| h[k] = heuristics[k] }
1531
+ q = Depq.new
1532
+ visited = {start => q.insert([nil, start], h[start])}
1533
+ until q.empty?
1534
+ path, w1 = q.delete_min_priority
1535
+ v1 = path.last
1536
+ w1 -= h[v1]
1537
+ y.yield [path.first, path.last, w1]
1538
+ find_nexts.call(v1).each {|v2, w2|
1539
+ w3 = w1 + w2 + h[v2]
1540
+ if !visited[v2]
1541
+ visited[v2] = q.insert([path.last,v2], w3)
1542
+ elsif w3 < visited[v2].priority
1543
+ visited[v2].update([path.last,v2], w3)
1544
+ end
1545
+ }
1546
+ end
1547
+ nil
1548
+ }
1549
+ end
1550
+
1439
1551
  private
1440
1552
  # :stopdoc:
1441
1553
 
@@ -1465,17 +1577,18 @@ class Depq
1465
1577
  def mm_downheap(i, upper)
1466
1578
  while true
1467
1579
  j = i*2+1
1468
- k = i*2+2
1580
+ k = j+1
1469
1581
  return if self.size <= j
1470
1582
  if self.size == k
1471
1583
  return if upper.call(i, j)
1472
1584
  swap(i, j)
1473
1585
  i = j
1586
+ return
1474
1587
  else
1475
1588
  return if upper.call(i, j) && upper.call(i, k)
1476
- loc = upper.call(j, k) ? j : k
1477
- swap(i, loc)
1478
- i = loc
1589
+ m = upper.call(j, k) ? j : k
1590
+ swap(i, m)
1591
+ i = m
1479
1592
  end
1480
1593
  end
1481
1594
  end
@@ -1490,7 +1603,7 @@ class Depq
1490
1603
  _, priority, subpriority = get_entry(i)
1491
1604
  last = self.size - 1
1492
1605
  loc.send(:internal_deleted, priority, subpriority)
1493
- el, pl, sl = delete_entry(last)
1606
+ el, pl, sl = delete_last_entry
1494
1607
  if i != last
1495
1608
  set_entry(i, el, pl, sl)
1496
1609
  el.send(:index=, i)
@@ -1642,10 +1755,10 @@ class Depq
1642
1755
  def itv_maxside(i) i | 1 end
1643
1756
  def itv_parent_minside(j) (j-2)/2 & ~1 end
1644
1757
  def itv_parent_maxside(j) (j-2)/2 | 1 end
1645
- def itv_child1_minside(i) i &= ~1; (i*2+2) & ~1 end
1646
- def itv_child1_maxside(i) i &= ~1; (i*2+2) | 1 end
1647
- def itv_child2_minside(i) i &= ~1; (i*2+4) & ~1 end
1648
- def itv_child2_maxside(i) i &= ~1; (i*2+4) | 1 end
1758
+ def itv_child1_minside(i) i &= ~1; i*2+2 end
1759
+ def itv_child1_maxside(i) i &= ~1; i*2+3 end
1760
+ def itv_child2_minside(i) i &= ~1; i*2+4 end
1761
+ def itv_child2_maxside(i) i &= ~1; i*2+5 end
1649
1762
 
1650
1763
  def pcmp(i, j)
1651
1764
  ei, pi, si = get_entry(i)
@@ -1672,7 +1785,7 @@ class Depq
1672
1785
  imin = itv_minside(i)
1673
1786
  imax = itv_maxside(i)
1674
1787
  if range.include?(imin) && range.include?(imax)
1675
- if pcmp(imin, imax) == 0 && scmp(imin, imax) > 0
1788
+ if scmp(imin, imax) > 0 && pcmp(imin, imax) == 0
1676
1789
  swap imin, imax
1677
1790
  end
1678
1791
  end
@@ -1926,7 +2039,7 @@ class Depq
1926
2039
  _, priority, subpriority = get_entry(i)
1927
2040
  last = self.size - 1
1928
2041
  loc.send(:internal_deleted, priority, subpriority)
1929
- el, pl, sl = delete_entry(last)
2042
+ el, pl, sl = delete_last_entry
1930
2043
  if i != last
1931
2044
  set_entry(i, el, pl, sl)
1932
2045
  el.send(:index=, i)
@@ -0,0 +1,43 @@
1
+ # Dijkstra's single source shortest path finding algorithm
2
+ #
3
+ # usage:
4
+ # ruby -Ilib sample/dijkstra.rb
5
+
6
+ require 'depq'
7
+
8
+ def dijkstra_shortest_path(start, edges)
9
+ h = {}
10
+ edges.each {|v1, v2, w|
11
+ (h[v1] ||= []) << [v2, w]
12
+ }
13
+ h.default = []
14
+ q = Depq.new
15
+ visited = {start => q.insert([start], 0)}
16
+ until q.empty?
17
+ path, w1 = q.delete_min_priority
18
+ v1 = path.last
19
+ h[v1].each {|v2, w2|
20
+ if !visited[v2]
21
+ visited[v2] = q.insert(path+[v2], w1 + w2)
22
+ elsif w1 + w2 < visited[v2].priority
23
+ visited[v2].update(path+[v2], w1 + w2) # update val/prio
24
+ end
25
+ }
26
+ end
27
+ result = []
28
+ visited.each_value {|loc|
29
+ result << [loc.value, loc.priority]
30
+ }
31
+ result
32
+ end
33
+
34
+ E = [
35
+ ['A', 'B', 2],
36
+ ['A', 'C', 4],
37
+ ['B', 'C', 1],
38
+ ['C', 'B', 2],
39
+ ['B', 'D', 3],
40
+ ['C', 'D', 1],
41
+ ]
42
+ p dijkstra_shortest_path('A', E)
43
+
@@ -0,0 +1,90 @@
1
+ # external quick sort
2
+ #
3
+ # usage:
4
+ # ruby -Ilib sample/exqsort.rb input-file
5
+
6
+ require 'tmpdir'
7
+ require 'depq'
8
+
9
+ NUM_PIVOTS = 1024
10
+ $tmpdir = nil
11
+ $filecount = 0
12
+
13
+ def partition(input)
14
+ q = Depq.new
15
+ fn1 = "#{$tmpdir}/#{$filecount += 1}"
16
+ fn2 = "#{$tmpdir}/#{$filecount += 1}"
17
+ fn3 = "#{$tmpdir}/#{$filecount += 1}"
18
+ open(fn1, "w") {|f1|
19
+ open(fn3, "w") {|f3|
20
+ n1 = n2 = n3 = 0
21
+ input.each_line {|line|
22
+ line = line.chomp
23
+ if q.size < NUM_PIVOTS
24
+ q.insert line
25
+ else
26
+ min, max = q.minmax
27
+ if line <= min
28
+ f1.puts line
29
+ n1 += 1
30
+ elsif line < max
31
+ q.insert line
32
+ if n1 < n2
33
+ f1.puts q.delete_min
34
+ n1 += 1
35
+ else
36
+ f3.puts q.delete_max
37
+ n3 += 1
38
+ end
39
+ else
40
+ f3.puts line
41
+ n3 += 1
42
+ end
43
+ end
44
+ }
45
+ }
46
+ }
47
+ open(fn2, "w") {|f2|
48
+ while !q.empty?
49
+ f2.puts q.delete_min
50
+ end
51
+ }
52
+ if File.size(fn1) == 0
53
+ File.delete fn1
54
+ fn1 = nil
55
+ end
56
+ if File.size(fn2) == 0
57
+ File.delete fn2
58
+ fn2 = nil
59
+ end
60
+ if File.size(fn3) == 0
61
+ File.delete fn3
62
+ fn3 = nil
63
+ end
64
+ [fn1, fn2, fn3]
65
+ end
66
+
67
+ def eqs(input)
68
+ fn1, fn2, fn3 = partition(input)
69
+ r = []
70
+ if fn1
71
+ r.concat(open(fn1) {|f| eqs(f) })
72
+ end
73
+ if fn2
74
+ r << fn2
75
+ end
76
+ if fn3
77
+ r.concat(open(fn3) {|f| eqs(f) })
78
+ end
79
+ r
80
+ end
81
+
82
+ Dir.mktmpdir {|d|
83
+ $tmpdir = d
84
+ fns = eqs(ARGF)
85
+ fns.each {|fn|
86
+ File.foreach(fn) {|line|
87
+ puts line
88
+ }
89
+ }
90
+ }
@@ -0,0 +1,37 @@
1
+ # Huffman coding
2
+ #
3
+ # usage:
4
+ # ruby -Ilib sample/huffman.rb input-file
5
+
6
+ require 'depq'
7
+
8
+ h = Hash.new(0)
9
+ ARGF.each {|line|
10
+ line.scan(/\S+/).each {|word|
11
+ h[word] += 1
12
+ }
13
+ }
14
+
15
+ if h.empty?
16
+ exit
17
+ end
18
+
19
+ q = Depq.new
20
+
21
+ h.each {|word, count|
22
+ q.insert({word => ""}, count)
23
+ }
24
+
25
+ while 1 < q.size
26
+ h0, count0 = q.delete_min_priority
27
+ h1, count1 = q.delete_min_priority
28
+ hh = {}
29
+ h0.each {|w, c| hh[w] = "0" + c }
30
+ h1.each {|w, c| hh[w] = "1" + c }
31
+ q.insert hh, count0+count1
32
+ end
33
+
34
+ hh = q.delete_min
35
+ hh.keys.sort_by {|w| h[w] }.each {|w| puts "#{hh[w]} #{h[w]} #{w.inspect}" }
36
+
37
+
@@ -0,0 +1,48 @@
1
+ # search integers x, y, z from smaller x*y*z where x >= y >= z >= 1.
2
+ #
3
+ # usage:
4
+ # ruby -Ilib sample/int-3d.rb
5
+
6
+ require 'depq'
7
+
8
+ # naive version
9
+ def gen1
10
+ q = Depq.new
11
+ q.insert [1, 1,1,1]
12
+ loop {
13
+ ary = q.delete_min
14
+ while q.find_min == ary
15
+ q.delete_min
16
+ end
17
+ yield ary
18
+ w, x,y,z = ary
19
+ x1 = x + 1
20
+ y1 = y + 1
21
+ z1 = z + 1
22
+ q.insert [x1*y*z, x1,y,z] if x1 >= y && y >= z
23
+ q.insert [x*y1*z, x,y1,z] if x >= y1 && y1 >= z
24
+ q.insert [x*y*z1, x,y,z1] if x >= y && y >= z1
25
+ }
26
+ end
27
+
28
+ # faster version
29
+ def gen2
30
+ q = Depq.new
31
+ q.insert [1, 1,1,1]
32
+ loop {
33
+ ary = q.delete_min
34
+ yield ary
35
+ w, x,y,z = ary
36
+ x1 = x + 1
37
+ y1 = y + 1
38
+ z1 = z + 1
39
+ q.insert [x1*y*z, x1,y,z]
40
+ q.insert [x*y1*z, x,y1,z] if x == y1
41
+ q.insert [x*y*z1, x,y,z1] if x == y && y == z1
42
+ }
43
+ end
44
+
45
+ gen2 {|w, x,y,z|
46
+ break if 100 <= w
47
+ p [w, x,y,z]
48
+ }
@@ -0,0 +1,55 @@
1
+ # Kruskal's algorithm
2
+ #
3
+ # finds a minimum spanning tree for a connected weighted graph
4
+ #
5
+ # http://en.wikipedia.org/wiki/Kruskal's_algorithm
6
+ #
7
+ # usage:
8
+ # ruby -Ilib sample/kruskal.rb
9
+
10
+ require 'depq'
11
+
12
+ def kruskal(edge_set)
13
+ q = Depq.new
14
+ parent = {}
15
+ edge_set.each {|v1, v2, w|
16
+ parent[v1] = nil
17
+ parent[v2] = nil
18
+ q.insert [v1, v2], w
19
+ }
20
+
21
+ edge_set2 = []
22
+
23
+ until q.empty?
24
+ v1, v2 = q.delete_min
25
+ r1 = v1
26
+ r1 = parent[r1] while parent[r1]
27
+ r2 = v2
28
+ r2 = parent[r2] while parent[r2]
29
+ if r1 != r2
30
+ edge_set2 << [v1, v2]
31
+ parent[r2] = r1
32
+ end
33
+ end
34
+
35
+ edge_set2
36
+ end
37
+
38
+ if $0 == __FILE__
39
+ E = [
40
+ ['A', 'B', 7],
41
+ ['A', 'D', 5],
42
+ ['B', 'C', 8],
43
+ ['B', 'D', 9],
44
+ ['B', 'E', 7],
45
+ ['C', 'E', 5],
46
+ ['D', 'E', 15],
47
+ ['D', 'F', 6],
48
+ ['E', 'F', 8],
49
+ ['E', 'G', 9],
50
+ ['F', 'G', 11],
51
+ ]
52
+
53
+ p kruskal(E)
54
+ #=> [["A", "D"], ["C", "E"], ["D", "F"], ["A", "B"], ["B", "E"], ["E", "G"]]
55
+ end
@@ -0,0 +1,103 @@
1
+ # solve a maze using A* search algorithm
2
+ #
3
+ # usage:
4
+ # ruby -Isample -Ilib sample/maze.rb
5
+
6
+ require 'depq'
7
+
8
+ Pos = Struct.new(:x, :y)
9
+
10
+ MAZE_MAP = <<'End'
11
+ OOOOOOOOOOOOOOOOOOOOOOOOO
12
+ O OSO O O
13
+ O OOOOOOOOO O O OOO OOO O
14
+ O O O O O O
15
+ O OOOOOOO OOOOOOO OOO O O
16
+ O O O O O O
17
+ OOOOO O O OOO OOOOOOOOO O
18
+ OG O O O O O O O
19
+ O O O O OOO OOO O O O OOO
20
+ O O O O O O O O
21
+ O OOO O OOOOOOOOOOOOOOO O
22
+ O O O
23
+ OOOOOOOOOOOOOOOOOOOOOOOOO
24
+ End
25
+
26
+ MAZE = MAZE_MAP.lines.map {|line| line.chomp.split(//) }
27
+
28
+ H = HEIGHT = MAZE.length
29
+ W = WIDTH = MAZE[0].length
30
+
31
+ MAZE.each_with_index {|line,y|
32
+ line.each_with_index {|cell,x|
33
+ if cell == 'S'
34
+ START = Pos[x,y]
35
+ MAZE[y][x] = ' '
36
+ elsif cell == 'G'
37
+ GOAL = Pos[x,y]
38
+ MAZE[y][x] = ' '
39
+ end
40
+ }
41
+ }
42
+
43
+ find_nexts4 = proc {|pos|
44
+ x, y = pos.x, pos.y
45
+ r = []
46
+ r << [Pos[x-1,y],1] if 0 < x && MAZE[y][x-1] == ' '
47
+ r << [Pos[x,y-1],1] if 0 < y && MAZE[y-1][x] == ' '
48
+ r << [Pos[x+1,y],1] if x < W-1 && MAZE[y][x+1] == ' '
49
+ r << [Pos[x,y+1],1] if y < H-1 && MAZE[y+1][x] == ' '
50
+ r
51
+ }
52
+
53
+ heuristics4 = proc {|pos|
54
+ x, y = pos.x, pos.y
55
+ (x-GOAL.x).abs + (y-GOAL.y).abs
56
+ }
57
+
58
+ find_nexts8 = proc {|pos|
59
+ x, y = pos.x, pos.y
60
+ r = []
61
+ r << [[x-1,y],1] if 0 < x && MAZE[y][x-1] == ' '
62
+ r << [[x,y-1],1] if 0 < y && MAZE[y-1][x] == ' '
63
+ r << [[x+1,y],1] if x < W-1 && MAZE[y][x+1] == ' '
64
+ r << [[x,y+1],1] if y < H-1 && MAZE[y+1][x] == ' '
65
+ r << [[x-1,y-1],2] if 0 < x && 0 < y && MAZE[y-1][x-1] == ' '
66
+ r << [[x-1,y+1],2] if 0 < x && y < H-1 && MAZE[y+1][x-1] == ' '
67
+ r << [[x+1,y-1],2] if x < W-1 && 0 < y && MAZE[y-1][x+1] == ' '
68
+ r << [[x+1,y+1],2] if x < W-1 && y < H-1 && MAZE[y+1][x+1] == ' '
69
+ r
70
+ }
71
+
72
+ heuristics8 = proc {|pos|
73
+ x, y = pos.x, pos.y
74
+ (x-GOAL.x).abs + (y-GOAL.y).abs
75
+ }
76
+
77
+ t1 = Time.now
78
+ searched = {}
79
+ path = Depq.astar_search(START, heuristics4, &find_nexts4).each {|prev, cur, w|
80
+ searched[cur] = [searched[prev], cur]
81
+ if cur == GOAL
82
+ break searched[cur].flatten.compact
83
+ end
84
+ }
85
+ t2 = Time.now
86
+ p t2-t1
87
+
88
+ searched.each_key {|pos|
89
+ x, y = pos.x, pos.y
90
+ MAZE[y][x] = '.'
91
+ }
92
+
93
+ path.each {|pos|
94
+ x, y = pos.x, pos.y
95
+ MAZE[y][x] = '*'
96
+ }
97
+
98
+ MAZE[START.y][START.x] = 'S'
99
+ MAZE[GOAL.y][GOAL.x] = 'G'
100
+
101
+ MAZE.each {|line|
102
+ puts line.join('')
103
+ }
@@ -0,0 +1,78 @@
1
+ # Prim's algorithm
2
+ #
3
+ # finds a minimum spanning tree for a connected weighted graph
4
+ #
5
+ # http://en.wikipedia.org/wiki/Prim's_algorithm
6
+ #
7
+ # usage:
8
+ # ruby -Ilib sample/prim.rb
9
+ #
10
+
11
+ require 'depq'
12
+
13
+ def prim(edge_set)
14
+ vertex_set1 = {}
15
+ adj = {}
16
+ weight = {}
17
+ edge_set.each {|v1, v2, w|
18
+ vertex_set1[v1] = true
19
+ vertex_set1[v2] = true
20
+ adj[v1] ||= []
21
+ adj[v1] << v2
22
+ adj[v2] ||= []
23
+ adj[v2] << v1
24
+ weight[[v1, v2]] = weight[[v2, v1]] = w
25
+ }
26
+ adj.default = []
27
+
28
+ start = vertex_set1.first[0]
29
+ q = Depq.new
30
+ vertex_set2 = {start => true}
31
+ edge_set2 = []
32
+ prev_locators = {}
33
+
34
+ adj[start].each {|v2|
35
+ prev_locators[v2] = [start, q.insert(v2, weight[[start, v2]])]
36
+ }
37
+
38
+ while vertex_set2.size < vertex_set1.size
39
+ v2 = q.delete_min
40
+ v1, _ = prev_locators[v2]
41
+ prev_locators.delete v2
42
+ vertex_set2[v2] = true
43
+ edge_set2 << [v1, v2]
44
+ adj[v2].each {|v3|
45
+ next if vertex_set2[v3]
46
+ if prev_loc = prev_locators[v3]
47
+ _, loc = prev_loc
48
+ if weight[[v2, v3]] < loc.priority
49
+ prev_loc[0] = v2
50
+ loc.update v3, weight[[v2, v3]]
51
+ end
52
+ else
53
+ prev_locators[v3] = [v2, q.insert(v3, weight[[v2, v3]])]
54
+ end
55
+ }
56
+ end
57
+ edge_set2
58
+ end
59
+
60
+ if $0 == __FILE__
61
+ E = [
62
+ ['A', 'B', 7],
63
+ ['A', 'D', 5],
64
+ ['B', 'C', 8],
65
+ ['B', 'D', 9],
66
+ ['B', 'E', 7],
67
+ ['C', 'E', 5],
68
+ ['D', 'E', 15],
69
+ ['D', 'F', 6],
70
+ ['E', 'F', 8],
71
+ ['E', 'G', 9],
72
+ ['F', 'G', 11],
73
+ ]
74
+
75
+ p prim(E)
76
+ #=> [["A", "D"], ["D", "F"], ["A", "B"], ["B", "E"], ["E", "C"], ["E", "G"]]
77
+ end
78
+
@@ -0,0 +1,68 @@
1
+ # scheduler
2
+ #
3
+ # needs Ruby 1.9.2 for timeout argument of ConditionVariable#wait.
4
+ #
5
+ # usage:
6
+ # ruby -Ilib sample/sched.rb
7
+
8
+ require 'depq'
9
+ require 'thread'
10
+
11
+ class Sched
12
+ def initialize
13
+ @q = Depq.new
14
+ @m = Mutex.new
15
+ @cv = ConditionVariable.new
16
+ end
17
+
18
+ def sync
19
+ @m.synchronize { yield }
20
+ end
21
+
22
+ def insert(time, &block)
23
+ sync {
24
+ @q.insert block, time
25
+ }
26
+ end
27
+
28
+ def wait_next_event
29
+ sync {
30
+ block, time = @q.find_min_priority
31
+ now = Time.now
32
+ if now < time
33
+ @cv.wait(@m, time - now)
34
+ end
35
+ now
36
+ }
37
+ end
38
+
39
+ def start
40
+ until sync { @q.empty? }
41
+ now = wait_next_event
42
+ loop {
43
+ block = time = nil
44
+ sync {
45
+ raise StopIteration if @q.empty?
46
+ block, time = @q.find_min_priority
47
+ raise StopIteration if now < time
48
+ block, time = @q.delete_min_priority
49
+ }
50
+ block.call
51
+ }
52
+ end
53
+ end
54
+ end
55
+
56
+ if $0 == __FILE__
57
+ now = Time.now
58
+ sc = Sched.new
59
+ Thread.new {
60
+ sleep 1.5
61
+ sc.insert(Time.now+1) { p Time.now-now }
62
+ }
63
+ sc.insert(now+4) { p Time.now-now }
64
+ sc.insert(now+3) { p Time.now-now }
65
+ sc.insert(now+2) { p Time.now-now }
66
+ sc.insert(now+1) { p Time.now-now }
67
+ sc.start
68
+ end
@@ -1097,4 +1097,75 @@ class TestDepq < Test::Unit::TestCase
1097
1097
  assert_raise(StopIteration) { e.next }
1098
1098
  end
1099
1099
 
1100
+ def test_mode_min_first
1101
+ q = Depq.new
1102
+ q.insert 1
1103
+ q.insert 2
1104
+ assert_equal(nil, q.instance_eval { @mode })
1105
+ assert_equal(1, q.delete_min)
1106
+ assert_equal(:min, q.instance_eval { @mode })
1107
+ assert_equal(2, q.delete_max)
1108
+ assert_equal(:interval, q.instance_eval { @mode })
1109
+ end
1110
+
1111
+ def test_mode_max_first
1112
+ q = Depq.new
1113
+ q.insert 1
1114
+ q.insert 2
1115
+ assert_equal(nil, q.instance_eval { @mode })
1116
+ assert_equal(2, q.delete_max)
1117
+ assert_equal(:max, q.instance_eval { @mode })
1118
+ assert_equal(1, q.delete_min)
1119
+ assert_equal(:interval, q.instance_eval { @mode })
1120
+ end
1121
+
1122
+ def test_astar
1123
+ g = {
1124
+ :A => [[:B, 7], [:E, 2]],
1125
+ :B => [[:C, 5], [:F, 4]],
1126
+ :C => [[:D, 1], [:G, 1]],
1127
+ :D => [[:H, 3]],
1128
+ :E => [[:F, 3]],
1129
+ :F => [[:G, 3]],
1130
+ :G => [[:H, 5]],
1131
+ :H => []
1132
+ }
1133
+ res = []
1134
+ Depq.astar_search(:A) {|n| g[n] }.each {|prev, curr, cost| res << [prev, curr, cost] }
1135
+ assert_equal(
1136
+ [[nil, :A, 0],
1137
+ [:A, :E, 2],
1138
+ [:E, :F, 5],
1139
+ [:A, :B, 7],
1140
+ [:F, :G, 8],
1141
+ [:B, :C, 12],
1142
+ [:G, :H, 13],
1143
+ [:C, :D, 13]],
1144
+ res)
1145
+
1146
+ # heuristics using Manhattan distance assuming the goal is H.
1147
+ h = {
1148
+ :A => 4,
1149
+ :B => 3,
1150
+ :C => 2,
1151
+ :D => 1,
1152
+ :E => 3,
1153
+ :F => 2,
1154
+ :G => 1,
1155
+ :H => 0
1156
+ }
1157
+ res = []
1158
+ Depq.astar_search(:A, h) {|n| g[n] }.each {|prev, curr, cost| res << [prev, curr, cost] }
1159
+ assert_equal(
1160
+ [[nil, :A, 0],
1161
+ [:A, :E, 2],
1162
+ [:E, :F, 5],
1163
+ [:F, :G, 8],
1164
+ [:A, :B, 7],
1165
+ [:G, :H, 13],
1166
+ [:B, :C, 12],
1167
+ [:C, :D, 13]],
1168
+ res)
1169
+ end
1170
+
1100
1171
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: depq
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.5'
4
+ version: '0.6'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-10-27 00:00:00.000000000 Z
12
+ date: 2011-11-29 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: ! 'depq is a Double-Ended Priority Queue library.
15
15
 
@@ -28,6 +28,14 @@ extra_rdoc_files: []
28
28
  files:
29
29
  - README
30
30
  - lib/depq.rb
31
+ - sample/dijkstra.rb
32
+ - sample/exqsort.rb
33
+ - sample/huffman.rb
34
+ - sample/int-3d.rb
35
+ - sample/kruskal.rb
36
+ - sample/maze.rb
37
+ - sample/prim.rb
38
+ - sample/sched.rb
31
39
  - test/test-depq.rb
32
40
  homepage: http://depq.rubyforge.org/
33
41
  licenses: []