1 ;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;; The data in this file contains enhancements. ;;;;;
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
*
27 (defun solcoef (m *c varl flag
)
28 (prog (cc answer leftover
)
29 (setq cc
(cdr (ratrep* *c
)))
30 (if (or (atom (car cc
))
31 (not (equal (cdar cc
) '(1 1)))
32 (not (equal 1 (cdr cc
))))
33 ;; NOTE TO TRANSLATORS: NOT CLEAR WHAT IS "UNACCEPTABLE" HERE
34 (merror (intl:gettext
"solve: unacceptable variable: ~M") *c
))
35 (setq answer
(ratreduce (prodcoef (car cc
) (car m
)) (cdr m
)))
36 (if (not flag
) (return answer
))
38 (rdis (ratplus m
(rattimes (ratminus answer
) cc t
))))
39 (if (or (not (freeof *c leftover
))
40 (dependsall (rdis answer
) varl
))
41 (rat-error "`non-linear'"))
44 (defun formx (flag nam eql varl
)
51 (setf (symbol-value nam
) (make-array (list (1+ (setq xn
* (length eql
)))
52 (1+ (setq xm
* (1+ (length varl
)))))))
53 (setq nam
(get-array-pointer nam
))
56 (cond ((null eql
) (return varlist
)))
60 (setf (aref nam ix xm
*) (const ax varl
))
62 (setq b varl
) (setq ax
(cdr (ratrep* ax
)))
67 (setf (aref nam ix j
) (solcoef ax x varl flag
))
71 (defun dependsall (exp l
)
73 ((or (not (freeof (car l
) exp
)) (dependsall exp
(cdr l
))) t
)
76 (setq *det
* nil
*ech
* nil
*tri
* nil
)
78 (defun ptorat (ax m n
)
80 (setq ax
(get-array-pointer ax
))
84 (when (equal i
1) (return nil
))
88 (when (equal j
1) (go loop1
))
90 (setf (aref ax i j
) (cons (aref ax i j
) 1))
94 "If Z is of the form lhs = rhs, return the expression lhs - rhs.
95 Otherwise, return Z unchanged."
96 (if (and (not (atom z
)) (eq (caar z
) 'mequal
))
97 (simplus (list '(mplus) (cadr z
) (list '(mtimes) -
1 (caddr z
))) 1 nil
)
100 (defun const (e varl
)
101 (setq varl
(mapcar #'(lambda(x) (caadr (ratrep* x
))) varl
))
102 (setq e
(cdr (ratrep* e
)))
103 (let ((zl (make-list (length varl
) :initial-element
0)))
104 (ratreduce (pctimes -
1 (pcsubsty zl varl
(car e
)))
105 (pcsubsty zl varl
(cdr e
)))))
107 (defvar *mosesflag nil
)
110 (let ((param (intern (format nil
"~A~D" '$%r
(incf $%rnum
)))))
111 (tuchus $%rnum_list param
)
115 (if (atom x
) nil
(nth (1- n
) x
)))
117 (defun polyize (ax r m mul
)
119 (do ((c 1 (1+ c
)) (d))
122 (setq d
(aref ax r c
))
123 (setq d
(cond ((equal mul
1) (car d
))
125 (pquotientchk mul
(cdr d
))))))
126 (setf (aref ax r c
) (if $sparse
(cons d
1) d
))))
128 ;; TWO-STEP FRACTION-FREE GAUSSIAN ELIMINATION ROUTINE
130 (defun tfgeli (ax n m
&aux
($sparse
(and $sparse
(or *det
* *inv
*))))
131 ;;$sparse is also controlling whether polyize stores polys or ratforms
132 (setq ax
(get-array-pointer ax
))
135 ((> r n
) (cond ((and $sparse
*det
*)(sprdet ax n
))
136 ((and *inv
* $sparse
)(newinv ax n m
))
137 (t (tfgeli1 ax n m
))))
142 (and *det
* (setq mul
* (ptimes mul
* mul
)))
143 (polyize ax r m mul
))
144 (cond ((equal 1 (setq d
(cdr (aref ax r c
)))) nil
)
145 (t (setq mul
(ptimes mul
(pquotient d
(pgcd mul d
)))))))))
147 ;; The author of the following programs is Tadatoshi Minamikawa (TM).
148 ;; This program is one-step fraction-free Gaussian elimination with
149 ;; optimal pivotting. DRB claims the hair in this program is not
150 ;; necessary and that straightforward Gaussian elimination is sufficient,
151 ;; for sake of future implementors.
153 ;; To debug, delete the comments around PRINT and BREAK statements.
155 (declare-top (special permsign a rank delta nrow nvar n m variableorder
156 dependentrows inconsistentrows l k
))
158 (defun tfgeli1 (ax n m
)
159 (prog (k l delta variableorder inconsistentrows
160 dependentrows nrow nvar rank permsign result
)
161 (setq ax
(get-array-pointer ax
))
162 (setq *col
* (make-array (1+ m
) :initial-element
0))
163 (setq *row
* (make-array (1+ n
) :initial-element
0))
164 (setq *colinv
* (make-array (1+ m
) :initial-element
0))
165 ;; (PRINT 'ONESTEP-LIPSON-WITH-PIVOTTING)
167 (setq nvar
(cond (*rank
* m
) (*det
* m
) (*inv
* n
) (*ech
* m
) (*tri
* m
) (t (1- m
))))
170 (setf (aref *row
* i
) i
))
173 (setf (aref *col
* i
) i
) (setf (aref *colinv
* i
) i
))
175 (cond (*rank
* (forward t
) rank
)
177 (cond ((= nrow n
) (cond (permsign (pminus delta
))
180 (*inv
* (forward t
) (backward) (recoverorder1))
181 (*ech
* (forward nil
) (recoverorder2))
182 (*tri
* (forward nil
) (recoverorder2))
183 (t (forward t
) (cond ($backsubst
(backward)))
185 (list dependentrows inconsistentrows variableorder
))))
188 ;;FORWARD ELIMINATION
189 ;;IF THE SWITCH *CPIVOT IS NIL, IT AVOIDS THE COLUMN PIVOTTING.
190 (defun forward (*cpivot
)
191 (setq delta
1) ;DELTA HOLDS THE CURRENT DETERMINANT
193 (nvar nvar
) ;PROTECTS AGAINST TEMPORARAY RESETS DONE IN PIVOT
195 ((or (> k nrow
) (> k nvar
)))
196 (cond ((pivot ax k
*cpivot
) (return nil
)))
197 ;; PIVOT IS T IF THERE IS NO MORE NON-ZERO ROW LEFT. THEN GET OUT OF THE LOOP
198 (do ((i (1+ k
) (1+ i
)))
200 (do ((j (1+ k
) (1+ j
)))
202 (setf (aref ax
(aref *row
* i
) (aref *col
* j
))
203 (pquotient (pdifference (ptimes (aref ax
(aref *row
* k
) (aref *col
* k
))
204 (aref ax
(aref *row
* i
) (aref *col
* j
)))
205 (ptimes (aref ax
(aref *row
* i
) (aref *col
* k
))
206 (aref ax
(aref *row
* k
) (aref *col
* j
))))
208 (do ((i (1+ k
) (1+ i
)))
210 (setf (aref ax
(aref *row
* i
) (aref *col
* k
)) 0))
211 (setq delta
(aref ax
(aref *row
* k
) (aref *col
* k
))))
212 ;; UNDOES COLUMN HACK IN PIVOT.
213 (or *cpivot
(do ((i 1 (1+ i
))) ((> i m
)) (setf (aref *col
* i
) i
)))
214 (setq rank
(min nrow nvar
)))
216 ;; BACKWARD SUBSTITUTION
218 (declare(special ax delta m rank
))
219 (do ((i (1- rank
) (1- i
)))
221 (do ((l (1+ rank
) (1+ l
)))
223 (setf (aref ax
(aref *row
* i
) (aref *col
* l
))
224 (let ((mess1 (pdifference
225 (ptimes (aref ax
(aref *row
* i
) (aref *col
* l
))
226 (aref ax
(aref *row
* rank
) (aref *col
* rank
)))
227 (do ((j (1+ i
) (1+ j
)) (sum 0))
229 (setq sum
(pplus sum
(ptimes (aref ax
(aref *row
* i
) (aref *col
* j
))
230 (aref ax
(aref *row
* j
) (aref *col
* l
))))))) )
231 (mess2 (aref ax
(aref *row
* i
) (aref *col
* i
)) ))
232 (cond ((equal 0 mess1
) 0)
234 (t ;; (pquotient mess1 mess2) ; fixed by line below. RJF 1/12/2017
236 (car (ratreduce mess1 mess2
))
239 (do ((l (1+ i
) (1+ l
)))
241 (setf (aref ax
(aref *row
* i
) (aref *col
* l
)) 0)))
242 ;; PUT DELTA INTO THE DIAGONAL MATRIX
243 (setq delta
(aref ax
(aref *row
* rank
) (aref *col
* rank
)))
246 (setf (aref ax
(aref *row
* i
) (aref *col
* i
)) delta
)) )
248 ;;RECOVER THE ORDER OF ROWS AND COLUMNS.
250 (defun recoverorder1 ()
252 (do ((i nvar
(1- i
)))
254 (setq variableorder
(cons i variableorder
)))
255 (do ((i (1+ rank
) (1+ i
)))
257 (cond ((equal (aref ax
(aref *row
* i
) (aref *col
* m
)) 0)
258 (setq dependentrows
(cons (aref *row
* i
) dependentrows
)))
259 (t (setq inconsistentrows
(cons (aref *row
* i
) inconsistentrows
)))))
262 (cond ((not (= (aref *row
* (aref *colinv
* i
)) i
))
267 (setq k
(aref *row
* (aref *colinv
* l
)))
268 (setf (aref *row
* (aref *colinv
* l
)) l
)
269 (cond ((= k i
) (moverow ax n m
0 l
))
270 (t (moverow ax n m k l
)
274 (defun recoverorder2 ()
275 (do ((i nvar
(1- i
)))
277 (setq variableorder
(cons (aref *col
* i
) variableorder
)))
278 (do ((i (1+ rank
) (1+ i
)))
280 (cond ((equal (aref ax
(aref *row
* i
) (aref *col
* m
)) 0)
281 (setq dependentrows
(cons (aref *row
* i
) dependentrows
)))
282 (t (setq inconsistentrows
(cons (aref *row
* i
) inconsistentrows
)))))
285 (cond ((not (= (aref *row
* i
) i
))
290 (setq k
(aref *row
* l
))
291 (setf (aref *row
* l
) l
)
292 (cond ((= k i
) (moverow ax n m
0 l
))
293 (t (moverow ax n m k l
)
298 (cond ((not (= (aref *col
* i
) i
))
303 (setq k
(aref *col
* l
))
304 (setf (aref *col
* l
) l
)
305 (cond ((= k i
) (movecol ax n m
0 l
))
306 (t (movecol ax n m k l
)
310 ;;THIS PROGRAM IS USED IN REARRANGEMENT
311 (defun moverow (ax n m i j
)
312 (do ((k 1 (1+ k
))) ((> k m
))
313 (setf (aref ax j k
) (aref ax i k
))))
315 (defun movecol (ax n m i j
)
316 (do ((k 1 (1+ k
))) ((> k n
))
317 (setf (aref ax k j
) (aref ax k i
))))
319 ;;COMPLEXITY IS DEFINED AS FOLLOWS
321 ;; COMPLEXITY(CONSTANT)=1
322 ;; COMPLEXITY(POLYNOMIAL)=1+SUM(COMPLEXITY(C(N))+COMPLEXITY(E(N)), FOR N=0,1 ...M)
323 ;; WHERE POLYNOMIAL IS OF THE FORM
324 ;; SUM(C(N)*X^E(N), FOR N=0,1 ... M) X IS THE VARIABLE
326 (defun complexity (exp)
330 (t (+ (complexity (car exp
)) (complexity (cdr exp
))))))
332 (defun complexity/row
(ax i j1 j2
)
333 (do ((j j1
(1+ j
)) (sum 0))
335 (incf sum
(complexity (aref ax
(aref *row
* i
) (aref *col
* j
))))))
337 (defun complexity/col
(ax j i1 i2
)
338 (do ((i i1
(1+ i
)) (sum 0))
340 (incf sum
(complexity (aref ax
(aref *row
* i
) (aref *col
* j
))))))
342 (defun zerop/row
(ax i j1 j2
)
345 (cond ((not (equal (aref ax
(aref *row
* i
) (aref *col
* j
)) 0)) (return nil
)))))
347 ;;PIVOTTING ALGORITHM
348 (defun pivot (ax k
*cpivot
)
349 (prog (row/optimal col
/optimal complexity
/i
/min complexity
/j
/min
350 complexity
/i complexity
/j complexity
/det complexity
/det
/min dummy
)
351 (setq row
/optimal k complexity
/i
/min
1000000. complexity
/j
/min
1000000.
)
352 ;;TEST THE SINGULARITY
353 (cond ((do ((i k
(1+ i
)) (isallzero t
))
354 ((> i nrow
) isallzero
)
355 loop
(cond ((zerop/row ax i k nvar
)
356 (cond (*inv
* (merror (intl:gettext
"solve: singular matrix.")))
357 (t (exchangerow i nrow
)
359 (unless (> i nrow
) (go loop
)))
360 (t (setq isallzero nil
))))
363 ;; FIND AN OPTIMAL ROW
364 ;; IF *CPIVOT IS NIL, (AX I K) WHICH IS TO BE THE PIVOT MUST BE NONZERO.
365 ;; BUT IF *CPIVOT IS T, IT IS UNNECESSARY BECAUSE WE CAN DO THE COLUMN PIVOT.
369 (cond ((or *cpivot
(not (equal (aref ax
(aref *row
* i
) (aref *col
* k
)) 0)))
370 (cond ((> complexity
/i
/min
371 (setq complexity
/i
(complexity/row ax i k m
)))
372 (setq row
/optimal i complexity
/i
/min complexity
/i
))))))
373 ;; EXCHANGE THE ROWS K AND ROW/OPTIMAL
374 (exchangerow k row
/optimal
)
376 ;; IF THE FLAG *CPIVOT IS NIL, THE FOLLOWING STEPS ARE NOT EXECUTED.
377 ;; THIS TREATMENT WAS DONE FOR THE LSA AND ECHELONTHINGS WHICH ARE NOT
378 ;; HAPPY WITH THE COLUMN OPERATIONS.
379 (cond ((null *cpivot
)
380 (cond ((not (equal (aref ax
(aref *row
* k
) (aref *col
* k
)) 0))
382 (t (do ((i k
(1+ i
))) ((= i nvar
))
383 (setf (aref *col
* i
) (aref *col
* (1+ i
))))
384 (setq nvar
(1- nvar
) m
(1- m
))
387 ;;STEP3 ... FIND THE OPTIMAL COLUMN
389 complexity
/det
/min
1000000.
390 complexity
/j
/min
1000000.
)
394 (cond ((not (equal (aref ax
(aref *row
* k
) (aref *col
* j
)) 0))
395 (cond ((> complexity
/det
/min
397 (complexity (aref ax
(aref *row
* k
) (aref *col
* j
)))))
399 complexity
/det
/min complexity
/det
400 complexity
/j
/min
(complexity/col ax j
(1+ k
) n
)))
401 ((equal complexity
/det
/min complexity
/det
)
402 (cond ((> complexity
/j
/min
404 (complexity/col ax j
(1+ k
) n
)))
406 complexity
/det
/min complexity
/det
407 complexity
/j
/min complexity
/j
))))))))
409 ;; EXCHANGE THE COLUMNS K AND COL/OPTIMAL
410 (exchangecol k col
/optimal
)
411 (setq dummy
(aref *colinv
* (aref *col
* k
)))
412 (setf (aref *colinv
* (aref *col
* k
)) (aref *colinv
* (aref *col
* col
/optimal
)))
413 (setf (aref *colinv
* (aref *col
* col
/optimal
)) dummy
)
416 (defun exchangerow (i j
)
418 (setq dummy
(aref *row
* i
))
419 (setf (aref *row
* i
) (aref *row
* j
))
420 (setf (aref *row
* j
) dummy
)
421 (cond ((= i j
) (return nil
))
422 (t (setq permsign
(not permsign
))))))
424 (defun exchangecol (i j
)
426 (setq dummy
(aref *col
* i
))
427 (setf (aref *col
* i
) (aref *col
* j
))
428 (setf (aref *col
* j
) dummy
)
429 (cond ((= i j
) (return nil
))
430 (t (setq permsign
(not permsign
))))))
432 ;; Displays list of solutions.
434 (defun solve2 (llist equations
)
435 (setq $multiplicities nil
)
436 (map2c #'(lambda (equatn multipl
)
438 (nconc equations
(list (displine equatn
))))
439 (push multipl $multiplicities
)
440 (if (and (> multipl
1) $dispflag
)
441 (mtell (intl:gettext
"solve: multiplicity ~A~%") multipl
)))
443 (values (setq $multiplicities
(cons '(mlist simp
) (nreverse $multiplicities
)))
446 ;; Displays an expression and returns its linelabel.
448 (defun displine (exp)
449 (let ($nolabels
(tim 0))
451 (cond ($dispflag
(remprop *linelabel
* 'nodisp
)
452 (setq tim
(get-internal-run-time))
454 (displa (list '(mlabel) *linelabel
* exp
))
456 (t (putprop *linelabel
* t
'nodisp
)))
459 (declare-top (unspecial permsign a rank delta nrow nvar n m variableorder
460 dependentrows inconsistentrows l k
))