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.
161 (defun numden-var (e var1
)
163 (setq varlist
(list var1
))
164 (newvar (setq e
(fmt e
)))
165 (setq e
(cdr (ratrep* e
)))
167 (simplifya (pdis (ratdenominator e
))
170 (simplifya (pdis (ratnumerator e
))
176 (cond ((atom exp
) exp
)
178 ((eq (caar exp
) 'mexpt
)
179 (cond ((and (mnump (caddr exp
))
180 (eq ($sign
(caddr exp
)) '$neg
))
183 (cond ((equal (caddr exp
) -
1)
185 (t (list (list (caar exp
))
187 (timesk -
1 (caddr exp
)))))))
189 (list (list (caar exp
))
192 ((and (mtimesp (setq nn
* (sratsimp (caddr exp
))))
194 (equal ($sign
(cadr nn
*)) '$neg
))
197 (list (list (caar exp
))
199 (cond ((equal (cadr nn
*) -
1)
203 ((eq (caar nn
*) 'mplus
)
204 (fmt (spexp (cdr nn
*) (cadr exp
))))
205 (t (cons (ncons (caar exp
))
206 (mapcar #'fmt
(cdr exp
))))))
207 (t (cons (delsimp (car exp
)) (mapcar #'fmt
(cdr exp
)))))))
209 (defun spexp (expl dn
*)
210 (cons '(mtimes) (mapcar #'(lambda (e) (list '(mexpt) dn
* e
)) expl
)))
213 (cond ((not (among var x
)) x
)
214 (t (maxima-substitute y var x
))))
216 ;; Like SUBIN but dependency on VAR is explicit. Use this instead
218 (defun subin-var (y x ivar
)
219 (cond ((not (among ivar x
)) x
)
220 (t (maxima-substitute y ivar x
))))
222 ;; Right-hand side (rhs) and left-hand side (lhs) of binary infix expressions.
223 ;; These are unambiguous for relational operators, some other built-in infix operators,
224 ;; and user-defined infix operators (declared by the infix function).
226 ;; a - b and a / b are somewhat problematic, since subtraction and division are not
227 ;; ordinarily represented as such (rather a - b = a + (-1)*b and a / b = a * b^(-1)).
228 ;; Also, - can be unary. So let's not worry about - and / .
230 ;; Other problematic cases: The symbols $< $<= $= $# $>= $> have a LED property,
231 ;; but these symbols never appear in expressions returned by the Maxima parser;
232 ;; MLESSP, MLEQP, MEQUAL etc are substituted. So ignore those symbols here.
235 ;; < <= = # equal notequal >= >
236 '(mlessp mleqp mequal mnotequal $equal $notequal mgeqp mgreaterp
237 %mlessp %mleqp %mequal %mnotequal %equal %notequal %mgeqp %mgreaterp
))
241 '(mdefine mdefmacro msetq mset marrow
242 %mdefine %mdefmacro %msetq %mset %marrow
)))
247 (if (or (member (caar rel
) (append relational-ops other-infix-ops
) :test
#'eq
)
248 ;; This test catches user-defined infix operators.
249 (eq (get (caar rel
) 'led
) 'parse-infix
))
256 (if (or (member (caar rel
) (append relational-ops other-infix-ops
) :test
#'eq
)
257 ;; This test catches user-defined infix operators.
258 (eq (get (caar rel
) 'led
) 'parse-infix
))
262 (defun ratgreaterp (x y
)
263 (cond ((and (ratnump x
) (ratnump y
))
265 ((equal ($asksign
(m- x y
)) '$pos
))))
267 ;; Simplify the exponential function of the type exp(p/q*%i*%pi+x) using the
268 ;; periodicity of the exponential function and special values for rational
269 ;; numbers with a denominator q = 2, 3, 4, or 6. e is the argument of the
270 ;; exponential function. For float and bigfloat numbers in the argument e only
271 ;; simplify for an integer representation or a half integral value.
272 ;; The result is an exponential function with a simplified argument.
274 (prog (varlist y k kk j ans $%emode $ratprint genvar
)
275 (let (($keepfloat nil
) ($float nil
))
276 (unless (setq y
(pip ($ratcoef e
'$%i
))) (return nil
))
277 ;; Subtract the term y*%i*%pi from the expression e.
278 (setq k
($expand
(add e
(mul -
1 '$%pi
'$%i y
)) 1))
279 ;; This is a workaround to get the type (integer, float, or bigfloat)
280 ;; of the expression. kk must evaluate to 1, 1.0, or 1.0b0.
281 ;; Furthermore, if e is nonlinear, kk does not simplify to a number ONE.
282 ;; Because of this we do not simplify something like exp((2+x)^2*%i*%pi)
283 (setq kk
(div (sub ($expand e
) k
) (mul '$%i
'$%pi y
)))
284 ;; Return if kk is not an integer or kk is ONE, but y not an integer
285 ;; or a half integral value.
286 (if (not (or (integerp kk
)
288 (integerp (add y y
)))))
291 (setq ans
(spang1 j t
)))
292 (cond ((among '%sin ans
)
293 (cond ((equal y j
) (return nil
))
295 ;; To preverse the type we add k into the result.
296 (return (power '$%e
(mul '$%pi
'$%i
(add k j
)))))
298 ;; To preserve the type we multiply kk into the result.
300 (power '$%e
(add (mul kk k
) (mul kk
'$%pi
'$%i j
))))))))
301 (setq y
(spang1 j nil
))
302 ;; To preserve the type we multiply kk into the result.
303 (return (mul (power '$%e
(mul kk k
)) (add y
(mul '$%i ans
))))))
307 (cond ((numberp r
) (return (cond ((even r
) 0) (t 1)))))
309 (cond ((minusp m
) (setq m
(- m
)) (setq flag t
)))
316 (cond (flag (- m
)) (t m
))
318 (return (cond (eo (addk m
(cond (flag 1) (t -
1))))
321 (defun polyinx (exp x ind
)
322 (prog (genvar varlist var $ratfac
)
324 (cond ((numberp exp
)(return t
))
330 (setq varlist
(list x
))
332 (setq exp
(cdr (ratrep* exp
)))
334 ((or (numberp (cdr exp
))
335 (not (eq (car (last genvar
)) (cadr exp
))))
336 (setq x
(pdis (cdr exp
)))
337 (return (cond ((eq ind
'leadcoef
)
338 (div* (pdis (caddr (car exp
))) x
))
339 (t (setq exp
(car exp
))
340 (div* (cond ((atom exp
) exp
)
342 (pdis (list (car exp
)
350 ((member (caar a
) '(mplus mtimes
) :test
#'eq
)
351 (every #'polyp
(cdr a
)))
352 ((eq (caar a
) 'mexpt
)
353 (cond ((free (cadr a
) var
)
354 (free (caddr a
) var
))
355 (t (and (integerp (caddr a
))
358 (t (andmapcar #'(lambda (subexp)
362 ;; Like polyp but takes an extra arg for the variable.
363 (defun polyp-var (a var2
)
365 ((member (caar a
) '(mplus mtimes
) :test
#'eq
)
369 ((eq (caar a
) 'mexpt
)
370 (cond ((free (cadr a
) var2
)
371 (free (caddr a
) var2
))
372 (t (and (integerp (caddr a
))
374 (polyp-var (cadr a
) var2
)))))
375 (t (andmapcar #'(lambda (subexp)
382 (cond ((not (member '$%pi varlist
:test
#'eq
)) (return nil
)))
383 (setq varlist
'($%pi
))
386 ;; non-nil $ratfac changes form of CRE
387 (setq e
(cdr (ratrep* e
))))
389 (cond ((not (atom d
)) (return nil
))
393 (setq c
(ptterm (cdar e
) 1))
395 (cond ((equal c
0) (return nil
))
396 ((equal 1 d
) (return c
))
397 (t (return (list '(rat) c d
))))))
398 (setq c
(ptterm (cdr c
) 0))
401 (defun spang1 (j ind
)
402 (prog (ang ep $exponentialize $float $keepfloat
)
403 (cond ((floatp j
) (setq j
(maxima-rationalize j
))
404 (setq j
(list '(rat simp
) (car j
) (cdr j
)))))
409 (cond ((zerop j
) (return 1)) (t (return -
1))))
411 (trigred (add2* '((rat simp
) 1 2)
415 (cond ((numberp j
) (return 0))
416 ((mnump j
) (setq j
(cdr j
))))
418 (cond ((equal j
'(1 2)) 1)
419 ((equal j
'(-1 2)) -
1)
420 ((or (equal j
'(1 3))
423 ((or (equal j
'(-1 3))
426 ((or (equal j
'(1 6))
429 ((or (equal j
'(-1 6))
432 ((or (equal j
'(1 4))
435 ((or (equal j
'(-1 4))
438 (t (cond ((mnegp ang
)
439 (setq ang
(timesk -
1 ang
) ep t
)))
440 (setq ang
(list '(mtimes simp
)
443 (cond (ind (cond (ep (list '(mtimes simp
)
445 (list '(%sin simp
) ang
)))
446 (t (list '(%sin simp
) ang
))))
447 (t (list '(%cos simp
) ang
))))))))
451 (cond ((and (equal a
1) (equal b
1)) v
)
452 ((and (equal b -
1) (equal 1 a
))
453 (list '(mtimes) -
1 v
))
455 (list '(mplus) '$%pi
(list '(mtimes) -
1 v
)))
456 (t (list '(mplus) v
(list '(mtimes) -
1 '$%pi
))))))
459 ;;; finds gensym coresponding to v h
460 (do ((varl (caddr h
) (cdr varl
))
461 (genl (cadddr h
) (cdr genl
)))
462 ;;;is car of rat form
463 ((eq (car varl
) v
) (car genl
))))