1 ;; Author Barton Willis
2 ;; University of Nebraska at Kearney
3 ;; Copyright (C) 2006, 2007, 2008, 2009, 2022 Barton Willis
5 ;; This program is free software; you can redistribute it and/or modify
6 ;; it under the terms of the GNU General Public License as published by
7 ;; the Free Software Foundation; either version 2 of the License, or
8 ;; (at your option) any later version.
10 ;; This program is distributed in the hope that it will be useful,
11 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ;; GNU General Public License for more details.
16 ($put
'$to_poly
2 '$version
)
18 (defmacro opapply
(op args
)
19 `(simplify (cons (list ,op
) ,args
)))
21 ;; The next three functions convert max and min to abs functions.
24 (reduce #'(lambda (a b
) (div (add (add a b
) (take '(mabs) (sub a b
))) 2)) e
))
27 (reduce #'(lambda (a b
) (div (sub (add a b
) (take '(mabs) (sub a b
))) 2)) e
))
29 (defun convert-from-max-min-to-abs (e)
30 (cond (($mapatom e
) e
)
31 ((op-equalp e
'$max
) (max-to-abs (mapcar 'convert-from-max-min-to-abs
(margs e
))))
32 ((op-equalp e
'$min
) (min-to-abs (mapcar 'convert-from-max-min-to-abs
(margs e
))))
33 (t (opapply (mop e
) (mapcar 'convert-from-max-min-to-abs
(margs e
))))))
35 (defun maxima-variable-p (e)
36 (or (symbolp e
) ($subvarp e
)))
38 (defun list-subst (l p
)
39 (if (null l
) p
(list-subst (rest l
) ($substitute
(first l
) p
))))
41 ;; to_poly(p,vars) returns a polynomial in the variables 'vars' that has a zero whenever
42 ;; p has a zero. When 1 is a member of vars, constant terms, such as sqrt(5) also get
43 ;; converted to polynomial form. The value of vars defaults to all variables including
47 (defun $to_poly
(p &optional
(vars 'convert-all-vars
))
48 (let (($listconstvars t
) (q) (convert-cnst nil
) (proviso nil
) (non-alg) (qk) (pp nil
) (subs))
50 (if (eq vars
'convert-all-vars
) (setq vars
($cons
1 ($listofvars p
))))
52 (if (not ($listp vars
))
53 (merror (intl:gettext
"The second argument to 'to_poly' must be a list")))
55 (cond (($member
1 vars
)
57 (setq vars
($delete
1 vars
))))
59 ;; If p is a list or a set, set p to the members in p; otherwise (list p)
60 (setq p
(if (or ($listp p
) ($setp p
)) (margs p
) (list p
)))
62 ;; Convert each member of p that is an equation to a nonequation.
63 ;; Thus transform a = b into a - b.
64 (setq p
(mapcar 'meqhk p
))
66 ;; Extract the denominators of p and require them to not vanish.
67 ;; Replace the list p by a list of the numerators.
68 (setq q
(mapcar '$ratdenom p
))
69 (setq p
(mapcar '$ratnumer p
))
71 (setq proviso
(delete t
(mapcar (lambda (s) (mnqp s
0)) q
)))
72 (setq proviso
(mapcar #'(lambda (s) (maxima-substitute 'mnotequal
'$notequal s
)) proviso
))
73 (setq p
(mapcar #'sratsimp p
))
74 ;;(multiple-value-setq (p g-vars) (non-algebraic-subst-list p vars))
75 (setq p
(non-algebraic-subst-list p vars
))
76 (setq non-alg
($second p
))
77 (setq p
(margs ($first p
)))
78 ;; It's OK to send every expression through convert-from-max-min-to-abs.
79 ;; I put in the conditional to skip the ratsimp for expressions that don't
80 ;; involve max or min.
85 (setq pk
(if ($freeof
'$max
'$min pk
) pk
(sratsimp (convert-from-max-min-to-abs pk
))))
86 (setq pk
(to-polynomial pk vars convert-cnst
))
88 ;; After conversion, the members of pp can be rational expressions, not polynomials.
89 ;; This happens, for example, when there is a 2 cos(x) --> exp(%i x) + 1/exp(%i x)
90 ;; conversion. So we need to extract numerators of the members of p.
92 (setq proviso
(append proviso
(mapcar #'sratsimp
(third pk
))))
93 (setq subs
(append subs
(mapcar #'sratsimp
(second pk
))))
94 (setq pk
(sratsimp (first pk
)))
95 (setq qk
(sratsimp ($ratdenom pk
)))
96 (if (not (eq t
(mnqp qk
0))) (push (take '(mnotequal) qk
0) proviso
))
97 (setq pk
(sratsimp ($ratnumer pk
)))
100 (setq pp
(append pp subs
))
102 (push '(mlist) proviso
)
103 (list '(mlist) pp proviso non-alg
)))
105 (defun to-polynomial (p vars convert-cnst
)
106 (let ((n) (b) (nv) (acc nil
) (subs nil
) (pk) (q) (inequal) (np-subs))
107 (cond ((or (maxima-variable-p p
)
109 (and ($emptyp vars
) (not convert-cnst
))
110 (and (not ($constantp p
)) ($lfreeof vars p
))
111 (and ($constantp p
) (not convert-cnst
))
112 (and (op-equalp p
'$conjugate
) (maxima-variable-p (second p
))))
113 (list p nil nil nil
))
120 ((and (integerp n
) (> n
0))
121 (list p nil nil nil
))
124 (setq b
(to-polynomial b vars convert-cnst
))
125 (setq subs
(second b
))
126 (setq inequal
(third b
))
127 (setq np-subs
(fourth b
))
129 (setq nv
(new-gentemp 'general
))
130 (cond ((or (mgrp n
0) (mnump b
))
131 (push (ftake 'mequal b
(ftake 'mexpt nv
($denom n
))) subs
)
132 (let ((ph (ftake '$parg nv
)) (angle (div '$%pi
($denom n
))))
133 (push (ftake 'mlessp
(neg angle
) ph
) inequal
)
134 (push (ftake 'mleqp ph angle
) inequal
))
135 (push (ftake 'mequal p
(ftake 'mexpt nv
($num n
))) np-subs
)
136 (list (ftake 'mexpt nv
($num n
)) subs inequal np-subs
))
139 (push (take '(mequal) 1 (mul (power nv
($denom n
)) (power b
($num n
)))) subs
)
140 (push (take '(mlessp) (take '($parg
) nv
) (mul n
'$%pi
)) inequal
)
141 (push (take '(mleqp) (mul -
1 '$%pi n
) (take '($parg
) nv
)) inequal
)
142 (push (take '(mnotequal) nv
0) inequal
)
143 (list nv subs inequal np-subs
))))
144 (t (merror (intl:gettext
"Nonalgebraic argument given to 'to_poly'")))))
147 (setq b
(to-polynomial (first (margs p
)) vars convert-cnst
))
148 (setq acc
(second b
))
149 (setq inequal
(third b
))
150 (setq np-subs
(fourth b
))
152 (setq nv
(new-gentemp '$general
))
153 ;; Ok, I'm indecisive.
154 ;(push (take '(mgeqp) nv 0) inequal)
155 ;(push (take '(mequal) (take '($parg) nv) 0) inequal)
156 (push (take '($isnonnegative_p
) nv
) inequal
)
157 (list nv
(cons (take '(mequal) (mul b
(take '($conjugate
) b
)) (mul nv
(take '($conjugate
) nv
))) acc
)
166 (setq q
(to-polynomial pk vars convert-cnst
))
167 (setq acc
(mul acc
(first q
)))
168 (setq subs
(append (second q
) subs
))
169 (setq inequal
(append inequal
(third q
)))
170 (setq np-subs
(append np-subs
(fourth q
)))
171 (setq vars
($append vars
($listofvars
`((mlist) ,@subs
))))
172 (setq p
(mapcar #'(lambda (s) (list-subst np-subs s
)) p
)))
174 (list acc subs inequal np-subs
))
182 (setq q
(to-polynomial pk vars convert-cnst
))
183 (setq acc
(add acc
(first q
)))
184 (setq subs
(append (second q
) subs
))
185 (setq inequal
(append (third q
) inequal
))
186 (setq np-subs
(append (fourth q
) np-subs
))
187 (setq vars
($append vars
($listofvars
`((mlist) ,@subs
))))
188 (setq p
(mapcar #'(lambda (s) (list-subst np-subs s
)) p
)))
189 (list acc subs inequal np-subs
))
192 (t (merror (intl:gettext
"Nonalgebraic argument given to 'to_poly'"))))))
196 Things I don
't like about eliminate
:
198 (1) eliminate
([x
+ x
*y
+ z-4
, x
+y
+z-12
, x^
2 + y^
2 + z^
2=7],[x
,y
,z
]) -
> [4]
200 Here Maxima solves for z. There are more than one solution for z, but Maxima returns
201 just one solution. A user might think that there is one solution or that
202 the equations are inconsistent.
204 (2) eliminate([x+y-1,x+y-8],[x,y]) -> Argument to `last' is empty.
206 Here the equations are inconsistent, but we get an error (from solve) instead
207 of a clear message about what happened.
209 (3) eliminate([a],[x]) -> Can't eliminate from only one equation -- an error.
210 but eliminate([a,a],[x]) -> [a,a]. This is silly.
212 (4) eliminate([x],[]) -> Can't eliminate from only one equation.
213 but eliminate([x,x],[]) -> [x,x]. Again, this is silly.
215 (5) elim([x^3-y^2,x^7 + y+z*p,q*q-23+ x+y,p-q,x+y+z-5],[x,y,z,p]) takes 0.3 second
216 but eliminate([x^3-y^2,x^7 + y+z*p,q*q-23+ x+y,p-q,x+y+z-5],[x,y,z,p]) takes
217 a long time (I never let it run to completion). Unlike 'eliminate,' the function 'elim'
218 makes some guesses about which polynomial to use as the pivot and which variable
222 (defun require-maxima-variable (x context-string)
223 (setq x (ratdisrep x))
224 (if (maxima-variable-p x) x
225 (merror (intl:gettext "Function ~:M expects a symbol, instead found ~:M") context-string x)))
227 ;; Simplify a polynomial equation p = 0 by
229 ;; (1) nonzero constant * p --> p,
232 ;; If you want to use $factor instead of $sqfr, go ahead. But if you do that, you might want to
233 ;; locally set factorflag to false.
235 (defun suppress-multiple-zeros (q)
237 (cond ((mnump q) (if (zerop1 q) 0 1))
238 ((mtimesp q) (muln (mapcar 'suppress-multiple-zeros (margs q)) t))
239 ((and (mexptp q) (integerp (third q)) (> (third q) 0)) (second q))
240 (($constantp q) 1) ; takes care of things like (1 + sqrt(5)) * x --> x.
243 ;; Using eq as the "pivot," eliminate x from the list or set of equations eqs.
245 (defun $eliminate_using (eqs eq x)
246 (if (or ($listp eqs) ($setp eqs))
248 (setq eqs (mapcar #'(lambda (s) ($ratexpand (meqhk s))) (margs eqs)))
249 (setq eqs (margs (opapply '$set eqs))))
250 (merror (intl:gettext "The first argument to 'eliminate_using' must be a list or a set")))
252 (setq x (require-maxima-variable x "$eliminate_using"))
254 (if (not (every #'(lambda (s) ($polynomialp s `((mlist) ,x)
255 `((lambda) ((mlist) s) (($freeof) ,x s)))) eqs))
256 (merror (intl:gettext "The first argument to 'eliminate_using' must be a set or list of polynomials")))
258 (setq eq ($ratexpand (meqhk eq)))
259 (if (not ($polynomialp eq `((mlist) ,x) `((lambda) ((mlist) s) (($freeof) ,x s))))
260 (merror (intl:gettext "The second argument to 'eliminate_using' must be a polynomial")))
262 (setq eqs (mapcar #'suppress-multiple-zeros eqs))
263 (setq eq (suppress-multiple-zeros eq))
264 (opapply '$set (eliminate-using eqs eq x)))
266 (defun eliminate-using (eqs eq x)
267 (delete 0 (mapcar #'(lambda (s) (suppress-multiple-zeros ($resultant s eq x))) eqs)))
269 ;; Return an upper bound for the total degree of the polynomial p in the variables vars.
270 ;; When p is fully expanded, the bound is exact.
272 (defun degree-upper-bound (p vars)
273 (cond ((maxima-variable-p p) (if (member p vars :test #'equal) 1 0))
277 ((and (mexptp p) (integerp (third p)) (> (third p) 0))
278 (* (degree-upper-bound (nth 1 p) vars) (nth 2 p)))
281 (reduce '+ (mapcar #'(lambda (s) (degree-upper-bound s vars)) (margs p))))
284 (simplify `(($max) ,@(mapcar #'(lambda (s) (degree-upper-bound s vars)) (margs p)))))
286 ((apply '$freeof (append vars (list p))) 0)
287 (t (merror (intl:gettext "Nonpolynomial argument given to degree-upper-bound")))))
289 (defun unk-eliminate (eqs vars &optional (pivots nil))
290 (let ((ni) (n-min nil) (xeqs `(($set))) (pivot-var) (pivot-eq) (acc `(($set))) ($ratfac nil))
291 (cond ((or (null vars) (null eqs)) (list eqs pivots))
294 ;; The pivot is a nonconstant member of eqs with minimal total degree.
295 ;; The constant members of eqs get adjoined into acc -- all other members get
296 ;; adjoined into xeqs. Since each member of eqs has been ratexpanded,
297 ;; the degree bound is exact.
300 (setq ei ($ratexpand (suppress-multiple-zeros ei)))
301 (setq ni (degree-upper-bound ei vars))
303 (if (and (or (null n-min) (< ni n-min)) (> ni 0))
304 (setq n-min ni pivot-eq ei))
306 (if (and (> ni 0) (not (equal 0 ei))) (setq xeqs ($adjoin ei xeqs)) (setq acc ($adjoin ei acc))))
308 (setq xeqs (margs xeqs))
309 (setq acc (margs acc))
310 ;; Now we'll decide which variable to eliminate. The pivot variable
311 ;; is the variable that has the least (but nonzero) degree in pivot-eq.
315 (setq ni (degree-upper-bound pivot-eq (list vi)))
316 (if (and (or (null n-min) (< ni n-min)) (> ni 0))
317 (setq pivot-var vi n-min ni)))
319 (if (null pivot-var) (list eqs pivots)
320 (unk-eliminate (append acc (eliminate-using xeqs pivot-eq pivot-var)) (delete pivot-var vars)
321 (cons pivot-eq pivots)))))))
324 (if (or ($listp eqs) ($setp eqs))
326 (setq eqs (mapcar #'(lambda (s) ($ratexpand (suppress-multiple-zeros (meqhk s)))) (margs eqs)))
327 (setq eqs (margs (opapply '$set eqs))))
328 (merror (intl:gettext "The first argument to 'elim' must be a list or a set")))
330 (setq x (margs (cond (($listp x) ($setify x))
332 (t (merror (intl:gettext "The second argument to 'elim' must be a list or a set"))))))
334 (setq x (mapcar #'(lambda (s) (require-maxima-variable s "$elim")) x))
336 (setq x (opapply 'mlist x))
337 (if (not (every #'(lambda (s) ($polynomialp s x `((lambda) ((mlist) s) (($lfreeof) ,x s)))) eqs))
338 (merror (intl:gettext "Each member of the first argument to 'elim' must be a polynomial")))
341 (opapply 'mlist (mapcar #'(lambda (s) (opapply 'mlist s)) (unk-eliminate eqs x))))
343 (defun $elim_allbut (eqs x)
344 (let (($listconstvars nil) (v))
345 (setq v ($listofvars eqs))
346 (setq x (cond (($listp x) ($setify x))
348 (t (take '($set) x))))
349 (setq v ($setdifference ($setify v) x))
350 ($elim eqs ($listify v))))
352 ;; Return a list of the arguments to the operator op in the expression e.
353 ;; This function only looks inside + and * and it doesn't recurse inside
356 ;; gather-args(log(x) + log(a + log(b)), log) --> (x, a + log(b)),
357 ;; gather-args(cos(log(x)), log) --> (),
358 ;; gather-args(x^log(x) + log(s)^x, log) --> ().
360 (defun gather-args (e op vars)
361 (cond ((and (consp e) (consp (car e)) (eq (caar e) 'mlist))
362 (apply 'append (mapcar #'(lambda (s) (gather-args s op vars)) (margs e))))
364 ((and (eq (mop e) op) (not ($lfreeof vars e))) (margs e))
365 ((memq (mop e) '(mplus mtimes))
369 (setq acc (append acc (gather-args ek op vars))))))
372 (defun gather-nonrational-powers (e vars)
373 (cond ((and (consp e) (consp (car e)) (eq (caar e) 'mlist))
374 (apply 'append (mapcar #'(lambda (s) (gather-nonrational-powers s vars)) (margs e))))
376 ((and (eq (mop e) 'mexpt) (memq (second e) vars) (not ($ratnump (third e)))) (list e))
377 ((memq (mop e) '(mplus mtimes))
378 (mapcan #'(lambda (s) (gather-nonrational-powers s vars)) (margs e)))
381 (defun gather-exp-args (e vars)
382 (cond (($mapatom e) nil)
384 (if (and (eq (second e) '$%e) (not ($lfreeof vars (third e)))) (list (third e))
385 (gather-exp-args (second e) vars)))
386 (t (mapcan #'(lambda (s) (gather-exp-args s vars)) (margs e)))))
388 ;; Return true iff the set {a,b} is linearly dependent. Thus return true iff
389 ;; either a = 0 or b = 0, or a/b is a number.
391 (defun $linearly_dependent_p (a b)
392 (linearly-dependent-p a b))
394 (defun linearly-dependent-p (a b)
397 (mnump (sratsimp (div a b)))) t nil))
399 (defun exponentialize-if (e vars)
400 (cond (($mapatom e) e)
401 ((and (trigp (mop e)) (not ($lfreeof vars e))) ($exponentialize e))
402 (t (opapply (mop e) (mapcar #'(lambda (s) (exponentialize-if s vars)) (margs e))))))
404 (defun logarc-if (e vars)
405 (cond (($mapatom e) e)
406 ((and (arcp (mop e)) (not ($lfreeof vars e))) ($logarc e))
407 (t (opapply (mop e) (mapcar #'(lambda (s) (logarc-if s vars)) (margs e))))))
409 (defun non-algebraic-subst (e vars)
410 (let ((log-args nil) (exp-args nil) (mexpt-args) (ee) (s) (g) (p) (q) (na-subs nil) (g-vars nil) (sz))
412 (setq e ($ratexpand (exponentialize-if (logarc-if e vars) vars)))
413 (setq log-args (gather-args e '%log vars))
414 (setq log-args (margs (opapply '$set log-args)))
415 (setq exp-args (gather-exp-args e vars))
416 (setq exp-args (opapply '$set exp-args))
417 (setq s (margs (simplify ($equiv_classes exp-args 'linearly-dependent-p))))
420 (setq g (new-gentemp '$general))
422 (setq sz ($first (apply '$ezgcd (margs sk))))
423 (setq p (power '$%e sz))
424 (push (take '(mequal) g p) na-subs)
427 (setq q (sratsimp (div sl sz)))
428 (setq e ($ratexpand ($substitute (power g q) (power '$%e sl) e)))))
430 (dolist (sk log-args)
431 (setq g (new-gentemp '$general))
433 (setq p (take '(%log) sk))
434 (setq e ($substitute g p e))
435 (push (take '(mequal) g p) na-subs))
437 ;; Attempt the substitution %g = x^a, where x is in vars and a is not a rational number.
438 ;; Accept the substitution if it eliminates x from e and it changes e, otherwise reject it.
440 (setq mexpt-args (gather-nonrational-powers e (margs vars)))
441 (dolist (sk mexpt-args)
442 (setq g (new-gentemp '$general))
443 (setq ee ($ratsubst g sk e))
444 (if (and (freeof (second sk) ee) (not (like e ee)))
448 (push (take '(mequal) g sk) na-subs))))
450 (values `((mlist) ,e ((mlist) ,@na-subs)) g-vars)))
452 (defun non-algebraic-subst-list (l vars)
453 (let ((log-args nil) (exp-args nil) (mexpt-args) (ll) (s) (g) (p) (q) (na-subs nil) (g-vars nil) (sz))
455 (setq l (mapcar #'(lambda (s) ($ratexpand (exponentialize-if (logarc-if s vars) vars))) l))
457 (setq log-args (gather-args l '%log vars))
458 (setq log-args (margs (opapply '$set log-args)))
460 (setq exp-args (gather-exp-args l vars))
461 (setq exp-args (opapply '$set exp-args))
462 (setq s (margs (simplify ($equiv_classes exp-args 'linearly-dependent-p))))
465 (setq g (new-gentemp '$general))
467 (setq sz ($first (apply '$ezgcd (margs sk))))
468 (setq p (power '$%e sz))
469 (push (take '(mequal) g p) na-subs)
472 (setq q (sratsimp (div sl sz)))
473 (setq l ($ratexpand ($substitute (power g q) (power '$%e sl) l)))))
475 (dolist (sk log-args)
476 (setq g (new-gentemp '$general))
478 (setq p (take '(%log) sk))
479 (setq l ($substitute g p l))
480 (push (take '(mequal) g p) na-subs))
482 ;; Attempt the substitution %g = x^a, where x is in vars and a is not a rational number.
483 ;; Accept the substitution if it eliminates x from e and it changes e, otherwise reject it.
485 (setq mexpt-args (gather-nonrational-powers l (margs vars)))
486 (dolist (sk mexpt-args)
487 (setq g (new-gentemp '$general))
488 (setq ll ($ratsubst g sk l))
489 (if (and (freeof (second sk) ll) (not (like l ll)))
493 (push (take '(mequal) g sk) na-subs))))
495 (values `((mlist) ,l ((mlist) ,@na-subs)) g-vars)))
497 ;; A simplifying carg function.
499 (setf (get '$parg 'operators) 'simp-parg)
501 (defun simp-parg (e yy z)
502 (declare (ignore yy))
503 (let (($domain '$complex) (sgn) (isgn))
506 (setq e (simplifya (specrepcheck (cadr e)) z))
507 (setq e (sratsimp ($exponentialize e)))
509 (cond ((zerop1 e) e) ;; parg(0) = 0,parg(0.0) = 0.0, parg(0.0b0) = 0.0b0.
511 ;; For a complex number, use atan2
512 ((complex-number-p e '$constantp)
513 (ftake '%atan2 ($imagpart e) ($realpart e)))
515 ;; off the negative real axis, parg(conjugate(x)) = -parg(x)
516 ((and (op-equalp e '$conjugate) (off-negative-real-axisp e))
517 (neg (take '($parg) (cadr e))))
519 ;; parg(a * x) = parg(x) provided a > 0.
520 ((and (mtimesp e) (eq t (mgrp (cadr e) 0)))
521 (take '($parg) (reduce 'mul (cddr e))))
523 ;; parg exp(a + %i*b) = %pi-mod(%pi-b,2*%pi)
524 ((and (mexptp e) (eq '$%e (second e)) (linearp (third e) '$%i))
525 (sub '$%pi (take '($mod) (sub '$%pi ($imagpart (third e))) (mul 2 '$%pi))))
527 ;; parg(x^number) = number * parg(x), provided number in (-1,1).
528 ((and (mexptp e) ($numberp (caddr e)) (eq t (mgrp (caddr e) -1)) (eq t (mgrp 1 (caddr e))))
529 (mul (caddr e) (take '($parg) (cadr e))))
531 ;; sign rules parg(x) = %pi, x < 0 and parg(x) = 0, x > 0
532 ((eq '$neg (setq sgn ($csign e))) '$%pi)
535 ;; more sign rules parg(%i * x) = %pi /2, x > 0 and -%pi / 2, x < 0.
536 ((and (eq '$imaginary sgn) (setq isgn ($csign (div e '$%i))) (eq '$pos isgn))
539 ((and (eq '$imaginary sgn) (eq '$neg isgn))
543 (t `(($parg simp) ,e)))))
545 (setf (get '$isreal_p 'operators) 'simp-isreal-p)
547 (defun simp-isreal-p (e yy z)
548 (declare (ignore yy))
550 (let ((ec) ($domain '$complex))
552 (setq e (simplifya (specrepcheck (cadr e)) z))
556 ;; (1) if r is real then isreal_p(r + x) --> isreal_p(x),
557 ;; (2) if r is real then isreal_p(r * x) --> isreal_p(x),
558 ;; (3) if e = conjugate(e) then true,
559 ;; (4) if is(notequal(e,conjugate(e))) then false.
562 (setq e (muln (mapcar #'(lambda (s) (if (eq t (take '($isreal_p) s)) 1 s)) (margs e)) t)))
564 (setq e (addn (mapcar #'(lambda (s) (if (eq t (take '($isreal_p) s)) 0 s)) (margs e)) t))))
566 ;; If e is constant, apply rectform.
567 (if ($constantp e) (setq e ($rectform e)))
568 (setq ec (take '($conjugate) e))
569 (cond ((eq t (meqp e ec)) t)
570 ((eq t (mnqp e ec)) nil)
571 (t `(($isreal_p simp) ,e)))))
573 (defvar *integer-gentemp-prefix* "$%Z")
574 (defvar *natural-gentemp-prefix* "$%N")
575 (defvar *real-gentemp-prefix* "$%R")
576 (defvar *complex-gentemp-prefix* "$%C")
577 (defvar *general-gentemp-prefix* "$%G")
579 ;; Return a new gentemp with a prefix that is determined by 'type.' Also put
580 ;; an identifying tag on the symbol property of each new gentemp.
582 (defun $new_variable (type)
585 (defun new-gentemp (type)
586 (flet ((%gentemp (prefix)
587 (intern (symbol-name (gensym prefix)) :maxima)))
591 (setq g (%gentemp *integer-gentemp-prefix*))
592 (setf (get g 'integer-gentemp) t)
593 (mfuncall '$declare g '$integer))
595 ((eq type '$natural_number)
596 (setq g (%gentemp *natural-gentemp-prefix*))
597 (setf (get g 'natural-gentemp) t)
598 (mfuncall '$declare g '$integer)
599 (mfuncall '$assume (take '(mgeqp) g 0)))
602 (setq g (%gentemp *real-gentemp-prefix*))
603 (setf (get g 'real-gentemp) t))
606 (setq g (%gentemp *complex-gentemp-prefix*))
607 (setf (get g 'complex-gentemp) t)
608 (mfuncall '$declare g '$complex))
611 (setq g (%gentemp *general-gentemp-prefix*))
612 (setf (get g 'general-gentemp) t)))
616 ;; Find all the new-gentemp variables in an expression e and re-index them starting from 0.
618 (defun $nicedummies (e)
619 (let (($listconstvars nil)
624 (g-vars nil) (g-k 0))
626 (mapcar #'(lambda (s) (let ((a))
628 ((get s 'integer-gentemp)
629 (setq a (symbolconc *integer-gentemp-prefix* z-k))
630 (mfuncall '$declare a '$integer)
632 (push `((mequal) ,s ,a) z-vars))
634 ((get s 'natural-gentemp)
635 (setq a (symbolconc *natural-gentemp-prefix* n-k))
636 (mfuncall '$declare a '$integer)
637 (mfuncall '$assume (take '(mgeqp) a 0))
639 (push `((mequal) ,s ,a) n-vars))
641 ((get s 'real-gentemp)
642 (setq a (symbolconc *real-gentemp-prefix* r-k))
644 (push `((mequal) ,s ,a) r-vars))
646 ((get s 'complex-gentemp)
647 (setq a (symbolconc *complex-gentemp-prefix* c-k))
648 (mfuncall '$declare a '$complex)
650 (push `((mequal) ,s ,a) c-vars))
652 ((get s 'general-gentemp)
653 (setq a (symbolconc *general-gentemp-prefix* g-k))
655 (push `((mequal) ,s ,a) g-vars)))))
656 (margs ($sort ($listofvars e))))
658 (push '(mlist) z-vars)
659 (push '(mlist) n-vars)
660 (push '(mlist) r-vars)
661 (push '(mlist) c-vars)
662 (push '(mlist) g-vars)
663 ($sublis g-vars ($sublis c-vars ($sublis r-vars ($sublis n-vars ($sublis z-vars e)))))))
665 (defun $complex_number_p (e)
666 (complex-number-p e #'$numberp))