1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
;; Copyright 2005 by Barton Willis
;; This is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License,
;; http://www.gnu.org/copyleft/gpl.html.
;; This software has NO WARRANTY, not even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
($put '$linalgutilities 2 '$version)
(defun inform (level pck msg &rest arg)
(if (member level (member ($get '$infolevel pck) `($debug $verbose $silent)))
(apply 'mtell `(,msg ,@arg))))
(defun $require_nonempty_matrix (m pos fun)
(if (not (and ($matrixp m) (> ($length m) 0) (> ($length ($first m)) 0)))
(merror "The ~:M argument of the function ~:M must be a nonempty matrix" pos fun)))
;; Why both some and every? Because we want blockmatrixp(matrix()) --> false.
(defun $blockmatrixp (m)
(and ($matrixp m) ($some '$matrixp m) ($every '$matrixp m)))
(defun $require_matrix (m pos fun)
(if (not ($matrixp m))
(merror "The ~:M argument of the function ~:M must be a matrix" pos fun)))
(defun $require_unblockedmatrix (m pos fun)
(if (or (not ($matrixp m)) ($blockmatrixp m))
(merror "The ~:M argument of the function ~:M must be an unblocked matrix" pos fun)))
(defun $require_square_matrix (m pos fun)
(if (not (and ($matrixp m) (= ($length m) ($length ($first m)))))
(merror "The ~:M argument of the function ~:M must be a square matrix" pos fun)))
(defun array-elem (m i j)
(nth j (nth i m)))
(defun $require_symmetric_matrix (m pos fun)
(if (not ($matrixp m)) (merror "The ~:M argument to ~:M must be a matrix" pos fun))
(let ((n ($matrix_size m)))
(if (not (= ($first n) ($second n)))
(merror "The ~:M argument to ~:M must be a square matrix" pos fun))
(if (not ($zeromatrixp (sub m ($transpose m))))
(merror "The ~:M argument to ~:M must be a symmetric matrix" pos fun)))
'$done)
(defun $require_real_symmetric_matrix (m pos fun)
(if (not ($matrixp m)) (merror "The ~:M argument to ~:M must be a matrix" pos fun))
(let ((n ($matrix_size m)))
(if (not (= ($first n) ($second n)))
(merror "The ~:M argument to ~:M must be a square matrix" pos fun))
(if (and ($zeromatrixp (sub m ($transpose m))) ($zeromatrixp (sub m (take '($conjugate) m)))) '$done
(merror "The ~:M argument to ~:M must be a real symmetric matrix" pos fun))))
(defun $require_selfadjoint_matrix (m fun pos)
(if (not ($matrixp m)) (merror "The ~:M argument to ~:M must be a matrix" pos fun))
(let ((n ($matrix_size m)))
(if (not (= ($first n) ($second n)))
(merror "The ~:M argument to ~:M must be a square matrix" pos fun))
(if (not ($zeromatrixp (sub m ($ctranspose m))))
(merror "The ~:M argument to ~:M must be a selfadjoint (hermitian) matrix" pos fun)))
'$done)
;; matrix() is a 0 x 0 matrix, and matrix([]) is a 1 x 0 matrix.
;; There is no representation for a 0 x 1 matrix. Currently,
;; transpose(matrix([])) => matrix(). And that's a bug.
(defun $matrix_size(m)
($require_matrix m "$first" "$matrix_size")
`((mlist) ,($length ($args m)) ,(if ($emptyp ($args m)) 0 ($length ($first ($args m))))))
(defun $require_list (lst pos fun)
(if (not ($listp lst))
(merror "The ~:M argument of the function ~:M must be a list" pos fun)))
(defun $require_posinteger(i pos fun)
(if (not (and (integerp i) (> i 0)))
(merror "The ~:M argument of the function ~:M must be a positive integer" pos fun)))
(defun matrix-map (f mat)
(setq mat (mapcar 'cdr (cdr mat)))
(setq mat (mapcar #'(lambda (s) (mapcar f s)) mat))
(setq mat (mapcar #'(lambda (s) (cons `(mlist simp) s)) mat))
`(($matrix simp) ,@mat))
;; Map the lisp function fn over the matrix m. This function is block matrix friendly.
(defun full-matrix-map (fn m)
(if (or ($listp m) ($matrixp m))
(cons (car m) (mapcar #'(lambda (s) (full-matrix-map fn s)) (cdr m)))
(funcall fn m)))
(defun $zerofor (mat &optional (fld-name '$generalring))
(let* ((fld ($require_ring fld-name "$second" "$zerofor"))
(add-id (funcall (mring-mring-to-maxima fld) (funcall (mring-add-id fld)))))
(zerofor mat add-id)))
(defun zerofor (mat zero)
(if (or ($matrixp mat) ($listp mat))
(cons (car mat) (mapcar #'(lambda (s) (zerofor s zero)) (cdr mat)))
zero))
;; Return an identity matrix that has the same shape as the matrix
;; mat. The first argument 'mat' should be a square Maxima matrix or a
;; non-matrix. When 'mat' is a matrix, each entry of 'mat' can be a
;; square matrix -- thus 'mat' can be a blocked Maxima matrix. The
;; matrix can be blocked to any (finite) depth.
(defun $identfor (mat &optional (fld-name '$generalring))
(let* ((fld ($require_ring fld-name "$second" "$zerofor"))
(add-id (funcall (mring-mring-to-maxima fld) (funcall (mring-add-id fld))))
(mult-id (funcall (mring-mring-to-maxima fld) (funcall (mring-mult-id fld)))))
(if ($matrixp mat) (identfor mat add-id mult-id) mult-id)))
(defun identfor (mat zero one)
(let ((i) (acc) (j) (new-mat))
(setq mat (rest mat))
(setq i 0)
(dolist (row mat)
(setq row (rest row))
(setq acc nil)
(setq j 0)
(dolist (aij row)
(push (cond (($matrixp aij)
(if (= i j) (identfor aij zero one) (zerofor aij zero)))
((= i j) one)
(t zero)) acc)
(incf j))
(incf i)
(push '(mlist) acc)
(push acc new-mat))
(push '($matrix) new-mat)))
(defun $ctranspose (m)
(mfuncall '$transpose (full-matrix-map #'(lambda (s) (simplifya `(($conjugate) ,s) nil)) m)))
(defun $zeromatrixp (m)
(if (or ($matrixp m) ($listp m)) (every '$zeromatrixp (cdr m))
(eq '$zero (csign ($rectform m)))))
(defun array-to-row-list (mat &optional (fn 'identity))
(let ((acc) (r (array-dimensions mat)) (row) (c))
(setq c (second r))
(setq r (first r))
(dotimes (i r)
(setq row nil)
(dotimes (j c)
(push (funcall fn (aref mat i j)) row))
(setq row (reverse row))
(push row acc))
(reverse acc)))
(defun array-to-maxima-matrix (mat &optional (fn 'identity))
(cons '($matrix) (mapcar #'(lambda (s) (cons '(mlist) s)) (array-to-row-list mat fn))))
(defun array-to-maxima-list (ar &optional (fn 'identity))
(cons '(mlist) (mapcar fn (coerce ar 'list))))
(defun maxima-to-array (mat &optional (fn 'identity) typ)
(let ((r ($matrix_size mat)) (c))
(setq c ($second r))
(setq r ($first r))
(setq mat (mapcar #'cdr (cdr mat)))
(setq mat (mapcar #'(lambda (s) (mapcar #'(lambda (w) (funcall fn w)) s)) mat))
(if typ (make-array (list r c) :element-type typ :initial-contents mat)
(make-array (list r c) :initial-contents mat))))
|