1 ;; Copyright 2006 by Barton Willis
3 ;; This is free software; you can redistribute it and/or
4 ;; modify it under the terms of the GNU General Public License,
5 ;; http://www.gnu.org/copyleft/gpl.html.
7 ;; This software has NO WARRANTY, not even the implied warranty of
8 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 ($put
'$linalgextra
1 '$version
)
13 (defun $circulant
(lst)
14 ($require_list lst
'$first
'$circulant
)
15 (let ((q) (n ($length lst
)))
20 (setq lst
`(,@(rest lst
) ,(car lst
)))
22 (setq q
(mapcar #'(lambda(s) (cons '(mlist) s
)) q
))
25 (defun $cauchy_matrix
(p &optional q
)
26 ($require_list p
'$first
'$cauchy_matrix
)
27 (if q
($require_list q
'$second
'$cauchy_matrix
) (setq q p
))
34 (push (div 1 (add pj qj
)) row
))
35 (setq row
(nreverse row
))
38 (setq mat
(nreverse mat
))
39 (push '($matrix
) mat
)))
41 (defun $hessian
(e vars
)
44 (setq vars
(margs vars
))
47 (push (cons '(mlist) (mapcar #'(lambda (s) ($diff z s
)) vars
)) mat
))
48 (cons '($matrix
) (reverse mat
))))
49 (t `(($hessian
) ,e
,vars
))))
51 (defun $jacobian
(e vars
)
52 (cond ((and ($listp vars
) ($listp e
))
54 (setq vars
(margs vars
))
57 (push (cons '(mlist) (mapcar #'(lambda (s) ($diff ei s
)) vars
)) mat
))
58 (cons '($matrix
) (reverse mat
))))
59 (t `(($jacobian
) ,e
,vars
))))
61 (defun $vandermonde_matrix
(l)
62 (let ((x) (q) (row) (acc nil
) (n))
63 (setq l
(require-list l
'$vandermonde_matrix
))
64 (setq n
(- (length l
) 1))
72 (setq row
(cons '(mlist) (nreverse row
)))
74 (simplify (cons '($matrix
) (nreverse acc
)))))
76 ;; Use Sylvester's criterion to decide if the self-adjoint part of a matrix is
77 ;; negative definite (neg) or positive definite (pos). For all other cases, return
78 ;; pnz. This algorithm is unable to determine if a matrix is negative semidefinite
79 ;; or positive semidefinite. The argument to this function must be a selfadjoint
82 (defun matrix-sign-sylvester (m)
83 (let ((n) (det) (p-sgn nil
) (n-sgn nil
))
84 (setq n
($first
($matrix_size m
)))
86 (loop for i from
1 to n do
87 (setq det
(ratdisrep (newdet m i nil
)))
88 (push (csign det
) p-sgn
)
89 (push (csign (mul (power -
1 i
) det
)) n-sgn
))
91 (cond ((every #'(lambda (s) (eq s
'$pos
)) p-sgn
) '$pos
)
92 ((every #'(lambda (s) (eq s
'$pos
)) n-sgn
) '$neg
)
95 (defun order-of-root (p x pt
)
98 (while (and (alike 0 ($substitute pt x p
)) (not (alike 0 p
)))
100 (setq p
($expand
($diff p x
))))
103 ;; Let M be the self-adjoint part of mat. By the self-adjoint part
104 ;; of a matrix M, I mean (M + M^*) / 2, where ^* is the conjugate transpose
107 ;; (a) neg if M is negative definite,
108 ;; (b) nz if M is negative semidefinite,
109 ;; (c) pz if M is positive semidefinite,
110 ;; (d) pos if M is positive definite,
111 ;; (e) pnz if M isn't a--d or if Maxima isn't able determine the matrix sign.
113 ;; When M is a matrix of rational numbers, look at the zeros of the characteristic polynomial;
114 ;; otherwise, use Sylvester's criterion.
116 (defun $matrix_sign
(mat)
117 (let ((z (gensym)) (p) (n) (nbr-zero-roots) (nbr-neg-roots) (nbr-pos-roots))
119 ($require_square_matrix mat
'$first
'$matrix_sign
)
120 (setq mat
(div (add mat
($ctranspose mat
)) 2))
121 (cond (($some
'((lambda) ((mlist) $s
) ((mnot) (($ratnump
) $s
))) mat
)
122 (matrix-sign-sylvester mat
))
124 (setq n
($first
($matrix_size mat
)))
125 (cond (($zeromatrixp mat
) '$zero
)
127 (setq p
($charpoly mat z
))
129 ;; number of roots of characteristic poly in {0}
130 (setq nbr-zero-roots
(order-of-root p z
0))
132 ;; number of roots of characteristic poly in (-inf,0)
133 (setq nbr-neg-roots
(- ($nroots p
'$minf
0) nbr-zero-roots
))
135 ;; number of roots of characteristic poly in (0,inf)
136 (setq nbr-pos-roots
($nroots p
0 '$inf
))
138 (cond ((= n nbr-neg-roots
) '$neg
)
139 ((= 0 nbr-pos-roots
) '$nz
)
140 ((= n nbr-pos-roots
) '$pos
)
141 ((= n
(+ nbr-pos-roots nbr-zero-roots
)) '$pz
)
144 (defun $sylvester_matrix
(p q z
)
145 (let ((p-coeff nil
) (q-coeff nil
) (mat nil
) (p-deg) (q-deg))
146 (if (or (not ($polynomialp p
`((mlist) ,z
) `((lambda) ((mlist) c
) (($freeof
) ,z c
))))
147 (not ($polynomialp q
`((mlist) ,z
) `((lambda) ((mlist) c
) (($freeof
) ,z c
)))))
148 (merror "The first two arguments to 'sylvester_matrix' must be polynomials"))
150 (setq p
($ratexpand p
))
151 (setq q
($ratexpand q
))
153 (setq p-deg
($hipow p z
))
154 (setq q-deg
($hipow q z
))
156 (dotimes (k (- q-deg
1))
159 (dotimes (k (+ p-deg
1))
160 (push ($ratcoef p z k
) p-coeff
))
162 (dotimes (k (- p-deg
1))
165 (dotimes (k (+ 1 q-deg
))
166 (push ($ratcoef q z k
) q-coeff
))
169 (push (cons '(mlist) p-coeff
) mat
)
170 (setq p-coeff
(butlast p-coeff
))
174 (push (cons '(mlist) q-coeff
) mat
)
175 (setq q-coeff
(butlast q-coeff
))
178 (simplify `(($matrix
) ,@(reverse mat
)))))
180 (defun $krylov_matrix
(v mat
&optional
(n 'no-value
))
181 ($require_square_matrix mat
'$second
'$krylov_matrix
)
182 (and ($listp v
) (setq v
($transpose v
)))
185 (= ($first
($matrix_size v
)) ($second
($matrix_size mat
)))))
186 (merror "Incompatible matrix sizes"))
187 (if (eq n
'no-value
) (setq n
($first
($matrix_size mat
))))
188 ($require_posinteger n
'$third
'$krylov_matrix
)
192 (setq v
(ncmul mat v
))
193 (setq acc
($addcol acc v
)))