Hi,
I need to construct matrices which are "semiconstant": many elements
are constant, but a few may be calculated runtime. A further
complication is that these matrices need to be columnmajor. I am
optimizing for speed (and not too much consing).
I thought I would write a macro that constructs a matrix and fills it
with elements. Since many elements are zero, I thought I would set
that in makearray and not set those elements individually. I am counting
on the compiler to fold (coerced) constants, so that I don't have to use
decimal dots, making usage convenient. Here is the resulting macro, with
an example:
(defmacro ccolmajormatrixdouble (&body listofrows)
"Construct a matrix of doublefloats from given elements (lists of
lists). Elements may be constants or forms, and are coerced to the
correct type."
(let* ((ncol (length (first listofrows)))
(nrow (length listofrows))
(arrayname (gensym "vector")))
`(let ((,arrayname (makearray '(,ncol ,nrow) :elementtype 'doublefloat
:initialelement 0d0)))
,@(iter outer
(for rowlist :in listofrows)
(for row :from 0)
(assert (= (length rowlist) ncol) ()
"Invalid number of elements in row ~A." row)
(iter
(for element :in rowlist)
(for col :from 0)
(unless (and (numberp element) (zerop element))
(in outer
(collect `(setf (aref ,arrayname ,col ,row)
(coerce ,element 'doublefloat)))))))
,arrayname)))
(defun makespecialmatrix (a b)
"Inane example."
(declare (optimize speed)
(doublefloat a b))
(ccolmajormatrixdouble (0 0 0 1 (* a b))
(12 a b 0 0)
(( a b) 0 0 0 7.8)))
where the macro expands to
(LET ((#:vector1541
(MAKEARRAY '(5 3) :ELEMENTTYPE 'DOUBLEFLOAT :INITIALELEMENT 0.0d0)))
(SETF (AREF #:vector1541 3 0) (COERCE 1 'DOUBLEFLOAT))
(SETF (AREF #:vector1541 4 0) (COERCE (* A B) 'DOUBLEFLOAT))
(SETF (AREF #:vector1541 0 1) (COERCE 12 'DOUBLEFLOAT))
(SETF (AREF #:vector1541 1 1) (COERCE A 'DOUBLEFLOAT))
(SETF (AREF #:vector1541 2 1) (COERCE B 'DOUBLEFLOAT))
(SETF (AREF #:vector1541 0 2) (COERCE ( A B) 'DOUBLEFLOAT))
(SETF (AREF #:vector1541 4 2) (COERCE 7.8 'DOUBLEFLOAT))
#:vector1541)
However, the disassembly indicates that this may not be the most
"natural" way to do this in SBCL. Is there a better one?
Thanks,
Tamas
