Which is preferable depends on the nature of the changes that your
matrices will undergo. For dense linear algebra, it's common for most
of a matrix to change with every operation. Hence you won't reap any
benefits from the persistence of Clojure's maps.

The problem with your first implementation isn't the use of flat
arrays but the fundamental inefficiency of a low-level
get-entry/set-entry interface. Even for a mutable matrix data
structure, I would consider such a thing.

Many sequence operations and virtually all linear algebra operations
produce matrices with a shape and size that is predictable ahead of
time. Mapping a function over a matrix yields a matrix of the same
size (an example is scalar multiplication). Mapping a function over
two matrices of the same size yields a matrix of the same size (an
example is matrix addition). Transposing a matrix of size m x n yields
a matrix of size n x m. Multiplying a matrix of size m x p with a
matrix of size p x n yields a matrix of size m x n.

These are the kind of primitive operations you should build your
interface on. With this, you can use float-arrays preallocated to just
the right size, fill in the entries by whatever means (e.g. calls to
user-provided functions in the case of mapping), and return that.
Everything is purely functional from the exterior.

-Per

On Tue, Mar 9, 2010 at 2:57 AM, Jonathan Shore <[email protected]> wrote:
> Hi,
> I'm still trying to work out the best way to deal with operations on
> heterogenous data in clojure.   I have a complex application which has such
> requirements.   I wrote a simple toy matrix as a means to explore closure
> versus map based implementations.   Note that in this case the "data
> structure" is not pure, rather mutable.    Here are 2 implementations I came
> up with (note this is my second day with closure, so my not be idiomatic):
> The first impl uses closures and provides access via a function (is there a
> more efficient way to do this?, avoiding the cond-dispatch?):
>
> (defn matrix-1 [nrow ncol]
>   (let [data (float-array (* nrow ncol))]
>     (fn [command & args]
>       (condp = command
>         :dim
>           [nrow ncol]
>         :get
>           (let [[i j] args] (aget data (* i j)))
>         :set
>           (let [[i j v] args] (aset-float data (* i j) v))))))
>
> The second implementation uses a map:
> (defn matrix-2 [nrow ncol]
>   { :data (float-array (* nrow ncol)), :nrow nrow, :ncol ncol })
> (defn mset! [mat i j v]
>   (aset-float (get mat :data) (* i j) v))
> (defn mget [mat i j]
>   (aget (get mat :data) (* i j)))
>
> (defn mdim [mat]
>   [(get mat :nrow) (get mat :ncol)])
> Both of these implementations bother me.  The first because of the dispatch,
> the second because maps clearly are not "near the metal".    It would seem
> would have to resort to java side classes, unless there is a better way?
> BTW, the map implementation is about 3x faster:
> (def m1 (matrix-1 10 10))
> (def m2 (matrix-2 10 10))
> ...
> (defn benchmark [what times f]
>   (let [
>     Tstart
>       (System/currentTimeMillis)
>     result
>       (loop [ntimes times]
>         (f)
>         (if (> ntimes 0)
>           (recur (- ntimes 1))))
>     Tend
>       (System/currentTimeMillis)]
>   (println "evaluating" what  "took" (- Tend Tstart) "ms")))
> (benchmark "map-based-matrix" 1000000 (fn [] (mset! m2 3 3 0.1234)))
> (benchmark "closure-based-matrix" 1000000 (fn [] (m1 :set 3 3 0.1234)))
>
>
>
>
>
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to [email protected]
> Note that posts from new members are moderated - please be patient with your
> first post.
> To unsubscribe from this group, send email to
> [email protected]
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to