Hi all,
I wrote this function for matrix multiplication:
--8<---------------cut here---------------start------------->8---
(defun multiply-matrices (m1 m2)
"Multiplies the given two matrices (2-dimensional arrays)."
(if (not (eql (array-dimension m1 1)
(array-dimension m2 0)))
(error "Dimension mismatch: you need (m x n) * (n x o)")
(progn
(let* ((m (array-dimension m1 0))
(o (car (last (array-dimensions m2))))
(result (make-array (list m o))))
(loop for i from 0 below m do
(loop for j from 0 below o do
(setf (aref result i j)
(scalar-product (matrix-row m1 i)
(matrix-col m2 j)))))
result))))
--8<---------------cut here---------------end--------------->8---
If I do this
,----
| CL-USER> *m1*
| #2A((1 2 3) (4 5 6))
| CL-USER> *m2*
| #2A((6 -1) (3 2) (0 -3))
| CL-USER> (multiply-matrices *m1* *m2*)
`----
I get this error:
,----
| There are 2 elements in the :INITIAL-CONTENTS, but the vector length
| is 3. [Condition of type SIMPLE-ERROR]
|
| Restarts:
| 0: [ABORT-REQUEST] Abort handling SLIME request.
| 1: [TERMINATE-THREAD] Terminate this thread
| (#<THREAD "repl-thread" {ACAC8F9}>)
|
| Backtrace:
| 0: (MAKE-ARRAY 3)
| Locals:
| SB-DEBUG::ARG-0 = 5
| SB-DEBUG::ARG-1 = 3
| 1: (MULTIPLY-MATRICES #2A((1 2 3) (4 5 6)) #2A((6 -1) (3 2) (0 -3)))
| Locals:
| SB-DEBUG::ARG-0 = #2A((1 2 3) (4 5 6))
| SB-DEBUG::ARG-1 = #2A((6 -1) (3 2) (0 -3))
| 2: (SB-INT:EVAL-IN-LEXENV (MULTIPLY-MATRICES *M1* *M2*)
| #<NULL-LEXENV>)
`----
If I print m and o before the call to make-array I can see that both of
them are 2, so the call should be (make-array (list 2 2)) which works at
the REPL.
What am I doing wrong?
Bye,
Tassilo
--
A morning without coffee is like something without something else.
I could not test your code, you did not provide the definitions for
scalar-product, matrix-row and matrix-column.
Anyway, this works for me, if it is of any help:
(defgeneric mat* (a b)
(:documentation
"Multiplies two arrays or an array with a scalar."))
(defmethod mat* ((a array) (b array))
(let* ((rows (array-dimension a 0))
(cols (array-dimension b 1))
(c (make-array (list rows cols))))
(dotimes (i rows c)
(dotimes (j cols)
(setf (aref c i j)
(sum (map 'vector #'*
(arow a i)
(acol b j))))))))
(defmethod mat* ((a number) (b array))
(let ((n (array-total-size b))
(c (make-array (array-dimensions b))))
(dotimes (i n c)
(setf (row-major-aref c i)
(* a (row-major-aref b i))))))
where sum is defined as:
(defun sum (seq)
"Sum of the elements of a sequence."
(reduce #'+ seq))
Disclaimer: I am new to lisp.
Regards,
-- Giorgos
Giorgos Pontikakis <···@freemail.gr> writes:
> I could not test your code, you did not provide the definitions for
> scalar-product, matrix-row and matrix-column.
>
> Anyway, this works for me, if it is of any help:
>
> (defgeneric mat* (a b)
> (:documentation
> "Multiplies two arrays or an array with a scalar."))
>
>
> (defmethod mat* ((a array) (b array))
> (let* ((rows (array-dimension a 0))
> (cols (array-dimension b 1))
> (c (make-array (list rows cols))))
> (dotimes (i rows c)
> (dotimes (j cols)
> (setf (aref c i j)
> (sum (map 'vector #'*
> (arow a i)
> (acol b j))))))))
>
>
> (defmethod mat* ((a number) (b array))
> (let ((n (array-total-size b))
> (c (make-array (array-dimensions b))))
> (dotimes (i n c)
> (setf (row-major-aref c i)
> (* a (row-major-aref b i))))))
>
>
> where sum is defined as:
>
> (defun sum (seq)
> "Sum of the elements of a sequence."
> (reduce #'+ seq))
>
> Disclaimer: I am new to lisp.
>
> Regards,
>
> -- Giorgos
Sorry, I just realised that I forgot to include the following
definitions in my post:
(defun arow (arr-in i)
"Returns a vector which is a part of a 2D array"
(let* ((ncols (array-dimension arr-in 1))
(result (make-array ncols)))
(dotimes (j ncols result)
(setf (svref result j) (aref arr-in i j)))))
(defun acol (arr-in j)
"Returns a vector which is a column of a 2D array"
(let* ((nrows (array-dimension arr-in 0))
(result (make-array nrows)))
(dotimes (i nrows result)
(setf (svref result i) (aref arr-in i j)))))
Bye,
-- Giorgos
Hi Giorgos,
some minutes after I posted this question I figured out the problem
(with the help of some guys on #lisp). The make-array in
multiply-matrices wasn't the problem, it was some more or less trivial
thing in another function, but the backtrace was kinda misleading.
Thanks anyway for you code, I'll have a look at it.
Bye,
Tassilo
--
My opinions may have changed, but not the fact that I am right.
Tassilo Horn <········@uni-koblenz.de> writes:
> Hi Giorgos,
>
> some minutes after I posted this question I figured out the problem
> (with the help of some guys on #lisp). The make-array in
> multiply-matrices wasn't the problem, it was some more or less trivial
> thing in another function, but the backtrace was kinda misleading.
(proclaim '(optimize (debug 3) (speed 0) (space 0)))
> Thanks anyway for you code, I'll have a look at it.
--
__Pascal Bourguignon__ http://www.informatimago.com/
"By filing this bug report you have challenged the honor of my
family. Prepare to die!"
In article <··············@baldur.nicundtas.de>,
Tassilo Horn <········@uni-koblenz.de> wrote:
> Hi all,
>
> I wrote this function for matrix multiplication:
>
> --8<---------------cut here---------------start------------->8---
> (defun multiply-matrices (m1 m2)
> "Multiplies the given two matrices (2-dimensional arrays)."
> (if (not (eql (array-dimension m1 1)
> (array-dimension m2 0)))
> (error "Dimension mismatch: you need (m x n) * (n x o)")
> (progn
> (let* ((m (array-dimension m1 0))
> (o (car (last (array-dimensions m2))))
> (result (make-array (list m o))))
> (loop for i from 0 below m do
> (loop for j from 0 below o do
> (setf (aref result i j)
> (scalar-product (matrix-row m1 i)
> (matrix-col m2 j)))))
> result))))
> --8<---------------cut here---------------end--------------->8---
>
> If I do this
>
> ,----
> | CL-USER> *m1*
> | #2A((1 2 3) (4 5 6))
> | CL-USER> *m2*
> | #2A((6 -1) (3 2) (0 -3))
> | CL-USER> (multiply-matrices *m1* *m2*)
> `----
>
> I get this error:
Unless either SCALAR-PRODUCT or MATRIX-ROW is a macro or inline
function, I don't see any way that the function above could produce this
error. The backtrace shows MAKE-ARRAY being called with an integer
argument, but the only call to MAKE-ARRAY above passes a two-element
list as the argument.
>
> ,----
> | There are 2 elements in the :INITIAL-CONTENTS, but the vector length
> | is 3. [Condition of type SIMPLE-ERROR]
> |
> | Restarts:
> | 0: [ABORT-REQUEST] Abort handling SLIME request.
> | 1: [TERMINATE-THREAD] Terminate this thread
> | (#<THREAD "repl-thread" {ACAC8F9}>)
> |
> | Backtrace:
> | 0: (MAKE-ARRAY 3)
> | Locals:
> | SB-DEBUG::ARG-0 = 5
> | SB-DEBUG::ARG-1 = 3
> | 1: (MULTIPLY-MATRICES #2A((1 2 3) (4 5 6)) #2A((6 -1) (3 2) (0 -3)))
> | Locals:
> | SB-DEBUG::ARG-0 = #2A((1 2 3) (4 5 6))
> | SB-DEBUG::ARG-1 = #2A((6 -1) (3 2) (0 -3))
> | 2: (SB-INT:EVAL-IN-LEXENV (MULTIPLY-MATRICES *M1* *M2*)
> | #<NULL-LEXENV>)
> `----
>
> If I print m and o before the call to make-array I can see that both of
> them are 2, so the call should be (make-array (list 2 2)) which works at
> the REPL.
>
> What am I doing wrong?
>
> Bye,
> Tassilo
--
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
Barry Margolin <······@alum.mit.edu> writes:
> Unless either SCALAR-PRODUCT or MATRIX-ROW is a macro or inline
> function, I don't see any way that the function above could produce this
> error. The backtrace shows MAKE-ARRAY being called with an integer
> argument, but the only call to MAKE-ARRAY above passes a two-element
> list as the argument.
A third way that the backtrace can look like this (and, I believe, the
actual reason) is if MATRIX-ROW or SCALAR-PRODUCT calls MAKE-ARRAY in
tail position, and the implementation has merged the tail call.
Christophe
Christophe Rhodes <·····@cam.ac.uk> writes:
Hi Christophe,
>> Unless either SCALAR-PRODUCT or MATRIX-ROW is a macro or inline
>> function, I don't see any way that the function above could produce
>> this error. The backtrace shows MAKE-ARRAY being called with an
>> integer argument, but the only call to MAKE-ARRAY above passes a
>> two-element list as the argument.
>
> A third way that the backtrace can look like this (and, I believe, the
> actual reason) is if MATRIX-ROW or SCALAR-PRODUCT calls MAKE-ARRAY in
> tail position, and the implementation has merged the tail call.
Exactly that was the problem. With the help of the guys on #lisp I
finally found the wrong call.
Thanks for your reply,
Tassilo
--
A morning without coffee is like something without something else.
Tassilo Horn wrote:
> Hi all,
>
> I wrote this function for matrix multiplication:
>
> --8<---------------cut here---------------start------------->8---
> (defun multiply-matrices (m1 m2)
> "Multiplies the given two matrices (2-dimensional arrays)."
> (if (not (eql (array-dimension m1 1)
> (array-dimension m2 0)))
> (error "Dimension mismatch: you need (m x n) * (n x o)")
> (progn
> (let* ((m (array-dimension m1 0))
> (o (car (last (array-dimensions m2))))
> (result (make-array (list m o))))
> (loop for i from 0 below m do
> (loop for j from 0 below o do
> (setf (aref result i j)
> (scalar-product (matrix-row m1 i)
> (matrix-col m2 j)))))
> result))))
> --8<---------------cut here---------------end--------------->8---
>
> If I do this
>
> ,----
> | CL-USER> *m1*
> | #2A((1 2 3) (4 5 6))
> | CL-USER> *m2*
> | #2A((6 -1) (3 2) (0 -3))
> | CL-USER> (multiply-matrices *m1* *m2*)
> `----
>
> I get this error:
>
> ,----
> | There are 2 elements in the :INITIAL-CONTENTS, but the vector length
> | is 3. [Condition of type SIMPLE-ERROR]
> |
> | Restarts:
> | 0: [ABORT-REQUEST] Abort handling SLIME request.
> | 1: [TERMINATE-THREAD] Terminate this thread
> | (#<THREAD "repl-thread" {ACAC8F9}>)
> |
> | Backtrace:
> | 0: (MAKE-ARRAY 3)
> | Locals:
> | SB-DEBUG::ARG-0 = 5
> | SB-DEBUG::ARG-1 = 3
> | 1: (MULTIPLY-MATRICES #2A((1 2 3) (4 5 6)) #2A((6 -1) (3 2) (0 -3)))
> | Locals:
> | SB-DEBUG::ARG-0 = #2A((1 2 3) (4 5 6))
> | SB-DEBUG::ARG-1 = #2A((6 -1) (3 2) (0 -3))
> | 2: (SB-INT:EVAL-IN-LEXENV (MULTIPLY-MATRICES *M1* *M2*)
> | #<NULL-LEXENV>)
> `----
>
> If I print m and o before the call to make-array I can see that both of
> them are 2, so the call should be (make-array (list 2 2)) which works at
> the REPL.
>
> What am I doing wrong?
It's somewhat easier in newLISP:
> (set 'A '((1 5)(9 -2)(0 -3)))
((1 5) (9 -2) (0 -3))
> (set 'B '((8 1 2)(4 3 7)))
((8 1 2) (4 3 7))
> (multiply A B)
((28 16 37) (64 3 4) (-12 -9 -21))