Dijkstra documented.
.PLT modified. svn: r159
This commit is contained in:
parent
cb87da8e26
commit
7c856d35a6
|
@ -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)
|
||||
|
|
|
@ -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))))
|
||||
|
||||
(printf "~n~n---output from dijkstra.ss:~n~a~n---~n"
|
||||
(solve g (reverse nodes) (n-ref 's))))
|
|
@ -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
|
||||
|
|
|
@ -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"))
|
||||
; for use not on PLaneT
|
||||
(pack-collections "mztake-distro.plt" "MzTake Debugger" '(("mztake")) #t '(("frtime") ("stepper")) my-filter))
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue
Block a user