;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; The data in this file contains enhancments. ;;;;; ;;; ;;;;; ;;; Copyright (c) 1984,1987 by William Schelter,University of Texas ;;;;; ;;; All rights reserved ;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; (c) Copyright 1982 Massachusetts Institute of Technology ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (in-package "MAXIMA") (macsyma-module mat) (COMMENT THIS IS THE MAT PACKAGE) (DECLARE-TOP(SPECIAL PIVSIGN* *ECH* *TRI* LSOLVEFLAG $ALGEBRAIC $MULTIPLICITIES EQUATIONS MUL* FORMATFORM DOSIMP $DISPFLAG $RATFAC *TB $NOLABELS ERRRJFFLAG *DET* GENVAR XM* XN* VARLIST AX LINELABLE $LINECHAR $LINENUM SOL) (*LEXPR $SOLVE $RAT) (ARRAY* (NOTYPE XA* 2)) (FIXNUM TIM) (GENPREFIX MAT)) ;;these are arrays. (DECLARE-TOP(SPECIAL *ROW* *COL* *COLINV*)) ;; The array declarations of ROW, COL, and COLINV aren't having any ;; effect on the Lisp Machine. Should be fixed somehow. ;(DECLARE (ARRAY* (FIXNUM *ROW* 1 *COL* 1 *COLINV* 1))) (DEFMVAR $GLOBALSOLVE NIL) (DEFMVAR $SPARSE NIL) (DEFMVAR $BACKSUBST T) (DEFMVAR *RANK* NIL) (DEFMVAR *INV* NIL) (DEFVAR SOLVEXP NIL) (DEFUN SOLCOEF (M *C VARL FLAG) (PROG (CC ANSWER LEFTOVER) (SETQ CC (CDR (RATREP* *C))) (IF (OR (ATOM (CAR CC)) (NOT (EQUAL (CDAR CC) '(1 1))) (NOT (EQUAL 1 (CDR CC)))) (MERROR "Unacceptable variable to SOLVE:~%~M" *C)) (SETQ ANSWER (RATREDUCE (PRODCOEF (CAR CC) (CAR M)) (CDR M))) (IF (NOT FLAG) (RETURN ANSWER)) (SETQ LEFTOVER (RDIS (RATPLUS M (RATTIMES (RATMINUS ANSWER) CC T)))) (IF (OR (NOT (FREEOF *C LEFTOVER)) (DEPENDSALL (RDIS ANSWER) VARL)) (ERRRJF "NON-LINEAR")) (RETURN ANSWER))) (DEFUN FORMX (FLAG NAM EQL VARL) (PROG (B AX X IX J) (SETQ VARLIST VARL) (MAPC #'NEWVAR EQL) (AND (NOT $ALGEBRAIC) (ORMAPC #'ALGP VARLIST) (SETQ $ALGEBRAIC T)) (SET NAM (*ARRAY nil t (f1+ (SETQ XN* (LENGTH EQL))) (f1+ (SETQ XM* (f1+ (LENGTH VARL)))))) (SETQ NAM (GET-ARRAY-POINTER NAM)) (SETQ IX 0) LOOP1 (COND ((NULL EQL) (RETURN VARLIST))) (SETQ AX (CAR EQL)) (SETQ EQL (CDR EQL)) (SETQ IX (f1+ IX)) (STORE (aref NAM IX XM*) (CONST AX VARL)) (SETQ J 0) (SETQ B VARL) (SETQ AX (CDR (RATREP* AX))) LOOP2 (SETQ X (CAR B)) (SETQ B (CDR B)) (SETQ J (f1+ J)) (STORE (aref NAM IX J) (SOLCOEF AX X VARL FLAG)) (COND (B (GO LOOP2))) (GO LOOP1))) (DEFUN DEPENDSALL (EXP L) (COND ((NULL L) NIL) ((OR (NOT (FREEOF (CAR L) EXP)) (DEPENDSALL EXP (CDR L))) T) (T NIL))) (SETQ *DET* NIL *ECH* NIL *TRI* NIL) (DEFUN PTORAT (AX M N) (PROG (I J) (SETQ AX (GET-ARRAY-POINTER AX)) (SETQ I (f1+ M) N (f1+ N)) LOOP1 (COND ((EQUAL I 1) (RETURN NIL))) (SETQ I (f1- I) J N) LOOP2 (COND ((EQUAL J 1) (GO LOOP1))) (SETQ J (f1- J)) (STORE (AREF AX I J) (CONS (AREF AX I J) 1)) (GO LOOP2))) (DEFUN MEQHK (Z) (COND ((AND (NOT (ATOM Z)) (EQ (CAAR Z) 'MEQUAL)) (SIMPLUS (LIST '(MPLUS) (CADR Z) (LIST '(MTIMES) -1 (CADDR Z))) 1 NIL)) (T Z))) (DEFUN CONST (E VARL) (PROG (ZL) (SETQ VARL (MAPCAR (FUNCTION (LAMBDA(X) (CAADR (RATREP* X)))) VARL)) (SETQ E (CDR(RATREP* E))) (SETQ ZL (NZEROS (LENGTH VARL) NIL)) (RETURN (RATREDUCE (PCTIMES -1 (PCSUBSTY ZL VARL (CAR E))) (PCSUBSTY ZL VARL (CDR E)))))) (DEFVAR *MOSESFLAG NIL) (DEFMVAR $%RNUM 0) (DEFMFUN MAKE-PARAM () (LET ((PARAM (CONCAT '$%R (SETQ $%RNUM (f1+ $%RNUM))))) (TUCHUS $%RNUM_LIST PARAM) PARAM)) (DEFMVAR $LINSOLVE_PARAMS T "LINSOLVE generates %Rnums") ;(DECLARE (FIXNUM N)) (DEFUN NCDR (X N) (NTHCDR (f1- N) X)) (DEFUN ITH (X N) (COND ((ATOM X) NIL) (T (CAR (NCDR X N))))) ;(DECLARE (NOTYPE N)) (DEFUN POLYIZE (AX R M MUL) (DECLARE (FIXNUM M)) (DO ((C 1 (f1+ C)) (D)) ((> C M) NIL) (DECLARE (FIXNUM C)) (SETQ D (AREF AX R C)) (SETQ D (COND ((EQUAL MUL 1) (CAR D)) (T (PTIMES (CAR D) (PQUOTIENTCHK MUL (CDR D)))))) (STORE (AREF AX R C) (IF $SPARSE (CONS D 1) D)))) ; TWO-STEP FRACTION-FREE GAUSSIAN ELIMINATION ROUTINE (DEFUN TFGELI (AX N M &AUX ($SPARSE (AND $SPARSE (OR *DET* *INV*)))) ;;$sparse is also controlling whether polyize stores polys or ratforms (SETQ AX (GET-ARRAY-POINTER AX)) (SETQ MUL* 1) (DO ((R 1 (f1+ R))) ((> R N) (COND ((AND $SPARSE *DET*)(SPRDET AX N)) ((AND *INV* $SPARSE)(NEWINV AX N M)) (T (TFGELI1 AX N M)))) (DO ((C 1 (f1+ C)) (D) (MUL 1)) ((> C M) (AND *DET* (SETQ MUL* (PTIMES MUL* MUL))) (POLYIZE AX R M MUL)) (COND ((EQUAL 1 (SETQ D (CDR (AREF AX R C)))) NIL) (T (SETQ MUL (PTIMES MUL (PQUOTIENT D (PGCD MUL D))))))))) (SETQ LSOLVEFLAG NIL) ;; The author of the following programs is Tadatoshi Minamikawa (TM). ;; This program is one-step fraction-free Gaussian elimination with ;; optimal pivotting. DRB claims the hair in this program is not ;; necessary and that straightforward Gaussian elimination is sufficient, ;; for sake of future implementors. ;; To debug, delete the comments around PRINT and BREAK statements. (DECLARE-TOP(SPECIAL PERMSIGN A RANK DELTA NROW NVAR N M VARIABLEORDER DEPENDENTROWS INCONSISTENTROWS L K) ;; We could just use fortran, you know. (FIXNUM NROW NVAR RANK I J K L M N)) (DEFUN TFGELI1 (AX N M) (PROG (K L DELTA VARIABLEORDER INCONSISTENTROWS DEPENDENTROWS NROW NVAR RANK PERMSIGN RESULT) (#-cl *ARRAY #+cl cl-*array '*ROW* 'fixnum (f1+ N)) (#-cl *ARRAY #+cl cl-*array '*COL* 'fixnum (f1+ M)) (#-cl *ARRAY #+cl cl-*array '*COLINV* 'fixnum (f1+ M)) ; #+LISPM (FILLARRAY (FUNCTION ROW) '(0)) ;implicit in *array ; #+LISPM (FILLARRAY (FUNCTION COL) '(0)) ; #+LISPM (FILLARRAY (FUNCTION COLINV) '(0)) (SETQ AX (GET-ARRAY-POINTER AX)) (setq *COL* (GET-ARRAY-POINTER *COL*)) (setq *ROW* (GET-ARRAY-POINTER *ROW*)) (setq *COLINV* (get-array-pointer *COLINV*)) ;; (PRINT 'ONESTEP-LIPSON-WITH-PIVOTTING) (SETQ NROW N) (SETQ NVAR (COND (*RANK* M) (*DET* M) (*INV* N) (*ECH* M) (*TRI* M) (T (f1- M)))) (DO ((I 1 (f1+ I))) ((> I N)) (STORE (AREF *ROW* I) I)) (DO ((I 1 (f1+ I))) ((> I M)) (STORE (AREF *COL* I) I) (STORE (AREF *COLINV* I) I)) (SETQ RESULT (COND (*RANK* (FORWARD T) RANK) (*DET* (FORWARD T) (COND ((= NROW N) (COND (PERMSIGN (PMINUS DELTA)) (T DELTA))) (T 0))) (*INV* (FORWARD T) (BACKWARD) (RECOVERORDER1)) (*ECH* (FORWARD NIL) (RECOVERORDER2)) (*TRI* (FORWARD NIL) (RECOVERORDER2)) (T (FORWARD T) (COND ($BACKSUBST (BACKWARD))) (RECOVERORDER2) (LIST DEPENDENTROWS INCONSISTENTROWS VARIABLEORDER)))) (*REARRAY '*ROW*) (*REARRAY '*COL*) (*REARRAY '*COLINV*) (RETURN RESULT))) ;FORWARD ELIMINATION ;IF THE SWITCH *CPIVOT IS NIL, IT AVOIDS THE COLUMN PIVOTTING. (DEFUN FORWARD (*CPIVOT) (SETQ DELTA 1) ;DELTA HOLDS THE CURRENT DETERMINANT (DO ((K 1 (f1+ K)) (NVAR NVAR) ;PROTECTS AGAINST TEMPORARAY RESETS DONE IN PIVOT (M M)) ((OR (> K NROW) (> K NVAR))) (COND ((PIVOT AX K *CPIVOT) (RETURN NIL))) ;; PIVOT IS T IF THERE IS NO MORE NON-ZERO ROW LEFT. THEN GET OUT OF THE LOOP (DO ((I (f1+ K) (f1+ I))) ((> I NROW)) (DO ((J (f1+ K) (f1+ J))) ((> J M)) (STORE ( AREF AX (AREF *ROW* I) (AREF *COL* J)) (PQUOTIENT (PDIFFERENCE (PTIMES ( AREF AX (AREF *ROW* K) (AREF *COL* K)) (AREF AX (AREF *ROW* I) (AREF *COL* J))) (PTIMES ( AREF AX (AREF *ROW* I) (AREF *COL* K)) ( AREF AX (AREF *ROW* K) (AREF *COL* J)))) DELTA)))) (DO ((I (f1+ K) (f1+ I))) ((> I NROW)) (STORE ( AREF AX (AREF *ROW* I) (AREF *COL* K)) 0)) (SETQ DELTA ( AREF AX (AREF *ROW* K) (AREF *COL* K)))) ;; UNDOES COLUMN HACK IN PIVOT. (OR *CPIVOT (DO ((I 1 (f1+ I))) ((> I M)) (STORE (AREF *COL* I) I))) (SETQ RANK (MIN NROW NVAR))) ; BACKWARD SUBSTITUTION (DEFUN BACKWARD () (DO ((I (f1- RANK) (f1- I))) ((< I 1)) (DO ((L (f1+ RANK) (f1+ L))) ((> L M)) (STORE (AREF AX (AREF *ROW* I) (AREF *COL* L)) (PQUOTIENT (PDIFFERENCE (PTIMES (AREF AX (AREF *ROW* I) (AREF *COL* L)) (AREF AX (AREF *ROW* RANK) (AREF *COL* RANK))) (DO ((J (f1+ I) (f1+ J)) (SUM 0)) ((> J RANK) SUM) (SETQ SUM (PPLUS SUM (PTIMES (AREF AX (AREF *ROW* I) (AREF *COL* J)) (AREF AX (AREF *ROW* J) (AREF *COL* L))))))) (AREF AX (AREF *ROW* I) (AREF *COL* I))))) (DO ((L (f1+ I) (f1+ L))) ((> L RANK)) (STORE (AREF AX (AREF *ROW* I) (AREF *COL* L)) 0))) ;; PUT DELTA INTO THE DIAGONAL MATRIX (SETQ DELTA (AREF AX (AREF *ROW* RANK) (AREF *COL* RANK))) (DO ((I 1 (f1+ I))) ((> I RANK)) (STORE (AREF AX (AREF *ROW* I) (AREF *COL* I)) DELTA))) ;RECOVER THE ORDER OF ROWS AND COLUMNS. (DEFUN RECOVERORDER1 () ;;(PRINT 'REARRANGE) (DO ((I NVAR (f1- I))) ((= I 0)) (SETQ VARIABLEORDER (CONS I VARIABLEORDER))) (DO ((I (f1+ RANK) (f1+ I))) ((> I N)) (COND ((EQUAL (AREF AX (AREF *ROW* I) (AREF *COL* M)) 0) (SETQ DEPENDENTROWS (CONS (AREF *ROW* I) DEPENDENTROWS))) (T (SETQ INCONSISTENTROWS (CONS (AREF *ROW* I) INCONSISTENTROWS))))) (DO ((I 1 (f1+ I))) ((> I N)) (COND ((NOT (= (AREF *ROW* (AREF *COLINV* I)) I)) (PROG () (MOVEROW AX N M I 0) (SETQ L I) LOOP (SETQ K (AREF *ROW* (AREF *COLINV* L))) (STORE (AREF *ROW* (AREF *COLINV* L)) L) (COND ((= K I) (MOVEROW AX N M 0 L)) (T (MOVEROW AX N M K L) (SETQ L K) (GO LOOP)))))))) (DEFUN RECOVERORDER2 () (DO ((I NVAR (f1- I))) ((= I 0)) (SETQ VARIABLEORDER (CONS (AREF *COL* I) VARIABLEORDER))) (DO ((I (f1+ RANK) (f1+ I))) ((> I N)) (COND ((EQUAL (AREF AX (AREF *ROW* I) (AREF *COL* M)) 0) (SETQ DEPENDENTROWS (CONS (AREF *ROW* I) DEPENDENTROWS))) (T (SETQ INCONSISTENTROWS (CONS (AREF *ROW* I) INCONSISTENTROWS))))) (DO ((I 1 (f1+ I))) ((> I N)) (COND ((NOT (= (AREF *ROW* I) I)) (PROG () (MOVEROW AX N M I 0) (SETQ L I) LOOP (SETQ K (AREF *ROW* L)) (STORE (AREF *ROW* L) L) (COND ((= K I) (MOVEROW AX N M 0 L)) (T (MOVEROW AX N M K L) (SETQ L K) (GO LOOP))))))) (DO ((I 1 (f1+ I))) ((> I NVAR)) (COND ((NOT (= (AREF *COL* I) I)) (PROG () (MOVECOL AX N M I 0) (SETQ L I) LOOP2 (SETQ K (AREF *COL* L)) (STORE (AREF *COL* L) L) (COND ((= K I) (MOVECOL AX N M 0 L)) (T (MOVECOL AX N M K L) (SETQ L K) (GO LOOP2)))))))) ;THIS PROGRAM IS USED IN REARRANGEMENT (DEFUN MOVEROW (AX N M I J) (DO ((K 1 (f1+ K))) ((> K M)) (STORE (AREF AX J K) (AREF AX I K)))) (DEFUN MOVECOL (AX N M I J) (DO ((K 1 (f1+ K))) ((> K N)) (STORE (AREF AX K J) (AREF AX K I)))) ;COMPLEXITY IS DEFINED AS FOLLOWS ; COMPLEXITY(0)=0 ; COMPLEXITY(CONSTANT)=1 ; COMPLEXITY(POLYNOMIAL)=1+SUM(COMPLEXITY(C(N))+COMPLEXITY(E(N)), FOR N=0,1 ...M) ; WHERE POLYNOMIAL IS OF THE FORM ; SUM(C(N)*X^E(N), FOR N=0,1 ... M) X IS THE VARIABLE (DEFUN COMPLEXITY (EXP) (COND ((NULL EXP) 0) ((EQUAL EXP 0) 0) ((ATOM EXP) 1) (T (PLUS (COMPLEXITY (CAR EXP)) (COMPLEXITY (CDR EXP)))))) (DEFUN COMPLEXITY/ROW (AX I J1 J2) (DO ((J J1 (f1+ J)) (SUM 0)) ((> J J2) SUM) (SETQ SUM (PLUS SUM (COMPLEXITY (AREF AX (AREF *ROW* I) (AREF *COL* J))))))) (DEFUN COMPLEXITY/COL (AX J I1 I2) (DO ((I I1 (f1+ I)) (SUM 0)) ((> I I2) SUM) (SETQ SUM (PLUS SUM (COMPLEXITY (AREF AX (AREF *ROW* I) (AREF *COL* J))))))) (DEFUN ZEROP/ROW (AX I J1 J2) (DO ((J J1 (f1+ J))) ((> J J2) T) (COND ((NOT (EQUAL (AREF AX (AREF *ROW* I) (AREF *COL* J)) 0)) (RETURN NIL))))) ;PIVOTTING ALGORITHM (DEFUN PIVOT (AX K *CPIVOT) (PROG ( ROW/OPTIMAL COL/OPTIMAL COMPLEXITY/I/MIN COMPLEXITY/J/MIN COMPLEXITY/I COMPLEXITY/J COMPLEXITY/DET COMPLEXITY/DET/MIN DUMMY) (SETQ ROW/OPTIMAL K COMPLEXITY/I/MIN 1000000. COMPLEXITY/J/MIN 1000000.) ;;TEST THE SINGULARITY (COND ((DO ((I K (f1+ I)) (ISALLZERO T)) ((> I NROW) ISALLZERO) LOOP (COND ((ZEROP/ROW AX I K NVAR) (COND (*INV* (MERROR "Singular")) (T (EXCHANGEROW I NROW) (SETQ NROW (f1- NROW)))) (COND ((NOT (> I NROW)) (GO LOOP)))) (T (SETQ ISALLZERO NIL)))) (RETURN T))) ;; FIND AN OPTIMAL ROW ;; IF *CPIVOT IS NIL, (AX I K) WHICH IS TO BE THE PIVOT MUST BE NONZERO. ;; BUT IF *CPIVOT IS T, IT IS UNNECESSARY BECAUSE WE CAN DO THE COLUMN PIVOT. FINDROW (DO ((I K (f1+ I))) ((> I NROW)) (COND ((OR *CPIVOT (NOT (EQUAL (AREF AX (AREF *ROW* I) (AREF *COL* K)) 0))) (COND ((> COMPLEXITY/I/MIN (SETQ COMPLEXITY/I (COMPLEXITY/ROW AX I K M))) (SETQ ROW/OPTIMAL I COMPLEXITY/I/MIN COMPLEXITY/I)))))) ;; EXCHANGE THE ROWS K AND ROW/OPTIMAL (EXCHANGEROW K ROW/OPTIMAL) ;; IF THE FLAG *CPIVOT IS NIL, THE FOLLOWING STEPS ARE NOT EXECUTED. ;; THIS TREATMENT WAS DONE FOR THE LSA AND ECHELONTHINGS WHICH ARE NOT ;; HAPPY WITH THE COLUMN OPERATIONS. (COND ((NULL *CPIVOT) (COND ((NOT (EQUAL (AREF AX (AREF *ROW* K) (AREF *COL* K)) 0)) (RETURN NIL)) (T (DO ((I K (f1+ I))) ((= I NVAR)) (STORE (AREF *COL* I) (AREF *COL* (f1+ I)))) (SETQ NVAR (f1- NVAR) M (f1- M)) (GO FINDROW))))) ;;STEP3 ... FIND THE OPTIMAL COLUMN (SETQ COL/OPTIMAL 0 COMPLEXITY/DET/MIN 1000000. COMPLEXITY/J/MIN 1000000.) (DO ((J K (f1+ J))) ((> J NVAR)) (COND ((NOT (EQUAL (AREF AX (AREF *ROW* K) (AREF *COL* J)) 0)) (COND ((> COMPLEXITY/DET/MIN (SETQ COMPLEXITY/DET (COMPLEXITY (AREF AX (AREF *ROW* K) (AREF *COL* J))))) (SETQ COL/OPTIMAL J COMPLEXITY/DET/MIN COMPLEXITY/DET COMPLEXITY/J/MIN (COMPLEXITY/COL AX J (f1+ K) N))) ((EQUAL COMPLEXITY/DET/MIN COMPLEXITY/DET) (COND ((> COMPLEXITY/J/MIN (SETQ COMPLEXITY/J (COMPLEXITY/COL AX J (f1+ K) N))) (SETQ COL/OPTIMAL J COMPLEXITY/DET/MIN COMPLEXITY/DET COMPLEXITY/J/MIN COMPLEXITY/J)))))))) ;(COND ((ZEROP COL/OPTIMAL) (COMMENT (PRINT '"SINGULAR!")))) ;; EXCHANGE THE COLUMNS K AND COL/OPTIMAL (EXCHANGECOL K COL/OPTIMAL) (SETQ DUMMY (AREF *COLINV* (AREF *COL* K))) (STORE (AREF *COLINV* (AREF *COL* K)) (AREF *COLINV* (AREF *COL* COL/OPTIMAL))) (STORE (AREF *COLINV* (AREF *COL* COL/OPTIMAL)) DUMMY) (RETURN NIL))) (DEFUN EXCHANGEROW (I J) (PROG (DUMMY) (SETQ DUMMY (AREF *ROW* I)) (STORE (AREF *ROW* I) (AREF *ROW* J)) (STORE (AREF *ROW* J) DUMMY) (COND ((= I J) (RETURN NIL)) (T (SETQ PERMSIGN (NOT PERMSIGN)))))) (DEFUN EXCHANGECOL (I J) (PROG (DUMMY) (SETQ DUMMY (AREF *COL* I)) (STORE (AREF *COL* I) (AREF *COL* J)) (STORE (AREF *COL* J) DUMMY) (COND ((= I J) (RETURN NIL)) (T (SETQ PERMSIGN (NOT PERMSIGN)))))) ;; Displays list of solutions. (DEFUN SOLVE2 (Llist) (SETQ $MULTIPLICITIES NIL) (MAP2C #'(LAMBDA (EQUATN MULTIPL) (SETQ EQUATIONS (NCONC EQUATIONS (LIST (DISPLINE EQUATN)))) (PUSH MULTIPL $MULTIPLICITIES) (IF (AND (> MULTIPL 1) $DISPFLAG) (MTELL "Multiplicity ~A~%" MULTIPL))) Llist) (SETQ $MULTIPLICITIES (CONS '(MLIST SIMP) (NREVERSE $MULTIPLICITIES)))) ;; Displays an expression and returns its linelabel. (DEFMFUN DISPLINE (EXP) (LET ($NOLABELS (TIM 0)) (ELABEL EXP) (COND ($DISPFLAG (REMPROP LINELABLE 'NODISP) (SETQ TIM (RUNTIME)) (MTERPRI) (DISPLA (LIST '(MLABLE) LINELABLE EXP)) (TIMEORG TIM)) (T (PUTPROP LINELABLE T 'NODISP))) LINELABLE))