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
-~----------~----~----~----~------~----~------~--~---

Reply via email to