From 7c856d35a6caee0461c87d892963779c93060163 Mon Sep 17 00:00:00 2001 From: Jono Spiro Date: Sun, 8 Aug 2004 00:04:09 +0000 Subject: [PATCH] Dijkstra documented. .PLT modified. svn: r159 --- .../mztake/demos/dijkstra/dijkstra-test.ss | 57 +++++++++++++++++-- collects/mztake/demos/dijkstra/dijkstra.ss | 12 ++-- collects/mztake/doc.txt | 7 +++ collects/mztake/make-plt.ss | 18 ++++-- collects/mztake/mztake.ss | 7 ++- 5 files changed, 82 insertions(+), 19 deletions(-) diff --git a/collects/mztake/demos/dijkstra/dijkstra-test.ss b/collects/mztake/demos/dijkstra/dijkstra-test.ss index 87ab190838..3d72f77241 100644 --- a/collects/mztake/demos/dijkstra/dijkstra-test.ss +++ b/collects/mztake/demos/dijkstra/dijkstra-test.ss @@ -1,3 +1,37 @@ +#| This script tests a priority queue (heap) that is correctly implemented, but incorrectly used. + It is not commented because it uses a some advanced FrTime concepts that can easily be looked + up in the help desk, and both the description and motivation of the example can be found in + "A Dataflow Language for Scriptable Debugging" (Marceau, Cooper, Krishnamurthi, Reiss), + available at: + + http://www.cs.brown.edu/~sk/Publications/Papers/Published/mckr-dataflow-lang-script-debug/ + + This script uses the concept of maintaining a local model of the heap being debugged, as a simple, + and very slow, list. The difference is that a fancy heap used can be naively implemented as a list, + simply removing only the smallest element each time. Models are external to your program, you don't + have to add any test code to your program to use them. By adding and removing the items to our local + "model" (the values come from the heap code we used), we can compare the results and assert whether + it is working correctly or not. Our model shows the values we should be getting from the program, + but clearly are not. + + To provide some context for this demo, and what debugging problem MzTake helps us explore, I offer + the following, out of context, taken directly from the paper: + We find that the queue's elements are not in sorted order while those in the model + are. More revealingly, the queue's elements are not the same as those in the model. + A little further study shows that the bug is in our usage of the priority queue: + we have failed to account for the fact that the assignment to dest.weight + in relax (figure 1) updates the weights of nodes already in the queue. Because + the queue is not sensitive to these updates, what it returns is no longer the + smallest element in the queue. + + On further reading, we trace the error to a subtle detail in the description of + Dijkstra's algorithm in Cormen, et al.'s book [9, page 530]. The book permits + the use of a binary heap (which is how we implemented the priority queue) for + sparse graphs, but subsequently amends the pseudocode to say that the assignment + to dest.weight must explicitly invoke a key-decrement operation. Our error, + therefore, was not in the implementation of the heap, but in using the (faster) + binary heap implementation without satisfying its (stronger) contract. |# + (require "dijkstra-solver.ss" (lib "match.ss")) @@ -6,6 +40,12 @@ ("heap.ss" [inserts 49 6 bind 'item] [removes 67 10 bind 'result])) +#| The following code merely observes the insertions and removals + from the heap. We notice whether any of the removals are out + of order based on the last item removed, as long as there are + no insertions between the two events. We can keep track of the + last 2 using history-e. |# + (define (not-in-order e) (filter-e (match-lambda @@ -24,16 +64,21 @@ (printf-b "all inserts and removes: ~a" (history-b inserts-and-removes-e)) (printf-b "all violations: ~a" (history-b violations)) (printf-b "latest-violation: ~a" (hold violations)) +#| This output indicates that the queue has yielded nodes whose weights are out of order. + This confirms our suspicion that the problem somehow involves the priority queue. |# -(define ((insert-in-model item) model) (cons item model)) -(define ((remove-from-model item) model) (filter (lambda (i) (eq? i item)) model)) -(define inserters (accum-e (inserts . ==> . insert-in-model) empty)) -(define removers (accum-e (removes . ==> . remove-from-model) empty)) +#| Implementation of the local model follows... |# +(define ((insert-in-model item) model) + (printf "~nInserting ~a into model containing:~n~a~n" item (value-now model)) + (cons item model)) -(define model (merge-e inserters removers)) +(define ((remove-from-model item) model) + (printf "~nRemoving ~a from model containing:~n~a~n" item (value-now model)) + (filter (lambda (i) (not (equal? i item))) model)) -(printf-b "model: ~a" model) +(define inserters (accum-b (inserts . ==> . insert-in-model) empty)) +(define removers (accum-b (removes . ==> . remove-from-model) inserters)) (start/resume p) diff --git a/collects/mztake/demos/dijkstra/dijkstra.ss b/collects/mztake/demos/dijkstra/dijkstra.ss index 7b69484f3a..32fd8fe695 100644 --- a/collects/mztake/demos/dijkstra/dijkstra.ss +++ b/collects/mztake/demos/dijkstra/dijkstra.ss @@ -17,7 +17,7 @@ (for-each (lambda (n) (graph-node-add! g n)) nodes) (define (n-ref label) (first (filter (lambda (n) (eq? label (node-label n))) nodes))) - + (define edges (list (list (n-ref 's) (n-ref '1)) (list (n-ref 's) (n-ref '2)) @@ -27,10 +27,6 @@ (list (n-ref 'J) (n-ref '6)))) (for-each (lambda (e) (graph-edge-add! g (first e) (second e))) edges) - - (require (lib "pretty.ss")) - ;(printf "input:~n") - ;(pretty-print (graph-to-list g)) - (printf "output:~n") - (print-struct #t) - (pretty-print (solve g (reverse nodes) (n-ref 's)))) \ No newline at end of file + + (printf "~n~n---output from dijkstra.ss:~n~a~n---~n" + (solve g (reverse nodes) (n-ref 's)))) \ No newline at end of file diff --git a/collects/mztake/doc.txt b/collects/mztake/doc.txt index e6d1dac8ac..808e3de467 100644 --- a/collects/mztake/doc.txt +++ b/collects/mztake/doc.txt @@ -588,6 +588,13 @@ Known Problems Tips and Tricks +* If output seems difficult to read in the script, e.g. you ever + see "struct:signal" and a lot of garbage, try (print-struct #f) + before you do any printing, or use (value-now behavior-name) to + get a more usable/printable version of a FrTime behavior (the + caveat is that it is no longer 'reactive' and it may be out of + date after the moment it is processed). + * You may want to bind more than one variable at a certain point so that you only get one change event -- otherwise, you will get multiple change events even if at the same trace point diff --git a/collects/mztake/make-plt.ss b/collects/mztake/make-plt.ss index 8f1c9f31a6..6ee06be828 100644 --- a/collects/mztake/make-plt.ss +++ b/collects/mztake/make-plt.ss @@ -10,8 +10,18 @@ (regexp-match #rx".1$" path) (regexp-match #rx"make" path))))) + ;For use with PLaneT + (parameterize ((current-directory ".")) + (pack "mztake-planet.plt" + "MzTake Debugger" + '(".") + '() + my-filter + #t + 'file + #f + #f + '(("frtime") ("stepper")))) - (pack-collections "mztake.plt" "MzTake Debugger" '(("mztake")) #t '(("frtime") ("stepper")) my-filter #t)) - -; Now, check-out -;(make-planet-archive "mztake.plt")) \ No newline at end of file + ; for use not on PLaneT + (pack-collections "mztake-distro.plt" "MzTake Debugger" '(("mztake")) #t '(("frtime") ("stepper")) my-filter)) \ No newline at end of file diff --git a/collects/mztake/mztake.ss b/collects/mztake/mztake.ss index f120a73ef6..39f3dcc1b3 100644 --- a/collects/mztake/mztake.ss +++ b/collects/mztake/mztake.ss @@ -1,6 +1,6 @@ (module mztake mzscheme - (define mztake-version "(rev. 8/6/2004)") + (define mztake-version "rev. 8/6/2004") #|:::::::::LOAD/ANNOTATOR BUGS::::::::::: * catch oops exception @@ -13,6 +13,11 @@ :::::::::::::::::::::::::::::::::::::::::: +Re-direct, or at least prefix, program output from the client so that it can be distinguished from the script + +Paramterize print-struct to #f for printing in the script + + DEMOS--------------------------------------------------------------------------------------- * Data structure examples Binary search over a tree, show which node is being examined, or the most commonly taken path