From: Karsten Wenzel on
Hi,

I need to operate on huge two-dimensional arrays.
For example, a matrix-multiplication.

For a first test, I tried to multiply two small
arrays 500x500 (dimension hard coded, no
error checking or whatever):

(defun mult-array (a b)
(let ((c (make-array '(500 500))))
(dotimes (i 500)
(dotimes (j 500)
(dotimes (k 500)
(setf (aref c i j) (+ (aref c i j)
(* (aref a i k) (aref b k j)))))))
c))

(setf a (make-array '(500 500)))
(setf b (make-array '(500 500)))
(fill-array a) ; Not shown here
(fill-array b)
(mult-array a b)

This was slow. The algorithm isn't very smart, but
that's not the point.

OK, these arrays should only contain integers.
So I tried to define the arrays this way:

(make-array '(500 500) :element-type 'fixnum)

But I got no speed-up. I checked LispWorks and OpenMCL
and both are slower this way.

How to do it really fast? What should I do better?
Are they faster ways to access elements other than
aref?

Thank you in advance,
Karsten
From: Edi Weitz on
On Tue, 07 Feb 2006 12:25:21 +0100, Karsten Wenzel <kwenzel(a)tfh-berlin.de> wrote:

> I need to operate on huge two-dimensional arrays. For example, a
> matrix-multiplication.
>
> For a first test, I tried to multiply two small arrays 500x500
> (dimension hard coded, no error checking or whatever):
>
> (defun mult-array (a b)
> (let ((c (make-array '(500 500))))
> (dotimes (i 500)
> (dotimes (j 500)
> (dotimes (k 500)
> (setf (aref c i j) (+ (aref c i j)
> (* (aref a i k) (aref b k j)))))))
> c))
>
> (setf a (make-array '(500 500)))
> (setf b (make-array '(500 500)))
> (fill-array a) ; Not shown here
> (fill-array b)
> (mult-array a b)
>
> This was slow. The algorithm isn't very smart, but that's not the
> point.
>
> OK, these arrays should only contain integers. So I tried to define
> the arrays this way:
>
> (make-array '(500 500) :element-type 'fixnum)
>
> But I got no speed-up. I checked LispWorks and OpenMCL and both are
> slower this way.
>
> How to do it really fast? What should I do better? Are they faster
> ways to access elements other than aref?

There are a couple of open questions here. First, what does "This was
slow" really mean? Do you have something to benchmark against, or
does it just /feel/ slow?

Second, as you haven't posted here before: Did you compile the code?
For implementations like LispWorks and OpenMCL that compile to native
code that'd make a big difference.

Apart from that, if this is really a bottleneck, you should add
declarations to your code, i.e. within MULT-ARRAY there should be a
DECLARE that declares the types of A, B, and C as accurately as
possible. Declaring the element type in MAKE-ARRAY as you did above
doesn't make a difference.

You can also try various OPTIMIZE qualities, including
implementation-dependent ones - for LispWorks for example you should
check chapter nine of the LispWorks User Guide.

HTH,
Edi.

--

Lisp is not dead, it just smells funny.

Real email: (replace (subseq "spamtrap(a)agharta.de" 5) "edi")
From: Förster vom Silberwald on

Karsten Wenzel wrote:

> This was slow. The algorithm isn't very smart, but
> that's not the point.
>
> OK, these arrays should only contain integers.
> So I tried to define the arrays this way:

I cannot comment on your code since my Lisp is zero. However, if you
are really after some fast matrix-multiplication algorithms you should
google around a bit. There exists some techniques for such kind of
things (loop unrolling, cache size awareness, etc..).

A good idea could be also to have a look at some specialized libraries
and write a binding to your Lisp implemenation.

Btw: profiling the code will alse lead to some better insight. Then you
can quickly decide where most of the time is spent off (is it floating
point performance, or memory).

Schneewittchen

From: Alexander Schmolck on
Karsten Wenzel <kwenzel(a)tfh-berlin.de> writes:

> Hi,
>
> I need to operate on huge two-dimensional arrays.
> For example, a matrix-multiplication.

Assuming you want to do number crunching, for best performance you'll want to
wrap atlas. There's very little chance you'll beat atlas performance with
home-brewn matrix multiplication etc. routines in any language and if most of
your arrays are large the FFI overhead should be negligible. Have a look at
matlisp as a possibly not great starting point (doesn't work with most
implementations, though).

> For a first test, I tried to multiply two small
> arrays 500x500 (dimension hard coded, no
> error checking or whatever):
>
> (defun mult-array (a b)
> (let ((c (make-array '(500 500))))
> (dotimes (i 500)
> (dotimes (j 500)
> (dotimes (k 500)
> (setf (aref c i j) (+ (aref c i j)
> (* (aref a i k) (aref b k j)))))))
> c))
>
> (setf a (make-array '(500 500)))
> (setf b (make-array '(500 500)))
> (fill-array a) ; Not shown here
> (fill-array b)
> (mult-array a b)
>
> This was slow. The algorithm isn't very smart, but
> that's not the point.
>
> OK, these arrays should only contain integers.
> So I tried to define the arrays this way:
>
> (make-array '(500 500) :element-type 'fixnum)

See Edi's reply, also once you (declare (optimize (speed 3))), cmucl and sbcl
will also give you hints where to put declarations.

But integer matrix multiplication used to be one of the benchmarks in doug
bagley's language shootout, so you should be able to find a lisp version that
does that reasonably well floating around on the web somewhere.

Are you sure you don't generally want floating point, though?

'as
From: Stephan Frank on
Karsten Wenzel wrote:
> Hi,
>
> I need to operate on huge two-dimensional arrays.
> For example, a matrix-multiplication.
>

Hallo Karsten,

apart from the other responses you already got, you might also want to
have a look at Cyrus Harmon's clem-library [1]. I have not looked at it
very deeply but according to the information given by its author it is
designed to provide very high performance for matrix math making use of
some macrology to make better use of the type information.

Regs,
Stephan

[1] http://www.cyrusharmon.org/cl/blog/display/37