[pending] fibonacci_heap -- not working

Hi, is there anybody out there using the fibonacci_heap.hpp? I have a working implementation of dijkstra's shortest path algorithm and was trying to use fibonacci_heap from boost/pending to optimize its performance. To me it seems that it is not working properly. A key feature of this structure is that it should be possible to mix 'pop' and 'update' calls -- but, unfortunatly, after the first call to pop I get arbitrary indices from the heap. Some are even popped more than once. I am using the most recent CVS version. Can anyone help me here? Thanks in advance Florian

On Thu, 2007-03-15 at 12:52 +0100, Florian Teichert wrote:
is there anybody out there using the fibonacci_heap.hpp?
Hopefully not :(
This unreviewed code has been languishing in Boost pending for years. I was going to remove it, but hadn't done so yet. I see that Aaron Windsor committed a fix to the RC_1_34_0 branch of CVS a few months ago: are you using that Fibonacci heap? I've just put Aaron's fix into CVS HEAD as well; an update might fix the problem you are seeing. That said, a Fibonacci heap is unlikely to improve the performance of Dijkstra's algorithm very much. It's asymptotically better than the using a binary heap, but the operations themselves are more complicated. More importantly, the operation that the Fibonacci heap is optimized for--update--tends to happen only O(|V|) times in most classes of graphs, so you don't get a win in the average case. We've recently been experimenting with an implementation of a different kind of priority queue for Dijkstra's algorithm, a multi-level bucket data structure that only partially maintains the ordering property. The papers we used as reference are: A. Goldberg. Shortest path algorithms: Engineering aspects. In Proceedings of 12th International Symposium, ISAAC. Springer, 2001. A. Goldberg. A simple shortest path algorithm with linear average time. Technical report, STAR Lab., InterTrust Tech., Inc., 2001. This data structure doesn't apply in all cases... it's limited to traditional applications of Dijkstra's algorithm where one is using < and + to order distances and accumulate distances, respectively, and it's internal bit-twiddling means that it works best on built-in integers and (through an extension) floats. That said, in some of our test data--road maps of the USA, with ~24M vertices and ~58M edges--we were getting results about 7x faster than with the current relaxed heap implementation. Our code isn't quite ready for inclusion in Boost. It needs to work with more than built-in integers (that's all we handle now), needs wider testing, and needs to be automatically enabled when the right combination of parameters are provided to the existing Dijkstra's algorithm. Cheers, Doug

... sure! I inlined some test code for basic operations. Depending on the activated parts (*A* - *D*) I see all sorts of strange behaviour. Sorting could be just wrong, some elements are shown more than once (somewhere within the sequence, or like repeating the largest element in the end, as below). In some cases (I think when updating first or last elements of w) the program hangs. In the beginning I tried to push vertices to the heap when I assign a path cost to them, instead of pushing all vertices (having infinite path cost then anyways) before I start the relaxing stuff -- doing this I saw the same kind of behaviour. The output of the code below executing, e.g. *A* only, results in: showing the *un-sorted* vector 10 9 8 7 6 5 4 3 2 1 smallest element w[9] == 1 call pop changing w[5] == 5 to -1, update Q showing the *sorted* vector -1 2 3 4 2 3 10 10 10 Any help would be appreciated! Thanks in advance Florian // filling a vector w with n descending numbers int N = 10; vector<float> w; for (int t = 0; t < N; ++t) w.push_back(N-t); cout << "showing the *un-sorted* vector" << endl; for (int i = 0; i < N; ++i) cout << w[i] << endl; // declaring the head (taken from an example on the web) typedef indirect_cmp<float*,std::less<float> > ICmp; ICmp cmp(&w[0], std::less<float>()); fibonacci_heap<int, ICmp> Q(N, cmp); // pushing all of w's indices to the Q for (int i = 0; i < N; ++i) Q.push(i); // top/pop smallest element (this is the last one in w) cout << "smallest element w[" << Q.top() << "] == " << w[Q.top()] << endl; cout << "call pop" << endl; Q.pop(); // change some elements in w and update Q // *A* cout << "changing w[5] == " << w[5] << " to -1, update Q" << endl; w[5] = -1.; Q.update(5); // *B* // cout << "changing w[8] == " << w[7] << " to -7, update Q" << endl; // w[7] = -7.; // Q.update(7); // *C* // cout << "changing w[3] == " << w[3] << " to -5, update Q" << endl; // w[3] = -5.; // Q.update(3); // *D* // cout << "changing w[0] == " << w[0] << " to -5, update Q" << endl; // w[0] = -5.; // Q.update(0); // output the rest of w, sorted cout << "showing the *sorted* vector" << endl; while (Q.size() > 0) { cout << w[Q.top()] << endl; Q.pop(); }

On 3/16/07, Florian Teichert <floteich@hrzpub.tu-darmstadt.de> wrote:
<snip code> Hi Florian, Thanks for your test code - it was very helpful in fixing a few more bugs. The fibonacci heap code is based very closely on Knuth's implementation from "The Stanford GraphBase" - but he uses some bit-level tricks, a few of which got lost in the translation. I just committed a fix to HEAD that I hope clears up the remaining bugs. Will you please pull it down and let us know? It would be great to have the fibonacci heap working to compare against mutable_queue and relaxed_heap. Regards, Aaron

Hi Aaron
After doing some tests with the new code you committed I integrated it into my program. As far as I can see it seems to work perfectly well! Having an assessment routine computing dijkstra's shortest path nearly 4000 time on different graphs I get *exactly* the same results I got before with my old implementation -- just faster :) Thank you very much for your fast response this takes me a big step further. Best wishes Florian
participants (3)
-
Aaron Windsor
-
Douglas Gregor
-
Florian Teichert