1 ;;;; matrices -- Basic matrix operations
3 ;;;; Copyright (c) 1991, by Luke Tierney. Permission is granted for
13 (in-package lisp-stat-basics
)
15 (in-package 'lisp-stat-basics
)
17 (export '(matrixp num-rows num-cols matmult identity-matrix diagonal
18 row-list column-list inner-product outer-product cross-product
19 transpose bind-columns bind-rows
))
23 Returns T if X is a matrix, NIL otherwise."
24 (and (arrayp x
) (= (array-rank x
) 2)))
28 Returns number of rows in X."
29 (array-dimension x
0))
33 Returns number of columns in X."
34 (array-dimension x
1))
36 (defun matmult (a b
&rest args
)
37 "Args: (a b &rest args)
38 Returns the matrix product of matrices a, b, etc. If a is a vector it is
39 treated as a row vector; if b is a vector it is treated as a column vector."
40 (let ((rtype (cond ((and (matrixp a
) (matrixp b
)) 'matrix
)
41 ((and (sequencep a
) (sequencep b
)) 'number
)
42 ((sequencep a
) (if (consp a
) 'list
'vector
))
43 ((sequencep b
) (if (consp b
) 'list
'vector
)))))
46 (setf a
(vector-to-array (coerce a
'vector
) (list 1 (length a
)))))
48 (setf b
(vector-to-array (coerce b
'vector
) (list (length b
) 1))))
49 (if (not (= (array-dimension a
1) (array-dimension b
0)))
50 (error "dimensions do not match"))
52 (reduce #'matmult args
:initial-value
(matmult a b
))
53 (let* ((n (array-dimension a
0))
54 (m (array-dimension b
1))
55 (p (array-dimension a
1))
56 (c (make-array (list n m
)))
58 (declare (fixnum n m p
))
67 (* (aref a i k
) (aref b k j
)))))
68 (setf (aref c i j
) x
)))
72 (t (coerce (compound-data-seq c
) rtype
)))))))
74 (defun identity-matrix (n)
76 Returns the identity matrix of rank N."
77 (let ((result (make-array (list n n
) :initial-element
0)))
80 (setf (aref result i i
) 1))))
82 ;; this thing is not very efficient at this point - too much coercing
85 If X is a matrix, returns the diagonal of X. If X is a sequence, returns a
86 diagonal matrix of rank (length X) with diagonal elements eq to the elements
89 (let* ((n (min (num-rows x
) (num-cols x
)))
90 (result (make-array n
)))
91 (dotimes (i n
(coerce result
'list
))
92 (setf (aref result i
) (aref x i i
)))))
94 (let* ((x (coerce x
'vector
))
96 (result (make-array (list n n
) :initial-element
0)))
98 (setf (aref result i i
) (aref x i
)))))
99 (t (error "argument must be a matrix or a sequence"))))
103 Returns a list of the rows of M as vectors"
105 (let ((m (num-rows x
))
108 (declare (fixnum m n
))
111 (let ((row (make-array n
)))
114 (setf (aref row i
) (aref x k i
))))))
115 (dotimes (i m result
)
117 (setf result
(cons (get-row (- m i
1)) result
))))))
119 (defun column-list (x)
121 Returns a list of the columns of M as vectors"
123 (let ((m (num-rows x
))
126 (declare (fixnum m n
))
129 (let ((col (make-array m
)))
132 (setf (aref col i
) (aref x i k
))))))
133 (dotimes (i n result
)
135 (setf result
(cons (get-col (- n i
1)) result
))))))
137 (defun inner-product (x y
)
139 Returns inner product of sequences X and Y."
143 (cx (make-next-element x
))
144 (cy (make-next-element y
))
147 (if (/= n
(length y
)) (error "sequence lengths do not match"))
148 (dotimes (i n result
)
151 (+ result
(* (get-next-element cx i
) (get-next-element cy i
)))))))
153 (defun outer-product (x y
&optional
(f #'*))
154 "Args: (x y &optional (fcn #'*))
155 Returns the generalized outer product of x and y, using fcn. Tat is, the result
156 is a matrix of dimension ((length x) (length y)) and the (i j) element of the
157 result is computed as (apply fcn (aref x i) (aref y j))."
158 (let* ((x (coerce x
'vector
))
159 (y (coerce y
'vector
))
162 (a (make-array (list m n
))))
163 (declare (fixnum m n
))
168 (setf (aref a i j
) (funcall f
(aref x i
) (aref y j
)))))))
170 (defun cross-product (x)
172 If X is a matrix returns (matmult (transpose X) X). If X is a vector returns
173 (inner-product X X)."
175 (let* ((n (num-rows x
))
177 (c (make-array (list p p
))))
178 (declare (fixnum n p
))
186 (incf val
(* (aref x k i
) (aref x k j
))))
187 (setf (aref c i j
) val
)
188 (setf (aref c j i
) val
))))))
190 (defun transpose-list (x)
191 (let ((m (length (first x
))))
193 (if (not (consp next
)) (error "not a list - ~a" x
))
194 (if (/= m
(length next
)) (error "sublists not the same length")))
195 (do* ((cx (copy-list x
))
196 (result (make-list m
))
197 (next result
(cdr next
)))
199 (setf (first next
) (mapcar #'first cx
))
200 (do ((next cx
(cdr next
)))
202 (setf (first next
) (rest (first next
)))))))
206 Returns the transpose of the matrix M."
208 ((consp x
) (transpose-list x
))
211 (let* ((m (num-rows x
))
213 (tx (make-array (list n m
))))
214 (declare (fixnum m n
))
219 (setf (aref tx j i
) (aref x i j
))))))))
221 (defun bind-columns (&rest args
)
223 The ARGS can be matrices, vectors, or lists. Arguments are bound into a matrix
225 Example: (bind-columns #2a((1 2)(3 4)) #(5 6)) returns #2a((1 2 5)(3 4 6))"
226 (flet ((check-arg (x)
227 (if (not (or (sequencep x
) (matrixp x
)))
228 (error "bad argument type")))
229 (arg-cols (x) (if (sequencep x
) 1 (num-cols x
)))
230 (arg-rows (x) (if (sequencep x
) (length x
) (num-rows x
))))
231 (dolist (x args
) (check-arg x
))
232 (let ((m (arg-rows (first args
)))
233 (n (arg-cols (first args
))))
234 (declare (fixnum m n
))
235 (dolist (x (rest args
))
236 (if (/= m
(arg-rows x
)) (error "column lengths do not match"))
237 (incf n
(arg-cols x
)))
238 (do* ((result (make-array (list m n
)))
239 (args args
(rest args
))
241 (x (first args
) (first args
)))
245 (let ((cx (make-next-element x
)))
247 (setf (aref result i firstcol
) (get-next-element cx i
)))))
249 (let ((k (arg-cols x
)))
252 (setf (aref result i
(+ firstcol j
)) (aref x i j
)))))))
253 (incf firstcol
(arg-cols x
))))))
255 (defun bind-rows (&rest args
)
257 The ARGS can be matrices, vectors, or lists. Arguments are bound into a matrix
259 Example: (bind-rows #2a((1 2)(3 4)) #(5 6)) returns #2a((1 2)(3 4)(5 6))"
260 (flet ((check-arg (x)
261 (if (not (or (sequencep x
) (matrixp x
)))
262 (error "bad argument type")))
263 (arg-cols (x) (if (sequencep x
) (length x
) (num-cols x
)))
264 (arg-rows (x) (if (sequencep x
) 1 (num-rows x
))))
265 (dolist (x args
) (check-arg x
))
266 (let ((m (arg-rows (first args
)))
267 (n (arg-cols (first args
))))
268 (declare (fixnum m n
))
269 (dolist (x (rest args
))
270 (if (/= n
(arg-cols x
)) (error "row lengths do not match"))
271 (incf m
(arg-rows x
)))
272 (do* ((result (make-array (list m n
)))
273 (args args
(rest args
))
275 (x (first args
) (first args
)))
279 (let ((cx (make-next-element x
)))
281 (setf (aref result firstrow i
) (get-next-element cx i
)))))
283 (let ((k (arg-rows x
)))
286 (setf (aref result
(+ firstrow j
) i
) (aref x j i
)))))))
287 (incf firstrow
(arg-rows x
))))))