2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4 ;; Some utilities for working with vectors.
6 ;; Copyright (C) Nov. 2008 Volker van Nek
8 ;; modified 08-12-03: vector_factor factors lists and matrices
9 ;; 08-12-05: vector_eval: $ratprint set to false
10 ;; 08-12-10: rename stardisp to stardisp1, assign property of $stardisp
11 ;; 08-12-14: vector_eval: cut out sratsimp, rename it to vector_simp
12 ;; $vector_rebuild: evaluate mnctimes, bugfix case mdefine
13 ;; 20-02-27: TeX-support added
15 ;; This program is free software; you can redistribute it and/or modify
16 ;; it under the terms of the GNU General Public License as published by
17 ;; the Free Software Foundation; either version 2 of the License, or
18 ;; (at your option) any later version.
20 ;; This program is distributed in the hope that it will be useful,
21 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
22 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 ;; GNU General Public License for more details.
25 ;; You should have received a copy of the GNU General Public License
26 ;; along with this program; if not, write to the Free Software
27 ;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
28 ;; MA 02110-1301, USA.
30 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
32 ;; Functions at Maxima level:
33 ;; vector_rebuild(x), vector_rebuild(x,[param_list])
34 ;; vector_simp(x), has evfun property
35 ;; vector_factor(x), has evfun property
36 ;; extract_equations(x)
38 ;; Operators at Maxima level:
40 ;; x~y cross product (lbp=134, rbp=133)
42 ;; Option variable at Maxima level:
43 ;; vector_factor_minus
45 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
49 ;; In combination with setting listarith & friends to false
50 ;; mtimesq allows to suppress automatic arithmetrics
51 ;; and to bypass the displa function dim-mquotient:
53 ;; 1/r*[2,3]; --> - [2, 3] or 1/r*matrix([2],[3]);--> - [ ]
55 ;; mtimesq display symbol is "*" and is settable by stardisp.
56 ;; One evaluation steps from mtimesq to mtimes and vice versa.
58 (meval `(($infix
) mtimesq
120 119))
59 (defprop mtimesq simp-mtimesq operators
)
61 (defun simp-mtimesq (a tmp z
)
62 (declare (ignore tmp
))
63 `((mtimesq simp
) ,(simplifya (cadr a
) z
) ,(simplifya (caddr a
) z
)))
65 (defmfun mtimesq
(a b
) `((mtimes simp
) ,a
,b
))
67 (putprop 'mtimesq
(get 'mtimes
'dissym
) 'dissym
)
69 ;; extend stardisp in displa.lisp :
70 (defun stardisp1 (symbol val
)
71 (declare (ignore symbol
))
72 (putprop 'mtimes
(if val
'(#\
*) '(#\space
)) 'dissym
)
73 (putprop 'mtimesq
(get 'mtimes
'dissym
) 'dissym
) )
75 (defprop $stardisp stardisp1 assign
)
77 (defun mtimesqp (expr)
78 (and (not (atom expr
)) (eq 'mtimesq
(caar expr
))) )
81 (putprop 'mtimesq
'tex-mtimesq
'tex
)
83 (defun tex-mtimesq (x l r
)
85 (tex (cadr x
) nil nil
'mparen
'mparen
)
87 ; `("\\cdot") ; if preferred
88 (tex (caddr x
) nil nil
'mparen
'mparen
)
91 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
95 (defun $vector_simp
(expre$$ion
)
96 (let (($listarith t
) ($doallmxops t
))
97 ($expand
(meval `(($ev
) ,expre$$ion $infeval
))) ))
98 ;; mtimesq needs an extra evaluation here
100 (putprop '$vector_simp t
'evfun
)
102 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
106 (defun $vector_rebuild
(expr &optional
(params '((mlist))) )
107 (when (or (not ($listp params
))
108 (some #'(lambda (p) (or ($constantp p
)
109 (not (or ($symbolp p
) ($subvarp p
)))))
112 (format nil
"The optional second argument to `vector_rebuild'~%~
113 must be a list of symbols or subscripted variables.")))
114 (if (or (atom expr
) ($scalarp expr
))
116 (let ((op (mop expr
))
117 (args (margs expr
)) )
118 (if (not (car args
)) (return-from $vector_rebuild expr
)) ;; noarg-op
122 (mapcar #'(lambda (arg) ($vector_rebuild arg params
)) args
) ))
124 (meval `((mdefine simp
)
126 ,($vector_rebuild
(caddr expr
) params
)) ))
128 (vector-rebuild expr
(cdr params
)) )))))
130 (defun vector-rebuild (expr params
)
131 (let (coef-matrix col-flag tmp-vec col
134 (vec ($vector_simp expr
)) )
135 (when (not (vector-p vec
)) (return-from vector-rebuild expr
))
136 (when (zero-vector-p vec
) (return-from vector-rebuild vec
))
137 (when (column-vector-p vec
) (setq col-flag t
))
138 (dolist (a (cdr vec
))
139 (when col-flag
(setq a
(cadr a
)))
141 (append coef-matrix
(list (coef-list a params
)))) )
142 (setq params
(append params
'(1)))
144 (setq col
(mapcar #'(lambda (row) (nth n row
)) coef-matrix
))
146 (when (some #'(lambda (e) (not (zerop1 e
))) col
)
148 (setq tmp-vec
`((mlist simp
) ,@col
) )
150 (setq tmp-vec
(row-to-column tmp-vec
)))
152 (append res
`(((mtimes) ,p
,tmp-vec
)) ))) ))
155 ;; e.g. expr=4-2*t+3*s, params=(s t) --> (3 -2 4)
156 (defun coef-list (expr params
)
159 (setq c
(meval `(($coeff
) ,expr
,p
)))
162 (meval `((mplus) ,expr
((mtimes) ((mminus) ,c
) ,p
))) ))
163 (reverse (cons expr res
)) ))
165 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
167 ;; $extract_equations
169 (defun $extract_equations
(equation)
170 (let ((err-msg "Argument to `extract_equations' is not a vector equation.")
172 (and (not (atom equation
))
173 (not (eq (mop equation
) 'mequal
))
175 (setq args
(cdr equation
))
176 (setq left
($vector_simp
(car args
)))
177 (setq right
($vector_simp
(cadr args
)))
179 ((and (vector-p left
) (vector-p right
))) ;; OK
180 ;; due to a bug in Maxima allow left or right to be zero:
181 ((and (eql 0 left
) (vector-p right
))
184 (make-list (vector-dim right
) :initial-element
0))) )
185 ((and (eql 0 right
) (vector-p left
))
188 (make-list (vector-dim left
) :initial-element
0))) )
191 (when (not ($listp left
)) (setq left
(column-to-row left
)))
192 (when (not ($listp right
)) (setq right
(column-to-row right
)))
193 (meval `(($map
) "=" ,left
,right
)) ))
195 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
199 (defun $vector_factor
(expr)
202 (let ((op (mop expr
)))
205 `((mequal simp
) ,@(mapcar #'$vector_factor
(cdr expr
))) )
207 (meval `((mdefine simp
)
209 ,($vector_factor
(caddr expr
))) ))
210 ((member op
'(mplus mnctimes crossq
) :test
#'eq
)
211 `((,op simp
) ,@(mapcar #'$vector_factor
(cdr expr
))) )
213 (vector-extract-gcd expr
) ))))) ;; incl. op=mtimes,mminus
215 (putprop '$vector_factor t
'evfun
)
217 ;; if you wish to factor out a minus sign, set this to true
218 (defmvar $vector_factor_minus nil
)
220 (defun vector-extract-gcd (expr)
221 (let (fac vec args minus-flag $ratprint
)
222 (setq vec
($vector_simp expr
))
224 ((or (zero-vector-p vec
) (zero-$matrix-p vec
))
226 ((or ($listp vec
) ($matrixp vec
))
230 (apply #'append
(mapcar #'cdr
(cdr vec
))) ))
232 (reduce #'(lambda (a b
) ($gcd a b
)) (cons (car args
) args
)))
236 ((lambda) ((mlist) e
) (($ratsimp
) ((mquotient) e
,fac
)))
241 #'(lambda (a) (eq t
(meval `(($is
) ((mlessp) ,a
0)))))
246 `(($fullmapl
) ((lambda) ((mlist) e
) ((mminus) e
)) ,vec
) )))
250 `((mminus) ((mtimesq) ,fac
,vec
)) )
253 `((mtimesq) ,fac
,vec
) )))
257 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
261 (meval `(($matchfix
) $\| $\|
))
263 (defprop $\| simp-vector-length operators
)
265 (defun simp-vector-length (a tmp z
)
266 (declare (ignore tmp
) (ignore z
))
268 (setq a
($vector_simp
(cadr a
)))
271 (meval `((mabs simp
) ,a
)) )
277 (mapcar #'cadr
(cdr a
)) ))
278 (setq args
(mapcar #'(lambda (a) (meval `((mexpt) ,a
2))) args
))
279 (meval `(($sqrt simp
) ((mplus simp
) ,@args
))) ))
283 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
287 (meval `(($infix
) $\~
134 133)) ;; lbp and rbp copied from vect.mac
289 (defprop $\~ simp-vector-cross operators
)
291 ;; if it seems fit we can suppress automatic simplification
292 ;; by using an alias:
294 ;; (meval `(($infix) crossq 134 133))
295 ;; (putprop 'crossq '(#\~) 'dissym)
297 ;; (defun simp-vector-cross (a tmp z)
298 ;; (declare (ignore tmp) (ignore z))
300 ;; `((crossq simp) ,(cadr a) ,(caddr a)) )
301 ;; ;; again, here is one more step of evaluation needed
303 ;; (defmfun crossq (a b)
304 ;; (let ((v ($vector_simp a))
305 ;; (w ($vector_simp b))
306 ;; cross col-flag dim-v dim-w) ;;))
308 (defun simp-vector-cross (a tmp z
)
309 (declare (ignore tmp
) (ignore z
))
311 (let ((v ($vector_simp
(cadr a
)))
312 (w ($vector_simp
(caddr a
)))
313 cross col-flag dim-v dim-w
)
314 (if (and (vector-p v
) (vector-p w
))
316 (when (column-vector-p v
)
317 (setq v
(column-to-row v
) col-flag t
))
318 (when (column-vector-p w
)
319 (setq w
(column-to-row w
) col-flag t
))
320 (setq dim-v
(1- (length v
)) dim-w
(1- (length w
)))
322 ((and (= 2 dim-v
) (= 2 dim-w
))
323 ;; v[1]*w[2]-v[2]*w[1]
324 (meval `((mplus simp
)
325 ((mtimes simp
) ,(cadr v
) ,(caddr w
))
326 ((mminus) ((mtimes simp
) ,(caddr v
) ,(cadr w
))) )))
327 ((and (= 3 dim-v
) (= 3 dim-w
))
328 ;; [ v[2]*w[3]-v[3]*w[2],
329 ;; v[3]*w[1]-v[1]*w[3],
330 ;; v[1]*w[2]-v[2]*w[1] ]
333 ,(meval `((mplus simp
)
334 ((mtimes simp
) ,(caddr v
) ,(cadddr w
))
335 ((mminus) ((mtimes simp
) ,(cadddr v
) ,(caddr w
))) ))
336 ,(meval `((mplus simp
)
337 ((mtimes simp
) ,(cadddr v
) ,(cadr w
))
338 ((mminus) ((mtimes simp
) ,(cadr v
) ,(cadddr w
))) ))
339 ,(meval `((mplus simp
)
340 ((mtimes simp
) ,(cadr v
) ,(caddr w
))
341 ((mminus) ((mtimes simp
) ,(caddr v
) ,(cadr w
))) )) ))
343 (row-to-column cross
)
349 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
351 ;; some small helpers
353 (defun column-to-row (col) ;; assume col to be a column vector (a $matrix)
355 (mapcar #'cadr
(cdr col
)) ))
357 (defun row-to-column (row) ;; assume row to be a row vector (a mlist)
358 (cons '($matrix simp
)
359 (mapcar #'(lambda (e) (list '(mlist simp
) e
))
362 (defun vector-dim (vec) ;; assume vec to be a row or column vector
365 (defun column-vector-p (obj)
367 (= 2 (length (cadr obj
))) ))
369 (defun vector-p (obj)
370 (or ($listp obj
) (column-vector-p obj
)))
372 (defun zero-vector-p (obj)
373 (or (zero-mlist-p obj
)
374 (and (zero-$matrix-p obj
) (= 2 (length (cadr obj
)))) ))
376 (defun zero-mlist-p (obj)
377 (and ($listp obj
) (every #'zerop1
(cdr obj
)) ))
379 (defun zero-$matrix-p
(obj)
380 (and ($matrixp obj
) (every #'zero-mlist-p
(cdr obj
)) ))
382 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;