1 ;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;; The data in this file contains enhancements. ;;;;;
5 ;;; Copyright (c) 1984,1987 by William Schelter,University of Texas ;;;;;
6 ;;; All rights reserved ;;;;;
7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
8 ;;; (c) Copyright 1980 Massachusetts Institute of Technology ;;;
9 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
13 (macsyma-module csimp
)
15 (declare-top (special $exponentialize
19 (load-macsyma-macros rzmac
)
22 '(%sin %asin %cos %acos %tan %atan
23 %cot %acot %sec %asec %csc %acsc
24 %sinh %asinh %cosh %acosh %tanh %atanh
25 %coth %acoth %sech %asech %csch %acsch
)
27 do
(putprop a b
'$inverse
) (putprop b a
'$inverse
))
29 (defmfun $demoivre
(exp)
30 (let ($exponentialize nexp
)
31 (cond ((atom exp
) exp
)
32 ((and (eq (caar exp
) 'mexpt
) (eq (cadr exp
) '$%e
)
33 (setq nexp
(demoivre (caddr exp
))))
35 (t (recur-apply #'$demoivre exp
)))))
38 (cond ($exponentialize
39 (merror (intl:gettext
"demoivre: 'demoivre' and 'exponentialize' cannot both be true.")))
40 (t (setq l
(islinear l
'$%i
))
41 (and l
(not (equal (car l
) 0))
43 (m+ (list '(%cos
) (car l
))
44 (m* '$%i
(list '(%sin
) (car l
)))))))))
46 ;; If expr is of the form a*var1+b where a is freeof var1
47 ;; then (a . b) is returned else nil.
48 (defun islinear (expr var1
)
49 (let ((a (let ((*islinp
* t
))
52 (cons a
(maxima-substitute 0 var1 expr
)))))
54 (defmfun $partition
(e var1
)
55 (let ((e (mratcheck e
))
59 (do ((l (cdr e
) (cdr l
)) (l1) (l2) (x))
60 ((null l
) (list '(mlist simp
)
61 (cons '(mlist simp
) (nreverse l1
))
62 (cons '(mlist simp
) (nreverse l2
))))
63 (setq x
(mratcheck (car l
)))
64 (cond ((free x var1
) (setq l1
(cons x l1
)))
65 (t (setq l2
(cons x l2
))))))
68 (destructuring-bind (constant . variable
) (partition e var1
0)
69 (list '(mlist simp
) constant variable
)))
72 (destructuring-bind (constant . variable
) (partition e var1
1)
73 (list '(mlist simp
) constant variable
)))
78 "partition: first argument must be a list or '+' or '*' expression; found ~M") e
)))))
80 ;; Apply PREDICATE to each element in the sequence SEQ and return
84 ;; where YES and NO are lists consisting of elements for which PREDICATE is true
85 ;; or false, respectively.
86 (defun partition-by (predicate seq
)
90 (if (funcall predicate x
)
96 ;; Partition an expression, EXP, into terms that contain VAR1 and terms that
97 ;; don't contain VAR1. EXP is either considered as a product or a sum (for which
98 ;; you should pass K = 1 or 0, respectively).
100 (defun partition (exp var1 k
)
101 (let ((op (if (= k
0) 'mplus
'mtimes
))
102 (exp-op (unless (atom exp
) (caar exp
))))
104 ;; Exit immediately if exp = var1
105 ((alike1 exp var1
) (cons k exp
))
107 ;; If we have the wrong operation then the expression is either entirely
108 ;; constant or entirely variable.
109 ((not (eq exp-op op
))
110 (if (freeof var1 exp
)
114 ;; Otherwise, we want to partition the arguments into constant and
117 (multiple-value-bind (constant variable
)
118 (partition-by (lambda (x) (freeof var1 x
)) (cdr exp
))
119 (cons (cond ((null constant
) k
)
120 ((null (cdr constant
)) (car constant
))
122 (cons (list op
) (nreverse constant
)) t
)))
123 (cond ((null variable
) k
)
124 ((null (cdr variable
)) (car variable
))
126 (cons (list op
) (nreverse variable
)) t
)))))))))
128 ;;To use this INTEGERINFO and *ASK* need to be special.
129 ;;(defun integerpw (x)
131 ;; (integerp10 (ssimplifya (sublis '((z** . 0) (*z* . 0)) x))))
134 ;;(defun integerp10 (x)
136 ;; (cond ((or (null x) (not (free x '$%i))) nil)
137 ;; ((mnump x) (integerp x))
138 ;; ((setq d (assolike x integerinfo)) (eq d 'yes))
139 ;; (*ask* (setq d (cond ((integerp x) 'yes) (t (needinfo x))))
140 ;; (setq integerinfo (cons (list x d) integerinfo))
144 (setq var
(make-symbol "foo"))
148 (setq varlist
(list var
))
149 (newvar (setq e
(fmt e
)))
150 (setq e
(cdr (ratrep* e
)))
152 (simplifya (pdis (ratdenominator e
))
155 (simplifya (pdis (ratnumerator e
))
159 ;; Like NUMDEN but dependency on VAR is explicit. Use this instead of
160 ;; NUMDEN if possible. Also, we do not set the special variables DN*
161 ;; and NN*. The callers are responsible for doing that, now.
162 (defun numden-var (e var1
)
163 (let ((varlist (list var1
))
165 (newvar (setq e
(fmt e
)))
166 (setq e
(cdr (ratrep* e
)))
168 (simplifya (pdis (ratdenominator e
))
171 (simplifya (pdis (ratnumerator e
))
177 (cond ((atom exp
) exp
)
179 ((eq (caar exp
) 'mexpt
)
180 (cond ((and (mnump (caddr exp
))
181 (eq ($sign
(caddr exp
)) '$neg
))
184 (cond ((equal (caddr exp
) -
1)
186 (t (list (list (caar exp
))
188 (timesk -
1 (caddr exp
)))))))
190 (list (list (caar exp
))
193 ((and (mtimesp (setq nn
* (sratsimp (caddr exp
))))
195 (equal ($sign
(cadr nn
*)) '$neg
))
198 (list (list (caar exp
))
200 (cond ((equal (cadr nn
*) -
1)
204 ((eq (caar nn
*) 'mplus
)
205 (fmt (spexp (cdr nn
*) (cadr exp
))))
206 (t (cons (ncons (caar exp
))
207 (mapcar #'fmt
(cdr exp
))))))
208 (t (cons (delsimp (car exp
)) (mapcar #'fmt
(cdr exp
)))))))
210 (defun spexp (expl dn
*)
211 (cons '(mtimes) (mapcar #'(lambda (e) (list '(mexpt) dn
* e
)) expl
)))
214 (cond ((not (among var x
)) x
)
215 (t (maxima-substitute y var x
))))
217 ;; Like SUBIN but dependency on VAR is explicit. Use this instead
219 (defun subin-var (y x ivar
)
220 (cond ((not (among ivar x
)) x
)
221 (t (maxima-substitute y ivar x
))))
223 ;; Right-hand side (rhs) and left-hand side (lhs) of binary infix expressions.
224 ;; These are unambiguous for relational operators, some other built-in infix operators,
225 ;; and user-defined infix operators (declared by the infix function).
227 ;; a - b and a / b are somewhat problematic, since subtraction and division are not
228 ;; ordinarily represented as such (rather a - b = a + (-1)*b and a / b = a * b^(-1)).
229 ;; Also, - can be unary. So let's not worry about - and / .
231 ;; Other problematic cases: The symbols $< $<= $= $# $>= $> have a LED property,
232 ;; but these symbols never appear in expressions returned by the Maxima parser;
233 ;; MLESSP, MLEQP, MEQUAL etc are substituted. So ignore those symbols here.
236 ;; < <= = # equal notequal >= >
237 '(mlessp mleqp mequal mnotequal $equal $notequal mgeqp mgreaterp
238 %mlessp %mleqp %mequal %mnotequal %equal %notequal %mgeqp %mgreaterp
))
242 '(mdefine mdefmacro msetq mset marrow
243 %mdefine %mdefmacro %msetq %mset %marrow
)))
248 (if (or (member (caar rel
) (append relational-ops other-infix-ops
) :test
#'eq
)
249 ;; This test catches user-defined infix operators.
250 (eq (get (caar rel
) 'led
) 'parse-infix
))
257 (if (or (member (caar rel
) (append relational-ops other-infix-ops
) :test
#'eq
)
258 ;; This test catches user-defined infix operators.
259 (eq (get (caar rel
) 'led
) 'parse-infix
))
263 (defun ratgreaterp (x y
)
264 (cond ((and (ratnump x
) (ratnump y
))
266 ((equal ($asksign
(m- x y
)) '$pos
))))
268 ;; Simplify the exponential function of the type exp(p/q*%i*%pi+x) using the
269 ;; periodicity of the exponential function and special values for rational
270 ;; numbers with a denominator q = 2, 3, 4, or 6. e is the argument of the
271 ;; exponential function. For float and bigfloat numbers in the argument e only
272 ;; simplify for an integer representation or a half integral value.
273 ;; The result is an exponential function with a simplified argument.
275 (prog (varlist y k kk j ans $%emode $ratprint genvar
)
276 (let (($keepfloat nil
) ($float nil
))
277 (unless (setq y
(pip ($ratcoef e
'$%i
))) (return nil
))
278 ;; Subtract the term y*%i*%pi from the expression e.
279 (setq k
($expand
(add e
(mul -
1 '$%pi
'$%i y
)) 1))
280 ;; This is a workaround to get the type (integer, float, or bigfloat)
281 ;; of the expression. kk must evaluate to 1, 1.0, or 1.0b0.
282 ;; Furthermore, if e is nonlinear, kk does not simplify to a number ONE.
283 ;; Because of this we do not simplify something like exp((2+x)^2*%i*%pi)
284 (setq kk
(div (sub ($expand e
) k
) (mul '$%i
'$%pi y
)))
285 ;; Return if kk is not an integer or kk is ONE, but y not an integer
286 ;; or a half integral value.
287 (if (not (or (integerp kk
)
289 (integerp (add y y
)))))
292 (setq ans
(spang1 j t
)))
293 (cond ((among '%sin ans
)
294 (cond ((equal y j
) (return nil
))
296 ;; To preverse the type we add k into the result.
297 (return (power '$%e
(mul '$%pi
'$%i
(add k j
)))))
299 ;; To preserve the type we multiply kk into the result.
301 (power '$%e
(add (mul kk k
) (mul kk
'$%pi
'$%i j
))))))))
302 (setq y
(spang1 j nil
))
303 ;; To preserve the type we multiply kk into the result.
304 (return (mul (power '$%e
(mul kk k
)) (add y
(mul '$%i ans
))))))
308 (cond ((numberp r
) (return (cond ((even r
) 0) (t 1)))))
310 (cond ((minusp m
) (setq m
(- m
)) (setq flag t
)))
317 (cond (flag (- m
)) (t m
))
319 (return (cond (eo (addk m
(cond (flag 1) (t -
1))))
322 (defun polyinx (exp x ind
)
323 (prog (genvar varlist var $ratfac
)
325 (cond ((numberp exp
)(return t
))
331 (setq varlist
(list x
))
333 (setq exp
(cdr (ratrep* exp
)))
335 ((or (numberp (cdr exp
))
336 (not (eq (car (last genvar
)) (cadr exp
))))
337 (setq x
(pdis (cdr exp
)))
338 (return (cond ((eq ind
'leadcoef
)
339 (div* (pdis (caddr (car exp
))) x
))
340 (t (setq exp
(car exp
))
341 (div* (cond ((atom exp
) exp
)
343 (pdis (list (car exp
)
351 ((member (caar a
) '(mplus mtimes
) :test
#'eq
)
352 (every #'polyp
(cdr a
)))
353 ((eq (caar a
) 'mexpt
)
354 (cond ((free (cadr a
) var
)
355 (free (caddr a
) var
))
356 (t (and (integerp (caddr a
))
359 (t (andmapcar #'(lambda (subexp)
363 ;; Like polyp but takes an extra arg for the variable.
364 (defun polyp-var (a var2
)
366 ((member (caar a
) '(mplus mtimes
) :test
#'eq
)
370 ((eq (caar a
) 'mexpt
)
371 (cond ((free (cadr a
) var2
)
372 (free (caddr a
) var2
))
373 (t (and (integerp (caddr a
))
375 (polyp-var (cadr a
) var2
)))))
376 (t (andmapcar #'(lambda (subexp)
383 (cond ((not (member '$%pi varlist
:test
#'eq
)) (return nil
)))
384 (setq varlist
'($%pi
))
387 ;; non-nil $ratfac changes form of CRE
388 (setq e
(cdr (ratrep* e
))))
390 (cond ((not (atom d
)) (return nil
))
394 (setq c
(ptterm (cdar e
) 1))
396 (cond ((equal c
0) (return nil
))
397 ((equal 1 d
) (return c
))
398 (t (return (list '(rat) c d
))))))
399 (setq c
(ptterm (cdr c
) 0))
402 (defun spang1 (j ind
)
403 (prog (ang ep $exponentialize $float $keepfloat
)
404 (cond ((floatp j
) (setq j
(maxima-rationalize j
))
405 (setq j
(list '(rat simp
) (car j
) (cdr j
)))))
410 (cond ((zerop j
) (return 1)) (t (return -
1))))
412 (trigred (add2* '((rat simp
) 1 2)
416 (cond ((numberp j
) (return 0))
417 ((mnump j
) (setq j
(cdr j
))))
419 (cond ((equal j
'(1 2)) 1)
420 ((equal j
'(-1 2)) -
1)
421 ((or (equal j
'(1 3))
424 ((or (equal j
'(-1 3))
427 ((or (equal j
'(1 6))
430 ((or (equal j
'(-1 6))
433 ((or (equal j
'(1 4))
436 ((or (equal j
'(-1 4))
439 (t (cond ((mnegp ang
)
440 (setq ang
(timesk -
1 ang
) ep t
)))
441 (setq ang
(list '(mtimes simp
)
444 (cond (ind (cond (ep (list '(mtimes simp
)
446 (list '(%sin simp
) ang
)))
447 (t (list '(%sin simp
) ang
))))
448 (t (list '(%cos simp
) ang
))))))))
452 (cond ((and (equal a
1) (equal b
1)) v
)
453 ((and (equal b -
1) (equal 1 a
))
454 (list '(mtimes) -
1 v
))
456 (list '(mplus) '$%pi
(list '(mtimes) -
1 v
)))
457 (t (list '(mplus) v
(list '(mtimes) -
1 '$%pi
))))))
460 ;;; finds gensym coresponding to v h
461 (do ((varl (caddr h
) (cdr varl
))
462 (genl (cadddr h
) (cdr genl
)))
463 ;;;is car of rat form
464 ((eq (car varl
) v
) (car genl
))))