Here are the major points:
The algorithm requires that for about 400,000 points there will be
~8,000,000 iterations. This is a very tight loop. You cannot create anything
in this loop, not even a regular Object, much less a temporary Clojure
vector for doing vector math.

The Java version avoids this problem entirely. It just operates on two
primitive double arrays, one for x values, and one for y values (The Clojure
version could probably in fact be made a bit faster by just supplying two
such primitive global arrays, but I'm tired/bored of optimizing this
further- this would eliminate the overhead of the javax.vecmath.Vector2d
calls).

Having tried to do vector math with Clojure persistent vectors before,
I've realized it's just not designed for that kind of thing (yet).
So I used javax.vecmath.Vector2d since it's readily available and seems to
have relatively good performance. One problem I ran into was that
javax.vecmath.Vector2d methods tend to mutate the original. This creates
problems for the algorithm. This was a issue- how to do vector math without
mutating instances in the original primitive array?

So I worked up this hack:

(def #^Vector2d mutable-point (point 0 0))
(defmacro sub [v1 v2]
  `(do
     (.set mutable-point (.x ~v1) (.y ~v1))
     (let [#^Vector2d mutable-point# mutable-point
           #^Vector2d v#             ~v2]
       (.sub mutable-point# ~v2)

       mutable-point#)))

This avoids
mutating the original array, it also avoids any overhead from creating
a javax.vecmath.Vector2d object in the inner loop.

Finally quadrant-one-pseudo-angle and
pseudo-angle were converted into macros. These functions essentially
got called for each iteration. By inlining them via macros, it
eliminates the overhead of 2 function calls per iteration.

That's about it.

While I recommend optimizing a slow Clojure prorgram at least once to get an
idea of how optimization can be done, writing this
kind of code in Clojure seems to me to be generally counter
productive. Java is painful for writing
general program logic, but for low-level code - it's pretty good for that
and easy to write.

David

On Sun, Aug 16, 2009 at 4:53 PM, Daniel Werner <
daniel.d.wer...@googlemail.com> wrote:

>
> David,
>
> could you please post a version of your solution[1] annotated with
> some comments on where you used which kind of optimization, and why?
> Your code looks very clean to me, and with some additional
> explanations I think this could become a good example on how to
> optimize computation-heavy Clojure code.
>
> [1] github.com/swannodette/convex-hull/tree/master
>
> Thanks!
>
> Daniel
>
> >
>

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