Improve the translation of notequal
[maxima.git] / src / csimp.lisp
blob179584aa7701d277db37b78e386c9e5f7e551423
1 ;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;; The data in this file contains enhancments. ;;;;;
4 ;;; ;;;;;
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 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
11 (in-package :maxima)
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)
29 (defvar rsn* nil)
30 (defvar plogabs 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.
41 (loop for (a b) on
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)
46 by #'cddr
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))))
54 nexp)
55 (t (recur-apply #'$demoivre exp)))))
57 (defun demoivre (l)
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))
62 (m* (m^ '$%e (cdr l))
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))
71 (sdiff expr var1))))
72 (if (freeof var1 a)
73 (cons a (maxima-substitute 0 var1 expr)))))
75 (defmfun $partition (e var1)
76 (let ((e (mratcheck e))
77 (var1 (getopr var1)))
78 (cond
79 (($listp 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))))))
88 ((mplusp e)
89 (destructuring-bind (constant . variable) (partition e var1 0)
90 (list '(mlist simp) constant variable)))
92 ((mtimesp e)
93 (destructuring-bind (constant . variable) (partition e var1 1)
94 (list '(mlist simp) constant variable)))
97 (merror
98 (intl:gettext
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
103 ;; (VALUES YES NO),
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)
108 (let ((yes) (no))
109 (map nil
110 (lambda (x)
111 (if (funcall predicate x)
112 (push x yes)
113 (push x no)))
114 seq)
115 (values yes no)))
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))))
124 (cond
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)
132 (cons exp k)
133 (cons k exp)))
135 ;; Otherwise, we want to partition the arguments into constant and
136 ;; variable.
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))
142 (t (simplifya
143 (cons (list op) (nreverse constant)) t)))
144 (cond ((null variable) k)
145 ((null (cdr variable)) (car variable))
146 (t (simplifya
147 (cons (list op) (nreverse variable)) t)))))))))
149 ;;To use this INTEGERINFO and *ASK* need to be special.
150 ;;(defun integerpw (x)
151 ;; ((lambda (*ask*)
152 ;; (integerp10 (ssimplifya (sublis '((z** . 0) (*z* . 0)) x))))
153 ;; t))
155 ;;(defun integerp10 (x)
156 ;; ((lambda (d)
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))
162 ;; (eq d 'yes))))
163 ;; nil))
165 (setq var (make-symbol "foo"))
167 (defun numden (e)
168 (prog (varlist)
169 (setq varlist (list var))
170 (newvar (setq e (fmt e)))
171 (setq e (cdr (ratrep* e)))
172 (setq dn*
173 (simplifya (pdis (ratdenominator e))
174 nil))
175 (setq nn*
176 (simplifya (pdis (ratnumerator e))
177 nil)))
178 (values nn* dn*))
180 (defun fmt (exp)
181 (let (nn*)
182 (cond ((atom exp) exp)
183 ((mnump exp) exp)
184 ((eq (caar exp) 'mexpt)
185 (cond ((and (mnump (caddr exp))
186 (eq ($sign (caddr exp)) '$neg))
187 (list '(mquotient)
189 (cond ((equal (caddr exp) -1)
190 (fmt (cadr exp)))
191 (t (list (list (caar exp))
192 (fmt (cadr exp))
193 (timesk -1 (caddr exp)))))))
194 ((atom (caddr exp))
195 (list (list (caar exp))
196 (fmt (cadr exp))
197 (caddr exp)))
198 ((and (mtimesp (setq nn* (sratsimp (caddr exp))))
199 (mnump (cadr nn*))
200 (equal ($sign (cadr nn*)) '$neg))
201 (list '(mquotient)
203 (list (list (caar exp))
204 (fmt (cadr exp))
205 (cond ((equal (cadr nn*) -1)
206 (cons '(mtimes)
207 (cddr nn*)))
208 (t (neg nn*))))))
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)))
218 (defun subin (y x)
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.
233 (let
234 ((relational-ops
235 ;; < <= = # equal notequal >= >
236 '(mlessp mleqp mequal mnotequal $equal $notequal mgeqp mgreaterp
237 %mlessp %mleqp %mequal %mnotequal %equal %notequal %mgeqp %mgreaterp))
239 (other-infix-ops
240 ;; := ::= : :: ->
241 '(mdefine mdefmacro msetq mset marrow
242 %mdefine %mdefmacro %msetq %mset %marrow)))
244 (defmfun $rhs (rel)
245 (if (atom rel)
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))
250 (caddr rel)
251 0)))
253 (defmfun $lhs (rel)
254 (if (atom rel)
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))
259 (cadr rel)
260 rel))))
262 (defun ratgreaterp (x y)
263 (cond ((and (ratnump x) (ratnump y))
264 (great x 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.
273 (defun %especial (e)
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)
287 (and (onep1 kk)
288 (integerp (add y y)))))
289 (return nil))
290 (setq j (trigred y))
291 (setq ans (spang1 j t)))
292 (cond ((among '%sin ans)
293 (cond ((equal y j) (return nil))
294 ((zerop1 k)
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.
299 (return
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))))))
305 (defun trigred (r)
306 (prog (m n eo flag)
307 (cond ((numberp r) (return (cond ((even r) 0) (t 1)))))
308 (setq m (cadr r))
309 (cond ((minusp m) (setq m (- m)) (setq flag t)))
310 (setq n (caddr r))
311 loop (cond ((> m n)
312 (setq m (- m n))
313 (setq eo (not eo))
314 (go loop)))
315 (setq m (list '(rat)
316 (cond (flag (- m)) (t m))
318 (return (cond (eo (addk m (cond (flag 1) (t -1))))
319 (t m)))))
321 (defun polyinx (exp x ind)
322 (prog (genvar varlist var $ratfac)
323 (setq var x)
324 (cond ((numberp exp)(return t))
325 ((polyp exp)
326 (cond (ind (go on))
327 (t (return t))))
328 (t (return nil)))
329 on (setq genvar nil)
330 (setq varlist (list x))
331 (newvar exp)
332 (setq exp (cdr (ratrep* exp)))
333 (cond
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)
343 (cadr exp)
344 (caddr exp)))))
346 ))))))
348 (defun polyp (a)
349 (cond ((atom a) t)
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))
356 (> (caddr a) 0)
357 (polyp (cadr a))))))
358 (t (andmapcar #'(lambda (subexp)
359 (free subexp var))
360 (cdr a)))))
362 (defun pip (e)
363 (prog (varlist d c)
364 (newvar e)
365 (cond ((not (member '$%pi varlist :test #'eq)) (return nil)))
366 (setq varlist '($%pi))
367 (newvar e)
368 (let (($ratfac nil))
369 ;; non-nil $ratfac changes form of CRE
370 (setq e (cdr (ratrep* e))))
371 (setq d (cdr e))
372 (cond ((not (atom d)) (return nil))
373 ((equal e '(0 . 1))
374 (setq c 0)
375 (go loop)))
376 (setq c (ptterm (cdar e) 1))
377 loop (cond ((atom c)
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))
382 (go loop)))
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)))))
388 (setq ang j)
389 (cond
390 (ind nil)
391 ((numberp j)
392 (cond ((zerop j) (return 1)) (t (return -1))))
393 (t (setq j
394 (trigred (add2* '((rat simp) 1 2)
395 (list (car j)
396 (- (cadr j))
397 (caddr j)))))))
398 (cond ((numberp j) (return 0))
399 ((mnump j) (setq j (cdr j))))
400 (return
401 (cond ((equal j '(1 2)) 1)
402 ((equal j '(-1 2)) -1)
403 ((or (equal j '(1 3))
404 (equal j '(2 3)))
405 (div ($sqrt 3) 2))
406 ((or (equal j '(-1 3))
407 (equal j '(-2 3)))
408 (div ($sqrt 3) -2))
409 ((or (equal j '(1 6))
410 (equal j '(5 6)))
411 '((rat simp) 1 2))
412 ((or (equal j '(-1 6))
413 (equal j '(-5 6)))
414 '((rat simp) -1 2))
415 ((or (equal j '(1 4))
416 (equal j '(3 4)))
417 (div 1 ($sqrt 2)))
418 ((or (equal j '(-1 4))
419 (equal j '(-3 4)))
420 (div -1 ($sqrt 2)))
421 (t (cond ((mnegp ang)
422 (setq ang (timesk -1 ang) ep t)))
423 (setq ang (list '(mtimes simp)
425 '$%pi))
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))))))))
432 (defun archk (a b v)
433 (simplify
434 (cond ((and (equal a 1) (equal b 1)) v)
435 ((and (equal b -1) (equal 1 a))
436 (list '(mtimes) -1 v))
437 ((equal 1 b)
438 (list '(mplus) '$%pi (list '(mtimes) -1 v)))
439 (t (list '(mplus) v (list '(mtimes) -1 '$%pi))))))
441 (defun genfind (h v)
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))))