matrix math in Scheme

Kragen Sitaker kragen@pobox.com
Sun, 2 Apr 2000 21:32:08 -0400


So here's a quick Scheme package to do some basic linear algebra.

I wrote it in a Scheme-textbook style --- lists for everything and lots
of recursion --- which is probably not the style best suited for the
material.  I suppose I should find out what R5RS says about #(vectors).

I had this grand plan to keep some kind of layer of abstraction between
the user and the package, but that sort of fell by the wayside.

The package is one page long; it contains matrix transpose, dot product,
vector magnitude, vector normalization, and scalar-matrix, scalar-vector, 
matrix-matrix, and matrix-vector multiplies, along with a little sample
data.

; provide facilities for playing with matrices in Scheme, by Kragen Sitaker

; I'm afraid I'm using a terribly recursive and functional way of doing
; things which may not be ideal in readability.  I did it for fun.

; And, obviously, using lists and recursion for everything is not
; ideal in speed.

; make a vector: (mmvec 1 2 3)
(define (mmvec . list) list)
; make a matrix: (mmmat (1 2 3) (4 5 6) (7 8 9))
(define (mmmat . list) list)

; sample data:
(define i3 (mmmat '(1 0 0) '(0 1 0) '(0 0 1)))
(define backwards3 (mmmat '(0 0 1) '(0 1 0) '(1 0 0)))
(define nine (mmmat '(1 2 3) '(4 5 6) '(7 8 9)))
(define get-x (mmmat '(1 0 0) '(0 0 0) '(0 0 0)))
(define v1 (mmvec 1 2 3))

; isn't there a mapcar in Scheme already?  I guess not . . .
(define (mapcar func list)
  (if (null? list) '()
      (cons (func (car list)) (mapcar func (cdr list)))))

; matrix transpose
(define (mmtranspose mat)
  (define (add-first-column vector matrix)
    (if (null? matrix) (mapcar (lambda (l) (list l)) vector)
	(cons (cons (car vector) (car matrix))
	      (add-first-column (cdr vector) (cdr matrix)))))
  (if (null? mat) '()
      (add-first-column (car mat) (mmtranspose (cdr mat))))  )

; dot product
(define (mmdot v1 v2)
  (if (null? v1) 0
      (+ (* (car v1) (car v2)) (mmdot (cdr v1) (cdr v2)))))

; matrix multiply:
; a row of the first matrix is dotted with a column of the second
; to form a single output cell.
(define (mmmm m1 m2)
  (mapcar (lambda (row-of-first-matrix) 
	    (mapcar (lambda (column-of-second-matrix)
		      (mmdot row-of-first-matrix column-of-second-matrix))
		    (mmtranspose m2))) m1))

; scalar multiply
(define (mmscmul s d)
  (mapcar (lambda (i) (if (pair? i) (mmscmul s i) (* s i))) d))

; magnitude
(define (mmmag v)
  (sqrt (mmdot v v)))

; normalize to unit magnitude
(define (mmnorm v)
  (mmscmul (/ (mmmag v)) v))

; a matrix-vector multiply, treating the vector as a column vector.
; (mmmv (mmmat '(1 2 3) '(4 5 6) '(7 8 9)) (mmvec 1 2 3))
(define (mmmv mat vec)
  (if (null? mat) '()
      (cons (mmdot (car mat) vec) (mmmv (cdr mat) vec))))