Hi,

Thank's for pointing this out for me. I didn't realize how to use
these constructs correctly. Seeing the !-mark i just thought that
assoc! was to be used like set! set-car! set-cdr! in Scheme... my
mistake.

On Tue, Aug 4, 2009 at 8:49 PM, Jarkko Oranen<chous...@gmail.com> wrote:
>
> 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.
Ok, I will try that

>
> 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)))
Nice, thank you!

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