| 1 | (******************************************************************************* |
|---|
| 2 | Copyright 2009 Sun Microsystems, Inc., |
|---|
| 3 | 4150 Network Circle, Santa Clara, California 95054, U.S.A. |
|---|
| 4 | All rights reserved. |
|---|
| 5 | |
|---|
| 6 | U.S. Government Rights - Commercial software. |
|---|
| 7 | Government users are subject to the Sun Microsystems, Inc. standard |
|---|
| 8 | license agreement and applicable provisions of the FAR and its supplements. |
|---|
| 9 | |
|---|
| 10 | Use is subject to license terms. |
|---|
| 11 | |
|---|
| 12 | This distribution may include materials developed by third parties. |
|---|
| 13 | |
|---|
| 14 | Sun, Sun Microsystems, the Sun logo and Java are trademarks or registered |
|---|
| 15 | trademarks of Sun Microsystems, Inc. in the U.S. and other countries. |
|---|
| 16 | ******************************************************************************) |
|---|
| 17 | |
|---|
| 18 | component Heap |
|---|
| 19 | export Heap |
|---|
| 20 | |
|---|
| 21 | (************************************************************ |
|---|
| 22 | * Mergeable, pure priority queues (heaps). *) |
|---|
| 23 | |
|---|
| 24 | (** At the moment we're baking off several potential priority queue |
|---|
| 25 | implementations, based on part on some advice from "Purely |
|---|
| 26 | Functional Data Structures" by Okasaki. |
|---|
| 27 | |
|---|
| 28 | * Pairing Heaps, the current default: |
|---|
| 29 | O(1) merge |
|---|
| 30 | O(lg n) amortized extractMinimum, with O(n) worst case. The worst |
|---|
| 31 | case is proportional to the number of deferred merge operations |
|---|
| 32 | performed with the min; if you merge n entries tree-fashion rather |
|---|
| 33 | than 1 at a time you should obtain O(lg n) worst case performance |
|---|
| 34 | as well. The heap(gen) function will follow the merge structure |
|---|
| 35 | of the underlying generator; for a well-written generator this |
|---|
| 36 | will be sufficient to give good performance. |
|---|
| 37 | |
|---|
| 38 | * Lazy-esque pairing heaps (supposedly slower but actually easier in |
|---|
| 39 | some ways to implement than pairing heaps, and avoiding a potential |
|---|
| 40 | stack overflow in the latter). These don't seem to be quite as |
|---|
| 41 | whizzy in this setting as ordinary Pairing Heaps. |
|---|
| 42 | O(lg n) merge |
|---|
| 43 | O(lg n) worst-case extractMinimum |
|---|
| 44 | |
|---|
| 45 | * Splay heaps (noted as "fastest in practice", borne out by other |
|---|
| 46 | experiments). Problem: O(n) merge operation, vs O(lg n) for |
|---|
| 47 | everything else. If we build heaps by performing reductions over |
|---|
| 48 | a generator, with each iteration generating a few elements, this |
|---|
| 49 | will be a problem. This is not yet implemented. |
|---|
| 50 | |
|---|
| 51 | Minimum complete implementation of Heap[\K,V\]: |
|---|
| 52 | empty |
|---|
| 53 | singleton |
|---|
| 54 | isEmpty |
|---|
| 55 | extractMinimum |
|---|
| 56 | merge(Heap[\K,V\]) |
|---|
| 57 | **) |
|---|
| 58 | trait Heap[\K,V\] extends Generator[\(K,V)\] |
|---|
| 59 | (** Given an instance of Heap[\K,V\], get the empty Heap[\K,V\] **) |
|---|
| 60 | getter empty(): Heap[\K,V\] |
|---|
| 61 | (** Get the (key,value) pair with minimal associated key **) |
|---|
| 62 | getter minimum(): Maybe[\(K,V)\] = |
|---|
| 63 | if (k,v,_) <- extractMinimum() then |
|---|
| 64 | Just[\(K,V)\](k,v) |
|---|
| 65 | else |
|---|
| 66 | Nothing[\(K,V)\] |
|---|
| 67 | end |
|---|
| 68 | (** Check the invariants on the heap. **) |
|---|
| 69 | check(): Heap[\K,V\] |
|---|
| 70 | (** Given an instance of Heap[\K,V\], generate a singleton Heap[\K,V\] **) |
|---|
| 71 | singleton(k:K, v:V): Heap[\K,V\] |
|---|
| 72 | (** Return a heap that contains the key-value pairings in both of |
|---|
| 73 | the heaps passed in. **) |
|---|
| 74 | merge(h:Heap[\K,V\]): Heap[\K,V\] |
|---|
| 75 | (** Return a heap that contains the additional key-value pairs **) |
|---|
| 76 | insert(k:K, v:V): Heap[\K,V\] = self.merge(self.singleton[\K,V\](k,v)) |
|---|
| 77 | (** Extract the (key,value) pair with minimal associated key, |
|---|
| 78 | along with a heap with that key and value pair removed. **) |
|---|
| 79 | extractMinimum(): Maybe[\(K,V,Heap[\K,V\])\] |
|---|
| 80 | (** Delete the minimum (key,value) pair (if any) from the heap, |
|---|
| 81 | and return the resulting heap. *) |
|---|
| 82 | deleteMinimum(): Heap[\K,V\] = |
|---|
| 83 | if (_,_,r) <- extractMinimum() then r else self end |
|---|
| 84 | (** We generate elements by repeated splitting. This is fairly |
|---|
| 85 | allocation-intensive (O(n) worst case) but gives reasonable |
|---|
| 86 | parallelism. **) |
|---|
| 87 | generate[\R\](r: Reduction[\R\], body: (K,V)->R): R = do |
|---|
| 88 | go(n:ZZ32, h: Heap[\K,V\]): R = |
|---|
| 89 | if h.isEmpty then |
|---|
| 90 | r.empty |
|---|
| 91 | else |
|---|
| 92 | kvs = array[\(K,V)\](n) |
|---|
| 93 | hh : Heap[\K,V\] := h |
|---|
| 94 | i : ZZ32 := 0 |
|---|
| 95 | while NOT hh.isEmpty AND i < n do |
|---|
| 96 | (k,v,hhh) = hh.extractMinimum().get |
|---|
| 97 | kvs.init(i,(k,v)) |
|---|
| 98 | i += 1 |
|---|
| 99 | hh := hhh |
|---|
| 100 | end |
|---|
| 101 | r.join(kvs[0#i].generate[\R\](r,body),go(n+n, hh)) |
|---|
| 102 | end |
|---|
| 103 | go(8,self) |
|---|
| 104 | end |
|---|
| 105 | end |
|---|
| 106 | |
|---|
| 107 | object HeapMerge[\K,V\](boiler: Heap[\K,V\]) |
|---|
| 108 | extends CommutativeMonoidReduction[\Heap[\K,V\]\] |
|---|
| 109 | getter asString():String = "Heap merge reduction" |
|---|
| 110 | getter empty(): Heap[\K,V\] = boiler.empty |
|---|
| 111 | join(a:Heap[\K,V\], b:Heap[\K,V\]): Heap[\K,V\] = a.merge(b) |
|---|
| 112 | end |
|---|
| 113 | |
|---|
| 114 | hm[\K,V\](boiler: Heap[\K,V\]):HeapMerge[\K,V\] = HeapMerge[\K,V\](boiler) |
|---|
| 115 | |
|---|
| 116 | trait Pairing[\K,V\] extends Heap[\K,V\] |
|---|
| 117 | comprises { EmptyP[\K,V\], NodeP[\K,V\] } |
|---|
| 118 | getter empty(): Pairing[\K,V\] = EmptyP[\K,V\] |
|---|
| 119 | getter asDebugString(): String |
|---|
| 120 | singleton(k:K, v:V): Pairing[\K,V\] = do |
|---|
| 121 | e = self.empty |
|---|
| 122 | NodeP[\K,V\](k,v,e,e) |
|---|
| 123 | end |
|---|
| 124 | (* emk merges a node and all its siblings. *) |
|---|
| 125 | emk(e: EmptyP[\K,V\]): Pairing[\K,V\] |
|---|
| 126 | (* ems merges a node with its left sibling, then merges that with |
|---|
| 127 | its remaining siblings. *) |
|---|
| 128 | ems(e: EmptyP[\K,V\], leftSib: NodeP[\K,V\]): NodeP[\K,V\] |
|---|
| 129 | end |
|---|
| 130 | |
|---|
| 131 | object EmptyP[\K,V\] extends Pairing[\K,V\] |
|---|
| 132 | getter isEmpty(): Boolean = true |
|---|
| 133 | getter minimum(): Nothing[\(K,V)\] = Nothing[\(K,V)\] |
|---|
| 134 | getter asDebugString(): String = "E" |
|---|
| 135 | check(): EmptyP[\K,V\] = self |
|---|
| 136 | check(pk:K):Boolean = true |
|---|
| 137 | merge(h:Heap[\K,V\]): Heap[\K,V\] = h |
|---|
| 138 | merge(h:Pairing[\K,V\]): Pairing[\K,V\] = h |
|---|
| 139 | insert(k:K, v:V): Pairing[\K,V\] = NodeP[\K,V\](k,v,self,self) |
|---|
| 140 | extractMinimum(): Nothing[\(K,V,Pairing[\K,V\])\] = Nothing[\(K,V,Pairing[\K,V\])\] |
|---|
| 141 | emk(e: EmptyP[\K,V\]): Pairing[\K,V\] = self |
|---|
| 142 | ems(_: EmptyP[\K,V\], leftSib: NodeP[\K,V\]): NodeP[\K,V\] = leftSib |
|---|
| 143 | generate[\R\](r: Reduction[\R\], body: (K,V)->R): R = r.empty |
|---|
| 144 | end |
|---|
| 145 | |
|---|
| 146 | object NodeP[\K,V\](k:K, v:V, sibs: Pairing[\K,V\], kids: Pairing[\K,V\]) |
|---|
| 147 | extends Pairing[\K,V\] |
|---|
| 148 | getter isEmpty(): Boolean = false |
|---|
| 149 | getter minimum(): Just[\(K,V)\] = Just[\(K,V)\](k,v) |
|---|
| 150 | getter asDebugString():String = "N(" k "," v "," sibs.asDebugString "," kids.asDebugString ")" |
|---|
| 151 | check():Heap[\K,V\] = do |
|---|
| 152 | if NOT sibs.isEmpty then |
|---|
| 153 | println( //"FAIL: Non-empty sibs in:" // self.asDebugString// ) |
|---|
| 154 | fail("dying") |
|---|
| 155 | end |
|---|
| 156 | if NOT kids.check(k) then |
|---|
| 157 | println( //"FAIL: heap structure violation in:" // self.asDebugString// ) |
|---|
| 158 | end |
|---|
| 159 | self |
|---|
| 160 | end |
|---|
| 161 | check(pk:K):Boolean = pk <= k AND sibs.check(pk) AND kids.check(k) |
|---|
| 162 | merge(other:Heap[\K,V\]): Heap[\K,V\] = merge(pairing[\K,V\](other)) |
|---|
| 163 | merge(_:Pairing[\K,V\]): Pairing[\K,V\] = |
|---|
| 164 | fail("Pairing but not NodeP/EmptyP") |
|---|
| 165 | merge(_:EmptyP[\K,V\]): Pairing[\K,V\] = self |
|---|
| 166 | merge(h:NodeP[\K,V\]): Pairing[\K,V\] = merge(self.empty,h) |
|---|
| 167 | merge(e:EmptyP[\K,V\], _:EmptyP[\K,V\]): Pairing[\K,V\] = self |
|---|
| 168 | merge(e:EmptyP[\K,V\], h:NodeP[\K,V\]): Pairing[\K,V\] = |
|---|
| 169 | if h.k <= k then |
|---|
| 170 | NodeP[\K,V\](h.k, h.v, e, NodeP[\K,V\]( k, v, h.kids, kids)) |
|---|
| 171 | else |
|---|
| 172 | NodeP[\K,V\]( k, v, e, NodeP[\K,V\](h.k, h.v, kids, h.kids)) |
|---|
| 173 | end |
|---|
| 174 | insert(k':K, v':V): Pairing[\K,V\] = |
|---|
| 175 | if k' <= k then (* ' *) |
|---|
| 176 | NodeP[\K,V\](k',v',self.empty,self) |
|---|
| 177 | else |
|---|
| 178 | e = self.empty |
|---|
| 179 | NodeP[\K,V\](k,v,e,NodeP[\K,V\](k',v',kids,e)) |
|---|
| 180 | end |
|---|
| 181 | extractMinimum(): Just[\(K,V,Pairing[\K,V\])\] = |
|---|
| 182 | Just[\(K,V,Pairing[\K,V\])\](k,v,kids.emk(self.empty)) |
|---|
| 183 | (* |
|---|
| 184 | emk(e: EmptyP[\K,V\]): Pairing[\K,V\] = do |
|---|
| 185 | res : Pairing[\K,V\] = e |
|---|
| 186 | todo : Pairing[\K,V\] := self |
|---|
| 187 | while NOT todo.isEmpty do |
|---|
| 188 | (m,td) = if todo.sibs.isEmpty then |
|---|
| 189 | (todo,e) |
|---|
| 190 | else |
|---|
| 191 | (todo.merge(e,todo.sibs),todo.sibs.sibs) |
|---|
| 192 | end |
|---|
| 193 | res := m.merge(e,res) |
|---|
| 194 | todo := td |
|---|
| 195 | end |
|---|
| 196 | res |
|---|
| 197 | end |
|---|
| 198 | *) |
|---|
| 199 | emk(e: EmptyP[\K,V\]): Pairing[\K,V\] = sibs.ems(e,self) |
|---|
| 200 | ems(e: EmptyP[\K,V\], leftSib: NodeP[\K,V\]): NodeP[\K,V\] = |
|---|
| 201 | merge(e,leftSib).merge(e,sibs.emk(e)) |
|---|
| 202 | end |
|---|
| 203 | |
|---|
| 204 | emptyPairing[\K,V\](): Pairing[\K,V\] = EmptyP[\K,V\] |
|---|
| 205 | singletonPairing[\K,V\](k:K, v:V): Pairing[\K,V\] = |
|---|
| 206 | emptyPairing[\K,V\]().singleton(k,v) |
|---|
| 207 | |
|---|
| 208 | pairing[\K,V\](g:Generator[\(K,V)\]): Pairing[\K,V\] = do |
|---|
| 209 | e = emptyPairing[\K,V\]() |
|---|
| 210 | g.generate[\Heap[\K,V\]\]( |
|---|
| 211 | hm[\K,V\](e), |
|---|
| 212 | fn (k:K, v:V): Pairing[\K,V\] => e.singleton(k,v)) |
|---|
| 213 | end |
|---|
| 214 | |
|---|
| 215 | (************************************************************ |
|---|
| 216 | * Not actually lazy pairing heaps; these are actuallly more |
|---|
| 217 | * eager in that they merge siblings incrementally on insertion. |
|---|
| 218 | *) |
|---|
| 219 | |
|---|
| 220 | trait LazyPairing[\K,V\] extends Heap[\K,V\] |
|---|
| 221 | comprises { EmptyLP[\K,V\], NodeLP[\K,V\] } |
|---|
| 222 | getter empty(): LazyPairing[\K,V\] = EmptyLP[\K,V\] |
|---|
| 223 | getter asDebugString(): String |
|---|
| 224 | singleton(k:K, v:V): LazyPairing[\K,V\] = do |
|---|
| 225 | e = self.empty |
|---|
| 226 | NodeLP[\K,V\](k,v,e,e) |
|---|
| 227 | end |
|---|
| 228 | (** link the min over the max, with the current node pending. **) |
|---|
| 229 | plink(e:EmptyLP[\K,V\],mn:NodeLP[\K,V\],mx:NodeLP[\K,V\]):NodeLP[\K,V\] |
|---|
| 230 | end |
|---|
| 231 | |
|---|
| 232 | object EmptyLP[\K,V\] extends LazyPairing[\K,V\] |
|---|
| 233 | getter isEmpty(): Boolean = true |
|---|
| 234 | getter minimum(): Nothing[\(K,V)\] = Nothing[\(K,V)\] |
|---|
| 235 | getter asDebugString(): String = "EL" |
|---|
| 236 | check():Heap[\K,V\] = self |
|---|
| 237 | check(pk:K):Boolean = true |
|---|
| 238 | merge(h:Heap[\K,V\]): Heap[\K,V\] = h |
|---|
| 239 | merge(h:LazyPairing[\K,V\]): LazyPairing[\K,V\] = h |
|---|
| 240 | insert(k:K, v:V): LazyPairing[\K,V\] = NodeLP[\K,V\](k,v,self,self) |
|---|
| 241 | extractMinimum(): Nothing[\(K,V,LazyPairing[\K,V\])\] = Nothing[\(K,V,LazyPairing[\K,V\])\] |
|---|
| 242 | plink(e:EmptyLP[\K,V\],mn:NodeLP[\K,V\],mx:NodeLP[\K,V\]):NodeLP[\K,V\] = |
|---|
| 243 | NodeLP[\K,V\](mn.k,mn.v,mx,mn.kids) |
|---|
| 244 | generate[\R\](r: Reduction[\R\], body: (K,V)->R): R = r.empty |
|---|
| 245 | end |
|---|
| 246 | |
|---|
| 247 | object NodeLP[\K,V\](k:K, v:V, pending: LazyPairing[\K,V\], kids: LazyPairing[\K,V\]) |
|---|
| 248 | extends LazyPairing[\K,V\] |
|---|
| 249 | getter isEmpty(): Boolean = false |
|---|
| 250 | getter minimum(): Just[\(K,V)\] = Just[\(K,V)\](k,v) |
|---|
| 251 | getter asDebugString():String = "NL(" k "," v "," pending.asDebugString "," kids.asDebugString ")" |
|---|
| 252 | check():Heap[\K,V\] = do |
|---|
| 253 | if NOT kids.check(k) then |
|---|
| 254 | println( //"FAIL: heap structure violation in:" // self.asDebugString// ) |
|---|
| 255 | end |
|---|
| 256 | self |
|---|
| 257 | end |
|---|
| 258 | check(pk:K):Boolean = pk <= k AND pending.check(k) AND kids.check(k) |
|---|
| 259 | merge(other:Heap[\K,V\]): Heap[\K,V\] = merge(lazy[\K,V\](other)) |
|---|
| 260 | merge(_:LazyPairing[\K,V\]): LazyPairing[\K,V\] = |
|---|
| 261 | fail("LazyPairing but not NodeLP/EmptyLP") |
|---|
| 262 | merge(_:EmptyLP[\K,V\]): LazyPairing[\K,V\] = self |
|---|
| 263 | merge(h:NodeLP[\K,V\]): LazyPairing[\K,V\] = merge(self.empty,h) |
|---|
| 264 | merge(e:EmptyLP[\K,V\], _:EmptyLP[\K,V\]): LazyPairing[\K,V\] = self |
|---|
| 265 | merge(e:EmptyLP[\K,V\], h:NodeLP[\K,V\]): LazyPairing[\K,V\] = |
|---|
| 266 | if h.k <= k then |
|---|
| 267 | h.link(e,self) |
|---|
| 268 | else |
|---|
| 269 | self.link(e,h) |
|---|
| 270 | end |
|---|
| 271 | insert(k':K, v':V): LazyPairing[\K,V\] = |
|---|
| 272 | if k' <= k then (* ' *) |
|---|
| 273 | NodeLP[\K,V\](k',v',self,self.empty) |
|---|
| 274 | else |
|---|
| 275 | e = self.empty |
|---|
| 276 | link(e,NodeLP[\K,V\](k',v',e,e)) |
|---|
| 277 | end |
|---|
| 278 | extractMinimum(): Just[\(K,V,LazyPairing[\K,V\])\] = |
|---|
| 279 | Just[\(K,V,LazyPairing[\K,V\])\](k,v,pending.merge(kids)) |
|---|
| 280 | link(e:EmptyLP[\K,V\],n:NodeLP[\K,V\]):NodeLP[\K,V\] = |
|---|
| 281 | pending.plink(e,self,n) |
|---|
| 282 | plink(e:EmptyLP[\K,V\],mn:NodeLP[\K,V\],mx:NodeLP[\K,V\]):NodeLP[\K,V\] = |
|---|
| 283 | NodeLP[\K,V\](mn.k,mn.v,e,self.merge(mx).merge(mn.kids)) |
|---|
| 284 | end |
|---|
| 285 | |
|---|
| 286 | emptyLazy[\K,V\](): LazyPairing[\K,V\] = EmptyLP[\K,V\] |
|---|
| 287 | singletonLazy[\K,V\](k:K, v:V): LazyPairing[\K,V\] = |
|---|
| 288 | emptyLazy[\K,V\]().singleton(k,v) |
|---|
| 289 | |
|---|
| 290 | lazy[\K,V\](g:Generator[\(K,V)\]): Heap[\K,V\] = do |
|---|
| 291 | e : Heap[\K,V\] = emptyLazy[\K,V\]() |
|---|
| 292 | g.generate[\Heap[\K,V\]\]( |
|---|
| 293 | hm[\K,V\](e), |
|---|
| 294 | fn (k:K, v:V): LazyPairing[\K,V\] => e.singleton(k,v)) |
|---|
| 295 | end |
|---|
| 296 | |
|---|
| 297 | (************************************************************ |
|---|
| 298 | * And the winner is... |
|---|
| 299 | * Non-lazy pairing heaps! |
|---|
| 300 | ************************************************************) |
|---|
| 301 | |
|---|
| 302 | emptyHeap[\K,V\](): Pairing[\K,V\] = emptyPairing[\K,V\]() |
|---|
| 303 | singletonHeap[\K,V\](k:K, v:V): Pairing[\K,V\] = singletonPairing[\K,V\](k,v) |
|---|
| 304 | heap[\K,V\](g:Generator[\(K,V)\]): Pairing[\K,V\] = pairing[\K,V\](g) |
|---|
| 305 | |
|---|
| 306 | end |
|---|