On Aug 4, 11:08 am, Jonas <jonas.enl...@gmail.com> wrote: > Hi > > I'm playing with the new transient/persistent! features in Clojure. I > have implemented quicksort as described on wikipedia (http:// > en.wikipedia.org/wiki/Quicksort#Algorithm). Here is the code: > > (defn swap-index! [v i j] > (let [tmp (v i)] > (assoc! v i (v j)) > (assoc! v j tmp)))
I think Rich mentioned on IRC that you should not reuse the transient vector binding after an operation; that it works is merely an implementation detail. The transient documentation page also says tells to "capture return value, use for next call". So: (defn swap-index! [tv i j] (let [tmp (tv i)] (-> tv (assoc! i (v j)) (assoc! j tmp)))) And similar modifications for the quicksort below. > > (defn partition! [v left-index right-index pivot-index] > (let [pivot-value (v pivot-index)] > (swap-index! v pivot-index right-index) > (loop [i left-index store-index left-index] > (if (< i right-index) > (if (<= (v i) pivot-value) > (do (swap-index! v i store-index) > (recur (inc i) (inc store-index))) > (recur (inc i) store-index)) > (do (swap-index! v store-index right-index) > store-index))))) > > (defn qsort! [v left right] > (when (> right left) > (let [pivot-index left > pivot-new-index (partition! v left right pivot-index)] > (qsort! v left (dec pivot-new-index)) > (qsort! v (inc pivot-new-index) right)))) > > (defn qsort [v] > (let [tv (transient v)] > (qsort! tv 0 (dec (count v))) > (persistent! tv))) > > This sorts a vector of doubles in about 6000-7000 msec on my machine: > > user=> (def s (time (qsort (rvector 1000000)))) > "Elapsed time: 6681.35889 msecs" > > This is much faster than the classical functional programming > "quicksort": > > ; Fromhttp://rosettacode.org/wiki/Quicksort#Clojure > (defn qsort-rs [[pivot & xs]] > (when pivot > (let [smaller #(< % pivot)] > (lazy-cat (qsort (filter smaller xs)) > [pivot] > (qsort (remove smaller xs)))))) > > user=> (def s (time (doall (qsort-rs (rvector 1000000))))) > "Elapsed time: 32565.537389 msecs" > > The Java sort however is about 5 times faster then the transient > version: > > user=> (def s (time (sort (rvector 1000000)))) > "Elapsed time: 1354.427239 msecs" > > Can you give any hints on how I can make the transient sort faster? I > would like to get as close as possible to the native Java speed. This is partially comparing apples to oranges though: sort returns a lazy seq, while the quicksort algorithm produces a proper vector. Anyway, (nth v i) might be somewhat faster than (v i) because it gets inlined. I did not try, though. Below is code that avoids reusing the reference to v: (defn swap-index! [v i j] (let [tmp (nth v i)] (-> v (assoc! i (nth v j)) (assoc! j tmp)))) (defn partition! [v left-index right-index pivot-index] (let [pivot-value (nth v pivot-index) new-v (swap-index! v pivot-index right-index)] (loop [v new-v, i left-index, store-index left-index] (if (< i right-index) (if (<= (nth v i) pivot-value) (recur (swap-index! v i store-index) (inc i) (inc store- index)) (recur v (inc i) store-index)) [(swap-index! v store-index right-index) store-index])))) (defn qsort! [v left right] (if (> right left) (let [pivot-index left [new-v pivot-new-index] (partition! v left right pivot- index)] (-> new-v (qsort! left (dec pivot-new-index)) (qsort! (inc pivot-new-index) right)))) v) (defn qsort [v] (let [tv (transient v)] (qsort! tv 0 (dec (count v))) (persistent! tv))) -- Jarkko --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---