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 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
13 (macsyma-module csimp2
)
15 (load-macsyma-macros rzmac
)
17 (declare-top (special var sign
))
19 (defmvar $gammalim
10000
20 "Controls simplification of gamma for rational number arguments.")
22 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
24 ;;; Implementation of the plog function
26 (def-simplifier plog
(x)
27 (prog (varlist dd y z
)
29 (merror (intl:gettext
"plog: plog(0) is undefined.")))
31 ;; This is used in DEFINT. 1/19/81. -JIM
33 ;; In particular, this is the call to KEYHOLE in ZTORAT
34 ;; for an integral like integrate(1/(x^2+x+1),x,0,inf).
35 ;; Without this, the integral is computed incorrectly.
37 ;; FIXME: We should be doing this.
41 ((and (member '$%i varlist
)
42 (not (some #'(lambda (v)
43 (and (atom v
) (not (eq v
'$%i
))))
45 (setq dd
(trisplit x
))
46 (cond ((setq z
(patan (car dd
) (cdr dd
)))
47 (return (add2* (ftake '%log
48 (power ($expand
(add* (power (car dd
) 2)
55 ((and (equal ($imagpart x
) 0)
56 (setq y
($asksign x
)))
58 (return (ftake '%log x
)))
59 ((and plogabs
(eq y
'$neg
))
60 (return (ftake '%log
(list '(mtimes) -
1 x
))))
63 (ftake '%log
(mul -
1 x
)))))
64 (t (merror (intl:gettext
"plog: plog(0) is undefined.")))))
65 ((and (equal ($imagpart
(setq z
(div* x
'$%i
))) 0)
66 (setq y
($asksign z
)))
69 (merror (intl:gettext
"plog: plog(0) is undefined.")))
70 (t (cond ((eq y
'$pos
)
74 (return (add2* (ftake '%log
(mul y z
))
75 (mul y
1//2 '$%i
'$%pi
)))))))
79 (let (($numer $numer
))
81 (setq i
(simplifya i nil
) r
(simplifya r nil
))
83 (if (floatp i
) (setq $numer t
))
85 (cond ((equal i
'$pos
) (return (simplify half%pi
)))
87 (return (mul2 -
1 (simplify half%pi
))))
88 (t (merror (intl:gettext
"plog: encountered atan(0/0).")))))
90 (cond ((floatp r
) (setq $numer t
)))
92 (cond ((equal r
'$pos
) (return 0))
93 ((equal r
'$neg
) (return (simplify '$%pi
)))
94 (t (merror (intl:gettext
"plog: encountered atan(0/0).")))))
95 ((and (among '%cos r
) (among '%sin i
))
96 ;; genvar and varlist, used by the rational function system,
97 ;; are bound in order to prevent the symbol 'xz from leaking
98 ;; out of this function.
99 (let ((var 'xz
) genvar varlist
)
101 (cond ((and (eq (caar nn
*) '%cos
) (eq (caar dn
*) '%sin
))
102 (return (cadr nn
*)))))))
103 (setq a
($sign r
) b
($sign i
))
104 (cond ((eq a
'$pos
) (setq a
1))
105 ((eq a
'$neg
) (setq a -
1))
106 ((eq a
'$zero
) (setq a
0)))
107 (cond ((eq b
'$pos
) (setq b
1))
108 ((eq b
'$neg
) (setq b -
1))
109 ((eq a
'$zero
) (setq b
0)))
111 (return (if (equal a
1) 0 (simplify '$%pi
))))
113 (return (cond ((equal b
1) (simplify half%pi
))
114 (t (mul2 '((rat simp
) -
1 2)
115 (simplify '$%pi
)))))))
116 (setq r
(simptimes (list '(mtimes) a b
(div* i r
)) 1 nil
))
117 (return (cond ((onep1 r
)
118 (archk a b
(list '(mtimes) '((rat) 1 4) '$%pi
)))
119 ((alike1 r
'((mexpt) 3 ((rat) 1 2)))
120 (archk a b
(list '(mtimes) '((rat) 1 3) '$%pi
)))
121 ((alike1 r
'((mexpt) 3 ((rat) -
1 2)))
122 (archk a b
(list '(mtimes) '((rat) 1 6) '$%pi
))))))))
124 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
126 ;;; Implementation of the Binomial coefficient
128 ;; Binomial has Mirror symmetry
129 (defprop %binomial t commutes-with-conjugate
)
131 (def-simplifier binomial
(u v
)
135 (if (and (integerp u
) (minusp u
) (< v u
))
138 ((or (zerop v
) (equal u v
)) 1)
139 ((and (integerp u
) (not (minusp u
)))
140 (bincomp u
(min v
(- u v
))))
142 ((integerp (setq y
(sub u v
)))
144 ;; u and v are equal, simplify not if argument can be negative
145 (if (member ($csign u
) '($pnz $pn $neg $nz
))
149 ((complex-float-numerical-eval-p u v
)
150 ;; Numercial evaluation for real and complex floating point numbers.
151 (let (($numer t
) ($float t
))
154 ($makegamma
(list '(%binomial
) ($float u
) ($float v
)))))))
155 ((complex-bigfloat-numerical-eval-p u v
)
156 ;; Numerical evaluation for real and complex bigfloat numbers.
159 ($makegamma
(list '(%binomial
) ($bfloat u
) ($bfloat v
))))))
165 ((mnump u
) (binocomp u v
))
166 (t (muln (bincomp1 u v
) nil
))))
168 (defun bincomp1 (u v
)
171 (list* u
(list '(mexpt) v -
1) (bincomp1 (add2 -
1 u
) (1- v
)))))
173 (defun binocomp (u v
)
176 loop
(if (zerop v
) (return ans
))
177 (setq ans
(timesk (timesk u ans
) (simplify (list '(rat) 1 v
))))
178 (setq u
(addk -
1 u
) v
(1- v
))
181 ;;; gradient of binomial
185 ((mtimes) -
1 ((%binomial
) a b
)
188 ((mqapply) (($psi array
) 0) ((mplus) 1 a
)))
189 ((mqapply) (($psi array
) 0)
190 ((mplus) 1 a
((mtimes) -
1 b
)))))
192 ((mtimes) -
1 ((%binomial
) a b
)
195 ((mqapply) (($psi array
) 0)
196 ((mplus) 1 a
((mtimes) -
1 b
))))
197 ((mqapply) (($psi array
) 0) ((mplus) 1 b
))))) grad
)
199 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
201 ;;; Implementation of the Beta function
203 (declare-top (special $gammalim
))
205 (defmvar $beta_args_sum_to_integer nil
)
207 ;;; The Beta function has mirror symmetry
208 (defprop %beta t commutes-with-conjugate
)
210 (def-simplifier beta
(u v
)
212 (cond ((or (zerop1 u
) (zerop1 v
))
216 (intl:gettext
"beta: expected nonzero arguments; found ~M, ~M")
219 ;; Check for numerical evaluation in float precision
220 ((complex-float-numerical-eval-p u v
)
222 ;; We use gamma(u)*gamma(v)/gamma(u+v) for numerical evaluation.
223 ;; Therefore u, v or u+v can not be a negative integer or a
224 ;; floating point representation of a negative integer.
225 ((and (or (not (numberp u
))
227 (not (= (nth-value 1 (truncate u
)) 0)))
228 (and (or (not (numberp v
))
230 (not (= (nth-value 1 (truncate v
)) 0)))
231 (and (or (not (numberp (add u v
)))
233 (not (= (nth-value 1 ($truncate
(add u v
))) 0))))))
236 (add ($log_gamma
($float u
))
237 ($log_gamma
($float v
))
238 (mul -
1 ($log_gamma
($float
(add u v
))))))))
239 ((or (and (numberp u
)
241 (= (nth-value 1 (truncate u
)) 0)
243 (eq ($sign
(sub ($truncate v
) v
)) '$zero
)
245 (eq ($sign
(add u v
)) '$pos
)))
246 (setq u
(truncate u
)))
249 (= (nth-value 1 (truncate u
)) 0)
251 (eq ($sign
(sub ($truncate u
) u
)) '$zero
)
253 (eq ($sign
(add u v
)) '$pos
)))
254 (setq v
(truncate v
))))
255 ;; One value is representing a negative integer, the other a
256 ;; positive integer and the sum is negative. Expand.
257 ($rectform
($float
(beta-expand-integer u v
))))
261 ;; Check for numerical evaluation in bigfloat precision
262 ((complex-bigfloat-numerical-eval-p u v
)
263 (let (($ratprint nil
))
265 ((and (or (not (mnump u
))
267 (not (eq ($sign
(sub ($truncate u
) u
)) '$zero
)))
270 (not (eq ($sign
(sub ($truncate v
) v
)) '$zero
)))
271 (or (not (mnump (add u v
)))
272 (eq ($sign
(add u v
)) '$pos
)
273 (not (eq ($sign
(sub ($truncate
(add u v
))
278 (add ($log_gamma
($bfloat u
))
279 ($log_gamma
($bfloat v
))
280 (mul -
1 ($log_gamma
($bfloat
(add u v
))))))))
283 (eq ($sign
(sub ($truncate u
) u
)) '$zero
)
285 (eq ($sign
(sub ($truncate v
) v
)) '$zero
)
287 (eq ($sign
(add u v
)) '$pos
)))
288 (setq u
($truncate u
)))
291 (eq ($sign
(sub ($truncate v
) v
)) '$zero
)
293 (eq ($sign
(sub ($truncate u
) u
)) '$zero
)
295 (eq ($sign
(add u v
)) '$pos
)))
296 (setq v
($truncate v
))))
297 ($rectform
($bfloat
(beta-expand-integer u v
))))
301 ((or (and (and (integerp u
)
304 (eq ($sign
(sub ($truncate v
) v
)) '$zero
)
306 (eq ($sign
(add u v
)) '$pos
))))
307 (and (and (integerp v
)
310 (eq ($sign
(sub ($truncate u
) u
)) '$zero
)
312 (eq ($sign
(add u v
)) '$pos
)))))
313 ;; Expand for a positive integer. But not if the other argument is
314 ;; a negative integer and the sum of the integers is not negative.
315 (beta-expand-integer u v
))
317 ;;; At this point both integers are negative. This code does not work for
318 ;;; negative integers. The factorial function is not defined.
319 ; ((and (integerp u) (integerp v))
320 ; (mul2* (div* (list '(mfactorial) (1- u))
321 ; (list '(mfactorial) (+ u v -1)))
322 ; (list '(mfactorial) (1- v))))
324 ((or (and (ratnump u
) (ratnump v
) (integerp (setq x
(addk u v
))))
325 (and $beta_args_sum_to_integer
326 (integerp (setq x
(expand1 (add2 u v
) 1 1)))))
327 (let ((w (if (symbolp v
) v u
)))
330 (add2 (1- x
) (neg w
))
332 `((%sin
) ((mtimes) ,w $%pi
)))))
334 ((and $beta_expand
(mplusp u
) (integerp (cadr u
)))
335 ;; Expand beta(a+n,b) where n is an integer.
337 (u (simplify (cons '(mplus) (cddr u
)))))
338 (beta-expand-add-integer n u v
)))
340 ((and $beta_expand
(mplusp v
) (integerp (cadr v
)))
341 ;; Expand beta(a,b+n) where n is an integer.
343 (v (simplify (cons '(mplus) (cddr v
)))))
344 (beta-expand-add-integer n v u
)))
348 (defun beta-expand-integer (u v
)
349 ;; One of the arguments is a positive integer. Do an expansion.
350 ;; BUT for a negative integer as second argument the expansion is only
351 ;; possible when the sum of the integers is negative too.
352 ;; This routine expects that the calling routine has checked this.
359 (sub (if (and (integerp u
) (plusp u
)) u v
) 1))))
362 (defun beta-expand-add-integer (n u v
)
364 (mul (simplify (list '($pochhammer
) u n
))
365 (power (simplify (list '($pochhammer
) (add u v
) n
)) -
1)
367 (mul (simplify (list '($pochhammer
) (add u v n
) (- n
)))
368 (power (simplify (list '($pochhammer
) (add u n
) (- n
))) -
1)
369 (ftake* '%beta u v
))))
371 ;; Derivative of beta function
372 ;; https://en.wikipedia.org/wiki/Beta_function
373 ;; https://functions.wolfram.com/GammaBetaErf/Beta/
380 ((mqapply) (($psi array
) 0) a
)
382 ((mqapply) (($psi array
) 0) ((mplus) a b
)))))
387 ((mqapply) (($psi
) 0) b
)
389 ((mqapply) (($psi array
) 0) ((mplus) a b
))))))
392 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
394 ;;; Implementation of the Gamma function
396 (def-simplifier gamma
(j)
397 (cond ((and (floatp j
)
400 (zerop (nth-value 1 (truncate j
))))))
401 (merror (intl:gettext
"gamma: gamma(~:M) is undefined.") j
))
402 ((float-numerical-eval-p j
) (gammafloat ($float j
)))
405 (and (eq ($sign j
) '$neg
)
406 (zerop1 (sub j
($truncate j
))))))
407 (merror (intl:gettext
"gamma: gamma(~:M) is undefined.") j
))
408 ((bigfloat-numerical-eval-p j
)
409 ;; Adding 4 digits in the call to bffac. For $fpprec up to about 256
410 ;; and an argument up to about 500.0 the accuracy of the result is
411 ;; better than 10^(-$fpprec).
412 (let ((z (bigfloat:to
($bfloat j
))))
414 ((bigfloat:<= (bigfloat:abs z
) (bigfloat:sqrt
(bigfloat:epsilon z
)))
415 ;; For small z, use gamma(z) = gamma(z+1)/z = z!/z
416 (div (mfuncall '$bffac
421 (let ((result (mfuncall '$bffac
(m+ ($bfloat j
) -
1) (+ $fpprec
4))))
422 ;; bigfloatp will round the result to the correct fpprec
423 (bigfloatp result
))))))
424 ((complex-float-numerical-eval-p j
)
425 (complexify (gamma-lanczos (complex ($float
($realpart j
))
426 ($float
($imagpart j
))))))
427 ((complex-bigfloat-numerical-eval-p j
)
428 (let ((z (bigfloat:to
($bfloat j
))))
430 ((bigfloat:<= (bigfloat:abs z
)
431 (bigfloat:sqrt
(bigfloat:epsilon z
)))
432 ;; For small z, use gamma(z) = gamma(z+1)/z = z!/z
433 (to (bigfloat:/ (bigfloat:to
(mfuncall '$cbffac
438 ;; Adding 4 digits in the call to cbffac. See comment above.
441 (add -
1 ($bfloat
($realpart j
))
442 (mul '$%i
($bfloat
($imagpart j
))))
444 (add (bigfloatp ($realpart result
))
445 (mul '$%i
(bigfloatp ($imagpart result
)))))))))
446 ((taylorize (mop form
) (cadr form
)))
447 ((eq j
'$inf
) '$inf
) ; Simplify to $inf to be more consistent.
451 ;; Expand gamma(z+n) for n an integer.
453 (z (simplify (cons '(mplus) (cddr j
)))))
456 (mul (simplify (list '($pochhammer
) z n
))
457 (simplify (list '(%gamma
) z
))))
460 (div (mul (power -
1 n
) (simplify (list '(%gamma
) z
)))
461 ;; We factor to get the order (z-1)*(z-2)*...
462 ;; and not (1-z)*(2-z)*...
464 (simplify (list '($pochhammer
) (sub 1 z
) n
))))))))
467 (cond ((<= j $factlim
)
468 ;; Positive integer less than $factlim. Evaluate.
469 (simplify (list '(mfactorial) (1- j
))))
470 ;; Positive integer greater $factlim. Noun form.
472 ;; Negative integer. Throw a Maxima error.
473 (errorsw (throw 'errorsw t
))
474 (t (merror (intl:gettext
"gamma: gamma(~:M) is undefined.") j
))))
475 ((alike1 j
'((rat) 1 2))
476 (list '(mexpt simp
) '$%pi j
))
478 (ratgreaterp $gammalim
(simplify (list '(mabs) j
)))
479 (or (ratgreaterp j
1) (ratgreaterp 0 j
)))
480 ;; Expand for rational numbers less than $gammalim.
484 ;; A sign function for gamma(x); when x > 0 return pos; when x < 0 or x > 0, return pn;
485 ;;; otherwise, return pnz (that is, nothing known).
486 (defun gamma-sign (x)
487 (let ((sgn ($csign
(second x
)))) ;; careful! x = ((%gamma) XXX)
489 (cond ((eql sgn
'$pos
) '$pos
)
490 ((or (eql sgn
'$neg
) (eql sgn
'$pn
)) '$pn
)
493 (putprop '%gamma
'gamma-sign
'sign-function
)
495 (defun gamma (y) ;;; numerical evaluation for 0 < y < 1
497 (setq coefs
(list 0.035868343 -
0.193527817 0.48219939
498 -
0.75670407 0.91820685 -
0.89705693
499 0.98820588 -
0.57719165))
500 (unless (atom y
) (setq y
(fpcofrat y
)))
501 (setq sum
(car coefs
) coefs
(cdr coefs
))
502 loop
(setq sum
(+ (* sum y
) (car coefs
)))
503 (when (setq coefs
(cdr coefs
)) (go loop
))
504 (return (+ (/ y
) sum
))))
506 (defun gammared (a) ;A is assumed to
507 (prog (m q n
) ;be '((RAT) M N)
508 (cond ((floatp a
) (return (gammafloat a
))))
509 (setq m
(cadr a
) ;Numerator
510 n
(caddr a
) ;denominator
511 q
(abs (truncate m n
))) ;integer part
513 (setq q
(1+ q
) m
(+ m
(* n q
)))
515 (simptimes (list '(mtimes)
517 (ftake* '%gamma
(list '(rat) m n
))
518 (list '(mexpt) (gammac m n q
) -
1))
521 (return (m* (gammac m n q
)
522 (ftake* '%gamma
(list '(rat) (rem m n
) n
))
525 (defun gammac (m n q
)
528 (setq q
(1- q
) m
(- m n
) ans
(* m ans
))))
531 ;; This implementation is based on Lanczos convergent formula for the
532 ;; gamma function for Re(z) > 0. We can use the reflection formula
534 ;; -z*Gamma(z)*Gamma(-z) = pi/sin(pi*z)
536 ;; to handle the case of Re(z) <= 0.
538 ;; See http://my.fit.edu/~gabdo/gamma.m for some matlab code to
539 ;; compute this and http://my.fit.edu/~gabdo/gamma.txt for a nice
540 ;; discussion of Lanczos method and an improvement of Lanczos method.
543 ;; The document says this should give about 15 digits of accuracy for
544 ;; double-precision IEEE floats. The document also indicates how to
545 ;; compute a new set of coefficients if you need more range or
548 (defun gamma-lanczos (z)
549 (declare (type (complex flonum
) z
)
550 (optimize (safety 3)))
551 (let ((c (make-array 15 :element-type
'flonum
553 '(0.99999999999999709182
554 57.156235665862923517
555 -
59.597960355475491248
556 14.136097974741747174
557 -
0.49191381609762019978
558 .33994649984811888699e-4
559 .46523628927048575665e-4
560 -
.98374475304879564677e-4
561 .15808870322491248884e-3
562 -
.21026444172410488319e-3
563 .21743961811521264320e-3
564 -
.16431810653676389022e-3
565 .84418223983852743293e-4
566 -
.26190838401581408670e-4
567 .36899182659531622704e-5))))
568 (declare (type (simple-array flonum
(15)) c
))
570 ((minusp (realpart z
))
571 ;; Use the reflection formula
572 ;; -z*Gamma(z)*Gamma(-z) = pi/sin(pi*z)
574 ;; Gamma(z) = pi/z/sin(pi*z)/Gamma(-z)
576 ;; If z is a negative integer, Gamma(z) is infinity. Should
577 ;; we test for this? Throw an error?
578 ;; The test must be done by the calling routine.
580 (* (- z
) (sin (* (float pi
) z
))
581 (gamma-lanczos (- z
)))))
582 ((<= (abs z
) (sqrt +flonum-epsilon
+))
583 ;; For |z| small, use Gamma(z) = Gamma(z+1)/z
584 (/ (gamma-lanczos (+ 1 z
))
592 (pp (1- (length c
)) (1- pp
)))
595 (incf sum
(/ (aref c pp
) (+ z pp
))))))
597 ;; We check for an overflow. The last positive value in
598 ;; double-float precicsion for which Maxima can calculate
599 ;; gamma is ~171.6243 (CLISP 2.46 and GCL 2.6.8)
601 (let ((zp (expt zgh
(/ zh
2))))
602 (* (sqrt (float (* 2 pi
)))
604 (* (/ zp
(exp zgh
)) zp
))))))
606 ;; No result. Overflow.
607 (merror (intl:gettext
"gamma: overflow in GAMMA-LANCZOS.")))
608 ((or (float-nan-p (realpart result
))
609 (float-inf-p (realpart result
)))
610 ;; Result, but beyond extreme values. Overflow.
611 (merror (intl:gettext
"gamma: overflow in GAMMA-LANCZOS.")))
614 (defun gammafloat (a)
617 ;; Reflection formula to make it positive: gamma(x) =
618 ;; %pi/sin(%pi*x)/x/gamma(-x)
620 (* a
(sin (* (float pi
) a
)))
622 ((<= a
(sqrt +flonum-epsilon
+))
623 ;; Use gamma(x) = gamma(1+x)/x when x is very small
624 (/ (gammafloat (+ 1 a
))
630 (let ((c (* (sqrt (* 2 (float pi
)))
631 (exp (slatec::d9lgmc a
)))))
632 (let ((v (expt a
(- (* .5e0 a
) 0.25e0
))))
636 (if (or (float-nan-p result
)
637 (float-inf-p result
))
638 (merror (intl:gettext
"gamma: overflow in GAMMAFLOAT."))
641 (defmfun $zeromatrix
(m n
) ($ematrix m n
0 1 1))
643 (defmfun $ematrix
(m n var i j
)
645 (cond ((equal m
0) (return (ncons '($matrix simp
))))
646 ((and (equal n
0) (fixnump m
) (> m
0))
647 (return (cons '($matrix simp
) (list-of-mlists m
))))
648 ((not (and (fixnump m
) (fixnump n
)
649 (fixnump i
) (fixnump j
)
650 (> m
0) (> n
0) (> i
0) (> j
0)))
651 (merror (intl:gettext
"ematrix: arguments must be positive integers; found ~M")
652 (list '(mlist simp
) m n i j
) )))
653 loop
(cond ((= m i
) (setq row
(onen j n var
0)) (go on
))
654 ((zerop m
) (return (cons '($matrix
) (mxc ans
)))))
656 (do ((n n
(1- n
))) ((zerop n
)) (setq row
(cons 0 row
)))
657 on
(setq ans
(cons row ans
) m
(1- m
))
660 (defun list-of-mlists (n)
662 (l nil
(cons (ncons '(mlist simp
)) l
)))
665 (defmfun $coefmatrix
(eql varl
) (coefmatrix eql varl nil
))
667 (defmfun $augcoefmatrix
(eql varl
) (coefmatrix eql varl t
))
669 (defun coefmatrix (eql varl ind
)
670 (prog (ans row a b elem
)
671 (if (not ($listp eql
)) (improper-arg-err eql
'$coefmatrix
))
672 (if (not ($listp varl
)) (improper-arg-err varl
'$coefmatrix
))
673 (dolist (v (cdr varl
))
674 (if (and (not (atom v
)) (member (caar v
) '(mplus mtimes
) :test
#'eq
))
675 (merror (intl:gettext
"coefmatrix: variables cannot be '+' or '*' expressions; found ~M") v
)))
676 (setq eql
(nreverse (mapcar #'meqhk
(cdr eql
)))
677 varl
(reverse (cdr varl
)))
678 loop1
(if (null eql
) (return (cons '($matrix
) (mxc ans
))))
679 (setq a
(car eql
) eql
(cdr eql
) row nil
)
680 (if ind
(setq row
(cons (const1 a varl
) row
)))
682 loop2
(setq elem
(ratcoef a
(car b
)))
683 (setq row
(cons (if $ratmx elem
(ratdisrep elem
)) row
))
684 (if (setq b
(cdr b
)) (go loop2
))
685 (setq ans
(cons row ans
))
688 (defun const1 (e varl
)
689 (dolist (v varl
) (setq e
(maxima-substitute 0 v e
))) e
)
691 (defmfun $entermatrix
(rows columns
)
692 (prog (row column vector matrix sym symvector
)
693 (cond ((or (not (fixnump rows
))
694 (not (fixnump columns
)))
695 (merror (intl:gettext
"entermatrix: arguments must be integers; found ~M, ~M") rows columns
)))
697 (unless (= rows columns
) (setq sym nil
) (go oloop
))
698 quest
(format t
"~%Is the matrix 1. Diagonal 2. Symmetric 3. Antisymmetric 4. General~%")
699 (setq sym
(retrieve "Answer 1, 2, 3 or 4 : " nil
))
700 (unless (member sym
'(1 2 3 4)) (go quest
))
701 oloop
(cond ((> (incf row
) rows
)
702 (format t
"~%Matrix entered.~%")
703 (return (cons '($matrix
) (mxc matrix
)))))
706 (let ((prompt (format nil
"Row ~a Column ~a: " row column
)))
709 (ncons (onen row columns
710 (meval (retrieve prompt nil
)) 0)))))
713 (setq column
(1- row
))
714 (cond ((equal row
1) (go iloop
)))
716 (cons (nthcdr column vector
) symvector
)
717 vector
(nreverse (mapcar 'car symvector
))
718 symvector
(mapcar 'cdr symvector
))
722 (cond ((equal row
1) (setq vector
(ncons 0)) (go iloop
)))
724 (cons (mapcar #'neg
(nthcdr (1- column
) vector
))
726 vector
(nreconc (mapcar 'car symvector
) (ncons 0))
727 symvector
(mapcar 'cdr symvector
))
729 (setq column
0 vector nil
)
730 iloop
(cond ((> (incf column
) columns
)
731 (setq matrix
(nconc matrix
(ncons vector
)))
733 (let ((prompt (format nil
"Row ~a Column ~a: " row column
)))
734 (setq vector
(nconc vector
(ncons (meval (retrieve prompt nil
))))))
737 (declare-top (special sn
* sd
* rsn
*))
741 ((mtimesp e
) (muln (mapcar '$xthru
(cdr e
)) nil
))
742 ((mplusp e
) (simplify (comdenom (mapcar '$xthru
(cdr e
)) t
)))
743 ((mexptp e
) (power ($xthru
(cadr e
)) (caddr e
)))
744 ((mbagp e
) (cons (car e
) (mapcar '$xthru
(cdr e
))))
747 (defun comdenom (l ind
)
750 (setq n
(m*l sn
*) sn
* nil
)
751 (setq d
(m*l sd
*) sd
* nil
)
752 loop
(setq l
(cdr l
))
754 (return (cond (ind (div* (cond (rsn* ($ratsimp n
))
759 (setq d
(comdenom1 n d
(m*l sn
*) (m*l sd
*)))
764 (defun prodnumden (e)
765 (cond ((atom e
) (prodnd (list e
)))
766 ((eq (caar e
) 'mtimes
) (prodnd (cdr e
)))
767 (t (prodnd (list e
)))))
772 (setq sn
* nil sd
* nil
)
773 loop
(cond ((null l
) (return nil
)))
775 (cond ((atom e
) (setq sn
* (cons e sn
*)))
777 (cond ((not (equal 1 (cadr e
)))
778 (setq sn
* (cons (cadr e
) sn
*))))
779 (setq sd
* (cons (caddr e
) sd
*)))
780 ((and (eq (caar e
) 'mexpt
)
782 (setq sd
* (cons (power (cadr e
)
783 (timesk -
1 (caddr e
)))
785 (t (setq sn
* (cons e sn
*))))
789 (defun comdenom1 (a b c d
)
791 (prodnumden (div* b d
))
792 (setq b1
(m*l sn
*) sn
* nil
)
793 (setq c1
(m*l sd
*) sd
* nil
)
795 (list (add2 (m* a c1
) (m* c b1
))
798 (declare-top (special ax
801 (defun xrutout (ax n m varl ind
)
802 (let (($linsolve_params
(and $backsubst $linsolve_params
)))
803 (prog (ix imin ans zz m-1 sol tim chk zzz
)
804 (setq ax
(get-array-pointer ax
) tim
0)
805 (if $linsolve_params
(setq $%rnum_list
(list '(mlist))))
806 (setq imin
(min (setq m-1
(1- m
)) n
))
807 (setq ix
(max imin
(length varl
)))
808 loop
(if (zerop ix
) (if ind
(go out
) (return (cons '(mlist) zz
))))
809 (when (or (> ix imin
) (equal (car (aref ax ix ix
)) 0))
811 (rform (if $linsolve_params
(make-param) (ith varl ix
))))
812 (if $linsolve_params
(go saval
) (go next
)))
813 (setq ans
(aref ax ix m
))
814 (setf (aref ax ix m
) nil
)
815 (do ((j (1+ ix
) (1+ j
)))
817 (setq ans
(ratdif ans
(rattimes (aref ax ix j
) (aref ax
0 j
) t
)))
818 (setf (aref ax ix j
) nil
))
819 (setf (aref ax
0 ix
) (ratquotient ans
(aref ax ix ix
)))
820 (setf (aref ax ix ix
) nil
)
822 saval
(push (cond (*mosesflag
(aref ax
0 ix
))
823 (t (list (if $globalsolve
'(msetq) '(mequal))
825 (simplify (rdis (aref ax
0 ix
))))))
828 (setf (aref ax
0 ix
) (rform (ith varl ix
))))
829 (and $globalsolve
(meval (car zz
)))
833 (cond ($dispflag
(mtell (intl:gettext
"Solution:~%"))))
834 (setq sol
(list '(mlist)) chk
(checklabel $linechar
))
835 (do ((ll zz
(cdr ll
)))
838 (setq zzz
(list '(mlabel)
843 (let (($nolabels nil
))
844 (makelabel $linechar
))
846 (setf (symbol-value *linelabel
*) zzz
)))
847 (nconc sol
(ncons *linelabel
*))
849 (setq tim
(get-internal-run-time))
850 (mtell-open "~%~M" zzz
)
853 (putprop *linelabel
* t
'nodisp
))))