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 ;;; **************************************************************
9 ;;; ***** HAYAT ******* Finite Power Series Routines *************
10 ;;; **************************************************************
11 ;;; ** (c) Copyright 1982 Massachusetts Institute of Technology **
12 ;;; ****** This is a read-only file! (All writes reserved) *******
13 ;;; **************************************************************
17 ;;; TOP LEVEL STRUCTURE
19 ;;; Power series have the following format when seen outside the power
22 ;;; ((MRAT SIMP <varlist> <genvar> <tlist> trunc) <poly-form>)
24 ;;; This is the form of the output of the expressions, to
25 ;;; be displayed they are RATDISREPed and passed to DISPLA.
27 ;;; The <poly-forms> consist of a header and list of exponent-coefficient
28 ;;; pairs as shown below. The PS is used to distinguish power series
29 ;;; from their coefficients which have a similar representation.
31 ;;; (PS (<var> . <ord-num>) (<trunc-lvl>)
32 ;;; (<exponent> . <coeff>) (<exponent> . <coeff>) . . .)
34 ;;; The <var> component of the power series is a gensym which represents the
35 ;;; kernel of the power series. If the package is called with the arguments:
36 ;;; Taylor(<expr>, x, a, n) then the kernel will be (x - a).
37 ;;; The <ord-num> is a relative ordering for the various kernels in a
38 ;;; multivariate expansion.
39 ;;; <trunc-lvl> is the highest degree of the variable <var> which is retained
40 ;;; in the current power series.
41 ;;; The terms in the list of exponent-coefficient pairs are ordered by
42 ;;; increasing degree.
44 ;;; Problem: fix expansion of logs so that taylor(log(1+exp(-1/x)),x,0,3)
47 ;;; Problem: taylor(log(1+exp(-1/x)),x,0,5) loses because, while
48 ;;; taylor_simplify_recurse'ing exp(-3/x) get trunc level = -3. FIxed.
50 ;;; Problem: Need to fix things so that asymptotic kernels aren't put onto
51 ;;; tvars via tlist merge etc. in taylor1. Done.
53 ;;; Problem: get-series returns 0 for taylor(log(1+exp(-1/x)),x,0,5) and
54 ;;; need to make log(exp(1/x)) -> 1/x. Fixed.
56 ;;; Problem: Fix psexpt-fn so that it doesn't lose via the invert-var
57 ;;; scheme, e.g. try taylor(exp(exp(-1/x)+x),x,0,5). Note that if it did
58 ;;; just that scheme. Done.
60 ;;; Problem: fix adjoin-tvar so that the new tvars are ordered correctly
61 ;;; according to their strength. This is necessary in order to read the limit
62 ;;; directly from the leading term. E.g. see the misordered:
63 ;;; taylor(subst(1/x,x,part(screw2,1)),x,0,2) from ALJABR;SCREW2 LIMIT.
64 ;;; Note that the answer given for this appear to be incorrect when the
65 ;;; truncation on x is < 4. Is this due to the misordering?
66 ;;; Also taylor(screwa,x,0,4)+taylor(screwb,x,0,8) doesn't agree with
67 ;;; taylor(screw,x,0,8) where it should (here screwa = part(screw,1),
68 ;;; screwb = part(screw, 2); is this a truncation problem on the
71 ;;; Problem: new gvars have to be intro'd for logs just as for exp's instead
72 ;;; of treating them like constants as currently done. For example,
73 ;;; taylor(log(1+1/log(x)),x,0,2) currently doesn't expand. Done.
75 ;;; Problem: The display routines need pieces of the taylor environment
76 ;;; (tvar-limits, tvars, tlist, etc.) to figure out how to order terms.
77 ;;; This means we'll probably have to store some of this on the local tlist.
78 ;;; When this is done the commented out code in psdisrep and psdisrep2 can
79 ;;; be re-inserted. Psdisrep2expand will also need to be modified.
80 ;;; I just fixed srdisrep to get the local env it needs; psdisrep2expand
81 ;;; still needs to be updated. The display order problem is still around
82 ;;; however: try taylor(exp(exp(-1/x)+x),x,0,3). After more investigation,
83 ;;; it seems that the term reversal always occurs for ps's that are coeff's
84 ;;; of terms whose expt is < 0. Probably the psdisrep routines should reverse
85 ;;; these terms to account for this (the bug is somewhere in the DISPLA
86 ;;; routines, possible DIM-MPLUS).
88 ;;; Problem: Since gvar's like exp(-1/x) can't be put on genvar, they have
89 ;;; to be saved somewhere locally and restored by everyone who needs to setup
90 ;;; disrep info etc. Done for re-taylor.
92 ;;; Problem: All new code needs to be checked to ensure it does the correct
93 ;;; thing when the expansion point is infinite (e.g. see the code in
94 ;;; TSEXPT-RED which handles this case).
96 ;;; Perhaps the code for exp's and log's which pushes trunc degrees
97 ;;; can be done by first computing exp(c0) or log(c0) first and see
98 ;;; how much to push by looking at this series. Done for exp in tsexpt-red.
100 ;;; Problems: taylor(part(screwa,2)-2/x,x,0,1) shouldn't be exact.
101 ;;; taylor(screwa,x,0,-2) misses the degree -2 term. This part is now fixed.
103 ;;; Tvar-limits should be stored locally so that psdisrep need not recompute
104 ;;; each gvar limit when disrepping.
106 (macsyma-module hayat
)
110 (defvar *within-srf?
* nil
)
112 (load-macsyma-macros mhayat rzmac ratmac
)
114 ;;; Subtitle Special Stuff for Compiling
118 *a
* ;Temporary special
119 tlist
;An association list which contains the
120 ;relevant information for the expansion which
121 ;is passed in at toplevel invocation.
122 log-1
;What log(-1) should be log(-1) or pi*i.
123 log%i
;Similarly for log(i)
124 exact-poly
;Inicates whether polynomials are to be
125 ;considered exact or not. True within SRF,
126 ;false within TAYLOR.
129 tay-const-expand
;For rediculousness like csch(log(x))
132 last-exp
;last-expression through taylor2
133 ivars
;Pairlist if gensym and disreped version
134 key-vars
;Pairlist of gensym and key var (for searching
140 *within-srf?
* ;flag for in srf
142 least_term?
; If non-null then the addition routines
143 ; are adding or subtracting coeff's of the
144 ; least term of a sum so they should do
145 ; zero checking on it if it is desired.
146 taylor_simplifier
; This is set by taylor1 to the object
147 ; which will be funcalled whenever
148 ; coefficient simplification is desired.
149 zerolist
; A list of constant expressions which have
150 ; been verified to be zero by a call to
151 ; $TAYLOR_SIMPLIFIER in taylor2. It is used to
152 ; suppress the message that TAYLOR is assuming
153 ; an expression to be zero.
154 ; 0p-funord lexp-non0 ; referenced only in commented-out code, so comment out here too
156 ) ;Don't want to see closed compilation notes.
158 (defmvar $psexpand
()
159 "When TRUE extended rational function expressions will be displayed fully
160 expanded. (RATEXPAND will also cause this.) If FALSE, multivariate
161 expressions will be displayed just as in the rational function package.
162 If PSEXPAND:MULTI, then terms with the same total degree in the variables
163 are grouped together.")
165 (defmvar $maxtayorder t
166 "When true TAYLOR retains as many terms as are certain to be correct
167 during power series arithmetic. Otherwise, truncation is controlled
168 by the arguments specified to TAYLOR.")
170 (defmvar $taylor_truncate_polynomials t
171 "When FALSE polynomials input to TAYLOR are considered to have infinite
172 precision; otherwise (the default) they are truncated based upon the input
175 (defmvar $taylor_logexpand t
176 "Unless FALSE log's of products will be expanded fully in TAYLOR (the default)
177 to avoid identically-zero constant terms which involve log's. When FALSE,
178 only expansions necessary to produce a formal series will be executed.")
180 (defmvar $taylor_simplifier
'simplify
181 "A function of one argument which TAYLOR uses to simplify coefficients
184 (defvar taylor_simplifier nil
)
186 ;;; Subtitle General Macsyma Free Predicates
189 (cond ((equal e x
) () )
192 (null (member x
(cdr ($listofvars e
)) :test
#'equal
)))
193 ('t
(do ((l (cdr e
) (cdr l
))) ((null l
) 't
)
194 (or (zfree (car l
) x
) (return () ))))))
196 (defun mfree (exp varl
)
197 (cond ((atom exp
) (not (member exp varl
:test
#'eq
)))
198 ((eq (caar exp
) 'mrat
)
199 (do ((l (mrat-varlist exp
) (cdr l
)))
201 (unless (mfree (car l
) varl
) (return () ))))
202 ((or (member (caar exp
) dummy-variable-operators
:test
#'eq
)
203 (member 'array
(cdar exp
) :test
#'eq
))
204 (do ((vars varl
(cdr vars
)))
206 (unless (freeof (car vars
) exp
) (return () ))))
207 ('t
(and (mfree (caar exp
) varl
) (mfreel (cdr exp
) varl
)))))
209 (defun mfreel (l varl
)
210 (or (null l
) (and (mfree (car l
) varl
) (mfreel (cdr l
) varl
))))
212 ;;; Subtitle Coefficient Arithmetic
215 (cond ((equal x
(rcone)) (rcone))
216 ((rczerop y
) (rcone))
217 ((and (equal (cdr y
) 1) (fixnump (car y
)))
219 ((and $radexpand
(numberp (car y
)) (numberp (cdr y
)))
221 (setq y
(maxima-rationalize (quot (car y
) (cdr y
)))))
222 (ratexpt (rcquo (rcexpt1 (car x
) (cdr y
))
223 (rcexpt1 (cdr x
) (cdr y
)))
226 (prep1 (m^
(rcdisrep x
) (rcdisrep y
)))))))
229 (cond ((equal p
1) (rcone))
230 ((pcoefp p
) (prep1 (m^
(pdis p
) (*red
1 n
))))
231 ;; psfr does a square-free decom on p yielding (p1 e1 p2 e2 ... pn en)
232 ;; where p = p1^e1 p2^e2 ... pn^en, the pi being square-free
233 (t (do ((l (psqfr p
) (cddr l
))
236 (if (not (equal (rem (cadr l
) n
) 0))
237 (setq ans
(rctimes ans
(prep1 (m^
(pdis (car l
))
238 (*red
(cadr l
) n
)))))
239 ;; If pi<0, n=2m and n|ei then ei=2e and
240 ;; (pi^ei)^(1/(2m)) = (-pi)^(e/m)
242 (when (and (evenp n
) (eq ($sign
(pdis (car l
))) '$neg
))
243 (rplaca l
(pminus (car l
))))
244 (setq ans
(rctimes ans
(ratexpt (cons (car l
) 1)
245 (truncate (cadr l
) n
))))))))))
247 (defun rccoefp (e) ;a sure check, but expensive
250 (member (caar e
) genvar
:test
#'eq
))
252 (member (cadr e
) genvar
:test
#'eq
))))
254 ;;; Subtitle Exponent arithmetic
257 (and (not (infp x
)) (signp e
(car x
))))
260 (cond ((or (infp x
) (infp y
)) (inf))
261 ((and (equal (cdr x
) 1) (equal (cdr y
) 1))
262 (cons (+ (car x
) (car y
)) 1))
263 (t (ereduce (+ (* (car x
) (cdr y
)) (* (cdr x
) (car y
)))
264 (* (cdr x
) (cdr y
))))))
267 (cond ((infp x
) (inf))
268 ((and (equal (cdr x
) 1) (equal (cdr y
) 1))
269 (cons (- (car x
) (car y
)) 1))
270 (t (ereduce (- (* (car x
) (cdr y
)) (* (cdr x
) (car y
)))
271 (* (cdr x
) (cdr y
))))))
276 ((equal (cdr x
) (cdr y
)) (cons (min (car x
) (car y
)) (cdr x
)))
277 ((< (* (car x
) (cdr y
)) (* (cdr x
) (car y
))) x
)
281 (cond ((or (infp x
) (infp y
)) (inf))
282 ((equal (cdr x
) (cdr y
)) (cons (max (car x
) (car y
)) (cdr x
)))
283 ((> (* (car x
) (cdr y
)) (* (cdr x
) (car y
))) x
)
287 (cond ((or (infp x
) (infp y
)) (inf))
288 ((and (equal (cdr x
) 1) (equal (cdr y
) 1))
289 (cons (* (car x
) (car y
)) 1))
290 (t (ereduce (* (car x
) (car y
)) (* (cdr x
) (cdr y
))))))
294 (cons (- (cdr e
)) (- (car e
)))
295 (cons (cdr e
) (car e
))))
298 (cond ((infp x
) (inf))
300 (t (ereduce (* (car x
) (cdr y
))
301 (* (cdr x
) (car y
))))))
304 (cond ((infp x
) (inf))
305 ((= (cdr x
) 1) (cons (1+ (car x
)) 1))
306 (t (cons (+ (cdr x
) (car x
)) (cdr x
)))))
309 (cond ((infp x
) (inf))
310 ((equal (cdr x
) 1) (cons (1- (car x
)) 1))
311 (t (cons (- (car x
) (cdr x
)) (cdr x
)))))
316 ((equal (cdr x
) (cdr y
)) (> (car x
) (car y
)))
317 (t (> (* (car x
) (cdr y
)) (* (car y
) (cdr x
))))))
321 ((or (null e1
) (null e2
)) ())
322 (t (and (equal (car e1
) (car e2
))
323 (equal (cdr e1
) (cdr e2
))))))
326 (if (signp l d
) (setq d
(- d
) n
(- n
)))
327 (if (zerop n
) (rczero)
328 (let ((gcd (gcd n d
)))
329 (cons (/ n gcd
) (/ d gcd
)))))
332 (let ((xn (abs (car x
))) (xd (cdr x
))
333 (yn (abs (car y
))) (yd (cdr y
)))
334 (cons (gcd xn yn
) (* xd
(/ yd
(gcd xd yd
))))))
336 ;;; Subtitle polynomial arithmetic
338 (declare-top (special vars
))
340 (defun ord-vector (p)
341 (let ((vars (mapcar #'(lambda (datum) (list (int-gvar datum
))) tlist
)))
342 (declare (special vars
))
343 (cond ((not (cdr vars
)) (ncons (ps-le* p
)))
344 (t (ord-vect1 p
) (mapcar #'(lambda (x) (or (cdr x
) (rczero))) vars
)))))
347 (declare (special vars
))
349 (let ((data (assoc (gvar p
) vars
:test
#'eq
))
351 (rplacd data
(cond ((not (cdr data
)) le
)
352 (t (emin (cdr data
) le
))))
353 (mapl #'(lambda (l) (ord-vect1 (lc l
))) (terms p
)))))
355 (defun trunc-vector (p min?
)
356 (let ((vars (mapcar #'(lambda (datum) (list (int-gvar datum
))) tlist
)))
357 (declare (special vars
))
358 (if (null (cdr vars
)) (ncons (if (psp p
) (trunc-lvl p
) () ))
361 (mapcar 'cdr vars
)))))
363 (defun trunc-vect1 (p min?
)
364 (declare (special vars
))
366 (let ((data (assoc (gvar p
) vars
:test
#'eq
))
367 (trunc (trunc-lvl p
)))
369 (rplacd data
(if (null (cdr data
)) trunc
370 (if min?
(emin (cdr data
) trunc
)
371 (emax (cdr data
) trunc
))))))
372 (dolist (term (terms p
))
373 (trunc-vect1 (c term
) min?
))))
375 (declare-top (unspecial vars
))
379 (cond ((pscoefp y
) (rcplus x y
))
382 ((pscoefp y
) (if (rczerop y
) x
(pscplus y x
)))
383 ((eqgvar (gvar-o x
) (gvar-o y
)) (psplus1 x y
))
384 ((pointerp (gvar-o x
) (gvar-o y
)) (pscplus y x
))
388 (if (not (and least_term? taylor_simplifier
)) (rcplus x y
)
389 (prep1 (funcall taylor_simplifier
(m+ (rcdisrep x
) (rcdisrep y
))))))
392 (cond ((pscoefp x
) (cond ((pscoefp y
) (rcdiff x y
))
393 ((rczerop x
) (pstimes (rcmone) y
))
394 (t (pscdiff x y
() ))))
395 ((pscoefp y
) (if (rczerop y
) x
(pscdiff y x t
)))
396 ((eqgvar (gvar-o x
) (gvar-o y
)) (psdiff1 x y
))
397 ((pointerp (gvar-o x
) (gvar-o y
)) (pscdiff y x t
))
398 (t (pscdiff x y
() ))))
401 (if (not (and least_term? taylor_simplifier
)) (rcdiff x y
)
402 (prep1 (funcall taylor_simplifier
(m- (rcdisrep x
) (rcdisrep y
))))))
405 (let ((ans (cons () () )))
406 (psplus2 (gvar-o x
) (emin (trunc-lvl x
) (trunc-lvl y
))
407 (cons 0 (terms x
)) (cons 0 (terms y
)) ans ans
)))
410 (if (e> (rczero) (trunc-lvl p
)) p
411 (pscheck (gvar-o p
) (poly-data p
) (pscplus1 c
(terms p
)))))
413 (defun pscdiff (c p fl
)
414 (if (e> (rczero) (trunc-lvl p
))
415 (if fl p
(psminus p
))
416 (pscheck (gvar-o p
) (poly-data p
)
417 (cond ((not fl
) (pscplus1 c
(psminus-terms (terms p
))))
418 (t (pscplus1 (psminus c
) (terms p
)))))))
420 (defun strip-zeroes (terms ps?
)
421 (cond ((or (null terms
) (null taylor_simplifier
)) terms
)
423 (do ((terms terms
(n-term terms
)))
425 (change-lc terms
(strip-zeroes (lc terms
) 't
))
426 (unless (rczerop (lc terms
)) (return terms
))))
428 (if (null taylor_simplifier
) terms
429 (let ((exp (rcdisrep terms
)))
430 ;; If a pscoeff is not free of tvars then the ps is a
431 ;; multivar series and we can't handle a recursive
432 ;; call to taylor (as opposed to a call to prep1, as below)
433 ;; because this would be circuler (e.g. try
434 ;; taylor(x/ (x^2+1),[x],%i,-1) ). Besides, in this case
435 ;; the pscoeff contains a tvar hence should not be 0.
436 (if (not (mfree exp tvars
)) terms
437 (prep1 (funcall taylor_simplifier exp
))))))
438 (t (pscheck (gvar-o terms
) (poly-data terms
)
439 (strip-zeroes (terms terms
) () )))))
441 (defun pscplus1 (c l
)
442 (cond ((null l
) (list (term (rczero) c
)))
443 ((rczerop (le l
)) (setq c
(psplus c
(lc l
)))
444 (if (rczerop c
) (strip-zeroes (n-term l
) () )
445 (cons (term (rczero) c
) (n-term l
))))
446 ((e> (le l
) (rczero)) (cons (term (rczero) c
) l
))
447 (t (cons (lt l
) (let ((least_term?
)) (pscplus1 c
(n-term l
)))))))
449 ;;; Both here and in psdiff2 xx and yy point one before where one
450 ;;; might think they should point so that extensions will be retained.
452 (defun psplus2 (varh trunc xx yy ans a
)
454 a
(cond ((mono-term? xx
)
455 (if (mono-term? yy
) (go end
) (go null
)))
456 ((mono-term? yy
) (setq yy xx
) (go null
)))
457 (cond ((equal (le (n-term xx
)) (le (n-term yy
)))
458 (setq xx
(n-term xx
) yy
(n-term yy
))
459 (setq c
(let ((least_term?
(null (n-term ans
))))
460 (psplus (lc xx
) (lc yy
))))
461 (if (rczerop c
) (go a
) (add-term a
(le xx
) c
)))
462 ((e> (le (n-term xx
)) (le (n-term yy
)))
463 (setq yy
(n-term yy
))
464 (add-term a
(lt yy
)))
465 (t (setq xx
(n-term xx
))
466 (add-term a
(lt xx
))))
469 null
(if (or (mono-term? yy
) (e> (le (n-term yy
)) trunc
))
472 (setq yy
(n-term yy
))
473 (add-term-&-pop a
(lt yy
))
475 end
(return (pscheck varh
(list trunc
) (cdr ans
)))))
478 (let ((ans (cons () () )))
479 (psdiff2 (gvar-o x
) (emin (trunc-lvl x
) (trunc-lvl y
))
480 (cons 0 (terms x
)) (cons 0 (terms y
)) ans ans
)))
482 (defun psdiff2 (varh trunc xx yy ans a
)
484 a
(cond ((mono-term? xx
)
489 (cons 0 (mapcar #'(lambda (q)
490 (term (e q
) (psminus (c q
))))
494 (setq yy xx
) (go null
)))
495 (cond ((equal (le (n-term xx
)) (le (n-term yy
)))
496 (setq xx
(n-term xx
) yy
(n-term yy
))
497 (setq c
(let ((least_term?
(null (n-term ans
))))
498 (psdiff (lc xx
) (lc yy
))))
499 (if (rczerop c
) (go a
)
500 (add-term a
(le xx
) c
)))
501 ((e> (le (n-term xx
)) (le (n-term yy
)))
502 (setq yy
(n-term yy
))
503 (add-term a
(le yy
) (psminus (lc yy
))))
504 (t (setq xx
(n-term xx
))
505 (add-term a
(lt xx
))))
508 null
(if (or (mono-term? yy
) (e> (le (n-term yy
)) trunc
))
511 (setq yy
(n-term yy
))
512 (add-term-&-pop a
(le yy
) (lc yy
))
514 end
(return (pscheck varh
(list trunc
) (cdr ans
)))))
517 (if (psp x
) (make-ps x
(psminus-terms (terms x
)))
520 (defun psminus-terms (terms)
521 (let ((ans (cons () () )))
522 (do ((q terms
(n-term q
))
525 (add-term a
(le q
) (psminus (lc q
))))))
527 (defun pscheck (a b terms
)
528 (cond ((null terms
) (rczero))
529 ((and (mono-term? terms
) (rczerop (le terms
)))
531 (t (make-ps a b terms
))))
533 (defun pstrim-terms (terms e
)
535 (cond ((null terms
) (return () ))
536 ((null (e> e
(le terms
))) (return terms
))
537 (t (setq terms
(n-term terms
))))))
539 (defun psterm (terms e
)
540 (psterm1 (pstrim-terms terms e
) e
))
543 (cond ((null l
) (rczero))
544 ((e= (le l
) e
) (lc l
))
547 (defun pscoeff1 (a b c
) ;a is an mrat!!!
548 (let ((tlist (mrat-tlist a
)))
549 (cons (nconc (list 'mrat
'simp
(mrat-varlist a
) (mrat-genvar a
))
550 (do ((l (mrat-tlist a
) (cdr l
))
551 (ans () (cons (car l
) ans
)))
553 (when (alike1 (caar l
) b
)
555 (and (or ans
(cdr l
))
556 (list (nreconc ans
(cdr l
)) 'trunc
))))))
557 (pscoef (mrat-ps a
) (int-gvar (get-datum b
)) (prep1 c
)))))
559 (defun pscoef (a b c
)
560 (cond ((pscoefp a
) (if (rczerop c
) a
(rczero)))
561 ((eq b
(gvar a
)) (psterm (terms a
) c
))
562 (t (do ((gvar-o (gvar-o a
))
563 (poly-data (poly-data a
))
565 (terms (terms a
) (n-term terms
))
568 (unless (rczerop (setq temp
(pscoef (lc terms
) b c
)))
569 (setq ans
(psplus ans
570 (make-ps gvar-o poly-data
571 (ncons (term (le terms
)
574 (defun psdisextend (p)
575 (cond ((not (psp p
)) p
)
576 (t (make-ps p
(mapcar #'(lambda (q) (cons (car q
) (psdisextend (cdr q
))))
580 (if (psp p
) (psfloat1 p
(trunc-lvl p
) (terms p
) (ncons 0))
581 (rctimes (rcfone) p
)))
583 (defun psfloat1 (p trunc l ans
)
585 (a (last ans
) (n-term a
)))
586 ((or (null l
) (e> (le l
) trunc
))
587 (pscheck (gvar-o p
) (poly-data p
) (cdr ans
)))
588 (add-term a
(le l
) (psfloat (lc l
)))
589 (setq l
(n-term l
))))
592 (pstrunc1 p
(mapcar #'(lambda (q) (cons (int-gvar q
) (current-trunc q
)))
595 (defun pstrunc1 (p trlist
)
599 (let ((trnc (cdr (assoc (gvar p
) trlist
:test
#'eq
))) (trunc-ps) (a nil
))
600 (do ((l (terms p
) (n-term l
)))
601 ((null l
) (pscheck (gvar-o p
) (ncons (trunc-lvl p
)) (nreverse a
)))
602 (when (e> (le l
) trnc
)
603 (return (pscheck (gvar-o p
) (ncons trnc
) (nreverse a
))))
604 (unless (rczerop (setq trunc-ps
(pstrunc1 (lc l
) trlist
)))
605 (push (term (le l
) trunc-ps
) a
)))))))
608 (cond ((or (rczerop x
) (rczerop y
)) (rczero))
609 ((pscoefp x
) (cond ((pscoefp y
) (rctimes x y
))
610 ((equal x
(rcone)) y
)
611 (t (psctimes* x y
))))
612 ((pscoefp y
) (if (equal y
(rcone)) x
(psctimes* y x
)))
613 ((eqgvar (gvar-o x
) (gvar-o y
)) (pstimes*1 x y
))
614 ((pointerp (gvar-o x
) (gvar-o y
)) (psctimes* y x
))
615 (t (psctimes* x y
))))
617 (defun psctimes* (c p
)
618 (make-ps p
(maplist #'(lambda (l)
619 (term (le l
) (pstimes c
(lc l
))))
622 (defun pstimes*1 (xa ya
)
623 (let ((ans (cons () () ))
624 (trunc (let ((lex (ps-le xa
)) (ley (ps-le ya
)))
625 (e+ (emin (e- (trunc-lvl xa
) lex
) (e- (trunc-lvl ya
) ley
))
628 (setq trunc
(emin trunc
(t-o-var (gvar xa
)))))
629 (pstimes*2 xa ya trunc ans
)))
631 (defun pstimes*2 (xa ya trunc ans
)
633 (setq x
(terms xa
) y
(setq yy
(terms ya
)) a ans
)
634 a
(cond ((or (null y
) (e> (setq e
(e+ (le x
) (le y
))) trunc
))
636 ((not (rczerop (setq c
(pstimes (lc x
) (lc y
)))))
637 (add-term-&-pop a e c
)))
640 b
(unless (setq x
(n-term x
))
641 (return (pscheck (gvar-o xa
) (list trunc
) (cdr ans
))))
643 c
(when (or (null y
) (e> (setq e
(e+ (le x
) (le y
))) trunc
))
645 (setq c
(pstimes (lc x
) (lc y
)))
646 d
(cond ((or (mono-term? a
) (e> (le (n-term a
)) e
))
647 (add-term-&-pop a e c
))
648 ((e> e
(le (n-term a
)))
651 (t (setq c
(psplus c
(lc (n-term a
))))
653 (rplacd a
(n-term (n-term a
)))
655 (change-lc (n-term a
) c
)
656 (setq a
(n-term a
))))))
660 (defun pscsubst (c v p
)
661 (cond ((pscoefp p
) p
)
662 ((eq v
(gvar p
)) (pscsubst1 c p
))
663 ((pointerp v
(gvar p
)) p
)
664 (t (make-ps p
(maplist
665 #'(lambda (q) (term (le q
)
666 (pscsubst c v
(lc q
))))
669 (defun pscsubst1 (v u
)
671 (ul (terms u
) (n-term ul
)))
673 (setq a
(psplus a
(pstimes (lc ul
) (psexpt v
(le ul
)))))))
675 (defun get-series (func trunc var e c
)
676 (let ((pw (e// trunc e
)))
677 (setq e
(if (and (equal e
(rcone)) (equal c
(rcone)))
678 (getexp-fun func var pw
)
679 (psmonsubst (getexp-fun func var pw
) trunc e c
)))
680 (if (and $float $keepfloat
) (psfloat e
) e
)))
682 (defun psmonsubst (p trunc e c
)
684 (psmonsubst1 p trunc e c
685 `(() .
,(terms p
)) (ncons () ) (rcone) (rczero))
689 (defun psmonsubst1 (p trunc e c l ans cc el
)
690 ;; We set $MAXTAYORDER to () here so that the calls to psexpt below
691 ;; won't do needless extra work, e.g. see rwg's complaint of 9/7/82.
692 (prog (a ee varh $maxtayorder
)
693 (setq a ans varh
(gvar-o p
))
694 a
(cond ((or (mono-term? l
)
695 (e> (setq ee
(e* e
(le (n-term l
)))) trunc
))
699 (psexpt c
(e- (le (setq l
(n-term l
)))
702 (add-term a ee
(pstimes cc
(lc l
)))))
703 (setq a
(n-term a
) el
(le l
))
705 end
(return (pscheck varh
(list trunc
) (cdr ans
)))))
707 (defun psexpon-gcd (terms)
708 (do ((gcd (le terms
) (egcd (le l
) gcd
))
709 (l (n-term terms
) (n-term l
)))
713 (if (psp p
) (psfind-s (psterm (terms p
) (rczero)))
717 (cond ((null (atom (cdr r
))) (rczero))
719 (t (do ((p (ptterm (cdar r
) 0) (ptterm (cdr p
) 0)))
720 ((atom p
) (cons p
(cdr r
)))))))
723 (cond ((rczerop n
) ;; p^0
724 (if (rczerop p
) ;; 0^0
725 (merror (intl:gettext
"taylor: 0^0 is undefined."))
726 (rcone))) ;; Otherwise can let p^0 = 1
727 ((or (equal n
(rcone)) (equal n
(rcfone))) p
) ;; p^1 cases
728 ((pscoefp p
) (rcexpt p n
))
729 ((mono-term?
(terms p
)) ;; A monomial to a power
730 (let ((s (psfind-s n
)) (n-s) (x) (l (terms p
)))
731 ;; s is the numeric part of the exponent
732 (if (floatp (car s
)) ;; Perhaps we shouldn't
733 ;; rationalize if $keepfloat is true?
734 (setq s
(maxima-rationalize (quot (car s
) (cdr s
)))))
735 (setq n-s
(psdiff n s
) ;; the non-numeric part of exponent
736 x
(e* s
(le l
))) ;; the degree of the lowest term
737 (setq x
(if (and (null $maxtayorder
) ;; if not getting all terms
738 (e> x
(t-o-var (gvar p
))))
739 ;; and result is of high order
740 (rczero) ;; then zero is enough
741 (pscheck (gvar-o p
) ;; otherwise
742 (ncons (e+ (trunc-lvl p
) ;; new trunc-level
743 (e- x
(le l
)))) ;; kick exponent
744 (ncons (term x
(psexpt (lc l
) n
))))))
746 (if (or (rczerop n-s
) (rczerop x
)) ;; is that good enough?
747 x
;; yes! The rest is bletcherous.
748 (pstimes x
(psexpt (prep1 (m^
(get-inverse (gvar p
))
751 (t (prog (l lc le inc trunc s lt mr lim lcinv ans
)
752 (setq lc
(lc (setq l
(terms p
)))
753 le
(le l
) lt
(lt l
) trunc
(trunc-lvl p
)
754 inc
(psexpon-gcd l
) s
(psfind-s n
))
755 (when (floatp (car s
))
756 (setq s
(maxima-rationalize (quot (car s
) (cdr s
)))))
757 (setq ans
(psexpt (setq lt
(pscheck (gvar-o p
) (list trunc
)
759 lcinv
(psexpt lc
(rcmone))
760 mr
(e+ inc
(e* s le
))
761 lim
(if (and (infp trunc
) (not (e> s
(rczero))))
763 ;; See the comment in PSEXPT1 below which tells
764 ;; why we don't allow inf. trunc's here.
765 (e+ (if (and (infp trunc
) (not (rcintegerp s
)))
766 (if (infp (setq lim
(t-o-var (gvar p
))))
772 (if (or (pscoefp ans
) (null (eq (gvar p
) (gvar ans
))))
773 (list 0 (term (rczero) ans
))
774 (cons 0 (terms ans
))))
775 (and (null $maxtayorder
)
778 (e> (e* s
(le (last l
))) (t-o-var (gvar p
))))
779 (setq lim
(emin lim
(t-o-var (gvar p
)))))
780 ;;(and (infp lim) (n-term l) (e> (rczero) n)
782 (return (psexpt1 (gvar-o p
)
783 lim l n s inc
1 mr ans le lcinv
))))))
785 (defun psexpt1 (varh trunc l n s inc m mr ans r linv
)
786 ;; n is the power we are raising the series to
787 ;; inc is the exponent increment
788 ;; mr is the current exponent
789 ;; tr is the truncation level desired
790 ;; m is the term index
792 (prog (a (k 0) ak cm-k c ma0 sum kr tr
)
794 ;; truly unfortunate that we need so many variables in this hack
795 (setq a
(last ans
) tr trunc
)
796 ;; I don't see what's wrong with truncating exact series when
797 ;; raising them to fractional powers so we'll allow it for now.
798 ;; This is accomplished above in PSEXPT (see the comment). Thus,
799 ;; presumably, this check should never be needed anymore.
800 ;; Bugs catching this clause were sqrt(1-x)*taylor(f1,x,0,0)
801 ;; and sqrt(taylor(x+x^2,x,0,2)),taylor_truncate_polynomials=false.
804 (setq tr
(e* s
(le (last l
))))
805 (merror (intl:gettext
"taylor: expected an integer, instead found: ~:M") s
)))
806 (when (infp tr
) (setq tr
(t-o-var (car varh
))))
807 b
(and (e> mr tr
) (go end
))
808 (setq kr inc ak l ma0
(pstimes (cons 1 m
) linv
)
810 a
(if (or (> k m
) (null (setq cm-k
(psterm (cdr ans
) (e- mr kr
)))))
812 (setq ak
(or (pstrim-terms ak
(e+ kr r
)) (go add-term
))
813 c
(pstimes (psdiff (pstimes (cons k
1) n
)
815 (pstimes (if (e= (e+ kr r
) (le ak
))
819 (setq sum
(psplus sum c
)
820 k
(1+ k
) kr
(e+ kr inc
))
823 (and (null (rczerop sum
))
824 (add-term-&-pop a mr
(pstimes ma0 sum
)))
825 (setq m
(1+ m
) mr
(e+ mr inc
))
827 end
(return (pscheck varh
(list trunc
) (cdr ans
)))))
829 (defun psderivative (p v
)
830 (cond ((pscoefp p
) (rcderiv p v
))
832 (if (prog1 (rczerop (ps-le p
))
833 (setq p
(psderiv1 (gvar-o p
)
834 (trunc-lvl p
) (cons 0 (terms p
)) (list 0))))
835 (strip-zeroes p
't
) p
))
836 (t (psderiv2 (gvar-o p
)
837 (trunc-lvl p
) v
(cons 0 (terms p
)) (list 0)))))
839 (defun psderiv1 (varh trunc l ans
)
841 ((or (mono-term? l
) (e> (le (n-term l
)) trunc
))
842 (pscheck varh
(list (e1- trunc
)) (cdr ans
)))
844 (when (not (rczerop (le l
)))
845 (add-term-&-pop a
(e1- (le l
)) (pstimes (le l
) (lc l
))))))
847 (defun psderiv2 (varh trunc v l ans
)
848 (do ((a (last ans
) (n-term a
)) (c))
849 ((or (mono-term? l
) (e> (le (n-term l
)) trunc
))
850 (pscheck varh
(list trunc
) (cdr ans
)))
852 (or (rczerop (setq c
(psderivative (lc l
) v
)))
853 (add-term a
(le l
) c
))))
857 (cond ((pscoefp p
) (rcderivx p
))
858 ((or (rczerop (setq temp
(getdiff (gvar-o p
))))
859 (eq (car temp
) 'multi
))
860 (setq temp2
(psdp2 (gvar-o p
) (trunc-lvl p
)
861 (cons 0 (terms p
)) (list 0)))
862 (if (eq (car temp
) 'multi
)
864 (make-ps (gvar-o p
) (ncons (inf))
865 (list (term (cdr temp
) (rcone)))))
868 (trunc-lvl p
) (cons 0 (terms p
))
871 (defun psdp1 (varh trunc l ans dx
)
872 (do ((a (last ans
)) (c (rczero)))
873 ((or (mono-term? l
) (e> (le (n-term l
)) trunc
))
874 (psplus c
(pscheck varh
(list (e1- trunc
)) (cdr ans
))))
876 (if (rczerop (le l
)) (setq c
(psdp (lc l
)))
878 a
(e1- (le l
)) (pstimes (le l
) (pstimes dx
(lc l
)))))))
880 (defun psdp2 (varh trunc l ans
)
881 (do ((a (last ans
)) (c))
882 ((or (mono-term? l
) (e> (le (n-term l
)) trunc
))
883 (pscheck varh
(list trunc
) (cdr ans
)))
885 (when (null (rczerop (setq c
(psdp (lc l
)))))
886 (add-term-&-pop a
(le l
) c
))))
890 ;;; (defun psintegrate (p v)
891 ;;; (cond ((rczerop p) (rczero))
893 ;;; (pstimes p (taylor2 (get-inverse (car v)))))
894 ;;; ((eqgvar v (gvar-o p))
895 ;;; (psinteg1 (gvar-o p)
896 ;;; (trunc-lvl p) (cons 0 (terms p)) (list 0)))
897 ;;; (t (psinteg2 (gvar-o p)
898 ;;; (trunc-lvl p) v (cons 0 (terms p)) (list 0)))))
900 ;;; (defun psinteg1 (varh trunc l ans)
902 ;;; (setq a (last ans))
903 ;;; a (if (or (null (n-term l)) (e> (le (n-term l)) trunc))
905 ;;; (add-term a (e1+ (le (setq l (n-term l))))
907 ;;; (if (e= (le l) (rcmone))
908 ;;; (prep1 (list '(%LOG)
912 ;;; (setq a (n-term a)))
914 ;;; end (return (pscheck varh (list (e1+ trunc)) (cdr ans)))))
916 ;;; (defun psinteg2 (varh trunc v l ans)
918 ;;; (setq a (last ans))
919 ;;; a (if (or (null (n-term l)) (e> (le (n-term l)) trunc))
921 ;;; (add-term a (le l)
922 ;;; (psintegrate (lc (setq l (n-term l))) v))
923 ;;; (setq a (n-term a)))
925 ;;; end (return (pscheck varh (list trunc) (cdr ans)))))
927 (defun psexpt-log-ord (p)
928 (cond ((null $maxtayorder
) (emin (trunc-lvl p
) (t-o-var (gvar p
))))
929 ((infp (trunc-lvl p
)) (t-o-var (gvar p
)))
938 (cond ((pscoefp p
) (psexpt-fn2 (rcdisrep p
)))
939 ((ps-lim-infp p
) (psexpt-fn-sing p
))
940 ((prog2 (setq ord
<0?
(e> (rczero) (ps-le p
)))
941 (null (n-term (terms p
))))
942 (setq ans
(get-series '%exp
(psexpt-log-ord p
) (gvar-o p
)
943 (if ord
<0?
(e- (ps-le p
)) (ps-le p
))
945 (if ord
<0?
(ps-invert-var ans
) ans
))
947 (when (e= (rczero) (e (setq ans
(ps-gt p
))))
948 (pstimes (psexpt-fn (pscheck (gvar-o p
) (list (trunc-lvl p
))
949 (delete ans
(terms p
) :test
#'eq
)))
950 (psexpt-fn2 (srdis (c ans
)))))
951 (when (e= (rczero) (ps-le p
))
952 (pstimes (psexpt-fn2 (srdis (lc (terms p
))))
953 (psexpt-fn (pscheck (gvar-o p
) (list (trunc-lvl p
))
954 (n-term (terms p
))))))) )
955 (t (prog (l inc trunc ea0 ans
)
958 ;(return (ps-invert-var (psexpt-fn (ps-invert-var p))))
959 (setq l
(invert-terms l
)))
960 (setq trunc
(trunc-lvl p
)
961 inc
(psexpon-gcd l
) ea0
(rcone))
962 (unless (e> (le l
) (rczero))
963 ;; MEANING OF FOLLOWING MESSAGE IS OBSCURE
964 (merror "PSEXPT-FN: unreachable point."))
966 (if (or (pscoefp ea0
) (null (eq (gvar p
) (gvar ea0
))))
967 (list 0 (term (rczero) ea0
))
968 (cons 0 (terms ea0
))))
970 (setq trunc
(emin trunc
(t-o-var (gvar p
)))))
971 (when (infp trunc
) (setq trunc
(t-o-var (gvar p
))))
972 (setq ans
(psexpt-fn1 (gvar-o p
) trunc l inc
1 inc ans
))
973 (return (if ord
<0?
(ps-invert-var ans
) ans
)))))))
975 (defun psexpt-fn-sing (p)
976 (let ((inf-var?
(member (gvar-lim (gvar p
)) '($inf $minf
) :test
#'eq
))
977 (c*logs
(c*logs
(lt-poly p
))) c strongest-term
)
978 ;; Must pull out out logs here: exp(ci*log(ui)+x) -> ui^ci*exp(x)
979 ;; since its much harder for adjoin-tvar to do this transformation
980 ;; below after things have been disrepped.
981 (setq c
(exp-c*logs c
*logs
) p
(psdiff p
(sum-c*logs c
*logs
)))
982 (if (not (ps-lim-infp p
))
983 ;; Here we just subtracted the only infinite term, e.g.
984 ;; p = 1/2*log(x)+1/log(x)+...
985 (pstimes c
(psexpt-fn p
))
987 (setq strongest-term
(if inf-var?
(ps-gt p
) (ps-lt p
)))
988 ;; If the strongest term has degree 0 in the mainvar then the singular
989 ;; terms occur in some other weaker var. There may be terms in this
990 ;; coef which arent singular (e.g. 1 in (1/x+1+...)+exp(-1/x)+...) so
991 ;; we must recursively psexpt-fn this term to get only what we need.
992 (if (rczerop (e strongest-term
))
993 (setq c
(pstimes c
(psexpt-fn (c strongest-term
))))
994 (dolist (exp (expand-and-disrep strongest-term p
))
995 (setq c
(pstimes c
(adjoin-tvar (m^
'$%e exp
))))))
996 (pstimes c
(psexpt-fn (pscheck (gvar-o p
) (list (trunc-lvl p
))
998 (delete strongest-term
(terms p
) :test
#'eq
)
999 (n-term (terms p
))))))))))
1001 (defun gvar-logp (gvar)
1002 (let ((var (get-inverse gvar
)))
1003 (and (consp var
) (eq (caar var
) 'mexpt
) (equal (caddr var
) -
1)
1004 (consp (setq var
(cadr var
))) (eq (caar var
) '%log
)
1009 (let ((log (gvar-logp (gvar p
))) c
)
1013 (setq c
(psconst (psterm (terms p
) (rcmone))))
1014 ;; We don't want e.g. exp(x^a*log(x)) -> x^x^a
1015 (if (not (mfree (rcdisrep c
) tvars
)) ()
1016 (cons (cons c
(cons log p
))
1017 (c*logs
(psterm (terms p
) (rczero))))))))))
1020 (if (pscoefp p
) p
(psconst (psterm (terms p
) (rczero)))))
1022 (defun exp-c*logs
(c*logs
)
1023 (if (null c
*logs
) (rcone)
1024 (pstimes (taylor2 `((mexpt) ,(cadr (cadr (car c
*logs
)))
1025 ,(rcdisrep (caar c
*logs
))))
1026 (exp-c*logs
(cdr c
*logs
)))))
1028 (defun sum-c*logs
(c*logs
)
1029 (if (null c
*logs
) (rczero)
1030 (let ((ps (cddr (car c
*logs
))))
1031 (psplus (make-ps ps
(ncons (term (ps-le ps
) (caar c
*logs
))))
1032 (sum-c*logs
(cdr c
*logs
))))))
1034 ;; Calculatest the limit of a series at the expansion point. Returns one of
1035 ;; {$zeroa, $zerob, $pos, $neg, $inf, $minf}.
1037 (defvar tvar-limits
()
1038 "A list of the form ((gvar . limit(gvar)) ...)")
1040 (defun ps-lim-infp (ps)
1042 ;; Assume taylor vars at 0+ for now. Should handle the cases when
1043 ;; the expansion point is INF, MINF,etc.
1044 (let* ((lim (gvar-lim (gvar ps
)))
1046 (if (member lim
'($inf $minf
) :test
#'eq
) (ps-gt ps
) (ps-lt ps
))))
1047 (if (ezerop (e strongest-term
))
1048 (ps-lim-infp (c strongest-term
))
1050 (setq lim
(lim-power lim
(e strongest-term
)))
1051 (and (lim-infp lim
) (not (eq lim
'$infinity
))))))))
1053 (defun lim-zerop (lim)
1054 (member lim
'($zeroa $zerob $zeroim
) :test
#'eq
))
1056 (defun lim-plusp (lim)
1057 (member lim
'($zeroa $pos $inf $finite
) :test
#'eq
))
1059 (defun lim-finitep (lim)
1060 (member lim
'($pos $neg $im $finite
) :test
#'eq
))
1062 (defun lim-infp (lim)
1063 (member lim
'($inf $minf $infinity
) :test
#'eq
))
1065 (defun lim-imagp (lim)
1066 (member lim
'($im $infinity
) :test
#'eq
))
1068 (defun lim-minus (lim)
1069 (cdr (assoc lim
'(($zeroa . $zerob
) ($zerob . $zeroa
) ($pos . $neg
) ($zero . $zero
)
1070 ($neg . $pos
) ($inf . $minf
) ($minf . $inf
)
1071 ($im . $im
) ($infinity . $infinity
) ($finite . $finite
)) :test
#'eq
)))
1072 (defun lim-abs (lim)
1073 (or (cdr (assoc lim
'(($zerob . $zeroa
) ($neg . $pos
) ($minf . $inf
)) :test
#'eq
))
1076 (defun lim-times (lim1 lim2
)
1078 (cond ((or (eq lim1
'$zero
) (eq lim2
'$zero
)) (setq lim
'$zero
))
1079 ((and (lim-infp lim1
) (lim-infp lim2
)) (setq lim
'$inf
))
1080 ((and (lim-zerop lim1
) (lim-zerop lim2
)) (setq lim
'$pos
))
1081 ((or (when (lim-finitep lim2
) (rotatef lim1 lim2
) 't
)
1083 (when (and (eq lim1
'$finite
) (lim-infp lim1
))
1084 (break "Undefined finite*inf in lim-times"))
1085 (setq lim
(lim-abs lim2
)))
1086 (t (break "Undefined limit product ~A * ~A in lim-times" lim1 lim2
)))
1087 (if (or (lim-imagp lim1
) (lim-imagp lim2
))
1088 (if (lim-infp lim
) '$infinity
'$im
)
1089 (if (and (lim-plusp lim1
) (lim-plusp lim2
)) lim
(lim-minus lim
)))))
1091 (defun lim-power (lim power
)
1092 (cond ((ezerop power
) '$pos
)
1093 ((e> (rczero) power
) (lim-recip (lim-power lim
(e- power
))))
1094 ((not (oddp (car power
)))
1095 (if (lim-plusp lim
) lim
(lim-minus lim
)))
1098 (defun lim-recip (lim)
1099 (or (cdr (assoc lim
'(($zeroa . $inf
) ($zerob . $minf
)
1100 ($inf . $zeroa
) ($minf . $zerob
)) :test
#'eq
))
1101 (if (eq lim
'$finite
) (break "inverting $finite?")
1104 (defun lim-exp (lim)
1106 (($zeroa $zerob $zero $pos $neg $minf
) '$zeroa
)
1107 (($inf $finite
) lim
)
1108 ($infinity
'$infinity
) ; actually only if Re lim = inf
1109 (t (break "Unhandled limit in lim-exp"))))
1111 (defun lim-log (lim)
1117 (t (break "Unhandled limit in lim-log"))))
1119 (defun expand-and-disrep (term p
)
1120 (let ((x^n
(list '(mexpt) (get-inverse (gvar p
)) (edisrep (e term
))))
1122 (if (pscoefp a
) (ncons (m* (srdis a
) x^n
))
1123 (mapcar #'(lambda (subterm)
1124 (m* (cons '(mtimes) (expand-and-disrep subterm a
)) x^n
))
1127 (defun adjoin-sing-datum (d)
1128 (let ((r (prep1 (datum-var d
))) (g (gensym)) (kernel (datum-var d
))
1129 (no (1+ (cdr (int-var (car (last tlist
)))))))
1130 (unless (and (equal (car r
) 1) (equal (cddr r
) '(1 1)))
1131 (break "bad singular datum"))
1132 (putprop g kernel
'disrep
)
1133 (rplacd (cdddr d
) (cons g no
))
1135 (push (cons (cadr r
) kernel
) key-vars
)
1136 (push (cons g kernel
) key-vars
)
1137 (push (car key-vars
) ivars
)
1138 ;(push (cons kernel (cons (pget g) 1)) genpairs)
1139 (push (cons g
(exp-pt d
)) tvar-limits
)))
1141 (defun adjoin-tvar (exp) (rat->ps
(prep1 exp
)))
1143 (defun rat->ps
(rat)
1144 (pstimes (poly->ps
(car rat
))
1145 (psexpt (poly->ps
(cdr rat
)) (rcmone))))
1147 (defun poly->ps
(poly)
1148 (if (or (pcoefp poly
) (mfree (pdis poly
) tvars
)) (prep1 poly
)
1149 (let ((g (p-var poly
)) datum
(pow (rcone)))
1150 (if (setq datum
(key-var-pow g
)) (desetq (g . pow
) datum
)
1151 (desetq (g . pow
) (adjoin-pvar g
)))
1152 (if (and (not (atom g
)) (psp g
))
1155 (setq datum
(gvar-data g
))
1156 (do ((po-terms (p-terms poly
) (p-red po-terms
))
1158 (push (term (e* pow
(prep1 (pt-le po-terms
)))
1159 (poly->ps
(pt-lc po-terms
)))
1162 ;; This must be exact so that when we invert in rat-ps above
1163 ;; we don't lose any terms. E.g. try
1164 ;; taylor(log(1+exp(-1/x)),x,0,5). When taylor2'ing exp(-1/x),
1165 ;; if you used current trunc here this would return exp(1/x)...5
1166 ;; which would then be trunc'd to degree 3 by psexpt.
1167 (make-ps (int-var datum
)
1168 (ncons (current-trunc datum
))
1169 (if (eq g
(data-gvar datum
)) ps-terms
1170 (invert-terms ps-terms
))))))))))
1172 (defun key-var-pow (g)
1173 (let ((var (get-key-var g
)) datum
)
1175 (setq datum
(get-datum var
))
1176 (if (eq g
(setq g
(data-gvar datum
))) (cons g
(rcone))
1177 (cons g
(rcmone))))))
1179 (defun adjoin-pvar (g)
1180 (let ((kernel (get g
'disrep
)) g
* lim datum ans
1181 (no (1+ (cdr (int-var (car (last tlist
)))))) (pow (rcone)) expt
)
1182 (when (assol kernel tlist
) (break "bad1"))
1183 (if (and (eq (caar kernel
) 'mexpt
) (eq (cadr kernel
) '$%e
)
1184 (not (atom (setq expt
(caddr kernel
))))
1185 (eq (caar expt
) 'mtimes
) (not (mfree expt
(ncons '$%i
))))
1186 (destructuring-let (((rpart . ipart
) (trisplit expt
)))
1187 (cons (pstimes (prep1 (m^
'$%e rpart
))
1188 (psplus (adjoin-tvar `((%cos
) ,ipart
))
1189 (pstimes (prep1 '$%i
)
1190 (adjoin-tvar `((%sin
) ,ipart
)))))
1193 (when (eq (caar kernel
) 'mexpt
)
1194 (when (and (not (atom (setq expt
(caddr kernel
))))
1195 (eq (caar expt
) 'mtimes
)
1196 ($ratnump
(cadr expt
)))
1197 (setq pow
(cadr expt
) kernel
(m^ kernel
(m// pow
))
1198 g
(prep1 kernel
) pow
(prep1 pow
))
1199 (unless (and (equal (cdr g
) 1) (equal (cdar g
) '(1 1)))
1200 (break "Illegal kernel in `adjoin-pvar'"))
1201 (setq g
(caar g
) kernel
(get g
'disrep
))))
1202 (if (setq ans
(key-var-pow g
))
1203 (cons (car ans
) (e* pow
(cdr ans
)))
1205 (when (lim-infp (or lim
(setq lim
(tvar-lim kernel
))))
1206 (setq g
* g g
(gensym) kernel
(m// kernel
)
1207 lim
(lim-recip lim
) pow
(e* (rcmone) pow
))
1208 (putprop g kernel
'disrep
)
1209 ;(push g genvar) (push kernel varlist)
1210 (push (cons g
* kernel
) key-vars
))
1211 (when (assol kernel tlist
) (break "bad2"))
1212 (setq datum
(list* kernel
1213 ;(mapcar #'(lambda (e) (emax e (rczero)))
1214 ; (trunc-stack (car tlist)))
1215 (copy-list (trunc-stack (car tlist
)))
1217 ;(setq tlist (nconc tlist (ncons datum)))
1218 (adjoin-datum datum
)
1219 (push (cons g kernel
) key-vars
)
1220 (push (car key-vars
) ivars
)
1221 ;(push (cons kernel (cons (pget g) 1)) genpairs)
1222 (push (cons g lim
) tvar-limits
)
1225 (defun adjoin-datum (datum)
1226 (do ((tlist* tlist
(cdr tlist
*))
1227 (tlist** () tlist
*))
1228 ((null tlist
*) (setq tlist
(nconc tlist
(ncons datum
))))
1229 (when (stronger-var?
(datum-var (car tlist
*)) (datum-var datum
))
1230 (return (if (null tlist
**)
1233 (renumber-tlist tlist
))
1235 (rplacd tlist
** (cons datum tlist
*))
1236 (renumber-tlist (cdr tlist
**))))))))
1238 ;; Maybe this should just permute the numbering in case it isn't sequential?
1240 (defun renumber-tlist (tlist)
1241 (rplacd (data-gvar-o (car tlist
)) (cdr (data-gvar-o (cadr tlist
))))
1242 (do ((tlist* (cdr tlist
) (cdr tlist
*)))
1244 (rplacd (data-gvar-o (car tlist
*))
1245 (1+ (cdr (data-gvar-o (car tlist
*)))))))
1247 (defun tvar?
(var) (or (atom var
) (member 'array
(cdar var
) :test
#'eq
)))
1249 ;; Needs to be extended to handle singular tvars in > 1 var's.
1251 (defun stronger-var?
(v1 v2
)
1252 (let ((e1 (rcone)) (e2 (rcone)) reverse? ans
)
1253 (when (alike1 v1 v2
)
1254 (tay-err (intl:gettext
"taylor: stronger-var? called on equal vars.")))
1255 (when (and (mexptp v1
) ($ratnump
(caddr v1
)))
1256 (setq e1
(prep1 (caddr v1
)) v1
(cadr v1
)))
1257 (when (and (mexptp v2
) ($ratnump
(caddr v2
)))
1258 (setq e2
(prep1 (caddr v2
)) v2
(cadr v2
)))
1262 (intl:gettext
"taylor: stronger-var? called on equal vars."))
1265 (when (eq (tvar-lim v2
) '$finite
)
1268 (setq reverse?
(not reverse?
)))
1269 (if (eq (tvar-lim v1
) '$finite
)
1270 (if (eq (tvar-lim v2
) '$finite
)
1271 (great v1 v2
) reverse?
)
1276 (setq reverse?
(not reverse?
)))
1279 (stronger-vars?
(order-vars-by-strength (cdr v1
))
1280 (order-vars-by-strength (if (mtimesp v2
) (cdr v2
)
1281 (ncons (m^ v2
(edisrep e2
))))))
1286 (setq reverse?
(not reverse?
)))
1289 (let ((n1 (cdr (data-gvar-o (get-datum v1 t
))))
1290 (n2 (cdr (data-gvar-o (get-datum v2 t
)))))
1292 ((mfree v2
(ncons v1
))
1294 (intl:gettext
"taylor: Unhandled multivar datum comparison.")))
1295 ((eq (caar v2
) '%log
) 't
)
1296 ((and (eq (caar v2
) 'mexpt
) (eq (cadr v2
) '$%e
))
1297 (stronger-var?
`((%log
) ,v1
) (caddr v2
)))
1298 (t (tay-err (intl:gettext
"taylor: Unhandled var in stronger-var?."))))
1300 (when (eq (caar v2
) '%log
)
1303 (setq reverse?
(not reverse?
)))
1304 (if (eq (caar v1
) '%log
)
1305 (cond ((eq (caar v2
) '%log
)
1306 (stronger-var?
(cadr v1
) (cadr v2
)))
1307 ((and (eq (caar v2
) 'mexpt
) (eq (cadr v2
) '$%e
))
1308 (stronger-var?
`((%log
) ,v1
) (caddr v2
)))
1309 (t (tay-err (intl:gettext
"taylor: Unhandled var in stronger-var?"))))
1310 (if (and (eq (caar v1
) 'mexpt
) (eq (cadr v1
) '$%e
)
1311 (eq (caar v2
) 'mexpt
) (eq (cadr v2
) '$%e
))
1312 (stronger-var?
(caddr v1
) (caddr v2
))
1313 (tay-err (intl:gettext
"taylor: Unhandled var in stronger-var?")))))))))
1314 (if reverse?
(not ans
) ans
)))))))
1316 (defun neg-monom?
(exp)
1317 (and (mtimesp exp
) (equal (cadr exp
) -
1) (null (cdddr exp
))
1320 (defun order-vars-by-strength (vars)
1321 (do ((vars* vars
(cdr vars
*)) (ordvars () ))
1322 ((null vars
*) ordvars
)
1323 (unless (mfree (car vars
*) tvars
) ; ignore constants
1324 (do ((ordvars* ordvars
(cdr ordvars
*)))
1326 (if (null ordvars
) (setq ordvars
(ncons (car vars
*)))
1327 (rplacd (last ordvars
) (ncons (car vars
*)))))
1328 (when (stronger-var?
(car vars
*) (car ordvars
*))
1329 (rplacd ordvars
* (cons (car ordvars
*) (cdr ordvars
*)))
1330 (rplaca ordvars
* (car vars
*))
1333 (defun stronger-vars?
(vars1 vars2
)
1334 (do ((vars1* vars1
(cdr vars1
*))
1335 (vars2* vars2
(cdr vars2
*)))
1337 (cond ((null vars1
*)
1339 ;; two equal vars generated
1341 (let ((lim (tvar-lim (car vars2
*))))
1343 (cond ((lim-infp lim
) ())
1344 ((lim-zerop lim
) 't
)
1345 (t (break "var with non-zero finite lim?")))))))
1347 (let ((lim (tvar-lim (car vars1
*))))
1349 (cond ((lim-infp lim
) 't
)
1350 ((lim-zerop lim
) ())
1351 (t (break "var with non-zero finite lim?"))))))
1352 ((alike1 (car vars1
*) (car vars2
*)) )
1353 ((return (stronger-var?
(car vars1
*) (car vars2
*)))))))
1355 (defun stronger-datum?
(d1 d2
)
1356 (setq d1
(datum-var d1
) d2
(datum-var d2
))
1357 (do ((end-flag) (answer))
1358 (end-flag (member answer
'($yes $y
) :test
#'eq
))
1359 (setq answer
(retrieve `((mtext) |Is |
,d1 | stronger than |
,d2 |?|
)
1361 (if (member answer
'($yes $y $no $n
) :test
#'eq
) (setq end-flag
't
)
1362 (mtell "~%Acceptable answers are: yes, y, no, n~%"))))
1364 (defun datum-lim (datum)
1365 (if (not (tvar?
(datum-var datum
)))
1367 (let ((pt (exp-pt datum
)))
1368 (if (member pt
'($inf $minf
) :test
#'eq
) pt
'$zeroa
))))
1370 (defun tvar-lim (kernel)
1371 (if (mfree kernel tvars
) (coef-sign kernel
)
1372 (let ((datum (get-datum kernel t
)) lim
)
1373 (or (and datum
(datum-lim datum
))
1374 (and (setq datum
(get-datum (m// kernel
) t
))
1375 (setq lim
(datum-lim datum
))
1379 (cond ((eq (caar kernel
) 'mexpt
)
1380 (cond ((and (setq datum
(get-datum (cadr kernel
) t
))
1381 ($ratnump
(caddr kernel
)))
1382 (lim-power (datum-lim datum
)
1383 (prep1 (caddr kernel
))))
1384 (($ratnump
(caddr kernel
))
1385 (lim-power (tvar-lim (cadr kernel
))
1386 (prep1 (caddr kernel
))))
1387 ((eq (cadr kernel
) '$%e
)
1388 (lim-exp (tvar-lim (caddr kernel
))))
1389 (t (tay-error "Unhandled case in tvar-lim" kernel
))))
1390 ((eq (caar kernel
) 'mtimes
)
1391 (do ((ans (tvar-lim (cadr kernel
))
1392 (lim-times ans
(tvar-lim (car facs
))))
1393 (facs (cddr kernel
) (cdr facs
)))
1395 ((eq (caar kernel
) '%log
)
1396 (lim-log (datum-lim (get-datum (cadr kernel
) t
))))
1397 ((member (caar kernel
) '(%sin %cos
) :test
#'eq
)
1398 (unless (lim-infp (tvar-lim (cadr kernel
)))
1399 (tay-error "Invalid trig kernel in tvar-lim" kernel
))
1401 (t (tay-error "Unhandled kernel in tvar-lim" kernel
))))
1404 (defun coef-sign (coef)
1405 (if (not ($freeof
'$%i
($rectform coef
)))
1409 (defun gvar-lim (gvar)
1410 (or (cdr (assoc gvar tvar-limits
:test
#'eq
))
1411 (if (member (gvar->var gvar
) tvars
:test
#'eq
) '$zeroa
; user tvars assumed 0+ now
1412 (break "Invalid gvar"))))
1414 (defun psexpt-fn1 (varh trunc l inc m mr ans
)
1415 (declare (fixnum m
))
1416 (prog (a (k 0) ak cm-k c sum kr lim
)
1417 (declare (fixnum k
))
1418 ;; truly unfortunate that we need so many variables in this hack
1420 b
(and (e> mr trunc
) (go end
))
1421 (setq kr inc ak l k
1 sum
(rczero) lim m
)
1422 a
(cond ((or (> k lim
)
1423 (null (setq cm-k
(psterm (cdr ans
) (e- mr kr
)))))
1425 (setq ak
(or (pstrim-terms ak kr
)
1427 c
(pstimes (ereduce k m
)
1428 (pstimes (psterm1 ak kr
) cm-k
))
1430 (setq k
(1+ k
) kr
(e+ kr inc
))
1433 (unless (rczerop sum
) (add-term-&-pop a mr sum
))
1434 (setq m
(1+ m
) mr
(e+ mr inc
))
1437 (return (pscheck varh
(list trunc
) (cdr ans
)))))
1439 ;;; PSEXPT-FN2 and RED-MONO-LOG are needed to reduce exponentials of logs.
1441 (defun psexpt-fn2 (p)
1442 (cond ((atom p
) (if (get-datum p
)
1443 (psexpt-fn (taylor2 p
))
1444 (prep1 `((mexpt) $%e
,p
))))
1445 ((eq (caar p
) '%log
)
1446 (if (get-datum (cadr p
)) (taylor2 (cadr p
)) (prep1 (cadr p
))))
1447 ((or (eq (caar p
) 'mplus
) (eq (caar p
) 'mtimes
))
1448 (let ((e ($ratexpand p
)) temp
)
1449 (cond ((not (and (consp e
) (member (caar e
) '(mplus mtimes
) :test
#'eq
)))
1452 (if (eq (caar e
) 'mplus
)
1453 (do ((sumnds (cdr e
) (cdr sumnds
)) (log-facs) (l))
1455 (cond ((not log-facs
) (tsexpt '$%e p
))
1456 (t (tstimes (cons (m^t
'$%e
(m+l l
)) log-facs
)))))
1457 (if (setq temp
(red-mono-log (car sumnds
)))
1458 (push temp log-facs
)
1459 (push (car sumnds
) l
)))
1461 (setq temp
(red-mono-log e
))
1464 (prep1 (power '$%e p
)))))))))
1465 (t (prep1 (power '$%e p
)))))
1467 (defun red-mono-log (e)
1469 ((eq (caar e
) '%log
) (cadr e
))
1471 (do ((facs (cdr e
) (cdr facs
)) (log-term))
1474 (m^t
(cadr log-term
) (m*l
(remove log-term
(cdr e
) :test
#'eq
)))))
1475 (if (and (null (atom (car facs
))) (eq (caaar facs
) '%log
))
1476 (if log-term
(return ()) (setq log-term
(car facs
)))
1477 (unless (mfree (car facs
) tvars
) (return nil
)))))
1481 (if (pscoefp p
) (pslog2 (rcdisrep p
))
1482 (let ((terms (terms p
)))
1483 (cond ((mono-term? terms
) ; log(c x^n) = log(c) + n log(x)
1484 ;; do this always for now
1485 (if 't
;$TAYLOR_LOGEXPAND
1486 ;(psplus (pslog (lc terms))
1487 ; (pstimes (le terms) (pslog-of-gvar (gvar p))))
1489 ;(prep1 `((%LOG) ,(term-disrep (lt terms) p)))
1491 ;; expand log(1+ax^n) directly by series substitution
1492 ((not (or (n-term (setq terms
(terms (psplus p
(rcmone)))))
1493 ;(e> (rczero) (le terms))
1495 (setq p
(get-series '%log
(psexpt-log-ord p
) (gvar-o p
)
1496 (if (e> (rczero) (le terms
)) (e- (le terms
))
1499 (if (e> (rczero) (le terms
)) (ps-invert-var p
) p
))
1500 (t (prog (l inc trunc lt ans lterm $maxtayorder gvar-lim gt
)
1501 ;; log(lt+y) = log(lt) + log(1 + y/lt) = lterm + p
1502 (setq trunc
(trunc-lvl p
))
1503 (if (not (member (setq gvar-lim
(gvar-lim (gvar p
)))
1504 '($zeroa $zerob $inf $minf
) :test
#'eq
))
1505 (tay-error "bad gvar lim" gvar-lim
)
1506 (if (member gvar-lim
'($inf $minf
) :test
#'eq
)
1507 (setq lt
(ps-gt p
) gt lt
)
1508 (setq lt
(ps-lt p
) gt
() )))
1510 (setq lt
(pscheck (gvar-o p
)
1513 p
(pstimes p
(let (($maxtayorder
't
))
1514 (psexpt lt
(rcmone)))))
1515 (when (and (member gvar-lim
'($inf $minf
) :test
#'eq
)
1516 (e> (le terms
) (rczero)))
1517 (return (psplus lterm
(pslog p
))))
1519 (unless (equal p
(rcone))
1520 (merror "PSLOG: internal error."))
1522 (setq l
(terms p
) inc
(psexpon-gcd l
))
1523 (if gt
(setq l
(delete (last l
) l
:test
#'equal
))
1524 (setq l
(n-term l
)))
1525 (setq ans
(ncons 0))
1526 (unless $maxtayorder
1527 (setq trunc
(emin trunc
(t-o-var (gvar p
)))))
1528 ;; When we've divided by the greatest term, all terms
1529 ;; have non-positive exponents and we must perform the
1530 ;; transformation x -> 1/x befor calling pslog1 and then
1531 ;; perform the inverse afterwards.
1532 (when gt
(setq l
(invert-terms l
)))
1533 (when (e> (rczero) inc
) (setq inc
(e- inc
)))
1534 (setq ans
(psplus lterm
1535 (pslog1 (gvar-o p
) trunc l inc
1 inc ans
)))
1537 (if (and gt
(psp ans
) (eq (gvar ans
) (gvar p
)))
1541 (defun invert-terms (terms)
1542 (nreverse (mapc #'(lambda (x) (rplaca x
(e- (e x
)))) terms
)))
1544 (defun ps-invert-var (ps)
1545 (when (psp ps
) (rplacd (cddr ps
) (invert-terms (terms ps
))))
1549 (if (pscoefp ps
) (term (rczero) ps
)
1550 (lt (last (terms ps
)))))
1552 (defun pslog1 (varh trunc l inc m mr ans
)
1553 (declare (fixnum m
))
1554 (prog (a (k 0) ak cm-k c sum kr m-kr
)
1555 (declare (fixnum k
))
1556 ;; truly unfortunate that we need so many variables in this hack
1559 b
(and (e> mr trunc
) (go end
))
1560 (setq kr inc ak l k
1 sum
(rczero))
1561 a
(cond ((or (= k m
)
1562 (null (setq cm-k
(psterm (cdr ans
)
1563 (setq m-kr
(e- mr kr
))))))
1565 (setq ak
(or (pstrim-terms ak kr
)
1567 c
(pstimes m-kr
(pstimes (psterm1 ak kr
) cm-k
))
1569 k
(1+ k
) kr
(e+ kr inc
))
1572 (cond ((setq c
(pstrim-terms ak mr
))
1573 (setq c
(psterm1 c mr
)))
1574 ((setq c
(rczero))))
1575 (setq sum
(psdiff c
(pstimes sum
(e// mr
))))
1576 (unless (rczerop sum
) (add-term-&-pop a mr sum
))
1577 (setq m
(1+ m
) mr
(e+ mr inc
))
1580 (return (pscheck varh
(list trunc
) (cdr ans
)))))
1582 ;; Computes log(monom), where monom = c x^n. Is extra careful trying to keep
1583 ;; singular logs going to INF and not generating log(-1)'s unless it is
1584 ;; necessary to transform a log at MINF to INF.
1586 (defun pslog-monom (monom)
1587 (let* ((gvar (gvar monom
))
1588 (datum (gvar-data gvar
)) var pt logvar c
)
1589 (if (switch 'multivar datum
)
1590 (pslog (ps-lc monom
))
1592 (setq var
(datum-var datum
))
1594 (if (not (member (setq pt
(exp-pt datum
)) '($inf $minf
) :test
#'eq
))
1595 (setq logvar
(adjoin-tvar `((%log
) ,(m- var pt
))))
1597 ;; At x = inf: log(c (1/x)^n) -> log(c) - n log(x)
1598 ;; At x = minf: log(c (-1/x)^n) -> log(c (-1)^n) - n log(x)
1599 (setq logvar
(psminus (adjoin-tvar `((%log
) ,var
))))
1600 (when (eq pt
'$minf
)
1601 (setq c
(rcexpt (rcmone) (ps-le monom
))))))
1602 (if (eq (caar var
) 'mexpt
)
1603 (if (equal (caddr var
) -
1);; var must be 1/log(y)
1604 ;; Try to keep inf's real. Here we want
1605 ;; log(c (1/log(x))^n) -> log(c (-1)^n) - n log(-log(x))
1606 (if (equal (tvar-lim (cadr var
)) '$minf
)
1607 (setq c
(rcexpt (rcmone) (ps-le monom
))
1609 (psminus (adjoin-tvar
1610 `((%log
) ,(m- (cadr var
))))))
1611 (setq logvar
(psminus
1612 (adjoin-tvar `((%log
) ,(cadr var
))))))
1613 (if (equal (cadr var
) '$%e
)
1614 (setq logvar
(taylor2 (caddr var
)))
1615 (break "Unhandled gvar in `pslog-of-gvar'")))))
1616 (psplus (pslog (if c
(pstimes c
(ps-lc monom
)) (ps-lc monom
)))
1617 (pstimes (ps-le monom
) logvar
))))))
1619 ;; Computes log(p), where p is an rcdisrep'd pscoef.
1621 (defun pslog2 (p) (let ($logarc
) (pslog3 p
)))
1625 (prep1 (cond ((equal p
1) 0)
1626 ((equal p -
1) log-1
)
1630 (merror (intl:gettext
"taylor: log(0) encountered while processing ~:M") last-exp
))
1633 (prep1 (cond ((not $taylor_logexpand
) `((%log
) ,p
))
1634 (t (m- `((%log
) ,(cadr p
)) `((%log
) ,(caddr p
)))))))
1635 ((and full-log
(not (free p
'$%i
)))
1636 (let ((full-log () )) (pslog3 ($polarform p
))))
1637 ((eq (caar p
) 'mexpt
)
1638 ;; Must handle things like x^a, %e^(a*x), etc. which are pscoef's.
1639 (pstimes (taylor2 (caddr p
)) (pslog (taylor2 (cadr p
)))))
1640 ((and (eq (caar p
) 'mtimes
) $taylor_logexpand
)
1641 (do ((l (cddr p
) (cdr l
))
1642 (ans (pslog3 (cadr p
)) (psplus ans
(pslog3 (car l
)))))
1644 (t (prep1 `((%log
) ,p
)))))
1646 ;;; Subtitle Extending Routines
1648 (defun getfun-lt (fun)
1649 (let ((exp-datum (get (oper-name fun
) 'exp-form
)))
1651 ;; Info not needed yet.
1652 ;; (or (atom (car exp-datum))
1653 ;; (setq 0p-funord (copy-tree (cdar exp-datum))))
1654 (exp-datum-lt fun exp-datum
))
1655 ((setq exp-datum
(get (oper-name fun
) 'sp2
))
1656 (setq exp-datum
(get-lexp (subst (dummy-var) 'sp2var exp-datum
)
1658 ;; Info not needed yet; need to bind lexp-non0 to T when
1659 ;; this is used though so n-term will be there.
1660 ;; (and (rczerop (le exp-datum))
1661 ;; (setq 0p-funord (le (n-term exp-datum))))
1662 (if (psp exp-datum
) (ps-lt exp-datum
)
1663 (term (rczero) exp-datum
)))
1664 (t (merror "GETFUN-LT: unknown function ~A" fun
)))))
1666 (declare-top (special var
))
1668 (defun getexp-fun (fun var pw
)
1669 (declare (special var
))
1670 (let ((exp-datum (copy-tree (get (oper-name fun
) 'exp-form
))))
1671 (cond ((infp pw
) (infin-ord-err))
1673 (if (null (setq exp-datum
1674 (get-ps-form (if (atom fun
) fun
(caar fun
)))))
1675 (merror (intl:gettext
"taylor: power series unavailable for function ~A") fun
)
1678 (do ((subvals (cdr fun
) (cdr subvals
))
1679 (subs (safe-get (caar fun
) 'sp2subs
) (cdr subs
)))
1680 ((or (null subvals
) (null subs
))
1681 (when (or subvals subs
)
1682 (merror (intl:gettext
"taylor: incorrect number of subscripts to the deftaylor'd function ~A") (caar fun
))))
1683 (setq exp-datum
(maxima-substitute (car subvals
) (car subs
)
1685 (ts-formula exp-datum var pw
))))
1686 ((e> (exp-datum-le fun exp-datum
) pw
) (pszero var pw
))
1688 (apply (exp-fun exp-datum
)
1689 (if (atom fun
) (cons pw
(cdr exp-datum
))
1690 (cons pw
(cons (cdr fun
) (cdr exp-datum
))))))
1691 (cond ((null exp-datum
) (pszero var pw
))
1692 ((psp exp-datum
) exp-datum
)
1693 (t (make-ps var
(ncons pw
) exp-datum
)))))))
1695 (declare-top (unspecial var
))
1697 (defun expexp-funs (pw l sign chng inc
)
1699 (setq e
(e l
) lt-l
(setq l
(ncons l
)))
1700 a
(cond ((e> (setq e
(e+ e inc
)) pw
) (return l
))
1705 (cond ((e= inc
(rcone)) e
)
1707 (cons 1 (cdr (lc lt-l
)))))
1708 (setq sign
(e* sign chng
))))
1711 ;; returns series expansion of %expintegral_si
1712 ;; from term x^i to term x^max
1713 ;; sign is sign of term x^i (1 or -1)
1714 ;; ifac is i! (to avoid repeated computation)
1715 (defun expsi_series (i sign ifac max
)
1717 nil
; we have all powers up to max
1718 (cons (cons (cons i
1) ; this is i'th term
1719 (cons sign
(* i ifac
))); i'th coefficient
1720 (expsi_series (+ 2 i
) ; advance to next even/odd power
1721 (* -
1 sign
) ; flip sign
1722 (* (+ 2 i
) (+ 1 i
) ifac
) ; update factorial
1723 max
)))) ; pass through the max
1725 ;; returns series expansion of %expintegral_si up to term with x^pw
1726 (defun exp_%expintegral_si
(pw l
)
1730 (/ (float (car pw
)) (float (cdr pw
)))))
1732 (defun explog-funs (pw l sign chng inc
)
1734 (setq e
(e l
) lt-l
(setq l
(ncons l
)))
1735 a
(cond ((e> (setq e
(e+ e inc
)) pw
) (return l
))
1736 (t (add-term lt-l e
(e// sign e
))
1737 (setq lt-l
(n-term lt-l
)
1738 sign
(e* sign chng
))))
1741 (defun exptan-funs (pw l chng
)
1742 (prog (e lt-l sign fact pow
)
1743 (setq e
(e l
) lt-l
(setq l
(ncons l
))
1744 sign
(rcone) fact
'(1 .
2) pow
'(4 .
1))
1745 a
(cond ((e> (setq e
(e+ (rctwo) e
)) pw
) (return l
))
1746 (t (setq fact
(e// fact
(e* e
(e1+ e
)))
1747 pow
(e* '(4 .
1) pow
)
1748 sign
(e* chng sign
))
1749 (add-term lt-l e
(e* (e* sign fact
)
1751 (ftake '%bern
(rcdisrep (e1+ e
))))
1752 (e* pow
(e1- pow
)))))
1753 (setq lt-l
(n-term lt-l
))))
1756 (defun expcot-funs (pw l sign chng plus
)
1757 (prog (e lt-l fact pow
)
1758 (setq e
(e l
) lt-l
(setq l
(ncons l
))
1759 fact
(rcone) pow
(rcone))
1760 a
(cond ((e> (setq e
(e+ (rctwo) e
)) pw
) (return l
))
1761 (t (setq fact
(e// fact
(e* e
(e1+ e
)))
1762 pow
(e* '(4 .
1) pow
)
1763 sign
(e* chng sign
))
1764 (add-term lt-l e
(e* (e* sign fact
)
1766 (ftake '%bern
(rcdisrep (e1+ e
))))
1768 (setq lt-l
(n-term lt-l
))))
1771 (defun expsec-funs (pw l chng
)
1772 (prog (e lt-l sign fact
)
1773 (setq e
(e l
) lt-l
(setq l
(ncons l
))
1774 sign
(rcone) fact
(rcone))
1775 a
(cond ((e> (setq e
(e+ (rctwo) e
)) pw
) (return l
))
1776 (t (setq fact
(e// fact
(e* e
(e1- e
)))
1777 sign
(e* chng sign
))
1778 (add-term lt-l e
(e* (e* sign fact
)
1779 (prep1 (ftake '%euler
(rcdisrep e
)))))
1780 (setq lt-l
(n-term lt-l
))))
1783 (defun expasin-funs (pw l chng
)
1784 (prog (e lt-l sign n d
)
1785 (setq e
(e l
) lt-l
(setq l
(ncons l
)) sign
1 n
1 d
1)
1786 a
(cond ((e> (setq e
(e+ (rctwo) e
)) pw
) (return l
))
1787 (t (setq n
(* n
(car (e- e
(rctwo))))
1788 d
(* d
(car (e1- e
)))
1790 (add-term lt-l e
; need to reduce here ? - check this.
1791 (let ((x (*red
(* n sign
)
1794 (cons (cadr x
) (caddr x
)))))
1795 (setq lt-l
(n-term lt-l
))))
1798 ;;; This is the table of expansion data for known functions.
1799 ;;; The format of the EXP-FORM property is as follows:
1800 ;;; (<name of the expanding routine for the function or
1801 ;;; (name . le of n-term) if expansion is of order 0>
1802 ;;; <first term in the expansion or the name of a routine which
1803 ;;; computes the order when it may depend on parameters (e.g subsripts)>
1804 ;;; <data for the expanding routine>)
1807 (loop for
(fun exp
) on
1808 '(%exp
((expexp-funs 1 .
1) ((0 .
1) 1 .
1) (1 .
1) (1 .
1) (1 .
1))
1809 %sin
(expexp-funs ((1 .
1) 1 .
1) (-1 .
1) (-1 .
1) (2 .
1))
1810 %cos
((expexp-funs 2 .
1) ((0 .
1) 1 .
1) (-1 .
1) (-1 .
1) (2 .
1))
1811 %sinh
(expexp-funs ((1 .
1) 1 .
1) (1 .
1) (1 .
1) (2 .
1))
1812 %cosh
((expexp-funs 2 .
1) ((0 .
1) 1 .
1) (1 .
1) (1 .
1) (2 .
1))
1813 %log
(explog-funs ((1 .
1) 1 .
1) (-1 .
1) (-1 .
1) (1 .
1))
1814 %atan
(explog-funs ((1 .
1) 1 .
1) (-1 .
1) (-1 .
1) (2 .
1))
1815 %atanh
(explog-funs ((1 .
1) 1 .
1) (1 .
1) (1 .
1) (2 .
1))
1816 %cot
(expcot-funs ((-1 .
1) 1 .
1) (1 .
1) (-1 .
1) (0 .
1))
1817 %csc
(expcot-funs ((-1 .
1) 1 .
1) (-1 .
1) (-1 .
1) (-2 .
1))
1818 %csch
(expcot-funs ((-1 .
1) 1 .
1) (-1 .
1) (1 .
1) (-2 .
1))
1819 %coth
(expcot-funs ((-1 .
1) 1 .
1) (1 .
1) (1 .
1) (0 .
1))
1820 %tan
(exptan-funs ((1 .
1) 1 .
1) (-1 .
1))
1821 %tanh
(exptan-funs ((1 .
1) 1 .
1) (1 .
1))
1822 %sec
((expsec-funs 2 .
1) ((0 .
1) 1 .
1) (-1 .
1))
1823 %sech
((expsec-funs 2 .
1) ((0 .
1) 1 .
1) (1 .
1))
1824 %asin
(expasin-funs ((1 .
1) 1 .
1) 1)
1825 %asinh
(expasin-funs ((1 .
1) 1 .
1) -
1)
1826 %gamma
(expgam-fun ((-1 .
1) 1 .
1))
1827 $li
(exp$li-fun li-ord
)
1828 %expintegral_si
(exp_%expintegral_si
((1 .
1) 1 .
1))
1829 $psi
(expplygam-funs plygam-ord
))
1831 do
(putprop fun exp
'exp-form
))
1834 (defun known-ps (fun)
1835 (getl fun
'(exp-form sp2
)))
1837 ;;; Autoload Properties
1839 ;;; Taylor series expansion routines
1841 ;;; SRF is only called externally; by RATF and SIMPEXPT.
1844 (let ((exact-poly t
) (tlist) (*within-srf?
* 't
))
1845 (setq x
(taylor1 x
()) tlist
(mrat-tlist x
))
1846 ;; Set trunc levels in the local tlist to correspond to the maximum
1847 ;; level occurring in any series.
1848 (do ((data tlist
(cdr data
))
1849 (truncs (trunc-vector (mrat-ps x
) () )))
1851 (when (and (car truncs
) (e> (car truncs
) (current-trunc (car data
))))
1852 (setf (current-trunc (car data
)) (car truncs
))))
1855 ;;; [var, pt, order, asymp]
1857 (defmfun $taylor
(e &rest args
)
1858 (when (not ($taylorp e
))
1859 ;; Not a taylor expression. Remove the special representation.
1860 (setq e
(specrepcheck e
)))
1863 (defun taylor* (arg l
)
1864 ;; We must bind $MAXTAYORDER to () below because of the problem of constants
1865 ;; not retaining their truncation level. This means that when we add a
1866 ;; series which has more terms than the user-specified truncation to a
1867 ;; constant we must truncate the series with more terms down to the user
1868 ;; specified level because, in the worst case, the constant could be a
1869 ;; series no better than to the user-specified level. Hence $MAXTAYORDER
1870 ;; is essentially useless until the constant problem is fixed. If one
1871 ;; decides to not bind $MAXTAYORDER below then the sum routines must
1872 ;; be updated to truncate series with more terms than the user-specified
1873 ;; level down to that level---taylor(sin(x)^2-cos(x)^2-1,x,0,1) would
1874 ;; give x^2+... in this case if the sum routines weren't updated.
1875 ;; Also, batch(mquery,160,aljabr) for another truncation bug which crops
1876 ;; up when $maxtayorder isn't bound here. Similarly, loadfile(taybad,rl,
1877 ;; aljabr) and see tomh's bug note of 4/15/81.
1878 (let ((tlist () ) ($maxtayorder
() ) (*within-srf?
* () )
1879 (exact-poly (if l
(not $taylor_truncate_polynomials
) 'user-specified
)))
1880 (declare (special *within-srf?
*))
1883 (taylor1 arg
(ncons tlist
))))
1885 (defun tay-order (n)
1886 (let (($float
) (modulus))
1887 (cond ((eq n
'$inf
) (ncons (inf)))
1888 ((null n
) (wna-err '$taylor
))
1890 (merror (intl:gettext
"taylor: expansion order must be a number; found: ~:M") n
))
1891 (t (ncons (prep1 n
))))))
1893 (defun re-erat (head exp
)
1894 (taylor1 exp
(list (cadddr (cdr head
)))))
1896 (defun parse-tay-args (l)
1899 (merror (intl:gettext
"taylor: variable of expansion cannot be a number: ~M") (car l
)))
1900 ((or (symbolp (car l
)) (not (eq (caaar l
) 'mlist
)))
1901 (parse-tay-args1 (list (car l
) ($ratdisrep
(cadr l
)) (caddr l
)))
1902 (parse-tay-args (cdddr l
)))
1903 ((do ((l (cddar l
) (cdr l
)))
1905 (and (or (mnump (car l
)) (eq (car l
) '$inf
))
1907 (parse-tay-args1 (cdar l
))
1908 (parse-tay-args (cdr l
)))
1909 (t (parse-tay-args2 (list (car l
) (cadr l
) (caddr l
)))
1910 (parse-tay-args (cdddr l
)))))
1912 (defun parse-tay-args1 (l)
1913 (if ($listp
(car l
)) (parse-tay-args2 l
)
1915 (pt ($ratdisrep
(cadr l
)))
1916 (ord (tay-order (caddr l
)))
1917 (switches (make-switch-list (cdddr l
))))
1918 (push (list v ord pt switches
) tlist
))))
1920 (defun parse-tay-args2 (l)
1921 (let ((label (gensym))
1923 (pts (make-long-list (if ($listp
(cadr l
))
1924 (copy-list (cdadr l
))
1925 (ncons (ratdisrep (cadr l
))))))
1927 (switches (make-switch-list (cdddr l
)))
1931 (setq lcm ord max ord ord
(make-long-list (ncons ord
)))
1933 (l (cdr ord
) (cdr l
)))
1934 ((null a
) (setq ord
(cdr ord
)))
1935 (cond ((not l
) (merror "PARSE-TAY-ARGS2: ran out of truncation levels."))
1936 (t (setq lcm
(lcm lcm
(car l
)) max
(max max
(car l
)))))))
1937 (push (list label
(tay-order max
) 0
1938 (ncons (list 'multivar lcm vs
)))
1940 (do ((vl vs
(cdr vl
))
1941 (ordl ord
(cdr ordl
))
1942 (ptl pts
(cdr ptl
)))
1944 (cond ((not ptl
) (merror "PARSE-TAY-ARGS2: ran out of matching points of expansion."))
1947 (list (car vl
) (tay-order (car ordl
)) (car ptl
)
1948 (cons (list 'multi label
(timesk lcm
(expta (car ordl
) -
1))) switches
))
1951 (defun make-switch-list (l)
1952 (mapcar #'(lambda (q) (cons q t
)) l
))
1954 (defun make-long-list (q)
1957 ;;; This checks to ensure that there isn't more than one set of multi-
1958 ;;; dependent variables with different orders of expansion, e.g.
1959 ;;; taylor(u+v+x+y,[u,v],0,[2,3],[x,y],0,[5,7]) is one.
1961 (defun ratwtsetup (l)
1962 (do ((l l
(cdr l
)) (a) (sw))
1964 (when (setq a
(switch 'multivar
(car l
)))
1965 (do ((ll (cadr a
) (cdr ll
)))
1967 (cond ((equal (cadr (switch 'multi
(get-datum (car ll
)))) 1) )
1968 (sw (merror (intl:gettext
"taylor: multiple dependent variables must all have the same order of expansion.")))
1969 ('t
(setq sw
't
) (return 't
)))))))
1971 (defmvar $taylor_order_coefficients t
1972 "When `true', coefficients of taylor series will be ordered canonically.")
1974 (defun taylor1 (e tlist
)
1975 (declare (special *within-srf?
* ))
1976 (setq tlist
(tlist-merge (nconc (find-tlists e
) tlist
)))
1977 (prog ($zerobern $simp $algebraic genpairs varlist tvars sing-tvars
1978 log-1 log%i ivars key-vars ans full-log last-exp
1979 mainvar-datum zerolist taylor_simplifier least_term? tvar-limits
1981 (setq tlist
(mapcan #'(lambda (d)
1982 (if (tvar?
(datum-var d
))
1988 (setq $zerobern t $simp t $algebraic t last-exp e least_term?
't
1989 log-1
'((%log simp
) -
1) log%i
'((%log simp
) $%i
)
1990 tvars
(mapcar 'car tlist
) varlist
(copy-list tvars
))
1991 (when $taylor_simplifier
1992 ; This symbolp/fboundp check is presumably for efficiency (so it
1993 ; can be directly funcalled).
1994 (setq taylor_simplifier
1995 (if (and (symbolp $taylor_simplifier
)
1996 (fboundp $taylor_simplifier
))
1998 'taylor_simplifier_caller
)))
1999 ;; Ensure that the expansion points don't depend on the expansion vars.
2000 ;; This could cause an infinite loop, e.g. taylor(x,x,x,1).
2001 (do ((tl tlist
(cdr tl
)))
2003 (unless (mfree (exp-pt (car tl
)) tvars
)
2004 (merror (intl:gettext
"taylor: attempt to expand ~M at a point depending on ~M.") e
(caar tl
))))
2005 ;; This drastic initialization ensures that ALGEBRAIC, TELLRAT, DISREP,
2006 ;; etc. prop's are removed from our gensyms. RATSETUP does not appear
2007 ;; to do this correctly, e.g. see ASB's bug of 1/10/83 (MQUERY 17).
2008 (mapc #'(lambda (g) (setf (symbol-plist g
) nil
)) genvar
)
2009 (ratsetup varlist genvar
)
2010 (when (and $taylor_order_coefficients
(not *within-srf?
*)) (newvar e
))
2011 (orderpointer varlist
)
2012 (maplist #'(lambda (q g
)
2013 (push (cons (car g
) (car q
)) key-vars
)
2014 (let ((data (get-datum (car q
))))
2015 (rplaca q
(transform-tvar (car q
) data
))
2016 (push (cons (car g
) (car q
)) ivars
)
2017 ;(setf (data-gvar-o data)
2018 ; (cons (car g) (valget (car g))))
2019 (rplacd (cdddr data
)
2020 (cons (car g
) (valget (car g
))))))
2021 (do ((v varlist
(cdr v
)))
2022 ((eq (car v
) (car tvars
)) v
))
2023 (do ((v varlist
(cdr v
))
2025 ((eq (car v
) (car tvars
)) g
)))
2026 (setq genpairs
(mapcar #'(lambda (y z
)
2027 (putprop z y
'disrep
)
2028 (cons y
(cons (pget z
) 1)))
2031 (setup-multivar-disrep () )
2032 (setq mainvar-datum
(car (last tlist
)))
2033 (mapc #'(lambda (d) (adjoin-sing-datum d
)) sing-tvars
)
2034 (setq ans
(catch 'tay-err
(taylor3 e
)))
2036 (if (atom (car ans
)) (tay-error (car ans
) (cadr ans
)) ans
))))
2038 (defun transform-tvar (var data
)
2039 (if (not (tvar? var
)) var
2040 (cond ((and (signp e
(exp-pt data
)) (null (switch '$asymp data
)))
2042 ((member (exp-pt data
) '($inf infinity
) :test
#'eq
)
2044 ((eq (exp-pt data
) '$minf
)
2046 ((let ((temp (m- var
(exp-pt data
))))
2047 (if (switch '$asymp data
) (m^ temp -
1) temp
))))))
2049 (defun taylor_simplifier_caller (exp)
2050 (mcall $taylor_simplifier exp
))
2052 (defun taylor_simplify_recurse (ps)
2053 (if (pscoefp ps
) (taylor2 (funcall taylor_simplifier
(rcdisrep ps
)))
2054 (let ((datum (ps-data ps
)) (var () ))
2055 ;; We must treat multivars like 1, since they'll reappear again
2056 ;; when we call taylor2 on their disrep'd coeff's.
2057 (if (switch 'multivar datum
)
2060 (setq var
(getdisrep (gvar-o ps
)))
2061 ;; Don't push pw's < 0, else constants will be truncated
2062 (push-pw datum
(emax (trunc-lvl ps
) (rczero)))))
2063 (do ((terms (terms ps
) (n-term terms
))
2064 (ans (rczero) (psplus (if (null datum
)
2065 (taylor_simplify_recurse (lc terms
))
2066 (pstimes (taylor_simplify_recurse
2069 ;; (taylor2 (funcall taylor_simplifier
2070 ;; (m^ var (edisrep (le terms)))))
2071 ;; causes terms to be lost when inverting. E.g.
2072 ;; taylor(log(1+exp(-1/x)),x,0,5) calls psexpt(<exp(1/x)^3>...3,-1)
2073 ;; which must return a series good to 3+3(-1-1)=-3 which, when added
2074 ;; to other terms will truncate them to degree -3 also.
2075 (if (ezerop (le terms
)) (rcone)
2078 (term (le terms
) (rcone)))))))
2082 (when datum
(pop-pw datum
))
2085 (defun push-pw (datum pw
)
2086 (push pw
(trunc-stack datum
))
2087 ;; When changing the truncation on an internal multivar we must also
2088 ;; propagate the change to all var's which depend upon it. See WGD's
2089 ;; bug report of 9/15/82 which exhibits the necessity of this.
2090 (when (setq datum
(switch 'multivar datum
))
2091 (do ((vars (cadr datum
) (cdr vars
)))
2093 (push pw
(trunc-stack (get-datum (car vars
)))))))
2095 (defun pop-pw (datum)
2096 (pop (trunc-stack datum
))
2097 ;; See the comment above in push-pw; here we must undo the propagation.
2098 (when (setq datum
(switch 'multivar datum
))
2099 (do ((vars (cadr datum
) (cdr vars
)))
2101 (pop (trunc-stack (get-datum (car vars
)))))))
2103 (defun setup-multivar-disrep (mrat?
)
2104 (let ((varlist varlist
) (genvar genvar
) (multivars () ))
2106 (setq varlist
(mrat-varlist mrat?
) genvar
(mrat-genvar mrat?
)))
2107 (mapc #'(lambda (datum)
2108 (when (switch 'multivar datum
)
2109 (push (car datum
) multivars
)
2110 ;; All genvar's corresponding to internally generated
2111 ;; multivars must "disappear" when disrep'd. If this
2112 ;; were not done then disrep'ing gx*gt would give x*t
2113 ;; which, upon, re-tayloring would give (gx*gt)*gt,
2114 ;; where t is the internal multivar for x, and gt, gx
2115 ;; are their genvars. An example where this would occur is
2116 ;; taylor(sin(x+y),[x],0,f1,[y],0,1).
2117 (putprop (int-gvar datum
) 1 'disrep
)))
2118 (if mrat?
(mrat-tlist mrat?
) tlist
))
2119 ;; Here we must substitute 1 for any genvars which depend on multivars.
2120 ;; For example, taylor(x^n,[x],0,0) generates a multivar^n.
2122 (do ((expl varlist
(cdr expl
))
2123 (gvarl genvar
(cdr gvarl
)))
2125 (unless (mfree (car expl
) multivars
)
2126 (putprop (car gvarl
) 1 'disrep
))))))
2128 ;; An example showing why this flag is need is given by
2129 ;; taylor(-exp(exp(-1/x)+2/x),x,0,-1). Without it, tstimes and
2130 ;; taylor_simplify_recurse end up trunc'ing the -1.
2132 (defvar trunc-constants?
't
)
2135 (cond ((mbagp e
) (cons (car e
) (mapcar #'taylor3
(cdr e
))))
2136 ((and (null tlist
) (not (eq exact-poly
'user-specified
)))
2138 (list 'mrat
'simp varlist genvar
)))
2139 (t (xcons (if (null taylor_simplifier
)
2142 (setq e
(taylor2 e
))
2143 (let ((exact-poly () ) (trunc-constants?
() ))
2144 (taylor_simplify_recurse e
))))
2145 (list 'mrat
'simp varlist genvar tlist
'trunc
)))))
2147 (defun find-tlists (e) (let (*a
*) (findtl1 e
) *a
*))
2150 (cond ((or (atom e
) (mnump e
)) )
2151 ((eq (caar e
) 'mrat
)
2152 (when (member 'trunc
(car e
) :test
#'eq
)
2153 (push (mapcar #'copy-tree
(mrat-tlist e
)) *a
*)))
2154 (t (mapc #'findtl1
(cdr e
)))))
2156 (defun tlist-merge (tlists)
2157 (do ((tlists tlists
(cdr tlists
)) (tlist () ))
2158 ((null tlists
) (nreverse tlist
))
2159 (do ((a_tlist (car tlists
) (cdr a_tlist
)) (temp nil
))
2161 (if (null (setq temp
(get-datum (datum-var (car a_tlist
)) t
)))
2162 (if (prog2 (setq temp
(car a_tlist
))
2163 (or (tvar?
(datum-var temp
))
2164 (member (caar (datum-var temp
)) '(mexpt %log
) :test
#'eq
)))
2165 (push (list (datum-var temp
) (trunc-stack temp
)
2166 (exp-pt temp
) (switches temp
))
2168 (merror (intl:gettext
"taylor: ~M cannot be a variable.") (datum-var temp
)))
2171 ;; We must take the max truncation level when $maxtayorder
2172 ;; is T, cf. JPG's bug of 9/15/82.
2173 (when (e> (current-trunc (car a_tlist
)) (current-trunc temp
))
2174 (setf (current-trunc temp
) (current-trunc (car a_tlist
))))
2175 (unless (e> (current-trunc (car a_tlist
)) (current-trunc temp
))
2176 (setf (current-trunc temp
) (current-trunc (car a_tlist
)))))
2177 (unless (alike1 (exp-pt temp
) (exp-pt (car a_tlist
)))
2178 (merror (intl:gettext
"taylor: cannot combine expressions expanded at different points.")))
2179 (setf (switches temp
)
2180 (union* (switches temp
) (switches (car a_tlist
)))))))))
2182 (defun compattlist (list)
2183 (do ((l list
(cdr l
)))
2185 (or (alike1 (exp-pt (get-datum (datum-var (car l
)))) (exp-pt (car l
)))
2189 (let ((last-exp e
)) ;; lexp-non0 should be bound here when needed
2190 (cond ((assolike e tlist
) (var-expand e
1 () ))
2191 ((or (mnump e
) (atom e
) (mfree e tvars
))
2192 (if (or (e> (rczero) (current-trunc mainvar-datum
))
2194 (pszero (data-gvar-o mainvar-datum
)
2195 (current-trunc mainvar-datum
))
2196 (if (and taylor_simplifier
(not (atom e
)))
2197 (let ((e-simp (prep1 (funcall taylor_simplifier e
))))
2198 (when (and (rczerop e-simp
) (not (member e-simp zerolist
:test
#'eq
)))
2202 ((null (atom (caar e
))) (merror "TAYLOR2: internal error."))
2204 (if (and (compatvarlist varlist
(mrat-varlist e
)
2205 genvar
(mrat-genvar e
))
2206 (compattlist (mrat-tlist e
)))
2208 (let ((exact-poly () )) (re-taylor e
))))
2209 ((eq (caar e
) 'mplus
) (tsplus (cdr e
)))
2210 ((eq (caar e
) 'mtimes
) (tstimes (cdr e
)))
2211 ((eq (caar e
) 'mexpt
) (tsexpt (cadr e
) (caddr e
)))
2212 ((eq (caar e
) '%log
) (tslog (cadr e
)))
2213 ((and (or (known-ps (caar e
)) (get (caar e
) 'tay-trans
))
2214 (not (member 'array
(cdar e
) :test
#'eq
))
2215 (try-expansion (if (cddr e
) (cdr e
) (cadr e
))
2218 (cond ((get (subfunname e
) 'spec-trans
)
2219 (funcall (get (subfunname e
) 'spec-trans
) e
))
2220 ((known-ps (subfunname e
))
2221 (try-expansion (caddr e
) (cadr e
))))) )
2222 ((and (member (caar e
) '(%sum %product
) :test
#'eq
)
2223 (mfreel (cddr e
) tvars
))
2224 (tsprsum (cadr e
) (cddr e
) (caar e
)))
2225 ;; If TSDIFF returns NIL, it means that the derivative is wrt to some variable
2226 ;; other than one of the taylor variables.
2227 ;; If so, keep going and handle E as if it were a general expression.
2228 ((and (eq (caar e
) '%derivative
) (tsdiff (cadr e
) (cddr e
) e
)))
2229 ((or (eq (caar e
) '%at
)
2230 (do ((l (mapcar 'car tlist
) (cdr l
)))
2232 (or (free e
(car l
)) (return ()))))
2234 (t (let ((exact-poly () )) ; Taylor series aren't exact
2235 (let ((ee (diff-expand e tlist
)))
2236 (cond ((equal (sratsimp e
) (sratsimp ee
)) (return-from taylor2
(prep1 ee
)))
2237 (t (taylor2 ee
)))))))))
2239 (defun compatvarlist (a b c d
)
2241 ((or (null b
) (null c
) (null d
)) () )
2242 ((alike1 (car a
) (car b
))
2243 (if (not (eq (car c
) (car d
))) ()
2244 (compatvarlist (cdr a
) (cdr b
) (cdr c
) (cdr d
))))
2245 (t (compatvarlist a
(cdr b
) c
(cdr d
)))))
2248 (defun re-taylor (mrat)
2249 (let ((old-tlist (mrat-tlist mrat
)) (old-varlist (mrat-varlist mrat
))
2250 (old-genvar (mrat-genvar mrat
)) old-ivars
)
2251 (declare (special old-tlist old-ivars
))
2252 ;; Put back the old disrpes so rcdisrep's will work correctly.
2253 (mapc #'(lambda (g v
) (putprop g v
'disrep
)) old-genvar old-varlist
)
2254 (setup-multivar-disrep mrat
)
2255 (setq old-ivars
(mapcar #'(lambda (g v
) (cons g v
))
2256 old-genvar old-varlist
))
2257 (prog1 (re-taylor-recurse (mrat-ps mrat
))
2258 ;; Restore the correct disreps.
2259 (mapc #'(lambda (g v
) (putprop g v
'disrep
)) genvar varlist
)
2260 (setup-multivar-disrep () ))))
2262 (defun re-taylor-recurse (ps)
2263 (declare (special old-tlist old-ivars
))
2264 (if (not (psp ps
)) (taylor2 (rcdisrep ps
))
2265 (let (var (datum () ))
2266 (setq var
(cdr (assoc (gvar ps
) old-ivars
:test
#'eq
)))
2267 ;; We must treat multivars like 1, since they'll reappear again
2268 ;; when we call taylor2 or var-expand below.
2269 (if (switch 'multivar
(assoc var old-tlist
:test
#'equal
))
2271 (when (setq datum
(var-data var
))
2272 (push-pw datum
(trunc-lvl ps
))))
2274 (do ((terms (terms ps
) (n-term terms
))
2276 (psplus (if (null var
) (re-taylor-recurse (lc terms
))
2277 (pstimes (re-taylor-recurse (lc terms
))
2279 (var-expand (car datum
)
2280 (edisrep (le terms
))
2283 (m^t var
(edisrep (le terms
)))))))
2286 (when datum
(pop-pw datum
))))))
2288 (defun var-expand (var exp dont-truncate?
)
2289 (let (($keepfloat
) ($float
) (modulus))
2290 (setq exp
(prep1 exp
))) ;; exp must be a rational integer
2291 (let ((temp (get-datum var
't
)))
2292 (cond ((null temp
) (merror "VAR-EXPAND: invalid call."))
2293 ((member (exp-pt temp
) '($inf $minf $infinity
) :test
#'eq
)
2294 (cond ((switch '$asymp temp
)
2295 (merror (intl:gettext
"taylor: cannot create an asymptotic expansion at infinity.")))
2296 ((e> (setq exp
(rcminus exp
)) (current-trunc temp
))
2298 (t (make-ps (int-var temp
)
2299 (ncons (if exact-poly
(inf) (current-trunc temp
)))
2301 (if (eq (exp-pt temp
) '$minf
)
2304 ;; multivar expansion does not work at infinity, so
2305 ;; expansion at infinity is handled by above clause even if doing multivar.
2306 ((switch 'multi temp
) ;; multivar expansion
2308 ;; The reason we call var-expand below instead of taylor2
2309 ;; is that we must be sure the call is not truncated to
2310 ;; 0 which would cause an error in psexpt if exp < 0.
2311 ;; For example, this occurred in TAYLOR(X^2/Y,[X,Y],0,2).
2313 ;; Must ensure that we get back a series truncated
2314 ;; to at least what is specified by tlist. This means
2315 ;; we'll have to push-pw unless exp>0 since psexpt'n
2316 ;; kills (exp-1) terms. The bug that discovered this
2317 ;; is taylor(li[2](x+1/2)/x,[x],0,0) missing 2*log(2).
2318 (if (not (e> exp
(rczero)))
2319 (let-pw (get-datum (car (switch 'multi temp
)))
2320 (e+ (current-trunc temp
) (e- (e1- exp
)))
2321 (var-expand (car (switch 'multi temp
)) 1 't
))
2322 (var-expand (car (switch 'multi temp
)) 1 't
))
2323 (cons (list (int-gvar temp
) 1 1) 1))
2324 (taylor2 (exp-pt temp
)))
2326 ((signp e
(exp-pt temp
))
2327 (let ((exp>trunc?
() ))
2328 (if (and (e> exp
(current-trunc temp
)) (setq exp
>trunc?
't
)
2329 (not dont-truncate?
))
2331 (make-ps (int-var temp
)
2332 (ncons (if exact-poly
(inf)
2333 (if exp
>trunc? exp
(current-trunc temp
))))
2334 (ncons (term (if (switch '$asymp temp
) (rcminus exp
)
2338 (make-ps (int-var temp
)
2339 (ncons (if exact-poly
(inf) (current-trunc temp
)))
2340 (ncons (term (if (switch '$asymp temp
)
2344 (taylor2 (exp-pt temp
)))
2347 (defun expand (arg func
)
2348 (or (try-expansion arg func
) (exp-pt-err)))
2350 (defun try-expansion (arg func
)
2351 (prog (funame funord fun-lc argord psarg arg-trunc temp exact-poly
)
2352 ;; We bind exact-poly to () since we don't want psexpt retaining
2353 ;; higher order terms when subst'ing into series (which aren't exact).
2354 ;; Try diff-expanding unknown subsripted functions.
2355 (unless (or (atom func
) (known-ps (caar func
)))
2356 (taylor2 (diff-expand `((mqapply) ,func
,arg
) tlist
)))
2357 (when (setq temp
(get (setq funame
(oper-name func
)) 'tay-trans
))
2358 (return (funcall temp arg func
)))
2359 (let ((lterm (getfun-lt func
)))
2360 (setq funord
(e lterm
) fun-lc
(c lterm
)))
2362 (when (rczerop (or psarg
(setq psarg
(get-lexp arg
(rcone) () ))))
2363 (if (e> (rczero) funord
)
2364 (if (rczerop (setq psarg
(get-lexp arg
(rcone) 't
)))
2366 (go begin-expansion
))
2367 (return (cond ((setq temp
(assoc funame tay-pole-expand
:test
#'eq
))
2368 (funcall (cdr temp
) arg psarg func
))
2369 ((rczerop funord
) fun-lc
)
2371 (when (pscoefp psarg
) (setq psarg
(taylor2 arg
)))
2372 (when (pscoefp psarg
)
2374 (cond ((null (mfree (rdis psarg
) tvars
))
2375 (symbolic-expand arg psarg func
))
2376 ((setq temp
(assoc funame tay-pole-expand
:test
#'eq
))
2377 (funcall (cdr temp
) arg psarg func
))
2379 (if (atom func
) `((,func
) ,(rcdisrep psarg
))
2380 `((mqapply) ,func
,(rcdisrep psarg
)))))))))
2381 (when (e> (rczero) (setq argord
(ps-le psarg
)))
2382 (cond ((not (member funame
'(%atan %asin %asinh %atanh
) :test
#'eq
))
2383 (if (e> (rczero) (ps-le* (setq psarg
(get-lexp arg
(rcone) 't
))))
2385 (go begin-expansion
)))
2387 (if (and (eq funame
'%atan
)
2388 (eq (coef-sign arg
) '$neg
))
2389 (return (psplus (atrigh arg func
) (taylor2 (m- '$%pi
))))
2390 (return (atrigh arg func
))))))
2391 (setq temp
(t-o-var (gvar psarg
)))
2392 (when (e> (e* funord argord
) temp
) (return (rczero)))
2393 ;; the following form need not be executed if psarg is really exact.
2394 ;; The constant problem does not allow one to determine this now,
2395 ;; so we always have to execute this currently.
2396 ;; This really should be
2397 ;; (unless (infp (trunc-lvl psarg)) ... )
2398 ;; Likewise, the infp checks shouldn't be there; have to assume
2399 ;; nothing is exact until constant problem is fixed.
2400 (setq arg-trunc
(if (and (not (infp (trunc-lvl psarg
)))
2401 (e= funord
(rcone)))
2403 (e- temp
(e* (e1- funord
) argord
)))
2404 psarg
(let-pw (get-datum (get-key-var (gvar psarg
)))
2406 (if (or (infp (trunc-lvl psarg
))
2407 (e> arg-trunc
(trunc-lvl psarg
)))
2410 ;; We must recalculate argord since pstrunc may have "picked"
2411 ;; a coeff out of a constant monomial; e.g. this occurs in
2412 ;; taylor(sin(x+y),x,0,0,y,0,1) where psarg is (Y+...)*X^0+...
2413 ;; which truncates to Y+... of order 1.
2414 argord
(ps-le* psarg
))
2415 (if (rczerop argord
)
2416 (cond ((member funame
'(%atan %asin %asinh %atanh
) :test
#'eq
)
2417 (return (atrigh arg func
)))
2418 ((setq temp
(assoc funame const-exp-funs
:test
#'eq
))
2419 (return (funcall (cdr temp
) arg psarg func
)))
2420 ((rczerop (ps-le* (setq psarg
(get-lexp arg
(rcone) 't
))))
2421 (return () )) ; Don't know an addition formula
2422 (t (go begin-expansion
)))
2424 (if (mono-term?
(terms psarg
))
2425 (get-series func
(current-trunc
2426 (get-datum (get-key-var (gvar psarg
))))
2427 (gvar-o psarg
) (ps-le psarg
) (ps-lc psarg
))
2429 (setq temp
(get-series func
2430 (e// temp argord
) (gvar-o psarg
)
2432 (cond ((not (psp temp
)) temp
)
2433 (t (pscsubst1 psarg temp
)))))))))
2435 (defun symbolic-expand (ign psarg func
) ; should be much stronger
2436 (declare (ignore ign
))
2437 (prep1 (simplifya (if (atom func
)
2438 `((,func
) ,(rcdisrep psarg
))
2439 `((mqapply) ,func
,(rcdisrep psarg
)))
2442 (defun expand-sing-trig?
(arg func
)
2443 (cond ((member func
*pscirc
:test
#'eq
) (tay-exponentialize arg func
))
2444 ((member func
*psacirc
:test
#'eq
) (atrigh arg func
))
2445 (t (essen-sing-err))))
2447 (defun trig-const (a arg func
)
2448 (let ((const (ps-lc* arg
)) (temp (cdr (assoc func trigdisp
:test
#'eq
))))
2449 (cond ((and (pscoefp const
)
2450 (member func
'(%tan %cot
) :test
#'eq
)
2451 (multiple-%pi a
(srdis const
) func
)))
2452 (temp (funcall temp
(setq const
(psdisrep const
))
2454 (t (tsexpt `((,(get func
'recip
)) ,(srdis arg
)) -
1)))))
2456 (defun multiple-%pi
(a const func
)
2458 (and (equal ($hipow const
'$%pi
) 1)
2459 ($ratnump
(setq coef
($ratcoef const
'$%pi
1)))
2460 (cond ((numberp coef
) (expand (m- a const
) func
))
2461 ((equal (caddr coef
) 2)
2462 (psminus (expand (m- a const
)
2463 (cond ((eq func
'%tan
) '%cot
)
2464 ((eq func
'%cot
) '%tan
)
2465 (t (merror "MULTIPLE-%PI: internal error in Taylor expansion."))))))))))
2467 (setq *pscirc
'(%cot %tan %csc %sin %sec %cos %coth
2468 %tanh %csch %sinh %sech %cosh
)
2470 *psacirc
'(%acot %atan %acsc %asin %asec %acos %acoth
2471 %atanh %acsch %asinh %asech %acosh
))
2473 (setq const-exp-funs
2474 `((%gamma . gam-const
) ($psi . plygam-const
)
2475 .
,(mapcar #'(lambda (q) (cons q
'trig-const
)) *pscirc
))
2477 trigdisp
'((%sin . psina
+b
) (%cos . pscosa
+b
) (%tan . pstana
+b
)
2478 (%sinh . psinha
+b
) (%cosh . pscosha
+b
) (%tanh . pstanha
+b
))
2480 tay-pole-expand
'((%gamma . plygam-pole
) ($psi . plygam-pole
))
2482 tay-const-expand
; !these should be handled by symbolic-expand
2483 ; be sure to change this with tay-exponentialize!
2484 (append (mapcar #'(lambda (q) (cons q
'tay-exponentialize
)) *pscirc
)
2485 (mapcar #'(lambda (q) (cons q
'tay-exponentialize
)) *psacirc
)))
2487 (mapc #'(lambda (q) (putprop q
'atrig-trans
'tay-trans
))
2488 '(%acos %acot %asec %acsc %acosh %acoth %asech %acsch
))
2490 (defprop mfactorial factorial-trans tay-trans
)
2492 (defun factorial-trans (arg func
)
2493 (declare (ignore func
))
2494 (taylor2 `((%gamma
) ,(m1+ arg
))))
2496 (defprop %signum signum-trans tay-trans
)
2498 ;; signum(x) => x/abs(x)
2499 ;; this gives an error at x=0 and a derivative of 0 elsewhere
2500 (defun signum-trans (arg func
)
2501 (declare (ignore func
))
2502 (taylor2 `((mtimes) ,arg
((mexpt) ((mabs) ,arg
) -
1))))
2504 (defprop %gamma_incomplete gamma-upper-trans tay-trans
)
2505 (defprop $gamma_incomplete gamma-upper-trans tay-trans
)
2506 (defprop %gamma_incomplete_lower gamma-lower-trans tay-trans
)
2507 (defprop $gamma_incomplete_lower gamma-lower-trans tay-trans
)
2509 ;; for gamma_incomplete(s,z)
2510 ;; translate into gamma_incomplete_lower if s>0 and z=0
2512 ;; June 2022: To workaround the bug
2513 ;; integrate(x*exp(-x^2)*sin(x),x,minf,inf)
2514 ;; limit: variable must be a symbol or subscripted symbol; found: sin(x)
2515 ;; I (Barton Willis) surrounded the call to $limit with errcatch with
2516 ;; $errormsg set to nil. This change allows Maxima to find the correct
2517 ;; value of this definite integral. But almost surely there is a bug
2518 ;; somewhere else that calls gamma-upper-trans with faulty arguments.
2519 ;; The real bug should be fixed, but inserting errcatch here is
2521 (defun gamma-upper-trans (arg func
)
2525 (eq ($sign s
) '$pos
)
2526 (let (($errormsg nil
))
2527 (zerop1 (car (errcatch ($limit z
(caar tlist
) (exp-pt (car tlist
))))))))
2528 (taylor2 `((mplus) ((%gamma
) ,s
)
2529 ((mtimes) -
1 ((%gamma_incomplete_lower
) ,s
,z
))))
2530 (taylor2 (diff-expand `((,func
) .
,arg
)
2533 ;; for gamma_incomplete_lower(s,z)
2534 ;; if z=0, use A&S 6.5.29
2538 ;;; gamma_incomplete_lower(s,z) = z^s * > ------------
2542 (defun gamma-lower-trans (arg func
)
2545 (if (zerop1 ($limit z
(caar tlist
) (exp-pt (car tlist
))))
2550 ((mexpt) ((mtimes) -
1 ,z
) k
)
2551 ((mexpt) ((mtimes) ((mfactorial) k
)
2557 (taylor2 (diff-expand `((,func
) .
,arg
)
2561 ;;; Not done properly yet
2563 ;;; (defprop $BETA BETA-TRANS TAY-TRANS)
2565 (defun psina+b
(a b
)
2566 (psplus (pstimes (expand a
'%sin
) (expand b
'%cos
))
2567 (pstimes (expand a
'%cos
) (expand b
'%sin
))))
2569 (defun pscosa+b
(a b
)
2570 (psdiff (pstimes (expand a
'%cos
) (expand b
'%cos
))
2571 (pstimes (expand a
'%sin
) (expand b
'%sin
))))
2573 (defun pstana+b
(a b
)
2574 (setq a
(expand a
'%tan
) b
(expand b
'%tan
))
2575 (pstimes (psplus a b
)
2576 (psexpt (psdiff (rcone) (pstimes a b
))
2579 (defun psinha+b
(a b
)
2580 (psplus (pstimes (expand a
'%sinh
) (expand b
'%cosh
))
2581 (pstimes (expand a
'%cosh
) (expand b
'%sinh
))))
2583 (defun pscosha+b
(a b
)
2584 (psplus (pstimes (expand a
'%cosh
) (expand b
'%cosh
))
2585 (pstimes (expand a
'%sinh
) (expand b
'%sinh
))))
2587 (defun pstanha+b
(a b
)
2588 (setq a
(expand a
'%tanh
) b
(expand b
'%tanh
))
2589 (pstimes (psplus a b
)
2590 (psexpt (psplus (rcone) (pstimes a b
))
2593 (defun atrig-trans (arg func
)
2595 (cond ((eq func
'%acos
)
2596 `((mplus) ,half%pi
((mtimes) -
1 ((%asin
) ,arg
))))
2599 `((mtimes) -
1 $%i
((mplus) ,half%pi
((mtimes) -
1 ((%asin
) ,arg
)))))
2602 `((,(cdr (assoc func
'((%acsc . %asin
) (%asec . %acos
)
2603 (%acot . %atan
) (%acsch . %asinh
)
2604 (%asech . %acosh
) (%acoth . %atanh
)) :test
#'eq
)))
2607 (defun atrigh (arg func
)
2608 (let ((full-log t
) ($logarc t
) (log-1 '((mtimes) $%i $%pi
))
2609 (log%i
'((mtimes) ((rat) 1 2) $%i $%pi
)))
2610 (taylor2 (simplify `((,func
) ,arg
)))))
2612 (defun tay-exponentialize (arg fun
) ; !this should be in symbolic-expand!
2613 (let (($exponentialize t
) ($logarc t
))
2614 (setq arg
(meval `((,fun
) ,arg
))))
2618 (do ((l (cdr l
) (cdr l
))
2619 (ans (taylor2 (car l
))
2620 (psplus ans
(taylor2 (car l
)))))
2623 (defun ts-formula (form var pw
)
2624 (let ((datum (get-datum (get-key-var (car var
)))))
2626 (taylor2 (subst (get-inverse (car var
)) 'sp2var form
)))))
2628 (defmacro next-series
(l) `(cdadr ,l
))
2630 (defun tstimes-get-pw (l pw
)
2631 (do ((l l
(cdr l
)) (vect))
2633 (setq pw
(mapcar #'(lambda (pwq ple
) (e+ pwq ple
))
2634 pw
(setq vect
(ord-vector (cdar l
)))))
2635 (rplacd (car l
) (cons (cdar l
) vect
))))
2637 (defun tstimes-l-mult (a)
2638 (do ((l (cdr a
) (cdr l
)) ($maxtayorder t
)
2639 (a (car a
) (pstimes a
(car l
))))
2645 (or (zfree e
(car l
)) (return () ))))
2647 ;;; The lists posl, negl and zerl have the following format:
2649 ;;; ( (<expression> <expansion> <order vector>) . . . )
2652 (*bind
* ((funl) (expl) (negl) (zerl) (posl)
2653 (pw) (negfl) (temp) (fixl (rcone)))
2654 (dolist (fun l
) ;; find the exponentials
2656 (push (if (free (caddr fun
) (car tvars
)) fun
2657 `((mexpt) $%e
,(m* (caddr fun
)
2658 `((%log
) ,(cadr fun
)))))
2662 (setq expl
(tsexp-comb expl
)) ;; simplify exps
2663 (setq expl
(tsbase-comb expl
))) ;; and again
2664 (setq l
(nconc expl funl
)) ;; now try expanding
2665 (let ((trunc-constants?
() ))
2666 (setq expl
(cons 0 (mapcar #'(lambda (exp)
2667 (cons exp
(taylor2 exp
)))
2669 ;; EXPL is now of the form (0 ( <form> . <taylor2(form)> ) ...)
2670 ;; L points behind the cons considered for destructive updating.
2671 (do ((l expl
) (tem))
2673 (cond ((rczerop (cdadr l
))
2674 ;; Consider taylor((a+1/x)*1/x,x,0,-2). Each factor will be on
2675 ;; zerl. Each factor will also appear to have le = 0 since its
2676 ;; series is 0, which would fool the get-pw routines below if
2677 ;; they tried to handle this case. The easiest fix for now
2678 ;; appears to be to always call get-lexp here, killing this:
2679 (cond ;((null $maxtayorder)
2680 ; (setq zerl (cons (cadr l) zerl))
2681 ; (rplacd l (cddr l)))
2682 ((rczerop (setq tem
(get-lexp (caadr l
) (rcone) ())))
2683 (return (setq zerl
0)))
2684 ('t
(setq posl
(cons (cons (caadr l
) tem
) posl
))
2685 (rplacd l
(cddr l
)))))
2686 ((pscoefp (cdadr l
))
2687 (cond ((mzfree (caadr l
) tvars
) ;must be zfree to permit ratfuns
2688 (setq fixl
(pstimes (cdadr l
) fixl
))
2689 (rplacd l
(cddr l
)))
2690 ((setq zerl
(cons (cadr l
) zerl
))
2691 (rplacd l
(cddr l
)))))
2692 ((rczerop (ps-le (cdadr l
)))
2693 (setq zerl
(cons (cadr l
) zerl
))
2694 (rplacd l
(cddr l
)))
2695 ((e> (ps-le (cdadr l
)) (rczero))
2696 (setq posl
(cons (cadr l
) posl
))
2697 (rplacd l
(cddr l
)))
2698 ('t
(setq l
(cdr l
)))))
2699 (when (equal zerl
0) (return (rczero)))
2700 (setq negl
(cdr expl
) temp
(ord-vector fixl
))
2701 (mapcar #'(lambda (x) (and (e> (rczero) x
) (setq negfl t
))) temp
)
2702 (tstimes-get-pw zerl temp
)
2703 (setq pw
(tstimes-get-pw posl
(tstimes-get-pw negl temp
)))
2706 (mapcar #'(lambda (x)
2707 (prog2 (mapcar #'(lambda (datum lel pwl
)
2709 (e+ (current-trunc datum
)
2713 (mapcar #'(lambda (datum) (pop-pw datum
))
2715 (nconc posl zerl negl
)))
2716 (setq posl
(nconc (mapcar 'cadr posl
) (mapcar 'cadr zerl
)
2717 (mapcar 'cadr negl
))))
2718 (setq posl
(tstimes-l-mult posl
))
2719 (let ((ans (cond ((null fixl
) posl
)
2721 ('t
(pstimes fixl posl
)))))
2722 (if $maxtayorder ans
(pstrunc ans
)))))
2724 ;;; This routine transforms a list of exponentials as follows:
2726 ;;; a^c*b^(n*c) ===> (a*b^n)^c, where n is free of var.
2728 ;;; This transformation is only applicable when c is not free of var.
2730 (defun tsexp-comb (l) ;; ***** clobbers l *****
2731 (setq l
(cons '* l
))
2732 (do ((a l
) (e)) ;; updated by a rplacd or cdr.
2733 ((null (cddr a
)) (cdr l
)) ;; get rid of the *
2734 (rplaca (cddadr a
) (setq e
($ratsimp
(caddr (cadr a
)))))
2735 ;; Must delete e^0 lest we divide by the 0 below. RWG's byzero bug
2736 ;; of 3/1/78 used to cause this.
2737 (if (equal e
0) (rplacd a
(cddr a
))
2738 (if (mfree (caddr (cadr a
)) tvars
) (pop a
)
2739 (do ((b (cddr a
) (cdr b
)) (n))
2740 ((null b
) (setq a
(cdr a
)))
2741 (when (mfree (setq n
($ratsimp
(m// (caddar b
)
2744 (rplaca b
(list '(mexpt simp
)
2746 (m^
(cadar b
) n
)) ;; b^n
2748 (rplacd a
(cddr a
)) ;; delete a^c
2751 ;;; This routine transforms a list of exponentials as follows:
2753 ;;; a^b*a^c ===> a^(b+c),
2755 ;;; this is only necessary when b and c depend on "var."
2757 (defun tsbase-comb (l) ;;; *******clobbers l********
2758 (setq l
(cons '* l
))
2759 (do ((a l
)) ;;; updated by a rplacd or cdr
2760 ((null (cddr a
)) (cdr l
))
2761 (do ((b (cddr a
) (cdr b
)))
2762 ((null b
) (pop a
)) ;;; did not return early so pop.
2763 (when (alike1 (cadar b
) (cadadr a
))
2764 (rplaca b
(m^
(cadar b
) (m+ (caddar b
) (caddr (cadr a
)))))
2769 (cond ((and (atom b
) (mnump e
)
2771 (not (eq (exp-pt (get-datum b
)) '$minf
)))
2772 ;; one could remove this clause and let this case be handled by tsexpt1
2773 (var-expand b e
() ))
2774 ((mfree e tvars
) (tsexpt1 b e
))
2775 ((eq '$%e b
) (tsexpt-red (list e
)))
2776 (t (tsexpt-red (list (list '(%log
) b
) e
)))))
2778 (defun tsexpt-red (l)
2779 (*bind
* ((free) (nfree) (full-log) ($logarc t
) (expt) (ps)
2780 (log-1 '((mtimes) $%i $%pi
))
2781 (log%i
'((mtimes) ((rat) 1 2) $%i $%pi
)))
2782 a
(do ((l l
(cdr l
)))
2784 (cond ((mtimesp (car l
)) (setq l
(append l
(cdar l
))))
2785 ((mfree (car l
) tvars
) (push (car l
) free
))
2786 (t (push (car l
) nfree
))))
2787 (cond ((or (cdr nfree
) (atom (car nfree
))) )
2788 ((eq (caaar nfree
) '%log
)
2789 (return (tsexpt1 (cadar nfree
) (m*l free
))))
2790 ((member (caaar nfree
) *psacirc
:test
#'eq
)
2791 (setq l
(ncons (simplifya ;; simplify after removing simp flag
2792 (cons (ncons (caaar nfree
)) (cdar nfree
))
2796 ;; Must have truncs > 0 so that logs in the expt aren't trunc'd.
2797 ;; E.g, consider taylor(x^(x-1),x,0,-1).
2798 (tlist-mapc d
(push-pw d
(emax (current-trunc d
) (rcone))))
2799 (setq ps
(taylor2 (setq expt
(m*l
(append nfree free
)))))
2800 (tlist-mapc d
(pop-pw d
))
2801 ;; Here we must account for the truncation gain or lossage that
2802 ;; is encountered in exp(c*log(x)+y) -> x^c*exp(y).
2803 (let ((c0 (if (pscoefp ps
) ps
(psterm (terms ps
) (rczero))))
2805 (unless (rczerop c0
)
2806 (setq ord-e^c0
(ord-vector (setq e^c0
(psexpt-fn c0
))))
2807 ;; Must emax with 0 so that new singular kernals won't be trunc'd
2808 ;; e.g exp(1/x+...) to degree -2 should be exp(-1/x)+...
2809 ;; Also try taylor(screwa,x,0,-2).
2810 (mapc #'(lambda (d o
) (push-pw d
(emax (e- (current-trunc d
) o
)
2813 (setq ps
(psdiff (taylor2 expt
) c0
)))
2814 (setq ps
(psexpt-fn ps
))
2816 (tlist-mapc d
(pop-pw d
))
2817 (setq ps
(pstimes e^c0 ps
)))
2820 ;; Taylor's b^e, where e is independent of tvars.
2822 (defun tsexpt1 (b e
)
2824 (setq e
(let ((modulus () )) ; Don't mod exponents! See WGM's bug
2825 (prog2 (mapcar ; of 3/6/83 for an example.
2828 (emax (current-trunc datum
) (rczero))))
2831 (mapcar #'(lambda (datum) (pop-pw datum
)) tlist
)))
2834 pw
(if (psp tb
) (current-trunc (get-datum
2835 (get-key-var (gvar tb
))))
2836 ;; Constant problem kludge.
2837 (if (rczerop tb
) (current-trunc (car tlist
)) (rczero))))
2838 (if (floatp (car s
))
2839 (setq s
(maxima-rationalize (quot (car s
) (cdr s
)))))
2840 ;; We must ensure that the lc is non-zero since it will be inverted in
2842 (setq tb
(strip-zeroes tb
't
))
2844 (when (or ;; When 1 > s we need more terms since -le*(s-1) > 0.
2846 (and (e> (rczero) pw
) (e> s
(rcone))))
2847 (setq tb
(get-lexp b
() 't
)))
2848 (setq le
(ps-le* tb
)))
2849 ((psp tb
) (setq le
(ps-le tb
)))
2850 (t (return (rcexpt tb e
))))
2851 (and (e> (e* s le
) pw
) (null $maxtayorder
) (return (rczero)))
2852 (setq s
(e- pw
(e* le
(e1- s
))))
2853 ;(setq le (increment-truncs tb))
2858 (pstrunc1 tb
(list (cons (gvar tb
) s
))))
2859 ;; because of constants not retaining info, have to
2860 ;; just keep the constant here
2861 (cond ((not (psp tb
)) tb
)
2862 (t (let-pw (get-datum (get-key-var (gvar tb
))) s
(strip-zeroes (taylor2 b
) 't
)))))
2865 ;;; the method of calculating truncation levels below is incorrect.
2866 ;;; (i.e. increment-truncs & decrement-truncs, also used above)
2867 ;;; Examples which exhibit this incorrectness are:
2868 ;;; taylor(log(sin(y)+x),x,0,2,y,0,1) is missing a y/6*x and -1/6*x^2
2869 ;;; taylor(log(sin(z)+sin(y)+x),x,0,f1,y,0,3,z,0,5) misses a z^5*y^3 term.
2871 ;;; TSLOG must find the lowest degree term in the expansion of the
2872 ;;; log arg, then expand with the orders of all var's in this low term
2873 ;;; incremented by their order in this low term. Note that this is
2874 ;;; only necessary for var's with ord > 0, since otherwise we have
2875 ;;; already expanded to a higher ord than required. Also we must
2876 ;;; not do this for var's with trunc < 0, since this may incorrectly
2877 ;;; truncate terms which should end up as logs.
2879 (defun increment-truncs (ps)
2880 (do ((ps ps
(ps-lc ps
)) (trunc (t-o-var (gvar ps
))) (data () ))
2882 (when (e> (ps-le ps
) (rczero))
2883 (push (assoc (get-key-var (gvar ps
)) tlist
:test
#'eq
) data
)
2884 (push-pw (car data
) (e+ (e* (e+ trunc
(rctwo)) (ps-le ps
))
2885 (current-trunc (car data
))))
2886 (setq trunc
(e+ trunc
(current-trunc (car data
))))
2889 (defun decrement-truncs (data)
2890 (mapc #'(lambda (data) (pop-pw data
)) data
))
2893 (let ((psarg (taylor2 arg
)) datum
)
2894 (when (rczerop psarg
) (setq psarg
(get-lexp arg
() 't
)))
2895 ;; We must ensure that the lc is non-zero since it will be inverted in pslog
2896 (setq psarg
(strip-zeroes psarg
't
))
2897 (do ((ps psarg
(ps-lc ps
)) (shift (rcone) (e* shift
(rctwo))))
2900 (when (rczerop (setq psarg
(taylor2 arg
)))
2901 (setq psarg
(get-lexp arg
() 't
)))
2902 (mapc #'(lambda (data) (pop-pw data
)) datum
))
2904 (push (get-datum (get-key-var (gvar ps
))) datum
)
2905 (if (and (e> (ps-le ps
) (rczero))
2906 (e> (current-trunc (car datum
)) (rczero)))
2907 (push-pw (car datum
) (e+ (e* shift
(ps-le ps
))
2908 (current-trunc (car datum
))))
2911 ;; When e-start is non-null we start expanding at order e-start, ... , 2^m,
2912 ;; then 2^m*pow, instead of the normal sequence pow, ... , 2^m*pow
2913 ;; (where m = $taylordepth, pow = ord of var). This is done because it is
2914 ;; usually much more efficient for large, non-trivial expansions when we only
2915 ;; want the lowest order term.
2917 (defun get-lexp (exp e-start zerocheck?
)
2923 (tlist-mapc d
(push-pw d
(or e-start
(emax (orig-trunc d
) (rcone)))))
2924 (do ((psexp) (i (1+ $taylordepth
) (1- i
)))
2926 (tlist-mapc d
(pop-pw d
))
2930 (unless silent-taylor-flag
(zero-warn exp
))
2932 (declare (fixnum i
))
2933 (cond ((and (rczerop (setq psexp
(if zerocheck?
2934 (strip-zeroes (taylor2 exp
) 't
)
2936 (not (member exp zerolist
:test
#'eq
))) )
2937 ;; Info not needed yet.
2938 ;; ((and lexp-non0 (rczerop (le (terms psexp)))
2939 ;; (mono-term? (terms psexp))))
2940 (t (tlist-mapc d
(pop-pw d
))
2942 (cond ((and (= i
1) e-start
)
2943 (setq e-start
() i
2)
2944 (tlist-mapc d
(push-pw d
(prog1 (e* (orig-trunc d
) (current-trunc d
))
2946 (t (tlist-mapc d
(push-pw d
(prog1 (e* (rctwo) (current-trunc d
))
2950 (or (equal x
1) (equal x
1.0)))
2952 (defun [max-trunc
] ()
2953 (do ((l tlist
(cdr l
)) (emax (rczero)))
2954 ((null l
) (1+ (truncate (car emax
) (cdr emax
))))
2955 (when (e> (current-trunc (car l
)) emax
)
2956 (setq emax
(orig-trunc (car l
))))))
2958 (defun tsprsum (f l type
)
2959 (if (mfree f tvars
) (newsym f
)
2960 (let ((li (ncons (car l
))) (hi (caddr l
)) (lv (ncons (cadr l
))) a aa
2961 ($maxtayorder
() ));; needed to determine when terms are 0
2962 (if (and (numberp (car lv
)) (numberp hi
) (> (car lv
) hi
))
2963 (if (eq type
'%sum
) (taylor2 0) (taylor2 1))
2965 (if (eq type
'%sum
) (setq type
'()))
2966 (do ((m (* ([max-trunc
]) (ash 1 $taylordepth
)))
2968 (ans (taylor2 (maxima-substitute (car lv
) (car li
) f
))))
2969 ((equal hi
(car lv
)) ans
)
2970 (rplaca lv
(m1+ (car lv
)))
2971 ;; A cheap heuristic to catch infinite recursion when
2972 ;; possible, should be improved in the future
2973 (if (> k m
) (exp-pt-err)
2974 (setq a
;(mlet li lv (taylor2 (setq aa (meval f))))
2975 (taylor2 (maxima-substitute (car lv
) (car li
) f
))))
2977 (if (and (1p (car a
)) (1p (cdr a
)) (not (1p aa
)))
2979 (setq ans
(pstimes a ans
)))
2980 (if (and (rczerop a
) (not (signp e aa
)))
2982 (setq ans
(psplus ans a
))))))))))
2984 (defun tsdiff (e l check
)
2985 (*bind
* ((n) (v) (u))
2986 (do ((l l
(cddr l
)))
2988 (if (and (atom (car l
)) (numberp (cadr l
))
2989 (assoc (car l
) tlist
:test
#'eq
))
2990 (setq n
(cons (cadr l
) n
) v
(cons (car l
) v
))
2991 (setq u
(cons (car l
) (cons (cadr l
) u
)))))
2992 ;; If N is null, it means that the derivative is wrt to some variable
2993 ;; other than one of the taylor variables.
2994 ;; If so, give up; let the caller handle it.
2996 (if u
(setq e
(meval (cons '($diff
) (cons e l
)))))
2997 (setq l
(mapcar #'(lambda (x) (get-datum x
)) v
))
2998 (mapcar #'(lambda (datum pw
)
2999 (push-pw datum
(e+ (current-trunc datum
) (prep1 pw
))))
3001 (setq e
(taylor2 e
))
3002 (mapc #'(lambda (datum) (pop-pw datum
)) l
)
3003 (do ((vl v
(cdr vl
))
3008 (mapc #'(lambda (a b
)
3009 (putprop a
(prep1 (sdiff b
(car v
)))
3012 (setq e
(psdp e
))))))
3015 (defun no-sing-err (x) ;; try to catch all singularities
3017 (let ((ans (catch 'errorsw
(eval x
))))
3018 (if (eq ans t
) (unfam-sing-err) ans
))))
3020 ;; evaluate deriv at location var=pt
3021 (defun eval-deriv (deriv var pt
)
3023 (let ((ans (no-sing-err `(meval '(($at
) ,deriv
((mequal) ,var
,pt
))))))
3026 (defun check-inf-sing (pt-list) ; don't know behavior of random fun's @ inf
3027 (and (or (member '$inf pt-list
:test
#'eq
) (member '$minf pt-list
:test
#'eq
))
3030 (defun diff-expand (exp l
) ;l is tlist
3031 (check-inf-sing (mapcar (function caddr
) l
))
3034 (setq exp
(diff-expand exp
(cdr l
)))
3035 (do ((deriv (sdiff exp
(caar l
)) (sdiff deriv var
))
3037 (coef 1 (* coef
(1+ cnt
)))
3039 (pt (exp-pt (car l
)))
3040 (lim (rcdisrep (current-trunc (car l
))))
3041 (ans (list (no-sing-err `(meval '(($at
) ,exp
((mequal) ,(caar l
) ,(exp-pt (car l
)))))))
3042 (cons `((mtimes) ((rat simp
) 1 ,coef
)
3043 ,(eval-deriv deriv var pt
)
3044 ((mexpt) ,(sub* var pt
) ,cnt
))
3046 ((or (great cnt lim
) (equal deriv
0)) (cons '(mplus) ans
))))))
3048 ;;; subtitle disreping routines
3051 (if (= (cdr e
) 1) (car e
) (list '(rat) (car e
) (cdr e
))))
3053 (defun striptimes (a)
3054 (if (mtimesp a
) (cdr a
) (ncons a
)))
3057 (let (($psexpand
() )) ; Called only internally, no need to expand.
3059 (cons (list 'mrat
'simp varlist genvar tlist
'trunc
)
3063 (let ((varlist (mrat-varlist r
)) (genvar (mrat-genvar r
)))
3064 (mapc #'(lambda (exp genv
) (putprop genv exp
'disrep
))
3066 (setup-multivar-disrep r
)
3067 ;; This used to return 0 if psdisrep returned () but this is wrong
3068 ;; since taylor(false,x,0,0) would lose. If psdisrep really wants to
3069 ;; return () for 0 then we will probably find out soon.
3070 (if (eq $psexpand
'$multi
) (psdisexpand (cdr r
))
3071 (psdisrep (cdr r
)))))
3075 (psdisrep+ (psdisrep2 (terms p
) (getdisrep (gvar-o p
)) (trunc-lvl p
))
3076 (if (or $psexpand
(trunc-lvl p
)) '(mplus trunc
)
3080 (defun psdisrep^
(n var
)
3081 ;; If var = () then it is an internal var generated in a multivariate
3082 ;; expansion so it shouldn't be displayed. If var = 1 then it probably
3083 ;; resulted from the substitution in srdisrep, so it depends on an
3084 ;; internal var and likewise shouldn't be displayed.
3085 (cond ((or (rczerop n
) (null var
) (equal var
1)) 1)
3086 ((equal n
(rcone)) var
)
3087 ((and (mexptp var
) (equal (caddr var
) -
1))
3088 ;; This used to be conditioned on ps-bmt-disrep which was
3089 ;; always true. But I (rtoy) can't find a case where it
3090 ;; would have made a difference. The testsuite doesn't have
3092 (psdisrep^
(e- n
) (cadr var
)))
3093 ('t
`((mexpt ratsimp
) ,var
,(edisrep n
)))))
3095 ;;; There used to be a hack below that would print a series consisting
3096 ;;; of merely one term as exact polynomial (i.e. no trailing "..."'s).
3097 ;;; This is, of course, wrong but the problem with the fix is that
3098 ;;; now exact things like taylor(y*x,x,0,f1,y,0,1) will display like
3099 ;;; (y+...) x+... because of the problem with $MAXTAYORDER being internally
3100 ;;; bound to ()---which causes exact things to look inexact, such as
3101 ;;; x and y above. See the comment above taylor* for the $MAXTAYORDER problem.
3103 (defun psdisrep+ (p plush
&aux lowest-degree-term
)
3104 (if;; An exact sum of one arg is just that arg.
3105 (and (null (cdr p
)) (eq (cadr plush
) 'exact
))
3108 ;; Since the DISPLAY package prints trunc'd sum's arguments
3109 ;; from right to left we must put the terms of any constant term
3110 ;; in decreasing order. Note that only a constant (wrt to the
3111 ;; mainvar) term can be a term which is a sum.
3112 (when (mplusp (setq lowest-degree-term
(car (last p
))))
3113 (rplacd lowest-degree-term
(nreverse (cdr lowest-degree-term
))))
3116 (defun psdisrep* (a b
)
3117 (cond ((equal a
1) b
)
3119 (t (cons '(mtimes ratsimp
)
3120 (nconc (striptimes a
) (striptimes b
))))))
3122 (defun psdisrep2 (p var trunc
)
3123 (if (or $ratexpand $psexpand
) (psdisrep2expand p var
)
3124 (do ((a () (cons (psdisrep* (psdisrep (lc p
)) (psdisrep^
(le p
) var
))
3127 ((or (null p
) (e> (le p
) trunc
)) a
))))
3129 (defun psdisrep2expand (p var
)
3131 (l () (nconc (psdisrep*expand
(psdisrep (lc p
)) (psdisrep^
(le p
) var
))
3135 (defun psdisrep*expand
(a b
)
3136 (cond ((equal a
1) (list b
))
3137 ((equal b
1) (list a
))
3139 (list (cons '(mtimes ratimes
) (nconc (striptimes a
) (striptimes b
)))))
3140 ('t
(mapcar #'(lambda (z) (psdisrep* z b
))
3144 (defun psdisexpand (p)
3145 (let ((ans (ncons ())))
3146 (declare (special ans
)) ;used in pans-add
3147 (psdisexcnt p
() (rczero))
3150 (mapcar #'(lambda (x) (cond ((not (cddr x
)) (cadr x
))
3151 (t (cons '(mplus trunc
) (cdr x
)))))
3153 (cond ((not (cdr ans
)) (car ans
))
3154 (t (cons '(mplus trunc
) ans
)))))
3156 (defun psdisexcnt (p l n
)
3158 (do ((var (getdisrep (gvar-o p
))) (ll (terms p
) (n-term ll
)))
3160 (if (rczerop (le ll
)) (psdisexcnt (lc ll
) l n
)
3162 (cons (psdisrep^
(le ll
) var
) l
)
3164 (psans-add (cond ((not l
) (rcdisrep p
))
3165 (t (psdisrep* (rcdisrep p
)
3166 (cond ((not (cdr l
)) (car l
))
3167 (t (cons '(mtimes trunc
) l
))))))
3170 (defun psans-add (exp n
)
3171 (declare (special ans
)) ;bound in psdisexpand
3172 (do ((l ans
(cdr l
)))
3173 ((cond ((null (cdr l
)) (rplacd l
(ncons (list n exp
))))
3174 ((e= (caadr l
) n
) (rplacd (cadr l
) (cons exp
(cdadr l
))))
3175 ((e> (caadr l
) n
) (rplacd l
(cons (list n exp
) (cdr l
))))))))
3177 (defun srconvert (r)
3178 (cond ((not (atom (caadr (cdddar r
))))
3179 (cons (car r
) (psdisextend (cdr r
))))
3181 (*bind
* ((trunclist (cadr (cdddar r
)))
3186 (gens (cadddr (car r
))))
3187 (setq gps
(mapcar #'cons gens vs
))
3188 (do ((tl (cdr trunclist
) (cddr tl
)))
3189 ((null tl
) (cons (list 'mrat
'simp vs gens tlist
'trunc
) (srconvert1 (cdr r
))))
3190 (setq temp
(cdr (assoc (car tl
) gps
:test
#'eq
)))
3191 (cond ((null (member (car tl
) (cdr trunclist
) :test
#'eq
)))
3192 ((mplusp temp
) (merror "SRCONVERT: internal error."))
3195 (cons (list* temp
(tay-order (cadr tl
)) 0 nil
3196 (cons (car tl
) (symbol-value (car tl
))))
3199 (defun srconvert1 (p)
3200 (cond ((not (member (car p
) genvar
:test
#'eq
)) p
)
3202 (do ((l (cdr p
) (cddr l
))
3203 (a nil
(cons (term (prep1 (car l
)) (srconvert1 (cadr l
))) a
)))
3205 (make-ps (cons (car p
) (symbol-value (car p
)))
3206 (tay-order (zl-get trunclist
(car p
))) a
))))))
3208 ;;; subtitle error handling
3210 (defun tay-error (msg exp
)
3211 (if silent-taylor-flag
(throw 'taylor-catch
())
3213 (merror "taylor: ~A~%~M" msg exp
)
3214 (merror "taylor: ~A" msg
))))
3216 (defun exp-pt-err ()
3217 (tay-err (intl:gettext
"unable to expand at a point specified in:")))
3219 (defun essen-sing-err ()
3220 (tay-err (intl:gettext
"encountered an essential singularity in:")))
3222 (defun unfam-sing-err ()
3223 (tay-err (intl:gettext
"encountered an unfamiliar singularity in:")))
3225 (defun infin-ord-err ()
3226 (tay-err (intl:gettext
"expansion to infinite order?")))
3228 (defun tay-depth-err ()
3229 (tay-err (intl:gettext
"'taylordepth' exceeded while expanding:")))
3231 ;;; Subtitle TAYLORINFO
3233 (defun taylor-trunc (q)
3234 (setq q
(current-trunc q
))
3235 (cond ((null q
) '$inf
)
3236 ((equal (cdr q
) 1) (car q
))
3237 (t `((rat) ,(car q
) ,(cdr q
)))))
3239 (defun taylor-info (q)
3240 (let ((acc-var nil
) (acc-pt nil
) (acc-ord nil
) (qk) (acc))
3241 (cond ((null q
) nil
)
3244 (cond ((and (fourth qk
) (consp (fourth qk
)) (eq (caar (fourth qk
)) 'multivar
)) nil
)
3245 ((and (fourth qk
) (consp (fourth qk
)) (eq (caar (fourth qk
)) 'multi
))
3246 (while (and (fourth qk
) (consp (fourth qk
)) (eq (caar (fourth qk
)) 'multi
))
3248 (push (taylor-trunc qk
) acc-ord
)
3249 (push (exp-pt qk
) acc-pt
)
3250 (push (datum-var qk
) acc-var
)
3252 (push '(mlist) acc-ord
)
3253 (push '(mlist) acc-pt
)
3254 (push '(mlist) acc-var
)
3255 (setq q
(taylor-info q
))
3256 (if (null q
) (list acc-var acc-pt acc-ord
) (append q
(list acc-var acc-pt acc-ord
))))
3259 (setq acc
(if (and (fourth qk
) (consp (fourth qk
)) (eq '$asympt
(caar (fourth qk
))))
3260 (list '$asympt
) nil
))
3261 (push (taylor-trunc qk
) acc
)
3262 (push (exp-pt qk
) acc
)
3263 (push (datum-var qk
) acc
)
3265 (setq q
(taylor-info q
))
3266 (if (null q
) (list acc
) (append q
(list acc
)))))))))
3268 (defmfun $taylorinfo
(x)
3269 (if (and (consp x
) (member 'trunc
(first x
) :test
#'eq
))
3270 (cons '(mlist) (taylor-info (mrat-tlist x
)))
3275 ;;; Lisp let-pw Indent:2