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 1980 Massachusetts Institute of Technology ;;;
9 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
13 (macsyma-module csimp
)
15 (declare-top (special rsn
* $factlim $exponentialize
16 var varlist genvar $%emode $ratprint
17 nn
* dn
* $errexp sqrt3
//2 -sqrt3
//2
18 $demoivre errorsw $keepfloat $ratfac
))
20 (load-macsyma-macros rzmac
)
22 (declare-top (special $nointegrate $lhospitallim $tlimswitch $limsubst plogabs
))
24 (defmvar $demoivre nil
)
25 (defmvar $nointegrate nil
)
26 (defmvar $lhospitallim
4)
27 (defmvar $tlimswitch t
)
28 (defmvar $limsubst nil
)
32 ;; Simplified shortcuts of constant expressions involving %pi.
33 (defvar %p%i
'((mtimes) $%i $%pi
))
34 (defvar fourth%pi
'((mtimes) ((rat simp
) 1 4) $%pi
))
35 (defvar half%pi
'((mtimes) ((rat simp
) 1 2) $%pi
))
36 (defvar %pi2
'((mtimes) 2 $%pi
))
37 (defvar half%pi3
'((mtimes) ((rat simp
) 3 2) $%pi
))
39 (defmvar $sumsplitfact t
) ;= nil minfactorial is applied after a factocomb.
42 '(%sin %asin %cos %acos %tan %atan
43 %cot %acot %sec %asec %csc %acsc
44 %sinh %asinh %cosh %acosh %tanh %atanh
45 %coth %acoth %sech %asech %csch %acsch
)
47 do
(putprop a b
'$inverse
) (putprop b a
'$inverse
))
49 (defmfun $demoivre
(exp)
50 (let ($exponentialize nexp
)
51 (cond ((atom exp
) exp
)
52 ((and (eq (caar exp
) 'mexpt
) (eq (cadr exp
) '$%e
)
53 (setq nexp
(demoivre (caddr exp
))))
55 (t (recur-apply #'$demoivre exp
)))))
58 (cond ($exponentialize
59 (merror (intl:gettext
"demoivre: 'demoivre' and 'exponentialize' cannot both be true.")))
60 (t (setq l
(islinear l
'$%i
))
61 (and l
(not (equal (car l
) 0))
63 (m+ (list '(%cos
) (car l
))
64 (m* '$%i
(list '(%sin
) (car l
)))))))))
66 ;; If expr is of the form a*var1+b where a is freeof var1
67 ;; then (a . b) is returned else nil.
68 (defun islinear (expr var1
)
69 (declare (special *islinp
*))
70 (let ((a (let ((*islinp
* t
))
73 (cons a
(maxima-substitute 0 var1 expr
)))))
75 (defmfun $partition
(e var1
)
76 (let ((e (mratcheck e
))
80 (do ((l (cdr e
) (cdr l
)) (l1) (l2) (x))
81 ((null l
) (list '(mlist simp
)
82 (cons '(mlist simp
) (nreverse l1
))
83 (cons '(mlist simp
) (nreverse l2
))))
84 (setq x
(mratcheck (car l
)))
85 (cond ((free x var1
) (setq l1
(cons x l1
)))
86 (t (setq l2
(cons x l2
))))))
89 (destructuring-bind (constant . variable
) (partition e var1
0)
90 (list '(mlist simp
) constant variable
)))
93 (destructuring-bind (constant . variable
) (partition e var1
1)
94 (list '(mlist simp
) constant variable
)))
99 "partition: first argument must be a list or '+' or '*' expression; found ~M") e
)))))
101 ;; Apply PREDICATE to each element in the sequence SEQ and return
105 ;; where YES and NO are lists consisting of elements for which PREDICATE is true
106 ;; or false, respectively.
107 (defun partition-by (predicate seq
)
111 (if (funcall predicate x
)
117 ;; Partition an expression, EXP, into terms that contain VAR1 and terms that
118 ;; don't contain VAR1. EXP is either considered as a product or a sum (for which
119 ;; you should pass K = 1 or 0, respectively).
121 (defun partition (exp var1 k
)
122 (let ((op (if (= k
0) 'mplus
'mtimes
))
123 (exp-op (unless (atom exp
) (caar exp
))))
125 ;; Exit immediately if exp = var1
126 ((alike1 exp var1
) (cons k exp
))
128 ;; If we have the wrong operation then the expression is either entirely
129 ;; constant or entirely variable.
130 ((not (eq exp-op op
))
131 (if (freeof var1 exp
)
135 ;; Otherwise, we want to partition the arguments into constant and
138 (multiple-value-bind (constant variable
)
139 (partition-by (lambda (x) (freeof var1 x
)) (cdr exp
))
140 (cons (cond ((null constant
) k
)
141 ((null (cdr constant
)) (car constant
))
143 (cons (list op
) (nreverse constant
)) t
)))
144 (cond ((null variable
) k
)
145 ((null (cdr variable
)) (car variable
))
147 (cons (list op
) (nreverse variable
)) t
)))))))))
149 ;;To use this INTEGERINFO and *ASK* need to be special.
150 ;;(defun integerpw (x)
152 ;; (integerp10 (ssimplifya (sublis '((z** . 0) (*z* . 0)) x))))
155 ;;(defun integerp10 (x)
157 ;; (cond ((or (null x) (not (free x '$%i))) nil)
158 ;; ((mnump x) (integerp x))
159 ;; ((setq d (assolike x integerinfo)) (eq d 'yes))
160 ;; (*ask* (setq d (cond ((integerp x) 'yes) (t (needinfo x))))
161 ;; (setq integerinfo (cons (list x d) integerinfo))
165 (setq var
(make-symbol "foo"))
169 (setq varlist
(list var
))
170 (newvar (setq e
(fmt e
)))
171 (setq e
(cdr (ratrep* e
)))
173 (simplifya (pdis (ratdenominator e
))
176 (simplifya (pdis (ratnumerator e
))
182 (cond ((atom exp
) exp
)
184 ((eq (caar exp
) 'mexpt
)
185 (cond ((and (mnump (caddr exp
))
186 (eq ($sign
(caddr exp
)) '$neg
))
189 (cond ((equal (caddr exp
) -
1)
191 (t (list (list (caar exp
))
193 (timesk -
1 (caddr exp
)))))))
195 (list (list (caar exp
))
198 ((and (mtimesp (setq nn
* (sratsimp (caddr exp
))))
200 (equal ($sign
(cadr nn
*)) '$neg
))
203 (list (list (caar exp
))
205 (cond ((equal (cadr nn
*) -
1)
209 ((eq (caar nn
*) 'mplus
)
210 (fmt (spexp (cdr nn
*) (cadr exp
))))
211 (t (cons (ncons (caar exp
))
212 (mapcar #'fmt
(cdr exp
))))))
213 (t (cons (delsimp (car exp
)) (mapcar #'fmt
(cdr exp
)))))))
215 (defun spexp (expl dn
*)
216 (cons '(mtimes) (mapcar #'(lambda (e) (list '(mexpt) dn
* e
)) expl
)))
219 (cond ((not (among var x
)) x
)
220 (t (maxima-substitute y var 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)
365 (cond ((not (member '$%pi varlist
:test
#'eq
)) (return nil
)))
366 (setq varlist
'($%pi
))
369 ;; non-nil $ratfac changes form of CRE
370 (setq e
(cdr (ratrep* e
))))
372 (cond ((not (atom d
)) (return nil
))
376 (setq c
(ptterm (cdar e
) 1))
378 (cond ((equal c
0) (return nil
))
379 ((equal 1 d
) (return c
))
380 (t (return (list '(rat) c d
))))))
381 (setq c
(ptterm (cdr c
) 0))
384 (defun spang1 (j ind
)
385 (prog (ang ep $exponentialize $float $keepfloat
)
386 (cond ((floatp j
) (setq j
(maxima-rationalize j
))
387 (setq j
(list '(rat simp
) (car j
) (cdr j
)))))
392 (cond ((zerop j
) (return 1)) (t (return -
1))))
394 (trigred (add2* '((rat simp
) 1 2)
398 (cond ((numberp j
) (return 0))
399 ((mnump j
) (setq j
(cdr j
))))
401 (cond ((equal j
'(1 2)) 1)
402 ((equal j
'(-1 2)) -
1)
403 ((or (equal j
'(1 3))
406 ((or (equal j
'(-1 3))
409 ((or (equal j
'(1 6))
412 ((or (equal j
'(-1 6))
415 ((or (equal j
'(1 4))
418 ((or (equal j
'(-1 4))
421 (t (cond ((mnegp ang
)
422 (setq ang
(timesk -
1 ang
) ep t
)))
423 (setq ang
(list '(mtimes simp
)
426 (cond (ind (cond (ep (list '(mtimes simp
)
428 (list '(%sin simp
) ang
)))
429 (t (list '(%sin simp
) ang
))))
430 (t (list '(%cos simp
) ang
))))))))
434 (cond ((and (equal a
1) (equal b
1)) v
)
435 ((and (equal b -
1) (equal 1 a
))
436 (list '(mtimes) -
1 v
))
438 (list '(mplus) '$%pi
(list '(mtimes) -
1 v
)))
439 (t (list '(mplus) v
(list '(mtimes) -
1 '$%pi
))))))
442 ;;; finds gensym coresponding to v h
443 (do ((varl (caddr h
) (cdr varl
))
444 (genl (cadddr h
) (cdr genl
)))
445 ;;;is car of rat form
446 ((eq (car varl
) v
) (car genl
))))