From cosmin1611 at gmail.com Tue Dec 18 15:54:37 2012 From: cosmin1611 at gmail.com (Cosmin Marian) Date: Tue, 18 Dec 2012 17:54:37 +0200 Subject: [cl-containers-devel] Two bugs in heaps.lisp Message-ID: <50D091BD.9080007@gmail.com> Hello, Playing with the cl-containers and the heap implementation I come across what looks like two bugs in heaps.lisp: 1/ delete-item/sift does not use the key of the elements stored in the heap in order to compare them. This is easy to see in the source code. 2/ it looks like node-parent-index is incorrect as you use 0 based indexes: It says: (defmethod node-parent-index ((node heap-node)) (ash (index node) -1)) But it should be (defmethod node-parent-index ((node heap-node)) (ash (1- (index node)) -1)) This is easy to test if you look at the result of (node-parent-index (r-child-index 0)) It should be 0 but returns 1. The formula for parent node index using 0 based indexes is documented in wikipedia: http://en.wikipedia.org/wiki/Binary_heap#Heap_implementation. It is parent/= a/[floor((/i/-1)/2)] This causes some subtle bugs, harder to catch. I attach two tests in a file. Regards, Cosmin -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- (in-package cl-containers) (defun test-parent () (let ((heap (make-container 'heap-container))) (insert-item heap (make-node-for-container heap 0)) (insert-item heap (make-node-for-container heap 3)) (insert-item heap (make-node-for-container heap 7)) (let* ((nodes (contents heap)) (l-child-index 1) (r-child-index 2) (p-index 0)) (and (eq p-index (cl-containers::node-parent-index (aref nodes l-child-index))) (eq p-index (cl-containers::node-parent-index (aref nodes r-child-index))))))) (defun test-sift () (let ((heap (make-container 'heap-container :sorter #'< :key #'car))) (insert-item heap (make-node-for-container heap '(0 20))) (insert-item heap (make-node-for-container heap '(3 20))) (insert-item heap (make-node-for-container heap '(7 20))) (insert-item heap (make-node-for-container heap '(4 20))) (insert-item heap (make-node-for-container heap '(5 20))) (insert-item heap (make-node-for-container heap '(8 20))) (insert-item heap (make-node-for-container heap '(9 20))) (insert-item heap (make-node-for-container heap '(6 20))) ;; we just get the a node from the contents array ;; this will cause a sift and expose the bug ;; the test data works only after fixing the parent bug ;; but it is easy to come up with test data even if not fixing the bug (print (contents heap)) (delete-item heap (aref (contents heap) 5)))) From gwking at metabang.com Thu Dec 20 18:23:44 2012 From: gwking at metabang.com (Gary King) Date: Thu, 20 Dec 2012 13:23:44 -0500 Subject: [cl-containers-devel] Two bugs in heaps.lisp In-Reply-To: <50D091BD.9080007@gmail.com> References: <50D091BD.9080007@gmail.com> Message-ID: <5659C7F5-8194-4F3F-9B58-BD47037F7769@metabang.com> Thanks Cosmin, Would you be able to submit a patch via github? > Playing with the cl-containers and the heap implementation I come across what looks like two bugs in heaps.lisp: > > 1/ delete-item/sift does not use the key of the elements stored in the heap in order to compare them. This is easy to see in the source code. > > 2/ it looks like node-parent-index is incorrect as you use 0 based indexes: > Yes. I noticed that at one point but didn't get the fix pushed back into cl-containers. :-( -- Gary Warren King, metabang.com Cell: (413) 559 8738 Fax: (206) 338-4052 gwkkwg on Skype * garethsan on AIM * gwking on twitter -------------- next part -------------- An HTML attachment was scrubbed... URL: From cosmin1611 at gmail.com Fri Dec 21 11:13:41 2012 From: cosmin1611 at gmail.com (Cosmin Marian) Date: Fri, 21 Dec 2012 13:13:41 +0200 Subject: [cl-containers-devel] Two bugs in heaps.lisp In-Reply-To: <5659C7F5-8194-4F3F-9B58-BD47037F7769@metabang.com> References: <50D091BD.9080007@gmail.com> <5659C7F5-8194-4F3F-9B58-BD47037F7769@metabang.com> Message-ID: <50D44465.2070104@gmail.com> Hello, I don't really work with git so I don't know how to submit a patch via github. But attached is the result of "git diff" command. Hope it helps. If not, let me know, I will try to look into github. Kind regards, Cosmin On 20/12/2012 20:23, Gary King wrote: > Would you be able to submit a patch via github? > >> Playing with the cl-containers and the heap implementation I come >> across what looks like two bugs in heaps.lisp: >> >> 1/ delete-item/sift does not use the key of the elements stored in >> the heap in order to compare them. This is easy to see in the source >> code. >> >> 2/ it looks like node-parent-index is incorrect as you use 0 based >> indexes: > [...] -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- diff --git a/dev/heaps.lisp b/dev/heaps.lisp index 30fa301..c62e234 100644 --- a/dev/heaps.lisp +++ b/dev/heaps.lisp @@ -41,7 +41,7 @@ (defmethod node-parent-index ((node heap-node)) - (ash (index node) -1)) + (ash (1- (index node)) -1)) (defmethod exchange-heap-nodes ((n1 heap-node) (n2 heap-node) (heap heap-container)) @@ -103,9 +103,10 @@ (defmethod delete-item ((heap heap-container) (node heap-node)) (labels ((sift (node) (when (and (/= 0 (index node)) - (funcall (sorter heap) - (element node) (element (heap-node-parent node heap)))) - (exchange-heap-nodes node (heap-node-parent node heap) heap) + (funcall (sorter heap) + (funcall (key heap) (element node)) + (funcall (key heap) (element (heap-node-parent node heap))))) + (exchange-heap-nodes node (heap-node-parent node heap) heap) (sift node)))) (let ((last (last-item heap)) (key (key heap)))