1 ;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;; The data in this file contains enhancments. ;;;;;
5 ;;; Copyright (c) 1984,1987 by William Schelter,University of Texas ;;;;;
6 ;;; All rights reserved ;;;;;
7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
8 ;;; (c) Copyright 1982 Massachusetts Institute of Technology ;;;
9 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
13 (macsyma-module rat3e
)
15 ;; This is the rational function package part 5.
16 ;; It includes the conversion and top-level routines used
17 ;; by the rest of the functions.
19 (declare-top (special intbs
* alflag var dosimp alc $myoptions
20 vlist scanmapp radlist expsumsplit
*ratsimp
* mplc
*
21 $ratsimpexpons $expop $expon $negdistrib $gcd
))
24 "List of gensyms used to point to kernels from within polynomials.
25 The values cell and property lists of these symbols are used to
26 store various information.")
28 (defmvar genpairs nil
)
29 (defmvar varlist nil
"List of kernels")
30 (defmvar *fnewvarsw nil
)
31 (defmvar *ratweights nil
)
33 (defvar *ratsimp
* nil
)
35 (defmvar factorresimp nil
"If `t' resimplifies factor(x-y) to x-y")
37 ;; User level global variables.
39 (defmvar $keepfloat nil
"If `t' floating point coeffs are not converted to rationals")
40 (defmvar $factorflag nil
"If `t' constant factor of polynomial is also factored")
41 (defmvar $dontfactor
'((mlist)))
43 (defmvar $ratweights
'((mlist simp
)))
45 (defmvar $ratfac nil
"If `t' cre-forms are kept factored")
46 (defmvar $algebraic nil
)
47 (defmvar $ratvars
'((mlist simp
)))
48 (defmvar $facexpand t
)
50 (declare-top (special evp $infeval
))
53 (let ((varlist (caddar x
)))
54 (cond ((and evp $infeval
) (meval ($ratdisrep x
)))
56 (and $float $keepfloat
)
57 (not (alike varlist
(mapcar #'meval varlist
))))
58 (ratf (meval ($ratdisrep x
))))
61 (defprop mrat mrateval mfexpr
*)
63 (defmfun $ratnumer
(x)
65 (cons (car x
) (mapcar '$ratnumer
(cdr x
))))
67 (setq x
(taychk2rat x
))
68 (cons (car x
) (cons (cadr x
) 1)))))
70 (defmfun $ratdenom
(x)
72 (cons (car x
) (mapcar '$ratdenom
(cdr x
))))
74 (setq x
(taychk2rat x
))
75 (cons (car x
) (cons (cddr x
) 1)))))
79 (member 'trunc
(cdar x
) :test
#'eq
))
83 (defmvar tellratlist nil
)
85 (defun tellratdisp (x)
86 (pdisrep+ (trdisp1 (cdr x
) (car x
))))
88 (defun trdisp1 (p var
)
90 (t (cons (pdisrep* (if (mtimesp (cadr p
))
92 (cadr p
)) ;prevents clobbering p
93 (pdisrep! (car p
) var
))
94 (trdisp1 (cddr p
) var
)))))
96 (defmfun $untellrat
(&rest args
)
98 (if (setq x
(assol x tellratlist
))
99 (setq tellratlist
(remove x tellratlist
:test
#'equal
))))
100 (cons '(mlist) (mapcar #'tellratdisp tellratlist
)))
102 (defmfun $tellrat
(&rest args
)
103 (mapc #'tellrat1 args
)
104 (unless (null args
) (add2lnc 'tellratlist $myoptions
))
105 (cons '(mlist) (mapcar #'tellratdisp tellratlist
)))
107 (defun tellrat1 (x &aux varlist genvar $algebraic $ratfac algvar
)
108 (setq x
($totaldisrep x
))
109 (and (not (atom x
)) (eq (caar x
) 'mequal
) (newvar (cadr x
)))
110 (newvar (setq x
(meqhk x
)))
111 (unless varlist
(merror (intl:gettext
"tellrat: argument must be a polynomial; found: ~M") x
))
112 (setq algvar
(car (last varlist
)))
113 (setq x
(p-terms (primpart (cadr (ratrep* x
)))))
114 (unless (equal (pt-lc x
) 1) (merror (intl:gettext
"tellrat: minimal polynomial must be monic.")))
115 (do ((p (pt-red x
) (pt-red p
)))
117 (setf (pt-lc p
) (pdis (pt-lc p
))))
118 (setq algvar
(cons algvar x
))
119 (if (setq x
(assol (car algvar
) tellratlist
))
120 (setq tellratlist
(remove x tellratlist
:test
#'equal
)))
121 (push algvar tellratlist
))
124 (defmfun $printvarlist
()
125 (cons '(mlist) (copy-tree varlist
)))
127 (defmfun $showratvars
(e)
130 (if (member 'trunc
(cdar e
) :test
#'eq
) (setq e
($taytorat e
)))
131 (caddar (minimize-varlist e
)))
132 (t (let (varlist) (lnewvar e
) varlist
)))))
134 (defmfun $ratvars
(&rest args
)
135 (add2lnc '$ratvars $myoptions
)
136 (setq $ratvars
(cons '(mlist simp
) (setq varlist
(mapfr1 args varlist
)))))
138 (defun mapfr1 (l varlist
)
139 (mapcar #'(lambda (z) (fr1 z varlist
)) l
))
141 (defmvar inratsimp nil
)
143 (defmfun $fullratsimp
(exp &rest argl
)
145 loop
(setq exp1
(simplify (apply #'$ratsimp
(cons exp argl
))))
146 (when (alike1 exp exp1
) (return exp
))
150 (defun fullratsimp (l)
151 (let (($expop
0) ($expon
0) (inratsimp t
) $ratsimpexpons
)
152 (when (not ($ratp l
))
153 ;; Not a mrat expression. Remove the special representation.
154 (setq l
(specrepcheck l
)))
155 (setq l
($totaldisrep l
))
158 (defmfun $totaldisrep
(l)
160 ((not (among 'mrat l
)) l
)
161 ((eq (caar l
) 'mrat
) (ratdisrep l
))
162 (t (cons (delete 'ratsimp
(car l
) :test
#'eq
) (mapcar '$totaldisrep
(cdr l
))))))
164 ;;;VARLIST HAS MAIN VARIABLE AT END
166 (defun joinvarlist (cdrl)
167 (mapc #'(lambda (z) (unless (memalike z varlist
) (push z varlist
)))
168 (reverse (mapfr1 cdrl nil
))))
170 (defmfun $rat
(e &rest vars
)
171 (cond ((not (null vars
))
180 (defun rat0 (exp) ;SIMP FLAGS?
182 (cons (car exp
) (mapcar #'rat0
(cdr exp
)))
185 (defmfun $ratsimp
(e &rest vars
)
186 (cond ((not (null vars
))
190 (t (fullratsimp e
))))
192 ;; $RATSIMP, $FULLRATSIMP and $RAT allow for optional extra
193 ;; arguments specifying the VARLIST.
195 ;;;PSQFR HAS NOT BEEN CHANGED TO MAKE USE OF THE SQFR FLAGS YET
198 (let ((varlist (cdr $ratvars
)) genvar $keepfloat $ratfac
)
199 (sublis '((factored . sqfred
) (irreducible . sqfr
))
200 (ffactor x
#'psqfr
))))
202 (declare-top (special fn
))
205 (cond ((and (mexptp p
) (integerp (caddr p
)))
206 (list '(mexpt) (whichfn (cadr p
)) (caddr p
)))
208 (cons '(mtimes) (mapcar #'whichfn
(cdr p
))))
209 (fn (ffactor p
#'pfactor
))
212 (declare-top (special var
))
214 (defmvar adn
* 1 "common denom for algebraic coefficients")
217 (prog (alc ans adn
* $gcd
)
218 (setq $gcd
'$algebraic
)
219 (when (or (atom p
) (numberp p
)) (return p
))
221 (when (and (not $nalgfac
) (not intbs
*))
222 (setq intbs
* (findibase minpoly
*)))
224 (setq ans
(ffactor p
#'pfactor
))
225 (cond ((eq (caar ans
) 'mplus
)
228 (setq ans
(albk ans
))))
229 (if (and (not alc
) (equal 1 adn
*)) (return ans
))
230 (setq ans
(partition ans
(car (last varlist
)) 1))
231 (return (mul (let ((dosimp t
))
232 (mul `((rat) 1 ,adn
*)
234 (if alc
(pdis alc
) 1)))
237 (defun albk (p) ;to undo monicizing subst
238 (let ((alpha (pdis alpha
)) ($ratfac t
))
239 (declare (special alpha
))
240 ;; don't multiply them back out
241 (maxima-substitute (list '(mtimes simp
) mplc
* alpha
) ;assumes mplc* is int
245 (defmfun $gfactor
(p &aux
(gauss t
))
246 (when ($ratp p
) (setq p
($ratdisrep p
)))
247 (setq p
($factor
(subst '%i
'$%i p
) '((mplus) 1 ((mexpt) %i
2))))
248 (setq p
(sublis '((factored . gfactored
) (irreducible . irreducibleg
)) p
))
249 (let (($expop
0) ($expon
0) $negdistrib
)
250 (maxima-substitute '$%i
'%i p
)))
252 (defmfun $factor
(e &optional
(mp nil mp?
))
253 (let ($intfaclim
(varlist (cdr $ratvars
)) genvar ans
)
254 (setq ans
(if mp?
(factor e mp
) (factor e
)))
255 (if (and factorresimp $negdistrib
256 (mtimesp ans
) (null (cdddr ans
))
257 (equal (cadr ans
) -
1) (mplusp (caddr ans
)))
258 (let (($expop
0) ($expon
0))
262 (defun factor (e &optional
(mp nil mp?
))
263 (let ((tellratlist nil
)
267 ($negdistrib $negdistrib
))
268 (prog (fn var mm
* mplc
* intbs
* alflag minpoly
* alpha p algfac
*
269 $keepfloat $algebraic cargs
)
270 (declare (special cargs fn alpha
))
271 (unless (member $gcd
*gcdl
* :test
#'eq
)
272 (setq $gcd
(car *gcdl
*)))
276 cargs
(if mp?
(list mp
) nil
))
277 (when (symbolp p
) (return p
))
279 (return (let (($factorflag
(not scanmapp
)))
282 (return (cons (car p
) (mapcar #'(lambda (x) (apply #'factor
(cons x cargs
))) (cdr p
)))))
284 (setq alpha
(meqhk mp
))
286 (setq minpoly
* (cadr (ratrep* alpha
)))
287 (when (or (pcoefp minpoly
*)
288 (not (univar (cdr minpoly
*)))
289 (< (cadr minpoly
*) 2))
290 (merror (intl:gettext
"factor: second argument must be a nonlinear, univariate polynomial; found: ~M") alpha
))
291 (setq alpha
(pdis (list (car minpoly
*) 1 1))
293 (unless (equal (caddr minpoly
*) 1)
294 (setq mplc
* (caddr minpoly
*))
295 (setq minpoly
* (pmonz minpoly
*))
296 (setq p
(maxima-substitute (div alpha mplc
*) alpha p
)))
298 ($tellrat
(pdis minpoly
*))
302 (unless scanmapp
(setq p
(let (($ratfac t
)) (sratsimp p
))))
304 (when (symbolp p
) (return p
))
306 (return (let (($factorflag
(not scanmapp
)))
308 (setq $negdistrib nil
)
309 (setq p
(let ($factorflag
($ratexpand $facexpand
))
312 (setq p
(let (($expop
0) ($expon
0))
314 (cond ((mnump p
) (return (factornumber p
)))
315 ((atom p
) (return p
)))
316 (and $ratfac
(not $factorflag
) ($ratp e
) (return ($rat p
)))
317 (and $factorflag
(mtimesp p
) (mnump (cadr p
))
318 (setq alpha
(factornumber (cadr p
)))
319 (cond ((alike1 alpha
(cadr p
)))
321 (setq p
(cons (car p
) (append (cdr alpha
) (cddr p
)))))
323 (setq p
(cons (car p
) (cons alpha
(cddr p
)))))))
324 (when (null (member 'factored
(car p
) :test
#'eq
))
325 (setq p
(cons (append (car p
) '(factored)) (cdr p
))))
328 (defun factornumber (n)
329 (setq n
(nretfactor1 (nratfact (cdr ($rat n
)))))
331 (cons '(mtimes simp factored
)
332 (if (equal (car n
) -
1)
333 (cons (car n
) (nreverse (cdr n
)))
338 (cons (cons (caaar n
) '(simp factored
)) (cdar n
)))))
341 (cond ((equal (cdr x
) 1) (cfactor (car x
)))
342 ((equal (car x
) 1) (revsign (cfactor (cdr x
))))
343 (t (nconc (cfactor (car x
)) (revsign (cfactor (cdr x
)))))))
345 ;;; FOR LISTS OF JUST NUMBERS
346 (defun nretfactor1 (l)
348 ((equal (cadr l
) 1) (cons (car l
) (nretfactor1 (cddr l
))))
349 (t (cons (if (equal (cadr l
) -
1)
350 (list '(rat simp
) 1 (car l
))
351 (list '(mexpt simp
) (car l
) (cadr l
)))
352 (nretfactor1 (cddr l
))))))
354 (declare-top (unspecial var
))
356 (defmfun $polymod
(p &optional
(m 0 m?
))
357 (let ((modulus modulus
))
360 (when (or (not (integerp modulus
)) (zerop modulus
))
361 (merror (intl:gettext
"polymod: modulus must be a nonzero integer; found: ~M") modulus
)))
362 (when (minusp modulus
)
363 (setq modulus
(abs modulus
)))
367 (if (mbagp e
) (cons (car e
) (mapcar 'mod1
(cdr e
)))
370 (setq formflag
($ratp e
) e
(ratrep* e
))
371 (setq e
(cons (car e
) (ratreduce (pmod (cadr e
)) (pmod (cddr e
)))))
372 (cond (formflag e
) (t (ratdisrep e
))))))
374 (defmfun $divide
(x y
&rest vars
)
375 (prog (h varlist tt ty formflag $ratfac
)
376 (when (and ($ratp x
) (setq formflag t
) (integerp (cadr x
)) (equal (cddr x
) 1))
378 (when (and ($ratp y
) (setq formflag t
) (integerp (cadr y
)) (equal (cddr y
) 1))
380 (when (and (integerp x
) (integerp y
))
382 (merror (intl:gettext
"divide: Quotient by zero")))
383 (return (cons '(mlist) (multiple-value-list (truncate x y
)))))
385 (mapc #'newvar
(reverse (cdr $ratvars
)))
391 (setq y
(cdr (ratrep* y
)))
392 (cond ((and (equal (setq tt
(cdr x
)) 1) (equal (cdr y
) 1))
393 (setq x
(pdivide (car x
) (car y
))))
395 (setq x
(ptimes (car x
) (cdr y
)))
396 (setq x
(pdivide x
(car y
)))
399 (ratqu (cadr x
) (ptimes tt ty
))))))
400 (setq h
(list '(mlist) (cons h
(car x
)) (cons h
(cadr x
))))
401 (return (if formflag h
($totaldisrep h
)))))
403 (defmfun $quotient
(&rest args
)
404 (cadr (apply '$divide args
)))
406 (defmfun $remainder
(&rest args
)
407 (caddr (apply '$divide args
)))
409 (defmfun $gcd
(x y
&rest vars
)
410 (prog (h varlist genvar $keepfloat formflag
)
411 (setq formflag
($ratp x
))
412 (and ($ratp y
) (setq formflag t
))
415 (when (numberp v
) (improper-arg-err v
'$gcd
)))
418 (when (and ($ratp x
) ($ratp y
) (equal (car x
) (car y
)))
419 (setq genvar
(car (last (car x
))) h
(car x
) x
(cdr x
) y
(cdr y
))
424 (setq y
(cdr (ratrep* y
)))
425 on
(setq x
(cons (pgcd (car x
) (car y
)) (plcm (cdr x
) (cdr y
))))
427 (return (if formflag h
(ratdisrep h
)))))
429 (defmfun $content
(x &rest vars
)
430 (prog (y h varlist formflag
)
431 (setq formflag
($ratp x
))
434 (desetq (h x . y
) (ratrep* x
))
436 ;; (CAR X) => gensym corresponding to apparent main var.
437 ;; MAIN-GENVAR => gensym corresponding to the genuine main var.
438 (let ((main-genvar (nth (1- (length varlist
)) genvar
)))
439 (unless (eq (car x
) main-genvar
)
440 (setq x
`(,main-genvar
0 ,x
)))))
443 (setq h
(list '(mlist)
444 (cons h
(rattimes (car x
) y nil
))
446 (return (if formflag h
($totaldisrep h
)))))
452 (and (mexptp x
) (eq (cadr x
) '$%e
)))
460 (defun algpchk ($x mpflag
&aux temp
)
461 (cond ((eq $x
'$%i
) '(2 -
1))
462 ((eq $x
'$%phi
) '(2 1 1 -
1 0 -
1))
465 (let ((r (prep1 (cadr $x
))))
466 (cond ((onep1 (cdr r
)) ;INTEGRAL ALG. QUANT.?
467 (list (caddr (caddr $x
))
469 (*ratsimp
* (setq radlist
(cons $x radlist
)) nil
)))))
470 ((not $algebraic
) nil
)
471 ((and (m$exp? $x
) (mtimesp (setq temp
(caddr $x
)))
472 (equal (cddr temp
) '($%i $%pi
))
473 (ratnump (setq temp
(cadr temp
))))
474 (if mpflag
(primcyclo (* 2 (caddr temp
))) t
))
475 ((not mpflag
) (assolike $x tellratlist
))
476 ((setq temp
(copy-list (assolike $x tellratlist
)))
477 (do ((p temp
(cddr p
))) ((null p
))
478 (rplaca (cdr p
) (car (prep1 (cadr p
)))))
480 (cond ((ptzerop (pt-red temp
)) (list (pt-le temp
) (pzero)))
481 ((zerop (pt-le (pt-red temp
)))
482 (list (pt-le temp
) (pminus (pt-lc (pt-red temp
)))))
484 (if (and (= (pt-le temp
) 1) (setq $x
(assol $x genpairs
)))
485 (rplacd $x
(cons (cadr temp
) 1)))
488 (defun radfunp (x funcflag
) ;FUNCFLAG -> TEST FOR ALG FUNCTION NOT NUMBER
490 ((not (eq (caar x
) 'mexpt
)) nil
)
491 ((not (ratnump (caddr x
))) nil
)
492 (funcflag (not (numberp (cadr x
))))
495 (defun ratsetup (vl gl
)
496 (ratsetup1 vl gl
) (ratsetup2 vl gl
))
498 (defun ratsetup1 (vl gl
)
500 (mapc #'(lambda (v g
)
501 (setq v
(assolike v
*ratweights
))
502 (if v
(putprop g v
'$ratweight
) (remprop g
'$ratweight
)))
505 (defun ratsetup2 (vl gl
)
507 (mapc #'(lambda (g) (remprop g
'algord
)) gl
)
508 (mapl #'(lambda (v lg
)
509 (cond ((setq v
(algpget (car v
)))
510 (algordset v lg
) (putprop (car lg
) v
'tellrat
))
511 (t (remprop (car lg
) 'tellrat
))))
513 (and $ratfac
(let ($ratfac
)
514 (mapc #'(lambda (v g
)
516 (putprop g
(car (prep1 v
)) 'unhacked
)
517 (remprop g
'unhacked
)))
521 (if (pcoefp p
) 0 (valget (car p
))))
523 (defun algordset (x gl
)
528 ((or (null l
) (> (valget (car l
)) mv
)))
529 (putprop (car l
) t
'algord
)))
530 (setq mv
(max mv
(porder (cadr p
))))))
532 (defun gensym-readable (name)
533 (cond ((symbolp name
)
534 (gensym (string-trim "$" (string name
))))
536 (setq name
(aformat nil
"~:M" name
))
537 (if name
(gensym name
) (gensym)))))
539 (defun orderpointer (l)
541 for i below
(- (length l
) (length genvar
))
542 collecting
(gensym-readable v
) into tem
543 finally
(setq genvar
(nconc tem genvar
))
544 (return (prenumber genvar
1))))
548 (push (gensym) genvar
)))
550 (defun prenumber (v n
)
554 (setf (symbol-value (car vl
)) i
)))
557 (cons (if (and $ratwtlvl
558 (or (fixnump $ratwtlvl
)
559 (merror (intl:gettext
"rat: 'ratwtlvl' must be an integer; found: ~M") $ratwtlvl
))
560 (> (or (get genv
'$ratweight
) -
1) $ratwtlvl
))
565 (defun ratrep (x varl
)
571 (orderpointer varlist
)
572 (ratsetup1 varlist genvar
)
573 (mapc #'(lambda (y z
) (push (cons y
(rget z
)) genpairs
)) varlist genvar
)
574 (ratsetup2 varlist genvar
)
575 (xcons (prep1 x
) ; PREP1 changes VARLIST
576 (list* 'mrat
'simp varlist genvar
; when $RATFAC is T.
577 (if (and (not (atom x
)) (member 'irreducible
(cdar x
) :test
#'eq
))
580 (defvar *withinratf
* nil
)
583 (prog (u *withinratf
*)
584 (setq *withinratf
* t
)
585 (when (eq '%%
(catch 'ratf
(newvar l
)))
586 (setq *withinratf
* nil
)
588 (setq u
(catch 'ratf
(ratrep* l
))) ; for truncation routines
589 (return (or u
(prog2 (setq *withinratf
* nil
) (srf l
))))))
592 (defun prep1 (x &aux temp
)
594 (cond ($keepfloat
(cons x
1.0))
596 ((integerp x
) (cons (cmod x
) 1))
599 (cons (numerator x
) (denominator x
))
600 (cquotient (numerator x
) (denominator x
))))
601 ((atom x
) (cond ((assolike x genpairs
))
603 ((and $ratfac
(assolike x genpairs
)))
604 ((eq (caar x
) 'mplus
)
606 (setq x
(mapcar #'prep1
(cdr x
)))
607 (cond ((every #'frpoly? x
)
608 (cons (mfacpplus (mapl #'(lambda (x) (rplaca x
(caar x
))) x
)) 1))
609 (t (do ((a (car x
) (facrplus a
(car l
)))
612 (t (do ((a (prep1 (cadr x
)) (ratplus a
(prep1 (car l
))))
613 (l (cddr x
) (cdr l
)))
615 ((eq (caar x
) 'mtimes
)
616 (do ((a (savefactors (prep1 (cadr x
)))
617 (rattimes a
(savefactors (prep1 (car l
))) sw
))
619 (sw (not (and $norepeat
(member 'ratsimp
(cdar x
) :test
#'eq
)))))
621 ((eq (caar x
) 'mexpt
)
622 (newvarmexpt x
(caddr x
) t
))
623 ((eq (caar x
) 'mquotient
)
624 (ratquotient (savefactors (prep1 (cadr x
)))
625 (savefactors (prep1 (caddr x
)))))
626 ((eq (caar x
) 'mminus
)
627 (ratminus (prep1 (cadr x
))))
629 (cond (modulus (cons (cquotient (cmod (cadr x
)) (cmod (caddr x
))) 1))
630 (t (cons (cadr x
) (caddr x
)))))
631 ((eq (caar x
) 'bigfloat
)(bigfloat2rat x
))
633 (cond ((and *withinratf
* (member 'trunc
(car x
) :test
#'eq
))
637 (setq temp
(compatvarl (caddar x
) varlist
(cadddr (car x
)) genvar
))
639 (cond ((member 'trunc
(car x
) :test
#'eq
)
641 ((and (not $keepfloat
)
642 (or (pfloatp (cadr x
)) (pfloatp (cddr x
))))
643 (cdr (ratrep* ($ratdisrep x
))))
644 ((sublis temp
(cdr x
)))))
645 (t (cdr (ratrep* ($ratdisrep x
))))))
646 ((assolike x genpairs
))
647 (t (setq x
(littlefr1 x
))
648 (cond ((assolike x genpairs
))
652 (defun putonvlist (x)
655 (setq x
(assolike x tellratlist
))
658 (setq expsumsplit t
) ;CONTROLS SPLITTING SUMS IN EXPONS
660 (defun newvarmexpt (x e flag
)
661 ;; WHEN FLAG IS T, CALL RETURNS RATFORM
663 (when (and (integerp e
) (not flag
))
664 (return (newvar1 (cadr x
))))
668 ;; X=B^N FOR N A NUMBER
670 (setq topexp
(* topexp e
))
674 ;; X=B^(P/Q) FOR P AND Q INTEGERS
676 (cond ((or (minusp (cadr e
)) (> (cadr e
) 1))
677 (setq topexp
(* topexp
(cadr e
)))
678 (setq x
(list '(mexpt)
680 (list '(rat) 1 (caddr e
))))))
681 (cond ((or flag
(numberp (cadr x
)) ))
683 (cond ((memalike x radlist
) (return nil
))
684 (t (setq radlist
(cons x radlist
))
685 (return (newvar1 (cadr x
))))) )
686 ($algebraic
(newvar1 (cadr x
)))))
688 ((eq (caar e
) 'mtimes
)
695 (setq topexp
(* topexp
(cadr e
)))
699 (and (not (atom (cadr e
)))
701 (not (equal 1 (cadadr e
)))
702 (setq topexp
(* topexp
(cadadr e
)))
703 (setq e
(cons (list '(rat)
710 (setq e
(simplify (cons '(mtimes)
715 ((and (eq (caar e
) 'mplus
) expsumsplit
) ;SWITCH CONTROLS
716 (setq ;SPLITTING EXPONENT
724 (simplify (list '(mtimes)
728 (cond (flag (return (prep1 x
)))
729 (t (return (newvar1 x
))))))
733 (not (eq (caar x
) 'mexpt
)))
735 ((or (memalike x varlist
) (memalike x vlist
))
737 (t (cond ((or (atom x
) (null *fnewvarsw
))
739 (t (setq x
(littlefr1 x
))
740 (mapc #'newvar1
(cdr x
))
741 (or (memalike x vlist
)
750 ((and (not (atom x
)) (eq (caar x
) 'mexpt
))
751 (cond ((assolike x genpairs
))
752 ;; *** SHOULD ONLY GET HERE IF CALLED FROM FR1. *FNEWVARSW=NIL
753 (t (setq x
(littlefr1 x
))
754 (cond ((assolike x genpairs
))
757 (t (ratexpt (prep1 x
) topexp
))))))
760 (cond ((numberp x
) nil
)
761 ((memalike x varlist
) nil
)
762 ((memalike x vlist
) nil
)
763 ((atom x
) (putonvlist x
))
765 '(mplus mtimes rat mdifference
766 mquotient mminus bigfloat
) :test
#'eq
)
767 (mapc #'newvar1
(cdr x
)))
768 ((eq (caar x
) 'mexpt
)
769 (newvarmexpt x
(caddr x
) nil
))
771 (and *withinratf
* (member 'trunc
(cdddar x
) :test
#'eq
) (throw 'ratf
'%%
))
772 (cond ($ratfac
(mapc 'newvar3
(caddar x
)))
773 (t (mapc #'newvar1
(reverse (caddar x
))))))
774 (t (cond (*fnewvarsw
(setq x
(littlefr1 x
))
775 (mapc #'newvar1
(cdr x
))
776 (or (memalike x vlist
)
779 (t (putonvlist x
))))))
782 (or (memalike x vlist
)
786 (defun fr1 (x varlist
) ;put radicands on initial varlist?
787 (prog (genvar $norepeat
*ratsimp
* radlist vlist nvarlist ovarlist genpairs
)
789 (setq nvarlist
(mapcar #'fr-args vlist
))
790 (cond ((not *ratsimp
*) ;*ratsimp* not set for initial varlist
791 (setq varlist
(nconc (sortgreat vlist
) varlist
))
792 (return (rdis (cdr (ratrep* x
))))))
793 (setq ovarlist
(nconc vlist varlist
)
795 (mapc #'newvar1 nvarlist
) ;*RATSIMP*=T PUTS RADICANDS ON VLIST
796 (setq nvarlist
(nconc nvarlist varlist
) ; RADICALS ON RADLIST
797 varlist
(nconc (sortgreat vlist
) (radsort radlist
) varlist
))
798 (orderpointer varlist
)
799 (setq genpairs
(mapcar #'(lambda (x y
) (cons x
(rget y
))) varlist genvar
))
800 (let (($algebraic $algebraic
) ($ratalgdenom $ratalgdenom
) radlist
)
801 (and (not $algebraic
)
802 (some #'algpget varlist
) ;NEEDS *RATSIMP*=T
803 (setq $algebraic t $ratalgdenom nil
))
804 (ratsetup varlist genvar
)
806 (mapcar #'(lambda (x y
) (cons x
(prep1 y
))) ovarlist nvarlist
))
807 (setq x
(rdis (prep1 x
)))
808 (cond (radlist ;rational radicands
810 (setq x
(ratsimp (simplify x
) nil nil
)))))
813 (defun ratsimp (x varlist genvar
) ($ratdisrep
(ratf x
)))
816 (cons (remove 'simp
(car x
) :test
#'eq
) (mapfr1 (cdr x
) nil
)))
818 ;;IF T RATSIMP FACTORS RADICANDS AND LOGANDS
819 (defmvar fr-factor nil
)
821 (defun fr-args (x) ;SIMP (A/B)^N TO A^N/B^N ?
823 (when (eq x
'$%i
) (setq *ratsimp
* t
)) ;indicates algebraic present
825 (t (setq *ratsimp
* t
) ;FLAG TO CHANGED ELMT.
826 (simplify (zp (cons (remove 'simp
(car x
) :test
#'eq
)
827 (if (or (radfunp x nil
) (eq (caar x
) '%log
))
828 (cons (if fr-factor
(factor (cadr x
))
829 (fr1 (cadr x
) varlist
))
832 (mapfr1 (cdr x
) varlist
)))))))))
834 ;;SIMPLIFY MEXPT'S & RATEXPAND EXPONENT
837 (if (and (mexptp x
) (not (atom (caddr x
))))
838 (list (car x
) (cadr x
)
839 (let ((varlist varlist
) *ratsimp
*)
840 ($ratexpand
(caddr x
))))
845 (when (setq g
(assolike e genpairs
))
847 (setq g
(gensym-readable e
))
848 (putprop g e
'disrep
)
850 (push (cons e
(rget g
)) genpairs
)
851 (valput g
(if genvar
(1- (valget (car genvar
))) 1))
853 (when (setq p
(and $algebraic
(algpget e
)))
855 (putprop g p
'tellrat
))
858 ;; Any program which calls RATF on
859 ;; a floating point number but does not wish to see "RAT replaced ..."
860 ;; message, must bind $RATPRINT to NIL.
862 (defmvar $ratprint t
)
864 (defmvar $ratepsilon
2e-15)
866 ;; This control of conversion from float to rational appears to be explained
869 (defun maxima-rationalize (x)
870 (cond ((not (floatp x
)) x
)
871 ;; Handle denormalized floats -- see maxima-discuss 2021-04-27 and bug 3777
872 ((and (not (= x
0.0)) (< (abs x
) COMMON-LISP
:LEAST-POSITIVE-NORMALIZED-DOUBLE-FLOAT
))
873 (let ((r ($rationalize x
)))
874 (cons (cadr r
) (caddr r
))))
876 (setq x
(ration1 (* -
1.0 x
)))
877 (rplaca x
(* -
1 (car x
))))
881 (let ((rateps (if (not (floatp $ratepsilon
))
884 (or (and (zerop x
) (cons 0 1))
887 ;; I (rtoy) think this is computing a continued fraction
888 ;; expansion of the given float.
890 ;; FIXME? CMUCL used to use this routine for its
891 ;; RATIONALIZE function, but there were known bugs in
892 ;; that implementation, where the result was not very
893 ;; accurate. Unfortunately, I can't find the example
894 ;; that demonstrates this. In any case, CMUCL replaced
895 ;; it with an algorithm based on the code in Clisp, which
897 (do ((xx x
(setq y
(/ 1.0 (- xx
(float a x
)))))
898 (num (setq a
(floor x
)) (+ (* (setq a
(floor y
)) num
) onum
))
899 (den 1 (+ (* a den
) oden
))
902 ((or (zerop (- xx
(float a x
)))
903 (and (not (zerop den
))
904 (not (> (abs (/ (- x
(/ (float num x
) (float den x
))) x
)) rateps
))))
905 (cons num den
))))))))
908 (cond (modulus (merror (intl:gettext
"rat: can't rationalize ~M when modulus = ~M") f modulus
))
909 ($ratprint
(mtell (intl:gettext
"~&rat: replaced ~A by") f
)))
910 (setq f
(maxima-rationalize f
))
912 (mtell " ~A/~A = ~A~%" (car f
) (cdr f
) (fpcofrat1 (car f
) (cdr f
))))
918 (pdisrep+ (pdisrep2 (cdr p
) (get (car p
) 'disrep
)))))
920 (defun pdisrep! (n var
)
922 ((equal n
1) (cond ((atom var
) var
)
923 ((or (eq (caar var
) 'mtimes
)
924 (eq (caar var
) 'mplus
))
928 (t (list '(mexpt ratsimp
) var n
))))
931 (cond ((null (cdr p
)) (car p
))
932 (t (let ((a (last p
)))
933 (cond ((mplusp (car a
))
935 (rplaca a
(cadar a
))))
936 (cons '(mplus ratsimp
) p
)))))
938 (defun pdisrep* (a b
)
939 (cond ((equal a
1) b
)
941 (t (cons '(mtimes ratsimp
) (nconc (pdisrep*chk a
) (pdisrep*chk b
))))))
943 (defun pdisrep*chk
(a)
944 (if (mtimesp a
) (cdr a
) (ncons a
)))
946 (defun pdisrep2 (p var
)
948 ($ratexpand
(pdisrep2expand p var
))
949 (t (do ((l () (cons (pdisrep* (pdisrep (cadr p
)) (pdisrep! (car p
) var
)) l
))
951 ((null p
) (nreverse l
))))))
953 ;; IF $RATEXPAND IS TRUE, (X+1)*(Y+1) WILL DISPLAY AS
954 ;; XY + Y + X + 1 OTHERWISE, AS (X+1)Y + X + 1
955 (defmvar $ratexpand nil
)
957 (defmfun $ratexpand
(x)
959 (cons (car x
) (mapcar '$ratexpand
(cdr x
)))
960 (let (($ratexpand t
) ($ratfac nil
))
961 (ratdisrep (ratf x
)))))
963 (defun pdisrep*expand
(a b
)
964 (cond ((equal a
1) (list b
))
965 ((equal b
1) (list a
))
966 ((or (atom a
) (not (eq (caar a
) 'mplus
)))
967 (list (cons (quote (mtimes ratsimp
))
968 (nconc (pdisrep*chk a
) (pdisrep*chk b
)))))
969 (t (mapcar #'(lambda (z) (if (equal z
1) b
970 (cons '(mtimes ratsimp
)
971 (nconc (pdisrep*chk z
)
975 (defun pdisrep2expand (p var
)
977 (t (nconc (pdisrep*expand
(pdisrep (cadr p
)) (pdisrep! (car p
) var
))
978 (pdisrep2expand (cddr p
) var
)))))
981 (defmvar $ratdenomdivide t
)
983 (defmfun $ratdisrep
(x)
985 ;; Distribute over lists, equations, and matrices.
986 (cons (car x
) (mapcar #'$ratdisrep
(cdr x
))))
989 (setq x
(ratdisrepd x
))
990 (if (and (not (atom x
))
991 (member 'trunc
(cdar x
) :test
#'eq
))
992 (cons (delete 'trunc
(copy-list (car x
)) :count
1 :test
#'eq
)
996 ;; RATDISREPD is needed by DISPLA. - JPG
997 (defun ratdisrepd (x)
998 (mapc #'(lambda (y z
) (putprop y z
(quote disrep
)))
1001 (let ((varlist (caddar x
)))
1002 (if (member 'trunc
(car x
) :test
#'eq
)
1004 (cdisrep (cdr x
)))))
1006 (defun cdisrep (x &aux n d sign
)
1007 (cond ((pzerop (car x
)) 0)
1008 ((or (equal 1 (cdr x
)) (floatp (cdr x
))) (pdisrep (car x
)))
1009 (t (setq sign
(cond ($ratexpand
(setq n
(pdisrep (car x
))) 1)
1011 (setq n
(pdisrep (pminus (car x
)))) -
1)
1012 (t (setq n
(pdisrep (car x
))) 1)))
1013 (setq d
(pdisrep (cdr x
)))
1014 (cond ((and (numberp n
) (numberp d
))
1015 (list '(rat) (* sign n
) d
))
1016 ((and $ratdenomdivide $ratexpand
1018 (eq (caar n
) 'mplus
))
1021 (list '(mtimes ratsimp
)
1022 (list '(rat) sign d
) n
))
1024 (cons '(mtimes ratsimp
)
1027 (list '(mexpt ratsimp
) d -
1)))
1028 (t (list sign n
(list '(mexpt ratsimp
) d -
1))))))
1030 (list '(mexpt ratsimp
) d -
1))
1031 (t (list '(mtimes ratsimp
) n
1032 (list '(mexpt ratsimp
) d -
1)))))))
1035 ;; FANCYDIS GOES THROUGH EACH TERM AND DIVIDES IT BY THE DENOMINATOR.
1037 (defun fancydis (n d
)
1038 (setq d
(simplify (list '(mexpt) d -
1)))
1039 (simplify (cons '(mplus)
1040 (mapcar #'(lambda (z) ($ratdisrep
(ratf (list '(mtimes) z d
))))
1044 (defun compatvarl (a b c d
)
1045 (cond ((null a
) nil
)
1046 ((or (null b
) (null c
) (null d
)) (throw 'compatvl nil
))
1047 ((alike1 (car a
) (car b
))
1048 (setq a
(compatvarl (cdr a
) (cdr b
) (cdr c
) (cdr d
)))
1049 (if (eq (car c
) (car d
))
1051 (cons (cons (car c
) (car d
)) a
)))
1052 (t (compatvarl a
(cdr b
) c
(cdr d
)))))
1054 (defun newvar (l &aux vlist
)
1056 (setq varlist
(nconc (sortgreat vlist
) varlist
)))
1058 (defun sortgreat (l)
1059 (and l
(nreverse (stable-sort l
'great
))));FIXME consider a total order function with #'sort
1061 (defun fnewvar (l &aux
(*fnewvarsw t
))
1064 (defun nestlev (exp)
1067 (do ((m (nestlev (cadr exp
)) (max m
(nestlev (car l
))))
1068 (l (cddr exp
) (cdr l
)))
1069 ((null l
) (1+ m
)))))
1072 (sort l
#'(lambda (a b
)
1073 (let ((na (nestlev a
)) (nb (nestlev b
)))
1076 (t (great b a
)))))))
1078 ;; THIS IS THE END OF THE NEW RATIONAL FUNCTION PACKAGE PART 5
1079 ;; IT INCLUDES THE CONVERSION AND TOP-LEVEL ROUTINES USED
1080 ;; BY THE REST OF THE FUNCTIONS.