From 7758070defbf3fb65d1b0993b2217b5a2f8f2624 Mon Sep 17 00:00:00 2001
From: Doug Coleman <doug.coleman@gmail.com>
Date: Wed, 31 Oct 2007 15:47:32 -0500
Subject: [PATCH] Port heaps to the new module system, add min-heap and
 max-heap

---
 extra/heaps/heaps-tests.factor |  32 ++++++++++
 extra/heaps/heaps.factor       | 112 +++++++++++++++++++++++++++++++++
 2 files changed, 144 insertions(+)
 create mode 100644 extra/heaps/heaps-tests.factor
 create mode 100644 extra/heaps/heaps.factor

diff --git a/extra/heaps/heaps-tests.factor b/extra/heaps/heaps-tests.factor
new file mode 100644
index 0000000000..a8087916e7
--- /dev/null
+++ b/extra/heaps/heaps-tests.factor
@@ -0,0 +1,32 @@
+! Copyright 2007 Ryan Murphy
+! See http://factorcode.org/license.txt for BSD license.
+
+USING: kernel math tools.test heaps heaps.private ;
+IN: temporary
+
+[ <min-heap> pop-heap ] unit-test-fails
+[ <max-heap> pop-heap ] unit-test-fails
+
+[ t ] [ <min-heap> heap-empty? ] unit-test
+[ f ] [ <min-heap> 1 over push-heap heap-empty? ] unit-test
+[ t ] [ <max-heap> heap-empty? ] unit-test
+[ f ] [ <max-heap> 1 over push-heap heap-empty? ] unit-test
+
+! Binary Min Heap
+{ 1 2 3 4 5 6 } [ 0 left 0 right 1 left 1 right 2 left 2 right ] unit-test
+{ t } [ 5 3 T{ min-heap } heap-compare ] unit-test
+{ f } [ 5 3 T{ max-heap } heap-compare ] unit-test
+
+[ T{ min-heap T{ heap f V{ -6 -4 2 1 5 3 2 4 3 7 6 8 3 4 4 6 5 5 } } } ]
+[ <min-heap> { 3 5 4 6 7 8 2 4 3 5 6 1 3 2 4 5 -6 -4 } over push-heap* ] unit-test
+
+[ T{ min-heap T{ heap f V{ 5 6 6 7 8 } } } ] [
+    <min-heap> { 3 5 4 6 5 7 6 8 } over push-heap*
+    3 [ dup pop-heap* ] times
+] unit-test
+
+[ 2 ] [ <min-heap> 300 over push-heap 200 over push-heap 400 over push-heap 3 over push-heap 2 over push-heap pop-heap ] unit-test
+
+[ 1 ] [ <min-heap> 300 over push-heap 200 over push-heap 400 over push-heap 3 over push-heap 2 over push-heap 1 over push-heap pop-heap ] unit-test
+
+[ 400 ] [ <max-heap> 300 over push-heap 200 over push-heap 400 over push-heap 3 over push-heap 2 over push-heap 1 over push-heap pop-heap ] unit-test
diff --git a/extra/heaps/heaps.factor b/extra/heaps/heaps.factor
new file mode 100644
index 0000000000..2ff9096483
--- /dev/null
+++ b/extra/heaps/heaps.factor
@@ -0,0 +1,112 @@
+! Copyright (C) 2007 Ryan Murphy, Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel math sequences ;
+IN: heaps
+
+<PRIVATE
+TUPLE: heap data ;
+
+: <heap> ( -- obj )
+    V{ } clone heap construct-boa ;
+PRIVATE>
+
+TUPLE: min-heap ;
+
+: <min-heap> ( -- obj )
+    <heap> min-heap construct-delegate ;
+
+TUPLE: max-heap ;
+
+: <max-heap> ( -- obj )
+    <heap> max-heap construct-delegate ;
+
+<PRIVATE
+: left ( n -- m ) 2 * 1+ ;
+: right ( n -- m ) 2 * 2 + ;
+: up ( n -- m ) 1- 2 /i ;
+: left-value ( n heap -- obj ) >r left r> nth ;
+: right-value ( n heap -- obj ) >r right r> nth ;
+: up-value ( n vec -- obj ) >r up r> nth ;
+: swap-up ( n vec -- ) >r dup up r> exchange ;
+: last-index ( vec -- n ) length 1- ;
+
+GENERIC: heap-compare ( obj1 obj2 heap -- ? )
+
+M: min-heap heap-compare drop <=> 0 > ;
+M: max-heap heap-compare drop <=> 0 < ;
+
+: left-bounds-check? ( m heap -- ? )
+    >r left r> heap-data length >= ;
+
+: right-bounds-check? ( m heap -- ? )
+    >r right r> heap-data length >= ;
+
+: (up-heap) ( vec heap -- )
+    [
+        >r [ last-index ] keep [ up-value ] keep peek r> heap-compare
+    ] 2keep rot [
+        >r dup last-index
+        [ over swap-up ] keep
+        up 1+ head-slice
+        r> (up-heap)
+    ] [
+        2drop
+    ] if ;
+
+: up-heap ( heap -- )
+    [ heap-data ] keep (up-heap) ;
+
+: child ( m heap -- n )
+    2dup right-bounds-check? [
+        drop left
+    ] [
+        dupd
+        [ heap-data left-value ] 2keep
+        [ heap-data right-value ] keep heap-compare [
+            right
+        ] [
+            left
+        ] if
+    ] if ;
+
+: swap-down ( m heap -- )
+    [ child ] 2keep heap-data exchange ;
+
+DEFER: down-heap
+
+: (down-heap) ( m heap -- )
+    2dup [ heap-data nth ] 2keep child pick
+    dupd [ heap-data nth swapd ] keep
+    heap-compare [
+        -rot [ swap-down ] keep down-heap
+    ] [
+        3drop
+    ] if ;
+
+: down-heap ( m heap -- )
+    2dup left-bounds-check? [ 2drop ] [ (down-heap) ] if ;
+
+PRIVATE>
+
+: push-heap ( obj heap -- )
+    tuck heap-data push up-heap ;
+
+: push-heap* ( seq heap -- )
+    swap [ swap push-heap ] curry* each ;
+
+: peek-heap ( heap -- obj )
+    heap-data first ;
+
+: pop-heap* ( heap -- )
+    dup heap-data length 1 > [
+        [ heap-data pop 0 ] keep
+        [ heap-data set-nth ] keep
+        >r 0 r> down-heap
+    ] [
+        heap-data pop*
+    ] if ;
+
+: pop-heap ( heap -- fist ) [ heap-data first ] keep pop-heap* ;
+
+: heap-empty? ( heap -- ? )
+    heap-data empty? ;