1 ;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;; The data in this file contains enhancments. ;;;;;
5 ;;; Copyright (c) 1984,1987 by William Schelter,University of Texas ;;;;;
6 ;;; All rights reserved ;;;;;
7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
8 ;;; (c) Copyright 1982 Massachusetts Institute of Technology ;;;
9 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
15 ;; this is the mat package
17 (declare-top (special *ech
* *tri
* $algebraic $multiplicities equations
18 mul
* $dispflag $nolabels
*det
*
19 xm
* xn
* varlist ax
*linelabel
*))
26 (defmvar $globalsolve nil
)
28 (defmvar $backsubst t
)
33 (defun solcoef (m *c varl flag
)
34 (prog (cc answer leftover
)
35 (setq cc
(cdr (ratrep* *c
)))
36 (if (or (atom (car cc
))
37 (not (equal (cdar cc
) '(1 1)))
38 (not (equal 1 (cdr cc
))))
39 ;; NOTE TO TRANSLATORS: NOT CLEAR WHAT IS "UNACCEPTABLE" HERE
40 (merror (intl:gettext
"solve: unacceptable variable: ~M") *c
))
41 (setq answer
(ratreduce (prodcoef (car cc
) (car m
)) (cdr m
)))
42 (if (not flag
) (return answer
))
44 (rdis (ratplus m
(rattimes (ratminus answer
) cc t
))))
45 (if (or (not (freeof *c leftover
))
46 (dependsall (rdis answer
) varl
))
47 (rat-error "`non-linear'"))
50 (defun formx (flag nam eql varl
)
57 (setf (symbol-value nam
) (make-array (list (1+ (setq xn
* (length eql
)))
58 (1+ (setq xm
* (1+ (length varl
)))))))
59 (setq nam
(get-array-pointer nam
))
62 (cond ((null eql
) (return varlist
)))
66 (setf (aref nam ix xm
*) (const ax varl
))
68 (setq b varl
) (setq ax
(cdr (ratrep* ax
)))
73 (setf (aref nam ix j
) (solcoef ax x varl flag
))
77 (defun dependsall (exp l
)
79 ((or (not (freeof (car l
) exp
)) (dependsall exp
(cdr l
))) t
)
82 (setq *det
* nil
*ech
* nil
*tri
* nil
)
84 (defun ptorat (ax m n
)
86 (setq ax
(get-array-pointer ax
))
90 (when (equal i
1) (return nil
))
94 (when (equal j
1) (go loop1
))
96 (setf (aref ax i j
) (cons (aref ax i j
) 1))
100 "If Z is of the form lhs = rhs, return the expression lhs - rhs.
101 Otherwise, return Z unchanged."
102 (if (and (not (atom z
)) (eq (caar z
) 'mequal
))
103 (simplus (list '(mplus) (cadr z
) (list '(mtimes) -
1 (caddr z
))) 1 nil
)
106 (defun const (e varl
)
107 (setq varl
(mapcar #'(lambda(x) (caadr (ratrep* x
))) varl
))
108 (setq e
(cdr (ratrep* e
)))
109 (let ((zl (make-list (length varl
) :initial-element
0)))
110 (ratreduce (pctimes -
1 (pcsubsty zl varl
(car e
)))
111 (pcsubsty zl varl
(cdr e
)))))
113 (defvar *mosesflag nil
)
117 (defmfun make-param
()
118 (let ((param (intern (format nil
"~A~D" '$%r
(incf $%rnum
)))))
119 (tuchus $%rnum_list param
)
122 (defmvar $linsolve_params t
"`linsolve' generates %Rnums")
125 (if (atom x
) nil
(nth (1- n
) x
)))
127 (defun polyize (ax r m mul
)
129 (do ((c 1 (1+ c
)) (d))
132 (setq d
(aref ax r c
))
133 (setq d
(cond ((equal mul
1) (car d
))
135 (pquotientchk mul
(cdr d
))))))
136 (setf (aref ax r c
) (if $sparse
(cons d
1) d
))))
138 ;; TWO-STEP FRACTION-FREE GAUSSIAN ELIMINATION ROUTINE
140 (defun tfgeli (ax n m
&aux
($sparse
(and $sparse
(or *det
* *inv
*))))
141 ;;$sparse is also controlling whether polyize stores polys or ratforms
142 (setq ax
(get-array-pointer ax
))
145 ((> r n
) (cond ((and $sparse
*det
*)(sprdet ax n
))
146 ((and *inv
* $sparse
)(newinv ax n m
))
147 (t (tfgeli1 ax n m
))))
152 (and *det
* (setq mul
* (ptimes mul
* mul
)))
153 (polyize ax r m mul
))
154 (cond ((equal 1 (setq d
(cdr (aref ax r c
)))) nil
)
155 (t (setq mul
(ptimes mul
(pquotient d
(pgcd mul d
)))))))))
157 ;; The author of the following programs is Tadatoshi Minamikawa (TM).
158 ;; This program is one-step fraction-free Gaussian elimination with
159 ;; optimal pivotting. DRB claims the hair in this program is not
160 ;; necessary and that straightforward Gaussian elimination is sufficient,
161 ;; for sake of future implementors.
163 ;; To debug, delete the comments around PRINT and BREAK statements.
165 (declare-top (special permsign a rank delta nrow nvar n m variableorder
166 dependentrows inconsistentrows l k
))
168 (defun tfgeli1 (ax n m
)
169 (prog (k l delta variableorder inconsistentrows
170 dependentrows nrow nvar rank permsign result
)
171 (setq ax
(get-array-pointer ax
))
172 (setq *col
* (make-array (1+ m
) :initial-element
0))
173 (setq *row
* (make-array (1+ n
) :initial-element
0))
174 (setq *colinv
* (make-array (1+ m
) :initial-element
0))
175 ;; (PRINT 'ONESTEP-LIPSON-WITH-PIVOTTING)
177 (setq nvar
(cond (*rank
* m
) (*det
* m
) (*inv
* n
) (*ech
* m
) (*tri
* m
) (t (1- m
))))
180 (setf (aref *row
* i
) i
))
183 (setf (aref *col
* i
) i
) (setf (aref *colinv
* i
) i
))
185 (cond (*rank
* (forward t
) rank
)
187 (cond ((= nrow n
) (cond (permsign (pminus delta
))
190 (*inv
* (forward t
) (backward) (recoverorder1))
191 (*ech
* (forward nil
) (recoverorder2))
192 (*tri
* (forward nil
) (recoverorder2))
193 (t (forward t
) (cond ($backsubst
(backward)))
195 (list dependentrows inconsistentrows variableorder
))))
198 ;;FORWARD ELIMINATION
199 ;;IF THE SWITCH *CPIVOT IS NIL, IT AVOIDS THE COLUMN PIVOTTING.
200 (defun forward (*cpivot
)
201 (setq delta
1) ;DELTA HOLDS THE CURRENT DETERMINANT
203 (nvar nvar
) ;PROTECTS AGAINST TEMPORARAY RESETS DONE IN PIVOT
205 ((or (> k nrow
) (> k nvar
)))
206 (cond ((pivot ax k
*cpivot
) (return nil
)))
207 ;; PIVOT IS T IF THERE IS NO MORE NON-ZERO ROW LEFT. THEN GET OUT OF THE LOOP
208 (do ((i (1+ k
) (1+ i
)))
210 (do ((j (1+ k
) (1+ j
)))
212 (setf (aref ax
(aref *row
* i
) (aref *col
* j
))
213 (pquotient (pdifference (ptimes (aref ax
(aref *row
* k
) (aref *col
* k
))
214 (aref ax
(aref *row
* i
) (aref *col
* j
)))
215 (ptimes (aref ax
(aref *row
* i
) (aref *col
* k
))
216 (aref ax
(aref *row
* k
) (aref *col
* j
))))
218 (do ((i (1+ k
) (1+ i
)))
220 (setf (aref ax
(aref *row
* i
) (aref *col
* k
)) 0))
221 (setq delta
(aref ax
(aref *row
* k
) (aref *col
* k
))))
222 ;; UNDOES COLUMN HACK IN PIVOT.
223 (or *cpivot
(do ((i 1 (1+ i
))) ((> i m
)) (setf (aref *col
* i
) i
)))
224 (setq rank
(min nrow nvar
)))
226 ;; BACKWARD SUBSTITUTION
228 (declare(special ax delta m rank
))
229 (do ((i (1- rank
) (1- i
)))
231 (do ((l (1+ rank
) (1+ l
)))
233 (setf (aref ax
(aref *row
* i
) (aref *col
* l
))
234 (let ((mess1 (pdifference
235 (ptimes (aref ax
(aref *row
* i
) (aref *col
* l
))
236 (aref ax
(aref *row
* rank
) (aref *col
* rank
)))
237 (do ((j (1+ i
) (1+ j
)) (sum 0))
239 (setq sum
(pplus sum
(ptimes (aref ax
(aref *row
* i
) (aref *col
* j
))
240 (aref ax
(aref *row
* j
) (aref *col
* l
))))))) )
241 (mess2 (aref ax
(aref *row
* i
) (aref *col
* i
)) ))
242 (cond ((equal 0 mess1
) 0)
244 (t ;; (pquotient mess1 mess2) ; fixed by line below. RJF 1/12/2017
246 (car (ratreduce mess1 mess2
))
249 (do ((l (1+ i
) (1+ l
)))
251 (setf (aref ax
(aref *row
* i
) (aref *col
* l
)) 0)))
252 ;; PUT DELTA INTO THE DIAGONAL MATRIX
253 (setq delta
(aref ax
(aref *row
* rank
) (aref *col
* rank
)))
256 (setf (aref ax
(aref *row
* i
) (aref *col
* i
)) delta
)) )
258 ;;RECOVER THE ORDER OF ROWS AND COLUMNS.
260 (defun recoverorder1 ()
262 (do ((i nvar
(1- i
)))
264 (setq variableorder
(cons i variableorder
)))
265 (do ((i (1+ rank
) (1+ i
)))
267 (cond ((equal (aref ax
(aref *row
* i
) (aref *col
* m
)) 0)
268 (setq dependentrows
(cons (aref *row
* i
) dependentrows
)))
269 (t (setq inconsistentrows
(cons (aref *row
* i
) inconsistentrows
)))))
272 (cond ((not (= (aref *row
* (aref *colinv
* i
)) i
))
277 (setq k
(aref *row
* (aref *colinv
* l
)))
278 (setf (aref *row
* (aref *colinv
* l
)) l
)
279 (cond ((= k i
) (moverow ax n m
0 l
))
280 (t (moverow ax n m k l
)
284 (defun recoverorder2 ()
285 (do ((i nvar
(1- i
)))
287 (setq variableorder
(cons (aref *col
* i
) variableorder
)))
288 (do ((i (1+ rank
) (1+ i
)))
290 (cond ((equal (aref ax
(aref *row
* i
) (aref *col
* m
)) 0)
291 (setq dependentrows
(cons (aref *row
* i
) dependentrows
)))
292 (t (setq inconsistentrows
(cons (aref *row
* i
) inconsistentrows
)))))
295 (cond ((not (= (aref *row
* i
) i
))
300 (setq k
(aref *row
* l
))
301 (setf (aref *row
* l
) l
)
302 (cond ((= k i
) (moverow ax n m
0 l
))
303 (t (moverow ax n m k l
)
308 (cond ((not (= (aref *col
* i
) i
))
313 (setq k
(aref *col
* l
))
314 (setf (aref *col
* l
) l
)
315 (cond ((= k i
) (movecol ax n m
0 l
))
316 (t (movecol ax n m k l
)
320 ;;THIS PROGRAM IS USED IN REARRANGEMENT
321 (defun moverow (ax n m i j
)
322 (do ((k 1 (1+ k
))) ((> k m
))
323 (setf (aref ax j k
) (aref ax i k
))))
325 (defun movecol (ax n m i j
)
326 (do ((k 1 (1+ k
))) ((> k n
))
327 (setf (aref ax k j
) (aref ax k i
))))
329 ;;COMPLEXITY IS DEFINED AS FOLLOWS
331 ;; COMPLEXITY(CONSTANT)=1
332 ;; COMPLEXITY(POLYNOMIAL)=1+SUM(COMPLEXITY(C(N))+COMPLEXITY(E(N)), FOR N=0,1 ...M)
333 ;; WHERE POLYNOMIAL IS OF THE FORM
334 ;; SUM(C(N)*X^E(N), FOR N=0,1 ... M) X IS THE VARIABLE
336 (defun complexity (exp)
340 (t (+ (complexity (car exp
)) (complexity (cdr exp
))))))
342 (defun complexity/row
(ax i j1 j2
)
343 (do ((j j1
(1+ j
)) (sum 0))
345 (incf sum
(complexity (aref ax
(aref *row
* i
) (aref *col
* j
))))))
347 (defun complexity/col
(ax j i1 i2
)
348 (do ((i i1
(1+ i
)) (sum 0))
350 (incf sum
(complexity (aref ax
(aref *row
* i
) (aref *col
* j
))))))
352 (defun zerop/row
(ax i j1 j2
)
355 (cond ((not (equal (aref ax
(aref *row
* i
) (aref *col
* j
)) 0)) (return nil
)))))
357 ;;PIVOTTING ALGORITHM
358 (defun pivot (ax k
*cpivot
)
359 (prog (row/optimal col
/optimal complexity
/i
/min complexity
/j
/min
360 complexity
/i complexity
/j complexity
/det complexity
/det
/min dummy
)
361 (setq row
/optimal k complexity
/i
/min
1000000. complexity
/j
/min
1000000.
)
362 ;;TEST THE SINGULARITY
363 (cond ((do ((i k
(1+ i
)) (isallzero t
))
364 ((> i nrow
) isallzero
)
365 loop
(cond ((zerop/row ax i k nvar
)
366 (cond (*inv
* (merror (intl:gettext
"solve: singular matrix.")))
367 (t (exchangerow i nrow
)
369 (unless (> i nrow
) (go loop
)))
370 (t (setq isallzero nil
))))
373 ;; FIND AN OPTIMAL ROW
374 ;; IF *CPIVOT IS NIL, (AX I K) WHICH IS TO BE THE PIVOT MUST BE NONZERO.
375 ;; BUT IF *CPIVOT IS T, IT IS UNNECESSARY BECAUSE WE CAN DO THE COLUMN PIVOT.
379 (cond ((or *cpivot
(not (equal (aref ax
(aref *row
* i
) (aref *col
* k
)) 0)))
380 (cond ((> complexity
/i
/min
381 (setq complexity
/i
(complexity/row ax i k m
)))
382 (setq row
/optimal i complexity
/i
/min complexity
/i
))))))
383 ;; EXCHANGE THE ROWS K AND ROW/OPTIMAL
384 (exchangerow k row
/optimal
)
386 ;; IF THE FLAG *CPIVOT IS NIL, THE FOLLOWING STEPS ARE NOT EXECUTED.
387 ;; THIS TREATMENT WAS DONE FOR THE LSA AND ECHELONTHINGS WHICH ARE NOT
388 ;; HAPPY WITH THE COLUMN OPERATIONS.
389 (cond ((null *cpivot
)
390 (cond ((not (equal (aref ax
(aref *row
* k
) (aref *col
* k
)) 0))
392 (t (do ((i k
(1+ i
))) ((= i nvar
))
393 (setf (aref *col
* i
) (aref *col
* (1+ i
))))
394 (setq nvar
(1- nvar
) m
(1- m
))
397 ;;STEP3 ... FIND THE OPTIMAL COLUMN
399 complexity
/det
/min
1000000.
400 complexity
/j
/min
1000000.
)
404 (cond ((not (equal (aref ax
(aref *row
* k
) (aref *col
* j
)) 0))
405 (cond ((> complexity
/det
/min
407 (complexity (aref ax
(aref *row
* k
) (aref *col
* j
)))))
409 complexity
/det
/min complexity
/det
410 complexity
/j
/min
(complexity/col ax j
(1+ k
) n
)))
411 ((equal complexity
/det
/min complexity
/det
)
412 (cond ((> complexity
/j
/min
414 (complexity/col ax j
(1+ k
) n
)))
416 complexity
/det
/min complexity
/det
417 complexity
/j
/min complexity
/j
))))))))
419 ;; EXCHANGE THE COLUMNS K AND COL/OPTIMAL
420 (exchangecol k col
/optimal
)
421 (setq dummy
(aref *colinv
* (aref *col
* k
)))
422 (setf (aref *colinv
* (aref *col
* k
)) (aref *colinv
* (aref *col
* col
/optimal
)))
423 (setf (aref *colinv
* (aref *col
* col
/optimal
)) dummy
)
426 (defun exchangerow (i j
)
428 (setq dummy
(aref *row
* i
))
429 (setf (aref *row
* i
) (aref *row
* j
))
430 (setf (aref *row
* j
) dummy
)
431 (cond ((= i j
) (return nil
))
432 (t (setq permsign
(not permsign
))))))
434 (defun exchangecol (i j
)
436 (setq dummy
(aref *col
* i
))
437 (setf (aref *col
* i
) (aref *col
* j
))
438 (setf (aref *col
* j
) dummy
)
439 (cond ((= i j
) (return nil
))
440 (t (setq permsign
(not permsign
))))))
442 ;; Displays list of solutions.
444 (defun solve2 (llist)
445 (setq $multiplicities nil
)
446 (map2c #'(lambda (equatn multipl
)
448 (nconc equations
(list (displine equatn
))))
449 (push multipl $multiplicities
)
450 (if (and (> multipl
1) $dispflag
)
451 (mtell (intl:gettext
"solve: multiplicity ~A~%") multipl
)))
453 (setq $multiplicities
(cons '(mlist simp
) (nreverse $multiplicities
))))
455 ;; Displays an expression and returns its linelabel.
457 (defmfun displine
(exp)
458 (let ($nolabels
(tim 0))
460 (cond ($dispflag
(remprop *linelabel
* 'nodisp
)
461 (setq tim
(get-internal-run-time))
463 (displa (list '(mlabel) *linelabel
* exp
))
465 (t (putprop *linelabel
* t
'nodisp
)))
468 (declare-top (unspecial permsign a rank delta nrow nvar n m variableorder
469 dependentrows inconsistentrows l k
))