Closed jszakmeister closed 10 years ago
So I tracked this down further. The call to remove
in scc
seems to be the culprit. It keeps building lazy sequence on top of lazy sequence to filter out the nodes, and eventually reaches a point that overflows the stack. Perhaps using an ordered set would be better here?
Could you please share the graph you're trying this on? Alternatively, could you try to see if the following fixes your problem:
(recur (doall (remove seen stack))
seen
(conj cc c))
on the following lines https://github.com/aysylu/loom/blob/master/src/loom/alg.clj#L312...L314?
Note the invocation of doall on the remove function.
I did try that after reporting the issue, but it turned out to be only part of the problem (sorry for not coming back and reporting that!).
I needed to make the change you recommended, and also change a line in traverse-all
:
[(into seen ctrav) (doall (concat trav ctrav))])))
(notice the doall
around the concat
).
Between the two changes, it ran to completion but extremely slow. It took 4 hrs and 45 minutes to complete, while the same algorithm with a rudimentary implementation in Python ran in 1 minute and 20 seconds on the graph of 200,000 vertices and 200,000 edges.
I put the edge list for the graph here: https://gist.github.com/jszakmeister/7068034
It shouldn't be hard to read it in and build the digraph from it.
Thanks for the follow-up and the test graph! It sounds like it's time for refactoring the algorithm for more optimized data structures. If you end up optimizing the function, your pull request will be very welcome.
Thanks @aysylu. I hope to get some time to spend looking at this in the next couple of weeks. If I figure something out, I'll be sure to send you a pull request.
BTW, how do you feel about introducing another dependency? I'm looking at possibly using https://github.com/flatland/ordered, which has an implementation of ordered sets. I think that'll be useful for solving the stack overflow issue in a more performant manner, but I want to make sure you're okay with that first.
Thanks!
Given the choice of having no other dependencies but Clojure and slow implementation of SCC or reasonably fast implementation of SCC and an extra dependency, I think it's fine to introduce another dependency. With the eventual goal of Loom becoming a Clojure contrib library, this will affect what we can include in the contrib version, but we can figure it out later.
Thank you, @jszakmeister!
@aysylu @jszakmeister I tried to reproduce this error. I see that the computation never completes for post-traverse and pre-traverse as well. I hope to work on this issue this week, if all goes well.
I haven't tracked down exactly where the issue is yet. It appears there is a recursive call somewhere that is not in a tail recursive form. This was the backtrace (with Clojure 1.5.1 and Loom 0.3.1), but it's not very helpful: