Paste number 51404: fuck me

Paste number 51404: fuck me
Pasted by: bsmntbombdood
9 months, 1 day ago
#lispcafe | Context in IRC logs
Paste contents:
Raw Source | XML | Display As
;;;;
;;;; Purely functional, mergeable priority queues.
;;;;
;;;; A priority queue is a bag of ordered elements, with addition of
;;;; elements, removal of the minimum element, and merging of two
;;;; queues into one.  The order of elements is given by a predicate
;;;; that's a curried argument to each operation; using different
;;;; predicates on the same queue will produce unpredictable results.
;;;;
;;;; PQ-MIN, PQ-INSERT, and PQ-MERGE are constant-time, while
;;;; PQ-REMOVE-MIN is conjectured to take logarithmic amortized time,
;;;; assuming a single thread of use; see Chris Okasaki's paper
;;;; ``Functional Data Structures'' for a way to handle general access
;;;; patterns efficiently.  This code is adapted from that paper.
;;;;
;;;; We represent a queue by a pairing heap: either the empty heap, or
;;;; a pair of the minimum element and a list of sub-heaps that merge
;;;; to form the overall heap.  The sub-heaps must not be empty.
;;;;
;;;; This code is in the public domain.
;;;;
;;;; Darius Bacon <darius@accesscom.com>
;;;; http://www.accesscom.com/~darius
;;;;


;; This is the only non-R4RS procedure used:
;(define error
;  (lambda (complaint object) ...))


;; For a significant speedup, get your compiler to inline these:
(define make-pq cons)
(define pq/elem car)
(define pq/rest cdr)


;; The priority queue with no elements.
(define empty-pq '())

;; True iff PQ is empty.
(define pq-empty? null?)

;; Return the minimum element of PQ.
;; Signals an error if PQ is empty.
(define pq-min
  (lambda (<=?)
    (lambda (pq)
      (if (pq-empty? pq)
          (error "PQ-MIN of an empty pq" '())
          (pq/elem pq)
)
)
)
)


;; Return a priority queue with a single element, ELEM.
(define unit-pq
  (lambda (<=?)
    (lambda (elem)
      (make-pq elem '())
)
)
)


;; Return a priority queue combining the elements of PQ1 and PQ2.
(define pq-merge
  (lambda (<=?)
    (lambda (pq1 pq2)
      (cond ((pq-empty? pq1) pq2)
            ((pq-empty? pq2) pq1)
            (else (let ((min1 (pq/elem pq1))
                        (min2 (pq/elem pq2))
)

                    (if (<=? min1 min2)
                        (make-pq min1 (cons pq2 (pq/rest pq1)))
                        (make-pq min2 (cons pq1 (pq/rest pq2)))
)
)
)
)
)
)
)


;; Return PQ with ELEM inserted.
(define pq-insert
  (lambda (<=?)
    (lambda (pq elem)
;     ((pq-merge <=?) (unit-pq elem) pq)))
      (cond ((pq-empty? pq) (make-pq elem '()))
            (else (let ((min1 (pq/elem pq))
                        (min2 elem)
)

                    (if (<=? min1 min2)
                        (make-pq min1 (cons (make-pq elem '()) (pq/rest pq)))
                        (make-pq min2 (cons pq '()))
)
)
)
)
)
)
)


;; Return PQ with its minimum element removed.
;; Signals an error if PQ is empty.
(define pq-remove-min
  (lambda (<=?)
    (let ((merge (pq-merge? <=?)))
      (lambda (pq)
        (if (pq-empty? pq)
            (error "PQ-REMOVE-MIN of empty pq" '())
            (let merging ((pqs (pq/rest pq)))
              (cond ((null? pqs) empty-pq)
                    ((null? (cdr pqs)) (car pqs))
                    (else (merge
                           ;((pq-merge <=?) (car pqs) (cadr pqs))
                           (let* ((pq1 (car pqs))
                                  (pq2 (cadr pqs))
                                  (min1 (pq/elem pq1))
                                  (min2 (pq/elem pq2))
)

                             (if (<=? min1 min2)
                                 (make-pq min1 (cons pq2 (pq/rest pq1)))
                                 (make-pq min2 (cons pq1 (pq/rest pq2)))
)
)

                           (merging (cddr pqs))
)
)
)
)
)
)
)
)
)



;;;
;;; Testing
;;;

(define int-min        (pq-min <=))
(define int-insert     (pq-insert <=))
(define int-remove-min (pq-remove-min <=))

(define grow-and-shrink
  (lambda (numbers empty empty? get-min insert remove-min)

    (let* ((history '())
           (insert (lambda (pq elem)
                     (let ((pq (insert pq elem)))
                       (set! history (cons (get-min pq) history))
                       pq
)
)
)

           (remove-min (lambda (pq)
                         (let ((pq (remove-min pq)))
                           (set! history (cons (if (empty? pq)
                                                   'empty
                                                   (get-min pq)
)

                                               history
)
)

                           pq
)
)
)
)


      (define growing
        (lambda (pq ns)
          (if (null? ns)
              pq
              (let ((pq (insert pq (car ns)))
                    (ns (cdr ns))
)

                (if (null? ns)
                    pq
                    (growing (remove-min (insert pq (car ns)))
                             (cdr ns)
)
)
)
)
)
)

      
      (define shrinking
        (lambda (pq ns)
          (if (empty? pq)
              (reverse history)
              (shrinking (remove-min
                          (remove-min
                           (insert pq (car ns))
)
)

                         (cdr ns)
)
)
)
)


      (shrinking (growing empty-pq numbers) numbers)
)
)
)


(define test-with
  (lambda (numbers)

    (define insert-sorted
      (lambda (ns n)
        (if (or (null? ns) (<= n (car ns)))
            (cons n ns)
            (cons (car ns)
                  (insert-sorted (cdr ns) n)
)
)
)
)


    (let ((history-1
           (grow-and-shrink
            numbers
            empty-pq pq-empty? int-min int-insert int-remove-min
)
)

          (history-2
           (grow-and-shrink numbers
                            '() null? car insert-sorted cdr
)
)
)

      (if (equal? history-1 history-2)
          history-1
          (error "Test failed" (list history-1 history-2))
)
)
)
)


(define test-each-tail
  (lambda (numbers)
    (do ((ns numbers (cdr ns)))
        ((null? ns))
      (test-with ns)
      (test-with (reverse ns))
)
)
)


(define test
  (lambda ()
    (test-each-tail
     '(3 1 4 1 5 9 2 6 5 3 5 8 9 7 9 3 2 3 8 4 6 2 6 4 3 3 8 3 2 7 9
         5 0 2 8 8 4 1 9 7 1 6 9 3 9 9 3 7 5 1 0
         2 7 1 8 2 8 1 8 2 8 4 5 9 0 4 5
)
)

    (test-each-tail '(0 1 2 3 4 5))
    (test-each-tail '(0 0 0 0 0))
)
)

This paste has no annotations.

Colorize as:
Show Line Numbers

Ads absolutely not by Google

Lisppaste pastes can be made by anyone at any time. Imagine a fearsomely comprehensive disclaimer of liability. Now fear, comprehensively.