Add a provide statement.
[bpt/emacs.git] / lisp / calc / calc-alg.el
CommitLineData
a1506d29 1;;; calc-alg.el --- algebraic functions for Calc
3132f345 2
d3896480 3;; Copyright (C) 1990, 1991, 1992, 1993, 2001 Free Software Foundation, Inc.
3132f345
CW
4
5;; Author: David Gillespie <daveg@synaptics.com>
0c908945 6;; Maintainer: Jay Belanger <belanger@truman.edu>
136211a9
EZ
7
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is distributed in the hope that it will be useful,
11;; but WITHOUT ANY WARRANTY. No author or distributor
12;; accepts responsibility to anyone for the consequences of using it
13;; or for whether it serves any particular purpose or works at all,
14;; unless he says so in writing. Refer to the GNU Emacs General Public
15;; License for full details.
16
17;; Everyone is granted permission to copy, modify and redistribute
18;; GNU Emacs, but only under the conditions described in the
19;; GNU Emacs General Public License. A copy of this license is
20;; supposed to have been given to you along with GNU Emacs so you
21;; can know your rights and responsibilities. It should be in a
22;; file named COPYING. Among other things, the copyright notice
23;; and this notice must be preserved on all copies.
24
3132f345 25;;; Commentary:
136211a9 26
3132f345 27;;; Code:
136211a9
EZ
28
29;; This file is autoloaded from calc-ext.el.
136211a9 30
41cf648d 31(require 'calc-ext)
136211a9
EZ
32(require 'calc-macs)
33
136211a9
EZ
34;;; Algebra commands.
35
36(defun calc-alg-evaluate (arg)
37 (interactive "p")
38 (calc-slow-wrapper
39 (calc-with-default-simplification
40 (let ((math-simplify-only nil))
41 (calc-modify-simplify-mode arg)
d3896480 42 (calc-enter-result 1 "dsmp" (calc-top 1))))))
136211a9
EZ
43
44(defun calc-modify-simplify-mode (arg)
45 (if (= (math-abs arg) 2)
46 (setq calc-simplify-mode 'alg)
47 (if (>= (math-abs arg) 3)
48 (setq calc-simplify-mode 'ext)))
49 (if (< arg 0)
d3896480 50 (setq calc-simplify-mode (list calc-simplify-mode))))
136211a9
EZ
51
52(defun calc-simplify ()
53 (interactive)
54 (calc-slow-wrapper
55 (calc-with-default-simplification
d3896480 56 (calc-enter-result 1 "simp" (math-simplify (calc-top-n 1))))))
136211a9
EZ
57
58(defun calc-simplify-extended ()
59 (interactive)
60 (calc-slow-wrapper
61 (calc-with-default-simplification
d3896480 62 (calc-enter-result 1 "esmp" (math-simplify-extended (calc-top-n 1))))))
136211a9
EZ
63
64(defun calc-expand-formula (arg)
65 (interactive "p")
66 (calc-slow-wrapper
67 (calc-with-default-simplification
68 (let ((math-simplify-only nil))
69 (calc-modify-simplify-mode arg)
a1506d29 70 (calc-enter-result 1 "expf"
136211a9
EZ
71 (if (> arg 0)
72 (let ((math-expand-formulas t))
73 (calc-top-n 1))
74 (let ((top (calc-top-n 1)))
75 (or (math-expand-formula top)
d3896480 76 top))))))))
136211a9
EZ
77
78(defun calc-factor (arg)
79 (interactive "P")
80 (calc-slow-wrapper
81 (calc-unary-op "fctr" (if (calc-is-hyperbolic)
82 'calcFunc-factors 'calcFunc-factor)
d3896480 83 arg)))
136211a9
EZ
84
85(defun calc-expand (n)
86 (interactive "P")
87 (calc-slow-wrapper
88 (calc-enter-result 1 "expa"
89 (append (list 'calcFunc-expand
90 (calc-top-n 1))
d3896480 91 (and n (list (prefix-numeric-value n)))))))
136211a9
EZ
92
93(defun calc-collect (&optional var)
94 (interactive "sCollect terms involving: ")
95 (calc-slow-wrapper
96 (if (or (equal var "") (equal var "$") (null var))
97 (calc-enter-result 2 "clct" (cons 'calcFunc-collect
98 (calc-top-list-n 2)))
99 (let ((var (math-read-expr var)))
100 (if (eq (car-safe var) 'error)
101 (error "Bad format in expression: %s" (nth 1 var)))
102 (calc-enter-result 1 "clct" (list 'calcFunc-collect
103 (calc-top-n 1)
d3896480 104 var))))))
136211a9
EZ
105
106(defun calc-apart (arg)
107 (interactive "P")
108 (calc-slow-wrapper
d3896480 109 (calc-unary-op "aprt" 'calcFunc-apart arg)))
136211a9
EZ
110
111(defun calc-normalize-rat (arg)
112 (interactive "P")
113 (calc-slow-wrapper
d3896480 114 (calc-unary-op "nrat" 'calcFunc-nrat arg)))
136211a9
EZ
115
116(defun calc-poly-gcd (arg)
117 (interactive "P")
118 (calc-slow-wrapper
d3896480 119 (calc-binary-op "pgcd" 'calcFunc-pgcd arg)))
136211a9 120
0c908945 121
136211a9
EZ
122(defun calc-poly-div (arg)
123 (interactive "P")
124 (calc-slow-wrapper
0c908945
JB
125 (let ((calc-poly-div-remainder nil))
126 (calc-binary-op "pdiv" 'calcFunc-pdiv arg)
127 (if (and calc-poly-div-remainder (null arg))
128 (progn
129 (calc-clear-command-flag 'clear-message)
130 (calc-record calc-poly-div-remainder "prem")
131 (if (not (Math-zerop calc-poly-div-remainder))
132 (message "(Remainder was %s)"
133 (math-format-flat-expr calc-poly-div-remainder 0))
134 (message "(No remainder)")))))))
136211a9
EZ
135
136(defun calc-poly-rem (arg)
137 (interactive "P")
138 (calc-slow-wrapper
d3896480 139 (calc-binary-op "prem" 'calcFunc-prem arg)))
136211a9
EZ
140
141(defun calc-poly-div-rem (arg)
142 (interactive "P")
143 (calc-slow-wrapper
144 (if (calc-is-hyperbolic)
145 (calc-binary-op "pdvr" 'calcFunc-pdivide arg)
d3896480 146 (calc-binary-op "pdvr" 'calcFunc-pdivrem arg))))
136211a9
EZ
147
148(defun calc-substitute (&optional oldname newname)
149 (interactive "sSubstitute old: ")
150 (calc-slow-wrapper
151 (let (old new (num 1) expr)
152 (if (or (equal oldname "") (equal oldname "$") (null oldname))
153 (setq new (calc-top-n 1)
154 old (calc-top-n 2)
155 expr (calc-top-n 3)
156 num 3)
157 (or newname
158 (progn (calc-unread-command ?\C-a)
159 (setq newname (read-string (concat "Substitute old: "
160 oldname
161 ", new: ")
162 oldname))))
163 (if (or (equal newname "") (equal newname "$") (null newname))
164 (setq new (calc-top-n 1)
165 expr (calc-top-n 2)
166 num 2)
167 (setq new (if (stringp newname) (math-read-expr newname) newname))
168 (if (eq (car-safe new) 'error)
169 (error "Bad format in expression: %s" (nth 1 new)))
170 (setq expr (calc-top-n 1)))
171 (setq old (if (stringp oldname) (math-read-expr oldname) oldname))
172 (if (eq (car-safe old) 'error)
173 (error "Bad format in expression: %s" (nth 1 old)))
174 (or (math-expr-contains expr old)
3132f345 175 (error "No occurrences found")))
d3896480 176 (calc-enter-result num "sbst" (math-expr-subst expr old new)))))
136211a9
EZ
177
178
179(defun calc-has-rules (name)
180 (setq name (calc-var-value name))
181 (and (consp name)
182 (memq (car name) '(vec calcFunc-assign calcFunc-condition))
d3896480 183 name))
136211a9 184
0c908945
JB
185;; math-eval-rules-cache and math-eval-rules-cache-other are
186;; declared in calc.el, but are used here by math-recompile-eval-rules.
187(defvar math-eval-rules-cache)
188(defvar math-eval-rules-cache-other)
189
136211a9
EZ
190(defun math-recompile-eval-rules ()
191 (setq math-eval-rules-cache (and (calc-has-rules 'var-EvalRules)
192 (math-compile-rewrites
193 '(var EvalRules var-EvalRules)))
194 math-eval-rules-cache-other (assq nil math-eval-rules-cache)
d3896480 195 math-eval-rules-cache-tag (calc-var-value 'var-EvalRules)))
136211a9
EZ
196
197
198;;; Try to expand a formula according to its definition.
199(defun math-expand-formula (expr)
200 (and (consp expr)
201 (symbolp (car expr))
202 (or (get (car expr) 'calc-user-defn)
203 (get (car expr) 'math-expandable))
204 (let ((res (let ((math-expand-formulas t))
205 (apply (car expr) (cdr expr)))))
206 (and (not (eq (car-safe res) (car expr)))
d3896480 207 res))))
136211a9
EZ
208
209
210
211
212;;; True if A comes before B in a canonical ordering of expressions. [P X X]
213(defun math-beforep (a b) ; [Public]
214 (cond ((and (Math-realp a) (Math-realp b))
215 (let ((comp (math-compare a b)))
216 (or (eq comp -1)
217 (and (eq comp 0)
218 (not (equal a b))
219 (> (length (memq (car-safe a)
220 '(bigneg nil bigpos frac float)))
221 (length (memq (car-safe b)
222 '(bigneg nil bigpos frac float))))))))
223 ((equal b '(neg (var inf var-inf))) nil)
224 ((equal a '(neg (var inf var-inf))) t)
225 ((equal a '(var inf var-inf)) nil)
226 ((equal b '(var inf var-inf)) t)
227 ((Math-realp a)
228 (if (and (eq (car-safe b) 'intv) (math-intv-constp b))
229 (if (or (math-beforep a (nth 2 b)) (Math-equal a (nth 2 b)))
230 t
231 nil)
232 t))
233 ((Math-realp b)
234 (if (and (eq (car-safe a) 'intv) (math-intv-constp a))
235 (if (math-beforep (nth 2 a) b)
236 t
237 nil)
238 nil))
239 ((and (eq (car a) 'intv) (eq (car b) 'intv)
240 (math-intv-constp a) (math-intv-constp b))
241 (let ((comp (math-compare (nth 2 a) (nth 2 b))))
242 (cond ((eq comp -1) t)
243 ((eq comp 1) nil)
244 ((and (memq (nth 1 a) '(2 3)) (memq (nth 1 b) '(0 1))) t)
245 ((and (memq (nth 1 a) '(0 1)) (memq (nth 1 b) '(2 3))) nil)
246 ((eq (setq comp (math-compare (nth 3 a) (nth 3 b))) -1) t)
247 ((eq comp 1) nil)
248 ((and (memq (nth 1 a) '(0 2)) (memq (nth 1 b) '(1 3))) t)
249 (t nil))))
250 ((not (eq (not (Math-objectp a)) (not (Math-objectp b))))
251 (Math-objectp a))
252 ((eq (car a) 'var)
253 (if (eq (car b) 'var)
254 (string-lessp (symbol-name (nth 1 a)) (symbol-name (nth 1 b)))
255 (not (Math-numberp b))))
256 ((eq (car b) 'var) (Math-numberp a))
257 ((eq (car a) (car b))
258 (while (and (setq a (cdr a) b (cdr b)) a
259 (equal (car a) (car b))))
260 (and b
261 (or (null a)
262 (math-beforep (car a) (car b)))))
d3896480 263 (t (string-lessp (symbol-name (car a)) (symbol-name (car b))))))
136211a9
EZ
264
265
d3896480 266(defsubst math-simplify-extended (a)
136211a9 267 (let ((math-living-dangerously t))
d3896480
CW
268 (math-simplify a)))
269
270(defalias 'calcFunc-esimplify 'math-simplify-extended)
136211a9 271
0c908945
JB
272;; math-top-only is local to math-simplify, but is used by
273;; math-simplify-step, which is called by math-simplify.
274(defvar math-top-only)
275
136211a9
EZ
276(defun math-simplify (top-expr)
277 (let ((math-simplifying t)
0c908945 278 (math-top-only (consp calc-simplify-mode))
136211a9
EZ
279 (simp-rules (append (and (calc-has-rules 'var-AlgSimpRules)
280 '((var AlgSimpRules var-AlgSimpRules)))
281 (and math-living-dangerously
282 (calc-has-rules 'var-ExtSimpRules)
283 '((var ExtSimpRules var-ExtSimpRules)))
284 (and math-simplifying-units
285 (calc-has-rules 'var-UnitSimpRules)
286 '((var UnitSimpRules var-UnitSimpRules)))
287 (and math-integrating
288 (calc-has-rules 'var-IntegSimpRules)
289 '((var IntegSimpRules var-IntegSimpRules)))))
290 res)
0c908945 291 (if math-top-only
136211a9
EZ
292 (let ((r simp-rules))
293 (setq res (math-simplify-step (math-normalize top-expr))
294 calc-simplify-mode '(nil)
295 top-expr (math-normalize res))
296 (while r
297 (setq top-expr (math-rewrite top-expr (car r)
298 '(neg (var inf var-inf)))
299 r (cdr r))))
300 (calc-with-default-simplification
301 (while (let ((r simp-rules))
302 (setq res (math-normalize top-expr))
303 (while r
304 (setq res (math-rewrite res (car r))
305 r (cdr r)))
306 (not (equal top-expr (setq res (math-simplify-step res)))))
307 (setq top-expr res)))))
d3896480
CW
308 top-expr)
309
310(defalias 'calcFunc-simplify 'math-simplify)
136211a9
EZ
311
312;;; The following has a "bug" in that if any recursive simplifications
313;;; occur only the first handler will be tried; this doesn't really
314;;; matter, since math-simplify-step is iterated to a fixed point anyway.
315(defun math-simplify-step (a)
316 (if (Math-primp a)
317 a
0c908945 318 (let ((aa (if (or math-top-only
136211a9
EZ
319 (memq (car a) '(calcFunc-quote calcFunc-condition
320 calcFunc-evalto)))
321 a
322 (cons (car a) (mapcar 'math-simplify-step (cdr a))))))
323 (and (symbolp (car aa))
324 (let ((handler (get (car aa) 'math-simplify)))
325 (and handler
326 (while (and handler
327 (equal (setq aa (or (funcall (car handler) aa)
328 aa))
329 a))
330 (setq handler (cdr handler))))))
d3896480 331 aa)))
136211a9
EZ
332
333
41cf648d
JB
334(defmacro math-defsimplify (funcs &rest code)
335 (append '(progn)
336 (mapcar (function
337 (lambda (func)
338 (list 'put (list 'quote func) ''math-simplify
339 (list 'nconc
340 (list 'get (list 'quote func) ''math-simplify)
341 (list 'list
342 (list 'function
343 (append '(lambda (math-simplify-expr))
344 code)))))))
345 (if (symbolp funcs) (list funcs) funcs))))
346(put 'math-defsimplify 'lisp-indent-hook 1)
136211a9 347
0c908945
JB
348;; The function created by math-defsimplify uses the variable
349;; math-simplify-expr, and so is used by functions in math-defsimplify
350(defvar math-simplify-expr)
351
136211a9
EZ
352(math-defsimplify (+ -)
353 (math-simplify-plus))
354
355(defun math-simplify-plus ()
0c908945
JB
356 (cond ((and (memq (car-safe (nth 1 math-simplify-expr)) '(+ -))
357 (Math-numberp (nth 2 (nth 1 math-simplify-expr)))
358 (not (Math-numberp (nth 2 math-simplify-expr))))
359 (let ((x (nth 2 math-simplify-expr))
360 (op (car math-simplify-expr)))
361 (setcar (cdr (cdr math-simplify-expr)) (nth 2 (nth 1 math-simplify-expr)))
362 (setcar math-simplify-expr (car (nth 1 math-simplify-expr)))
363 (setcar (cdr (cdr (nth 1 math-simplify-expr))) x)
364 (setcar (nth 1 math-simplify-expr) op)))
365 ((and (eq (car math-simplify-expr) '+)
366 (Math-numberp (nth 1 math-simplify-expr))
367 (not (Math-numberp (nth 2 math-simplify-expr))))
368 (let ((x (nth 2 math-simplify-expr)))
369 (setcar (cdr (cdr math-simplify-expr)) (nth 1 math-simplify-expr))
370 (setcar (cdr math-simplify-expr) x))))
371 (let ((aa math-simplify-expr)
136211a9
EZ
372 aaa temp)
373 (while (memq (car-safe (setq aaa (nth 1 aa))) '(+ -))
0c908945
JB
374 (if (setq temp (math-combine-sum (nth 2 aaa) (nth 2 math-simplify-expr)
375 (eq (car aaa) '-)
376 (eq (car math-simplify-expr) '-) t))
136211a9 377 (progn
0c908945
JB
378 (setcar (cdr (cdr math-simplify-expr)) temp)
379 (setcar math-simplify-expr '+)
136211a9
EZ
380 (setcar (cdr (cdr aaa)) 0)))
381 (setq aa (nth 1 aa)))
0c908945
JB
382 (if (setq temp (math-combine-sum aaa (nth 2 math-simplify-expr)
383 nil (eq (car math-simplify-expr) '-) t))
136211a9 384 (progn
0c908945
JB
385 (setcar (cdr (cdr math-simplify-expr)) temp)
386 (setcar math-simplify-expr '+)
136211a9 387 (setcar (cdr aa) 0)))
0c908945 388 math-simplify-expr))
136211a9
EZ
389
390(math-defsimplify *
391 (math-simplify-times))
392
393(defun math-simplify-times ()
0c908945
JB
394 (if (eq (car-safe (nth 2 math-simplify-expr)) '*)
395 (and (math-beforep (nth 1 (nth 2 math-simplify-expr)) (nth 1 math-simplify-expr))
396 (or (math-known-scalarp (nth 1 math-simplify-expr) t)
397 (math-known-scalarp (nth 1 (nth 2 math-simplify-expr)) t))
398 (let ((x (nth 1 math-simplify-expr)))
399 (setcar (cdr math-simplify-expr) (nth 1 (nth 2 math-simplify-expr)))
400 (setcar (cdr (nth 2 math-simplify-expr)) x)))
401 (and (math-beforep (nth 2 math-simplify-expr) (nth 1 math-simplify-expr))
402 (or (math-known-scalarp (nth 1 math-simplify-expr) t)
403 (math-known-scalarp (nth 2 math-simplify-expr) t))
404 (let ((x (nth 2 math-simplify-expr)))
405 (setcar (cdr (cdr math-simplify-expr)) (nth 1 math-simplify-expr))
406 (setcar (cdr math-simplify-expr) x))))
407 (let ((aa math-simplify-expr)
136211a9 408 aaa temp
0c908945
JB
409 (safe t) (scalar (math-known-scalarp (nth 1 math-simplify-expr))))
410 (if (and (Math-ratp (nth 1 math-simplify-expr))
411 (setq temp (math-common-constant-factor (nth 2 math-simplify-expr))))
136211a9 412 (progn
0c908945
JB
413 (setcar (cdr (cdr math-simplify-expr))
414 (math-cancel-common-factor (nth 2 math-simplify-expr) temp))
415 (setcar (cdr math-simplify-expr) (math-mul (nth 1 math-simplify-expr) temp))))
136211a9
EZ
416 (while (and (eq (car-safe (setq aaa (nth 2 aa))) '*)
417 safe)
0c908945
JB
418 (if (setq temp (math-combine-prod (nth 1 math-simplify-expr)
419 (nth 1 aaa) nil nil t))
136211a9 420 (progn
0c908945 421 (setcar (cdr math-simplify-expr) temp)
136211a9
EZ
422 (setcar (cdr aaa) 1)))
423 (setq safe (or scalar (math-known-scalarp (nth 1 aaa) t))
424 aa (nth 2 aa)))
0c908945 425 (if (and (setq temp (math-combine-prod aaa (nth 1 math-simplify-expr) nil nil t))
136211a9
EZ
426 safe)
427 (progn
0c908945 428 (setcar (cdr math-simplify-expr) temp)
136211a9 429 (setcar (cdr (cdr aa)) 1)))
0c908945
JB
430 (if (and (eq (car-safe (nth 1 math-simplify-expr)) 'frac)
431 (memq (nth 1 (nth 1 math-simplify-expr)) '(1 -1)))
432 (math-div (math-mul (nth 2 math-simplify-expr)
433 (nth 1 (nth 1 math-simplify-expr)))
434 (nth 2 (nth 1 math-simplify-expr)))
435 math-simplify-expr)))
136211a9
EZ
436
437(math-defsimplify /
438 (math-simplify-divide))
439
440(defun math-simplify-divide ()
0c908945 441 (let ((np (cdr math-simplify-expr))
136211a9 442 (nover nil)
0c908945
JB
443 (nn (and (or (eq (car math-simplify-expr) '/)
444 (not (Math-realp (nth 2 math-simplify-expr))))
445 (math-common-constant-factor (nth 2 math-simplify-expr))))
136211a9
EZ
446 n op)
447 (if nn
448 (progn
0c908945
JB
449 (setq n (and (or (eq (car math-simplify-expr) '/)
450 (not (Math-realp (nth 1 math-simplify-expr))))
451 (math-common-constant-factor (nth 1 math-simplify-expr))))
136211a9
EZ
452 (if (and (eq (car-safe nn) 'frac) (eq (nth 1 nn) 1) (not n))
453 (progn
0c908945
JB
454 (setcar (cdr math-simplify-expr)
455 (math-mul (nth 2 nn) (nth 1 math-simplify-expr)))
456 (setcar (cdr (cdr math-simplify-expr))
457 (math-cancel-common-factor (nth 2 math-simplify-expr) nn))
136211a9 458 (if (and (math-negp nn)
0c908945
JB
459 (setq op (assq (car math-simplify-expr) calc-tweak-eqn-table)))
460 (setcar math-simplify-expr (nth 1 op))))
136211a9
EZ
461 (if (and n (not (eq (setq n (math-frac-gcd n nn)) 1)))
462 (progn
0c908945
JB
463 (setcar (cdr math-simplify-expr)
464 (math-cancel-common-factor (nth 1 math-simplify-expr) n))
465 (setcar (cdr (cdr math-simplify-expr))
466 (math-cancel-common-factor (nth 2 math-simplify-expr) n))
136211a9 467 (if (and (math-negp n)
0c908945
JB
468 (setq op (assq (car math-simplify-expr)
469 calc-tweak-eqn-table)))
470 (setcar math-simplify-expr (nth 1 op))))))))
136211a9 471 (if (and (eq (car-safe (car np)) '/)
0c908945 472 (math-known-scalarp (nth 2 math-simplify-expr) t))
136211a9 473 (progn
0c908945 474 (setq np (cdr (nth 1 math-simplify-expr)))
136211a9
EZ
475 (while (eq (car-safe (setq n (car np))) '*)
476 (and (math-known-scalarp (nth 2 n) t)
0c908945 477 (math-simplify-divisor (cdr n) (cdr (cdr math-simplify-expr)) nil t))
136211a9 478 (setq np (cdr (cdr n))))
0c908945 479 (math-simplify-divisor np (cdr (cdr math-simplify-expr)) nil t)
136211a9 480 (setq nover t
0c908945 481 np (cdr (cdr (nth 1 math-simplify-expr))))))
136211a9
EZ
482 (while (eq (car-safe (setq n (car np))) '*)
483 (and (math-known-scalarp (nth 2 n) t)
0c908945 484 (math-simplify-divisor (cdr n) (cdr (cdr math-simplify-expr)) nover t))
136211a9 485 (setq np (cdr (cdr n))))
0c908945
JB
486 (math-simplify-divisor np (cdr (cdr math-simplify-expr)) nover t)
487 math-simplify-expr))
488
489;; The variables math-simplify-divisor-nover and math-simplify-divisor-dover
490;; are local variables for math-simplify-divisor, but are used by
491;; math-simplify-one-divisor.
492(defvar math-simplify-divisor-nover)
493(defvar math-simplify-divisor-dover)
136211a9 494
0c908945
JB
495(defun math-simplify-divisor (np dp math-simplify-divisor-nover
496 math-simplify-divisor-dover)
136211a9 497 (cond ((eq (car-safe (car dp)) '/)
0c908945
JB
498 (math-simplify-divisor np (cdr (car dp))
499 math-simplify-divisor-nover
500 math-simplify-divisor-dover)
136211a9
EZ
501 (and (math-known-scalarp (nth 1 (car dp)) t)
502 (math-simplify-divisor np (cdr (cdr (car dp)))
0c908945
JB
503 math-simplify-divisor-nover
504 (not math-simplify-divisor-dover))))
505 ((or (or (eq (car math-simplify-expr) '/)
136211a9
EZ
506 (let ((signs (math-possible-signs (car np))))
507 (or (memq signs '(1 4))
0c908945 508 (and (memq (car math-simplify-expr) '(calcFunc-eq calcFunc-neq))
136211a9
EZ
509 (eq signs 5))
510 math-living-dangerously)))
511 (math-numberp (car np)))
358c90f4
JB
512 (let (d
513 (safe t)
514 (scalar (math-known-scalarp (car np))))
136211a9
EZ
515 (while (and (eq (car-safe (setq d (car dp))) '*)
516 safe)
517 (math-simplify-one-divisor np (cdr d))
518 (setq safe (or scalar (math-known-scalarp (nth 1 d) t))
519 dp (cdr (cdr d))))
520 (if safe
d3896480 521 (math-simplify-one-divisor np dp))))))
136211a9
EZ
522
523(defun math-simplify-one-divisor (np dp)
0c908945
JB
524 (let ((temp (math-combine-prod (car np) (car dp) math-simplify-divisor-nover
525 math-simplify-divisor-dover t))
526 op)
527 (if temp
528 (progn
529 (and (not (memq (car math-simplify-expr) '(/ calcFunc-eq calcFunc-neq)))
530 (math-known-negp (car dp))
531 (setq op (assq (car math-simplify-expr) calc-tweak-eqn-table))
532 (setcar math-simplify-expr (nth 1 op)))
533 (setcar np (if math-simplify-divisor-nover (math-div 1 temp) temp))
534 (setcar dp 1))
535 (and math-simplify-divisor-dover (not math-simplify-divisor-nover)
536 (eq (car math-simplify-expr) '/)
537 (eq (car-safe (car dp)) 'calcFunc-sqrt)
538 (Math-integerp (nth 1 (car dp)))
539 (progn
540 (setcar np (math-mul (car np)
541 (list 'calcFunc-sqrt (nth 1 (car dp)))))
542 (setcar dp (nth 1 (car dp))))))))
136211a9
EZ
543
544(defun math-common-constant-factor (expr)
545 (if (Math-realp expr)
546 (if (Math-ratp expr)
547 (and (not (memq expr '(0 1 -1)))
548 (math-abs expr))
549 (if (math-ratp (setq expr (math-to-simple-fraction expr)))
550 (math-common-constant-factor expr)))
551 (if (memq (car expr) '(+ - cplx sdev))
552 (let ((f1 (math-common-constant-factor (nth 1 expr)))
553 (f2 (math-common-constant-factor (nth 2 expr))))
554 (and f1 f2
555 (not (eq (setq f1 (math-frac-gcd f1 f2)) 1))
556 f1))
557 (if (memq (car expr) '(* polar))
558 (math-common-constant-factor (nth 1 expr))
559 (if (eq (car expr) '/)
560 (or (math-common-constant-factor (nth 1 expr))
561 (and (Math-integerp (nth 2 expr))
d3896480 562 (list 'frac 1 (math-abs (nth 2 expr))))))))))
136211a9
EZ
563
564(defun math-cancel-common-factor (expr val)
565 (if (memq (car-safe expr) '(+ - cplx sdev))
566 (progn
567 (setcar (cdr expr) (math-cancel-common-factor (nth 1 expr) val))
568 (setcar (cdr (cdr expr)) (math-cancel-common-factor (nth 2 expr) val))
569 expr)
570 (if (eq (car-safe expr) '*)
571 (math-mul (math-cancel-common-factor (nth 1 expr) val) (nth 2 expr))
d3896480 572 (math-div expr val))))
136211a9
EZ
573
574(defun math-frac-gcd (a b)
575 (if (Math-zerop a)
576 b
577 (if (Math-zerop b)
578 a
579 (if (and (Math-integerp a)
580 (Math-integerp b))
581 (math-gcd a b)
582 (and (Math-integerp a) (setq a (list 'frac a 1)))
583 (and (Math-integerp b) (setq b (list 'frac b 1)))
584 (math-make-frac (math-gcd (nth 1 a) (nth 1 b))
d3896480 585 (math-gcd (nth 2 a) (nth 2 b)))))))
136211a9
EZ
586
587(math-defsimplify %
588 (math-simplify-mod))
589
590(defun math-simplify-mod ()
0c908945
JB
591 (and (Math-realp (nth 2 math-simplify-expr))
592 (Math-posp (nth 2 math-simplify-expr))
593 (let ((lin (math-is-linear (nth 1 math-simplify-expr)))
136211a9
EZ
594 t1 t2 t3)
595 (or (and lin
596 (or (math-negp (car lin))
0c908945 597 (not (Math-lessp (car lin) (nth 2 math-simplify-expr))))
136211a9
EZ
598 (list '%
599 (list '+
600 (math-mul (nth 1 lin) (nth 2 lin))
0c908945
JB
601 (math-mod (car lin) (nth 2 math-simplify-expr)))
602 (nth 2 math-simplify-expr)))
136211a9
EZ
603 (and lin
604 (not (math-equal-int (nth 1 lin) 1))
605 (math-num-integerp (nth 1 lin))
0c908945
JB
606 (math-num-integerp (nth 2 math-simplify-expr))
607 (setq t1 (calcFunc-gcd (nth 1 lin) (nth 2 math-simplify-expr)))
136211a9
EZ
608 (not (math-equal-int t1 1))
609 (list '*
610 t1
611 (list '%
612 (list '+
613 (math-mul (math-div (nth 1 lin) t1)
614 (nth 2 lin))
615 (let ((calc-prefer-frac t))
616 (math-div (car lin) t1)))
0c908945
JB
617 (math-div (nth 2 math-simplify-expr) t1))))
618 (and (math-equal-int (nth 2 math-simplify-expr) 1)
136211a9
EZ
619 (math-known-integerp (if lin
620 (math-mul (nth 1 lin) (nth 2 lin))
0c908945 621 (nth 1 math-simplify-expr)))
d3896480 622 (if lin (math-mod (car lin) 1) 0))))))
136211a9
EZ
623
624(math-defsimplify (calcFunc-eq calcFunc-neq calcFunc-lt
625 calcFunc-gt calcFunc-leq calcFunc-geq)
0c908945 626 (if (= (length math-simplify-expr) 3)
136211a9
EZ
627 (math-simplify-ineq)))
628
629(defun math-simplify-ineq ()
0c908945 630 (let ((np (cdr math-simplify-expr))
136211a9
EZ
631 n)
632 (while (memq (car-safe (setq n (car np))) '(+ -))
0c908945 633 (math-simplify-add-term (cdr (cdr n)) (cdr (cdr math-simplify-expr))
136211a9
EZ
634 (eq (car n) '-) nil)
635 (setq np (cdr n)))
0c908945
JB
636 (math-simplify-add-term np (cdr (cdr math-simplify-expr)) nil
637 (eq np (cdr math-simplify-expr)))
136211a9 638 (math-simplify-divide)
0c908945
JB
639 (let ((signs (math-possible-signs (cons '- (cdr math-simplify-expr)))))
640 (or (cond ((eq (car math-simplify-expr) 'calcFunc-eq)
136211a9
EZ
641 (or (and (eq signs 2) 1)
642 (and (memq signs '(1 4 5)) 0)))
0c908945 643 ((eq (car math-simplify-expr) 'calcFunc-neq)
136211a9
EZ
644 (or (and (eq signs 2) 0)
645 (and (memq signs '(1 4 5)) 1)))
0c908945 646 ((eq (car math-simplify-expr) 'calcFunc-lt)
136211a9
EZ
647 (or (and (eq signs 1) 1)
648 (and (memq signs '(2 4 6)) 0)))
0c908945 649 ((eq (car math-simplify-expr) 'calcFunc-gt)
136211a9
EZ
650 (or (and (eq signs 4) 1)
651 (and (memq signs '(1 2 3)) 0)))
0c908945 652 ((eq (car math-simplify-expr) 'calcFunc-leq)
136211a9
EZ
653 (or (and (eq signs 4) 0)
654 (and (memq signs '(1 2 3)) 1)))
0c908945 655 ((eq (car math-simplify-expr) 'calcFunc-geq)
136211a9
EZ
656 (or (and (eq signs 1) 0)
657 (and (memq signs '(2 4 6)) 1))))
0c908945 658 math-simplify-expr))))
136211a9
EZ
659
660(defun math-simplify-add-term (np dp minus lplain)
661 (or (math-vectorp (car np))
662 (let ((rplain t)
663 n d dd temp)
664 (while (memq (car-safe (setq n (car np) d (car dp))) '(+ -))
665 (setq rplain nil)
666 (if (setq temp (math-combine-sum n (nth 2 d)
667 minus (eq (car d) '+) t))
668 (if (or lplain (eq (math-looks-negp temp) minus))
669 (progn
670 (setcar np (setq n (if minus (math-neg temp) temp)))
671 (setcar (cdr (cdr d)) 0))
672 (progn
673 (setcar np 0)
674 (setcar (cdr (cdr d)) (setq n (if (eq (car d) '+)
675 (math-neg temp)
676 temp))))))
677 (setq dp (cdr d)))
678 (if (setq temp (math-combine-sum n d minus t t))
679 (if (or lplain
680 (and (not rplain)
681 (eq (math-looks-negp temp) minus)))
682 (progn
683 (setcar np (setq n (if minus (math-neg temp) temp)))
684 (setcar dp 0))
685 (progn
686 (setcar np 0)
d3896480 687 (setcar dp (setq n (math-neg temp)))))))))
136211a9
EZ
688
689(math-defsimplify calcFunc-sin
0c908945
JB
690 (or (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-arcsin)
691 (nth 1 (nth 1 math-simplify-expr)))
692 (and (math-looks-negp (nth 1 math-simplify-expr))
693 (math-neg (list 'calcFunc-sin (math-neg (nth 1 math-simplify-expr)))))
136211a9 694 (and (eq calc-angle-mode 'rad)
0c908945 695 (let ((n (math-linear-in (nth 1 math-simplify-expr) '(var pi var-pi))))
136211a9
EZ
696 (and n
697 (math-known-sin (car n) (nth 1 n) 120 0))))
698 (and (eq calc-angle-mode 'deg)
0c908945 699 (let ((n (math-integer-plus (nth 1 math-simplify-expr))))
136211a9
EZ
700 (and n
701 (math-known-sin (car n) (nth 1 n) '(frac 2 3) 0))))
0c908945
JB
702 (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-arccos)
703 (list 'calcFunc-sqrt (math-sub 1 (math-sqr
704 (nth 1 (nth 1 math-simplify-expr))))))
705 (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-arctan)
706 (math-div (nth 1 (nth 1 math-simplify-expr))
136211a9 707 (list 'calcFunc-sqrt
0c908945
JB
708 (math-add 1 (math-sqr
709 (nth 1 (nth 1 math-simplify-expr)))))))
710 (let ((m (math-should-expand-trig (nth 1 math-simplify-expr))))
136211a9
EZ
711 (and m (integerp (car m))
712 (let ((n (car m)) (a (nth 1 m)))
713 (list '+
714 (list '* (list 'calcFunc-sin (list '* (1- n) a))
715 (list 'calcFunc-cos a))
716 (list '* (list 'calcFunc-cos (list '* (1- n) a))
d3896480 717 (list 'calcFunc-sin a))))))))
136211a9
EZ
718
719(math-defsimplify calcFunc-cos
0c908945
JB
720 (or (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-arccos)
721 (nth 1 (nth 1 math-simplify-expr)))
722 (and (math-looks-negp (nth 1 math-simplify-expr))
723 (list 'calcFunc-cos (math-neg (nth 1 math-simplify-expr))))
136211a9 724 (and (eq calc-angle-mode 'rad)
0c908945 725 (let ((n (math-linear-in (nth 1 math-simplify-expr) '(var pi var-pi))))
136211a9
EZ
726 (and n
727 (math-known-sin (car n) (nth 1 n) 120 300))))
728 (and (eq calc-angle-mode 'deg)
0c908945 729 (let ((n (math-integer-plus (nth 1 math-simplify-expr))))
136211a9
EZ
730 (and n
731 (math-known-sin (car n) (nth 1 n) '(frac 2 3) 300))))
0c908945
JB
732 (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-arcsin)
733 (list 'calcFunc-sqrt
734 (math-sub 1 (math-sqr (nth 1 (nth 1 math-simplify-expr))))))
735 (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-arctan)
136211a9
EZ
736 (math-div 1
737 (list 'calcFunc-sqrt
0c908945
JB
738 (math-add 1
739 (math-sqr (nth 1 (nth 1 math-simplify-expr)))))))
740 (let ((m (math-should-expand-trig (nth 1 math-simplify-expr))))
136211a9
EZ
741 (and m (integerp (car m))
742 (let ((n (car m)) (a (nth 1 m)))
743 (list '-
744 (list '* (list 'calcFunc-cos (list '* (1- n) a))
745 (list 'calcFunc-cos a))
746 (list '* (list 'calcFunc-sin (list '* (1- n) a))
d3896480 747 (list 'calcFunc-sin a))))))))
136211a9
EZ
748
749(defun math-should-expand-trig (x &optional hyperbolic)
750 (let ((m (math-is-multiple x)))
751 (and math-living-dangerously
752 m (or (and (integerp (car m)) (> (car m) 1))
753 (equal (car m) '(frac 1 2)))
754 (or math-integrating
755 (memq (car-safe (nth 1 m))
756 (if hyperbolic
757 '(calcFunc-arcsinh calcFunc-arccosh calcFunc-arctanh)
758 '(calcFunc-arcsin calcFunc-arccos calcFunc-arctan)))
759 (and (eq (car-safe (nth 1 m)) 'calcFunc-ln)
760 (eq hyperbolic 'exp)))
d3896480 761 m)))
136211a9
EZ
762
763(defun math-known-sin (plus n mul off)
764 (setq n (math-mul n mul))
765 (and (math-num-integerp n)
766 (setq n (math-mod (math-add (math-trunc n) off) 240))
767 (if (>= n 120)
768 (and (setq n (math-known-sin plus (- n 120) 1 0))
769 (math-neg n))
770 (if (> n 60)
771 (setq n (- 120 n)))
772 (if (math-zerop plus)
773 (and (or calc-symbolic-mode
774 (memq n '(0 20 60)))
775 (cdr (assq n
776 '( (0 . 0)
777 (10 . (/ (calcFunc-sqrt
778 (- 2 (calcFunc-sqrt 3))) 2))
779 (12 . (/ (- (calcFunc-sqrt 5) 1) 4))
780 (15 . (/ (calcFunc-sqrt
781 (- 2 (calcFunc-sqrt 2))) 2))
782 (20 . (/ 1 2))
783 (24 . (* (^ (/ 1 2) (/ 3 2))
784 (calcFunc-sqrt
785 (- 5 (calcFunc-sqrt 5)))))
786 (30 . (/ (calcFunc-sqrt 2) 2))
787 (36 . (/ (+ (calcFunc-sqrt 5) 1) 4))
788 (40 . (/ (calcFunc-sqrt 3) 2))
789 (45 . (/ (calcFunc-sqrt
790 (+ 2 (calcFunc-sqrt 2))) 2))
791 (48 . (* (^ (/ 1 2) (/ 3 2))
792 (calcFunc-sqrt
793 (+ 5 (calcFunc-sqrt 5)))))
794 (50 . (/ (calcFunc-sqrt
795 (+ 2 (calcFunc-sqrt 3))) 2))
796 (60 . 1)))))
797 (cond ((eq n 0) (math-normalize (list 'calcFunc-sin plus)))
798 ((eq n 60) (math-normalize (list 'calcFunc-cos plus)))
d3896480 799 (t nil))))))
136211a9
EZ
800
801(math-defsimplify calcFunc-tan
0c908945
JB
802 (or (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-arctan)
803 (nth 1 (nth 1 math-simplify-expr)))
804 (and (math-looks-negp (nth 1 math-simplify-expr))
805 (math-neg (list 'calcFunc-tan (math-neg (nth 1 math-simplify-expr)))))
136211a9 806 (and (eq calc-angle-mode 'rad)
0c908945 807 (let ((n (math-linear-in (nth 1 math-simplify-expr) '(var pi var-pi))))
136211a9
EZ
808 (and n
809 (math-known-tan (car n) (nth 1 n) 120))))
810 (and (eq calc-angle-mode 'deg)
0c908945 811 (let ((n (math-integer-plus (nth 1 math-simplify-expr))))
136211a9
EZ
812 (and n
813 (math-known-tan (car n) (nth 1 n) '(frac 2 3)))))
0c908945
JB
814 (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-arcsin)
815 (math-div (nth 1 (nth 1 math-simplify-expr))
136211a9 816 (list 'calcFunc-sqrt
0c908945
JB
817 (math-sub 1 (math-sqr (nth 1 (nth 1 math-simplify-expr)))))))
818 (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-arccos)
136211a9 819 (math-div (list 'calcFunc-sqrt
0c908945
JB
820 (math-sub 1 (math-sqr (nth 1 (nth 1 math-simplify-expr)))))
821 (nth 1 (nth 1 math-simplify-expr))))
822 (let ((m (math-should-expand-trig (nth 1 math-simplify-expr))))
136211a9
EZ
823 (and m
824 (if (equal (car m) '(frac 1 2))
825 (math-div (math-sub 1 (list 'calcFunc-cos (nth 1 m)))
826 (list 'calcFunc-sin (nth 1 m)))
0c908945
JB
827 (math-div (list 'calcFunc-sin (nth 1 math-simplify-expr))
828 (list 'calcFunc-cos (nth 1 math-simplify-expr))))))))
136211a9
EZ
829
830(defun math-known-tan (plus n mul)
831 (setq n (math-mul n mul))
832 (and (math-num-integerp n)
833 (setq n (math-mod (math-trunc n) 120))
834 (if (> n 60)
835 (and (setq n (math-known-tan plus (- 120 n) 1))
836 (math-neg n))
837 (if (math-zerop plus)
838 (and (or calc-symbolic-mode
839 (memq n '(0 30 60)))
840 (cdr (assq n '( (0 . 0)
841 (10 . (- 2 (calcFunc-sqrt 3)))
842 (12 . (calcFunc-sqrt
843 (- 1 (* (/ 2 5) (calcFunc-sqrt 5)))))
844 (15 . (- (calcFunc-sqrt 2) 1))
845 (20 . (/ (calcFunc-sqrt 3) 3))
846 (24 . (calcFunc-sqrt
847 (- 5 (* 2 (calcFunc-sqrt 5)))))
848 (30 . 1)
849 (36 . (calcFunc-sqrt
850 (+ 1 (* (/ 2 5) (calcFunc-sqrt 5)))))
851 (40 . (calcFunc-sqrt 3))
852 (45 . (+ (calcFunc-sqrt 2) 1))
853 (48 . (calcFunc-sqrt
854 (+ 5 (* 2 (calcFunc-sqrt 5)))))
855 (50 . (+ 2 (calcFunc-sqrt 3)))
856 (60 . (var uinf var-uinf))))))
857 (cond ((eq n 0) (math-normalize (list 'calcFunc-tan plus)))
858 ((eq n 60) (math-normalize (list '/ -1
859 (list 'calcFunc-tan plus))))
d3896480 860 (t nil))))))
136211a9
EZ
861
862(math-defsimplify calcFunc-sinh
0c908945
JB
863 (or (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-arcsinh)
864 (nth 1 (nth 1 math-simplify-expr)))
865 (and (math-looks-negp (nth 1 math-simplify-expr))
866 (math-neg (list 'calcFunc-sinh (math-neg (nth 1 math-simplify-expr)))))
867 (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-arccosh)
136211a9 868 math-living-dangerously
0c908945
JB
869 (list 'calcFunc-sqrt
870 (math-sub (math-sqr (nth 1 (nth 1 math-simplify-expr))) 1)))
871 (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-arctanh)
136211a9 872 math-living-dangerously
0c908945 873 (math-div (nth 1 (nth 1 math-simplify-expr))
136211a9 874 (list 'calcFunc-sqrt
0c908945
JB
875 (math-sub 1 (math-sqr (nth 1 (nth 1 math-simplify-expr)))))))
876 (let ((m (math-should-expand-trig (nth 1 math-simplify-expr) t)))
136211a9
EZ
877 (and m (integerp (car m))
878 (let ((n (car m)) (a (nth 1 m)))
879 (if (> n 1)
880 (list '+
881 (list '* (list 'calcFunc-sinh (list '* (1- n) a))
882 (list 'calcFunc-cosh a))
883 (list '* (list 'calcFunc-cosh (list '* (1- n) a))
d3896480 884 (list 'calcFunc-sinh a)))))))))
136211a9
EZ
885
886(math-defsimplify calcFunc-cosh
0c908945
JB
887 (or (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-arccosh)
888 (nth 1 (nth 1 math-simplify-expr)))
889 (and (math-looks-negp (nth 1 math-simplify-expr))
890 (list 'calcFunc-cosh (math-neg (nth 1 math-simplify-expr))))
891 (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-arcsinh)
136211a9 892 math-living-dangerously
0c908945
JB
893 (list 'calcFunc-sqrt
894 (math-add (math-sqr (nth 1 (nth 1 math-simplify-expr))) 1)))
895 (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-arctanh)
136211a9
EZ
896 math-living-dangerously
897 (math-div 1
898 (list 'calcFunc-sqrt
0c908945
JB
899 (math-sub 1 (math-sqr (nth 1 (nth 1 math-simplify-expr)))))))
900 (let ((m (math-should-expand-trig (nth 1 math-simplify-expr) t)))
136211a9
EZ
901 (and m (integerp (car m))
902 (let ((n (car m)) (a (nth 1 m)))
903 (if (> n 1)
904 (list '+
905 (list '* (list 'calcFunc-cosh (list '* (1- n) a))
906 (list 'calcFunc-cosh a))
907 (list '* (list 'calcFunc-sinh (list '* (1- n) a))
d3896480 908 (list 'calcFunc-sinh a)))))))))
136211a9
EZ
909
910(math-defsimplify calcFunc-tanh
0c908945
JB
911 (or (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-arctanh)
912 (nth 1 (nth 1 math-simplify-expr)))
913 (and (math-looks-negp (nth 1 math-simplify-expr))
914 (math-neg (list 'calcFunc-tanh (math-neg (nth 1 math-simplify-expr)))))
915 (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-arcsinh)
136211a9 916 math-living-dangerously
0c908945 917 (math-div (nth 1 (nth 1 math-simplify-expr))
136211a9 918 (list 'calcFunc-sqrt
0c908945
JB
919 (math-add (math-sqr (nth 1 (nth 1 math-simplify-expr))) 1))))
920 (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-arccosh)
136211a9
EZ
921 math-living-dangerously
922 (math-div (list 'calcFunc-sqrt
0c908945
JB
923 (math-sub (math-sqr (nth 1 (nth 1 math-simplify-expr))) 1))
924 (nth 1 (nth 1 math-simplify-expr))))
925 (let ((m (math-should-expand-trig (nth 1 math-simplify-expr) t)))
136211a9
EZ
926 (and m
927 (if (equal (car m) '(frac 1 2))
928 (math-div (math-sub (list 'calcFunc-cosh (nth 1 m)) 1)
929 (list 'calcFunc-sinh (nth 1 m)))
0c908945
JB
930 (math-div (list 'calcFunc-sinh (nth 1 math-simplify-expr))
931 (list 'calcFunc-cosh (nth 1 math-simplify-expr))))))))
136211a9
EZ
932
933(math-defsimplify calcFunc-arcsin
0c908945
JB
934 (or (and (math-looks-negp (nth 1 math-simplify-expr))
935 (math-neg (list 'calcFunc-arcsin (math-neg (nth 1 math-simplify-expr)))))
936 (and (eq (nth 1 math-simplify-expr) 1)
136211a9 937 (math-quarter-circle t))
0c908945 938 (and (equal (nth 1 math-simplify-expr) '(frac 1 2))
136211a9
EZ
939 (math-div (math-half-circle t) 6))
940 (and math-living-dangerously
0c908945
JB
941 (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-sin)
942 (nth 1 (nth 1 math-simplify-expr)))
136211a9 943 (and math-living-dangerously
0c908945 944 (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-cos)
136211a9 945 (math-sub (math-quarter-circle t)
0c908945 946 (nth 1 (nth 1 math-simplify-expr))))))
136211a9
EZ
947
948(math-defsimplify calcFunc-arccos
0c908945 949 (or (and (eq (nth 1 math-simplify-expr) 0)
136211a9 950 (math-quarter-circle t))
0c908945 951 (and (eq (nth 1 math-simplify-expr) -1)
136211a9 952 (math-half-circle t))
0c908945 953 (and (equal (nth 1 math-simplify-expr) '(frac 1 2))
136211a9 954 (math-div (math-half-circle t) 3))
0c908945 955 (and (equal (nth 1 math-simplify-expr) '(frac -1 2))
136211a9
EZ
956 (math-div (math-mul (math-half-circle t) 2) 3))
957 (and math-living-dangerously
0c908945
JB
958 (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-cos)
959 (nth 1 (nth 1 math-simplify-expr)))
136211a9 960 (and math-living-dangerously
0c908945 961 (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-sin)
136211a9 962 (math-sub (math-quarter-circle t)
0c908945 963 (nth 1 (nth 1 math-simplify-expr))))))
136211a9
EZ
964
965(math-defsimplify calcFunc-arctan
0c908945
JB
966 (or (and (math-looks-negp (nth 1 math-simplify-expr))
967 (math-neg (list 'calcFunc-arctan (math-neg (nth 1 math-simplify-expr)))))
968 (and (eq (nth 1 math-simplify-expr) 1)
136211a9
EZ
969 (math-div (math-half-circle t) 4))
970 (and math-living-dangerously
0c908945
JB
971 (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-tan)
972 (nth 1 (nth 1 math-simplify-expr)))))
136211a9
EZ
973
974(math-defsimplify calcFunc-arcsinh
0c908945
JB
975 (or (and (math-looks-negp (nth 1 math-simplify-expr))
976 (math-neg (list 'calcFunc-arcsinh (math-neg (nth 1 math-simplify-expr)))))
977 (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-sinh)
136211a9 978 (or math-living-dangerously
0c908945
JB
979 (math-known-realp (nth 1 (nth 1 math-simplify-expr))))
980 (nth 1 (nth 1 math-simplify-expr)))))
136211a9
EZ
981
982(math-defsimplify calcFunc-arccosh
0c908945 983 (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-cosh)
136211a9 984 (or math-living-dangerously
0c908945
JB
985 (math-known-realp (nth 1 (nth 1 math-simplify-expr))))
986 (nth 1 (nth 1 math-simplify-expr))))
136211a9
EZ
987
988(math-defsimplify calcFunc-arctanh
0c908945
JB
989 (or (and (math-looks-negp (nth 1 math-simplify-expr))
990 (math-neg (list 'calcFunc-arctanh (math-neg (nth 1 math-simplify-expr)))))
991 (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-tanh)
136211a9 992 (or math-living-dangerously
0c908945
JB
993 (math-known-realp (nth 1 (nth 1 math-simplify-expr))))
994 (nth 1 (nth 1 math-simplify-expr)))))
136211a9
EZ
995
996(math-defsimplify calcFunc-sqrt
d3896480 997 (math-simplify-sqrt))
136211a9
EZ
998
999(defun math-simplify-sqrt ()
0c908945
JB
1000 (or (and (eq (car-safe (nth 1 math-simplify-expr)) 'frac)
1001 (math-div (list 'calcFunc-sqrt
1002 (math-mul (nth 1 (nth 1 math-simplify-expr))
1003 (nth 2 (nth 1 math-simplify-expr))))
1004 (nth 2 (nth 1 math-simplify-expr))))
1005 (let ((fac (if (math-objectp (nth 1 math-simplify-expr))
1006 (math-squared-factor (nth 1 math-simplify-expr))
1007 (math-common-constant-factor (nth 1 math-simplify-expr)))))
136211a9
EZ
1008 (and fac (not (eq fac 1))
1009 (math-mul (math-normalize (list 'calcFunc-sqrt fac))
1010 (math-normalize
1011 (list 'calcFunc-sqrt
0c908945
JB
1012 (math-cancel-common-factor
1013 (nth 1 math-simplify-expr) fac))))))
136211a9 1014 (and math-living-dangerously
0c908945
JB
1015 (or (and (eq (car-safe (nth 1 math-simplify-expr)) '-)
1016 (math-equal-int (nth 1 (nth 1 math-simplify-expr)) 1)
1017 (eq (car-safe (nth 2 (nth 1 math-simplify-expr))) '^)
1018 (math-equal-int (nth 2 (nth 2 (nth 1 math-simplify-expr))) 2)
1019 (or (and (eq (car-safe (nth 1 (nth 2 (nth 1 math-simplify-expr))))
136211a9
EZ
1020 'calcFunc-sin)
1021 (list 'calcFunc-cos
0c908945
JB
1022 (nth 1 (nth 1 (nth 2 (nth 1 math-simplify-expr))))))
1023 (and (eq (car-safe (nth 1 (nth 2 (nth 1 math-simplify-expr))))
136211a9
EZ
1024 'calcFunc-cos)
1025 (list 'calcFunc-sin
0c908945
JB
1026 (nth 1 (nth 1 (nth 2
1027 (nth 1 math-simplify-expr))))))))
1028 (and (eq (car-safe (nth 1 math-simplify-expr)) '-)
1029 (math-equal-int (nth 2 (nth 1 math-simplify-expr)) 1)
1030 (eq (car-safe (nth 1 (nth 1 math-simplify-expr))) '^)
1031 (math-equal-int (nth 2 (nth 1 (nth 1 math-simplify-expr))) 2)
1032 (and (eq (car-safe (nth 1 (nth 1 (nth 1 math-simplify-expr))))
136211a9
EZ
1033 'calcFunc-cosh)
1034 (list 'calcFunc-sinh
0c908945
JB
1035 (nth 1 (nth 1 (nth 1 (nth 1 math-simplify-expr)))))))
1036 (and (eq (car-safe (nth 1 math-simplify-expr)) '+)
1037 (let ((a (nth 1 (nth 1 math-simplify-expr)))
1038 (b (nth 2 (nth 1 math-simplify-expr))))
136211a9 1039 (and (or (and (math-equal-int a 1)
0c908945 1040 (setq a b b (nth 1 (nth 1 math-simplify-expr))))
136211a9
EZ
1041 (math-equal-int b 1))
1042 (eq (car-safe a) '^)
1043 (math-equal-int (nth 2 a) 2)
1044 (or (and (eq (car-safe (nth 1 a)) 'calcFunc-sinh)
1045 (list 'calcFunc-cosh (nth 1 (nth 1 a))))
1046 (and (eq (car-safe (nth 1 a)) 'calcFunc-tan)
1047 (list '/ 1 (list 'calcFunc-cos
1048 (nth 1 (nth 1 a)))))))))
0c908945 1049 (and (eq (car-safe (nth 1 math-simplify-expr)) '^)
136211a9 1050 (list '^
0c908945
JB
1051 (nth 1 (nth 1 math-simplify-expr))
1052 (math-div (nth 2 (nth 1 math-simplify-expr)) 2)))
1053 (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-sqrt)
1054 (list '^ (nth 1 (nth 1 math-simplify-expr)) (math-div 1 4)))
1055 (and (memq (car-safe (nth 1 math-simplify-expr)) '(* /))
1056 (list (car (nth 1 math-simplify-expr))
1057 (list 'calcFunc-sqrt (nth 1 (nth 1 math-simplify-expr)))
1058 (list 'calcFunc-sqrt (nth 2 (nth 1 math-simplify-expr)))))
1059 (and (memq (car-safe (nth 1 math-simplify-expr)) '(+ -))
1060 (not (math-any-floats (nth 1 math-simplify-expr)))
136211a9 1061 (let ((f (calcFunc-factors (calcFunc-expand
0c908945 1062 (nth 1 math-simplify-expr)))))
136211a9
EZ
1063 (and (math-vectorp f)
1064 (or (> (length f) 2)
1065 (> (nth 2 (nth 1 f)) 1))
1066 (let ((out 1) (rest 1) (sums 1) fac pow)
1067 (while (setq f (cdr f))
1068 (setq fac (nth 1 (car f))
1069 pow (nth 2 (car f)))
1070 (if (> pow 1)
1071 (setq out (math-mul out (math-pow
1072 fac (/ pow 2)))
1073 pow (% pow 2)))
1074 (if (> pow 0)
1075 (if (memq (car-safe fac) '(+ -))
1076 (setq sums (math-mul-thru sums fac))
1077 (setq rest (math-mul rest fac)))))
1078 (and (not (and (eq out 1) (memq rest '(1 -1))))
1079 (math-mul
1080 out
1081 (list 'calcFunc-sqrt
d3896480 1082 (math-mul sums rest))))))))))))
136211a9
EZ
1083
1084;;; Rather than factoring x into primes, just check for the first ten primes.
1085(defun math-squared-factor (x)
1086 (if (Math-integerp x)
1087 (let ((prsqr '(4 9 25 49 121 169 289 361 529 841))
1088 (fac 1)
1089 res)
1090 (while prsqr
1091 (if (eq (cdr (setq res (math-idivmod x (car prsqr)))) 0)
1092 (setq x (car res)
1093 fac (math-mul fac (car prsqr)))
1094 (setq prsqr (cdr prsqr))))
d3896480 1095 fac)))
136211a9
EZ
1096
1097(math-defsimplify calcFunc-exp
0c908945 1098 (math-simplify-exp (nth 1 math-simplify-expr)))
136211a9
EZ
1099
1100(defun math-simplify-exp (x)
1101 (or (and (eq (car-safe x) 'calcFunc-ln)
1102 (nth 1 x))
1103 (and math-living-dangerously
1104 (or (and (eq (car-safe x) 'calcFunc-arcsinh)
1105 (math-add (nth 1 x)
1106 (list 'calcFunc-sqrt
1107 (math-add (math-sqr (nth 1 x)) 1))))
1108 (and (eq (car-safe x) 'calcFunc-arccosh)
1109 (math-add (nth 1 x)
1110 (list 'calcFunc-sqrt
1111 (math-sub (math-sqr (nth 1 x)) 1))))
1112 (and (eq (car-safe x) 'calcFunc-arctanh)
1113 (math-div (list 'calcFunc-sqrt (math-add 1 (nth 1 x)))
1114 (list 'calcFunc-sqrt (math-sub 1 (nth 1 x)))))
1115 (let ((m (math-should-expand-trig x 'exp)))
1116 (and m (integerp (car m))
1117 (list '^ (list 'calcFunc-exp (nth 1 m)) (car m))))))
1118 (and calc-symbolic-mode
1119 (math-known-imagp x)
1120 (let* ((ip (calcFunc-im x))
1121 (n (math-linear-in ip '(var pi var-pi)))
1122 s c)
1123 (and n
1124 (setq s (math-known-sin (car n) (nth 1 n) 120 0))
1125 (setq c (math-known-sin (car n) (nth 1 n) 120 300))
d3896480 1126 (list '+ c (list '* s '(var i var-i))))))))
136211a9
EZ
1127
1128(math-defsimplify calcFunc-ln
0c908945 1129 (or (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-exp)
136211a9 1130 (or math-living-dangerously
0c908945
JB
1131 (math-known-realp (nth 1 (nth 1 math-simplify-expr))))
1132 (nth 1 (nth 1 math-simplify-expr)))
1133 (and (eq (car-safe (nth 1 math-simplify-expr)) '^)
1134 (equal (nth 1 (nth 1 math-simplify-expr)) '(var e var-e))
136211a9 1135 (or math-living-dangerously
0c908945
JB
1136 (math-known-realp (nth 2 (nth 1 math-simplify-expr))))
1137 (nth 2 (nth 1 math-simplify-expr)))
136211a9 1138 (and calc-symbolic-mode
0c908945
JB
1139 (math-known-negp (nth 1 math-simplify-expr))
1140 (math-add (list 'calcFunc-ln (math-neg (nth 1 math-simplify-expr)))
2c6dfebb 1141 '(* (var pi var-pi) (var i var-i))))
136211a9 1142 (and calc-symbolic-mode
0c908945
JB
1143 (math-known-imagp (nth 1 math-simplify-expr))
1144 (let* ((ip (calcFunc-im (nth 1 math-simplify-expr)))
136211a9
EZ
1145 (ips (math-possible-signs ip)))
1146 (or (and (memq ips '(4 6))
1147 (math-add (list 'calcFunc-ln ip)
1148 '(/ (* (var pi var-pi) (var i var-i)) 2)))
1149 (and (memq ips '(1 3))
1150 (math-sub (list 'calcFunc-ln (math-neg ip))
d3896480 1151 '(/ (* (var pi var-pi) (var i var-i)) 2))))))))
136211a9
EZ
1152
1153(math-defsimplify ^
1154 (math-simplify-pow))
1155
1156(defun math-simplify-pow ()
1157 (or (and math-living-dangerously
0c908945 1158 (or (and (eq (car-safe (nth 1 math-simplify-expr)) '^)
136211a9 1159 (list '^
0c908945
JB
1160 (nth 1 (nth 1 math-simplify-expr))
1161 (math-mul (nth 2 math-simplify-expr)
1162 (nth 2 (nth 1 math-simplify-expr)))))
1163 (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-sqrt)
136211a9 1164 (list '^
0c908945
JB
1165 (nth 1 (nth 1 math-simplify-expr))
1166 (math-div (nth 2 math-simplify-expr) 2)))
1167 (and (memq (car-safe (nth 1 math-simplify-expr)) '(* /))
1168 (list (car (nth 1 math-simplify-expr))
1169 (list '^ (nth 1 (nth 1 math-simplify-expr))
1170 (nth 2 math-simplify-expr))
1171 (list '^ (nth 2 (nth 1 math-simplify-expr))
1172 (nth 2 math-simplify-expr))))))
1173 (and (math-equal-int (nth 1 math-simplify-expr) 10)
1174 (eq (car-safe (nth 2 math-simplify-expr)) 'calcFunc-log10)
1175 (nth 1 (nth 2 math-simplify-expr)))
1176 (and (equal (nth 1 math-simplify-expr) '(var e var-e))
1177 (math-simplify-exp (nth 2 math-simplify-expr)))
1178 (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-exp)
136211a9 1179 (not math-integrating)
0c908945
JB
1180 (list 'calcFunc-exp (math-mul (nth 1 (nth 1 math-simplify-expr))
1181 (nth 2 math-simplify-expr))))
1182 (and (equal (nth 1 math-simplify-expr) '(var i var-i))
136211a9 1183 (math-imaginary-i)
0c908945
JB
1184 (math-num-integerp (nth 2 math-simplify-expr))
1185 (let ((x (math-mod (math-trunc (nth 2 math-simplify-expr)) 4)))
136211a9 1186 (cond ((eq x 0) 1)
0c908945 1187 ((eq x 1) (nth 1 math-simplify-expr))
136211a9 1188 ((eq x 2) -1)
0c908945 1189 ((eq x 3) (math-neg (nth 1 math-simplify-expr))))))
136211a9 1190 (and math-integrating
0c908945
JB
1191 (integerp (nth 2 math-simplify-expr))
1192 (>= (nth 2 math-simplify-expr) 2)
1193 (or (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-cos)
1194 (math-mul (math-pow (nth 1 math-simplify-expr)
1195 (- (nth 2 math-simplify-expr) 2))
136211a9
EZ
1196 (math-sub 1
1197 (math-sqr
1198 (list 'calcFunc-sin
0c908945
JB
1199 (nth 1 (nth 1 math-simplify-expr)))))))
1200 (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-cosh)
1201 (math-mul (math-pow (nth 1 math-simplify-expr)
1202 (- (nth 2 math-simplify-expr) 2))
136211a9
EZ
1203 (math-add 1
1204 (math-sqr
1205 (list 'calcFunc-sinh
0c908945
JB
1206 (nth 1 (nth 1 math-simplify-expr)))))))))
1207 (and (eq (car-safe (nth 2 math-simplify-expr)) 'frac)
1208 (Math-ratp (nth 1 math-simplify-expr))
1209 (Math-posp (nth 1 math-simplify-expr))
1210 (if (equal (nth 2 math-simplify-expr) '(frac 1 2))
1211 (list 'calcFunc-sqrt (nth 1 math-simplify-expr))
1212 (let ((flr (math-floor (nth 2 math-simplify-expr))))
136211a9 1213 (and (not (Math-zerop flr))
0c908945
JB
1214 (list '* (list '^ (nth 1 math-simplify-expr) flr)
1215 (list '^ (nth 1 math-simplify-expr)
1216 (math-sub (nth 2 math-simplify-expr) flr)))))))
1217 (and (eq (math-quarter-integer (nth 2 math-simplify-expr)) 2)
136211a9
EZ
1218 (let ((temp (math-simplify-sqrt)))
1219 (and temp
0c908945 1220 (list '^ temp (math-mul (nth 2 math-simplify-expr) 2)))))))
136211a9
EZ
1221
1222(math-defsimplify calcFunc-log10
0c908945
JB
1223 (and (eq (car-safe (nth 1 math-simplify-expr)) '^)
1224 (math-equal-int (nth 1 (nth 1 math-simplify-expr)) 10)
136211a9 1225 (or math-living-dangerously
0c908945
JB
1226 (math-known-realp (nth 2 (nth 1 math-simplify-expr))))
1227 (nth 2 (nth 1 math-simplify-expr))))
136211a9
EZ
1228
1229
1230(math-defsimplify calcFunc-erf
0c908945
JB
1231 (or (and (math-looks-negp (nth 1 math-simplify-expr))
1232 (math-neg (list 'calcFunc-erf (math-neg (nth 1 math-simplify-expr)))))
1233 (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-conj)
1234 (list 'calcFunc-conj
1235 (list 'calcFunc-erf (nth 1 (nth 1 math-simplify-expr)))))))
136211a9
EZ
1236
1237(math-defsimplify calcFunc-erfc
0c908945
JB
1238 (or (and (math-looks-negp (nth 1 math-simplify-expr))
1239 (math-sub 2 (list 'calcFunc-erfc (math-neg (nth 1 math-simplify-expr)))))
1240 (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-conj)
1241 (list 'calcFunc-conj
1242 (list 'calcFunc-erfc (nth 1 (nth 1 math-simplify-expr)))))))
136211a9
EZ
1243
1244
1245(defun math-linear-in (expr term &optional always)
1246 (if (math-expr-contains expr term)
1247 (let* ((calc-prefer-frac t)
1248 (p (math-is-polynomial expr term 1)))
1249 (and (cdr p)
1250 p))
d3896480 1251 (and always (list expr 0))))
136211a9
EZ
1252
1253(defun math-multiple-of (expr term)
1254 (let ((p (math-linear-in expr term)))
1255 (and p
1256 (math-zerop (car p))
d3896480 1257 (nth 1 p))))
136211a9 1258
d3896480 1259; not perfect, but it'll do
136211a9
EZ
1260(defun math-integer-plus (expr)
1261 (cond ((Math-integerp expr)
1262 (list 0 expr))
1263 ((and (memq (car expr) '(+ -))
1264 (Math-integerp (nth 1 expr)))
1265 (list (if (eq (car expr) '+) (nth 2 expr) (math-neg (nth 2 expr)))
1266 (nth 1 expr)))
1267 ((and (memq (car expr) '(+ -))
1268 (Math-integerp (nth 2 expr)))
1269 (list (nth 1 expr)
1270 (if (eq (car expr) '+) (nth 2 expr) (math-neg (nth 2 expr)))))
d3896480 1271 (t nil)))
136211a9
EZ
1272
1273(defun math-is-linear (expr &optional always)
1274 (let ((offset nil)
1275 (coef nil))
1276 (if (eq (car-safe expr) '+)
1277 (if (Math-objectp (nth 1 expr))
1278 (setq offset (nth 1 expr)
1279 expr (nth 2 expr))
1280 (if (Math-objectp (nth 2 expr))
1281 (setq offset (nth 2 expr)
1282 expr (nth 1 expr))))
1283 (if (eq (car-safe expr) '-)
1284 (if (Math-objectp (nth 1 expr))
1285 (setq offset (nth 1 expr)
1286 expr (math-neg (nth 2 expr)))
1287 (if (Math-objectp (nth 2 expr))
1288 (setq offset (math-neg (nth 2 expr))
1289 expr (nth 1 expr))))))
1290 (setq coef (math-is-multiple expr always))
1291 (if offset
1292 (list offset (or (car coef) 1) (or (nth 1 coef) expr))
1293 (if coef
d3896480 1294 (cons 0 coef)))))
136211a9
EZ
1295
1296(defun math-is-multiple (expr &optional always)
1297 (or (if (eq (car-safe expr) '*)
1298 (if (Math-objectp (nth 1 expr))
1299 (list (nth 1 expr) (nth 2 expr)))
1300 (if (eq (car-safe expr) '/)
1301 (if (and (Math-objectp (nth 1 expr))
1302 (not (math-equal-int (nth 1 expr) 1)))
1303 (list (nth 1 expr) (math-div 1 (nth 2 expr)))
1304 (if (Math-objectp (nth 2 expr))
1305 (list (math-div 1 (nth 2 expr)) (nth 1 expr))
1306 (let ((res (math-is-multiple (nth 1 expr))))
1307 (if res
1308 (list (car res)
1309 (math-div (nth 2 (nth 1 expr)) (nth 2 expr)))
1310 (setq res (math-is-multiple (nth 2 expr)))
1311 (if res
1312 (list (math-div 1 (car res))
1313 (math-div (nth 1 expr)
1314 (nth 2 (nth 2 expr)))))))))
1315 (if (eq (car-safe expr) 'neg)
1316 (list -1 (nth 1 expr)))))
1317 (if (Math-objvecp expr)
1318 (and (eq always 1)
1319 (list expr 1))
a1506d29 1320 (and always
d3896480 1321 (list 1 expr)))))
136211a9
EZ
1322
1323(defun calcFunc-lin (expr &optional var)
1324 (if var
1325 (let ((res (math-linear-in expr var t)))
1326 (or res (math-reject-arg expr "Linear term expected"))
1327 (list 'vec (car res) (nth 1 res) var))
1328 (let ((res (math-is-linear expr t)))
1329 (or res (math-reject-arg expr "Linear term expected"))
d3896480 1330 (cons 'vec res))))
136211a9
EZ
1331
1332(defun calcFunc-linnt (expr &optional var)
1333 (if var
1334 (let ((res (math-linear-in expr var)))
1335 (or res (math-reject-arg expr "Linear term expected"))
1336 (list 'vec (car res) (nth 1 res) var))
1337 (let ((res (math-is-linear expr)))
1338 (or res (math-reject-arg expr "Linear term expected"))
d3896480 1339 (cons 'vec res))))
136211a9
EZ
1340
1341(defun calcFunc-islin (expr &optional var)
1342 (if (and (Math-objvecp expr) (not var))
1343 0
1344 (calcFunc-lin expr var)
d3896480 1345 1))
136211a9
EZ
1346
1347(defun calcFunc-islinnt (expr &optional var)
1348 (if (Math-objvecp expr)
1349 0
1350 (calcFunc-linnt expr var)
d3896480 1351 1))
136211a9
EZ
1352
1353
1354
1355
1356;;; Simple operations on expressions.
1357
6f826971 1358;;; Return number of occurrences of thing in expr, or nil if none.
136211a9
EZ
1359(defun math-expr-contains-count (expr thing)
1360 (cond ((equal expr thing) 1)
1361 ((Math-primp expr) nil)
1362 (t
1363 (let ((num 0))
1364 (while (setq expr (cdr expr))
1365 (setq num (+ num (or (math-expr-contains-count
1366 (car expr) thing) 0))))
1367 (and (> num 0)
d3896480 1368 num)))))
136211a9
EZ
1369
1370(defun math-expr-contains (expr thing)
1371 (cond ((equal expr thing) 1)
1372 ((Math-primp expr) nil)
1373 (t
1374 (while (and (setq expr (cdr expr))
1375 (not (math-expr-contains (car expr) thing))))
d3896480 1376 expr)))
136211a9
EZ
1377
1378;;; Return non-nil if any variable of thing occurs in expr.
1379(defun math-expr-depends (expr thing)
1380 (if (Math-primp thing)
1381 (and (eq (car-safe thing) 'var)
1382 (math-expr-contains expr thing))
1383 (while (and (setq thing (cdr thing))
1384 (not (math-expr-depends expr (car thing)))))
d3896480 1385 thing))
136211a9
EZ
1386
1387;;; Substitute all occurrences of old for new in expr (non-destructive).
0c908945
JB
1388
1389;; The variables math-expr-subst-old and math-expr-subst-new are local
1390;; for math-expr-subst, but used by math-expr-subst-rec.
1391(defvar math-expr-subst-old)
1392(defvar math-expr-subst-new)
1393
1394(defun math-expr-subst (expr math-expr-subst-old math-expr-subst-new)
d3896480
CW
1395 (math-expr-subst-rec expr))
1396
1397(defalias 'calcFunc-subst 'math-expr-subst)
136211a9
EZ
1398
1399(defun math-expr-subst-rec (expr)
0c908945 1400 (cond ((equal expr math-expr-subst-old) math-expr-subst-new)
136211a9
EZ
1401 ((Math-primp expr) expr)
1402 ((memq (car expr) '(calcFunc-deriv
1403 calcFunc-tderiv))
1404 (if (= (length expr) 2)
0c908945
JB
1405 (if (equal (nth 1 expr) math-expr-subst-old)
1406 (append expr (list math-expr-subst-new))
136211a9
EZ
1407 expr)
1408 (list (car expr) (nth 1 expr)
1409 (math-expr-subst-rec (nth 2 expr)))))
1410 (t
1411 (cons (car expr)
d3896480 1412 (mapcar 'math-expr-subst-rec (cdr expr))))))
136211a9
EZ
1413
1414;;; Various measures of the size of an expression.
1415(defun math-expr-weight (expr)
1416 (if (Math-primp expr)
1417 1
1418 (let ((w 1))
1419 (while (setq expr (cdr expr))
1420 (setq w (+ w (math-expr-weight (car expr)))))
d3896480 1421 w)))
136211a9
EZ
1422
1423(defun math-expr-height (expr)
1424 (if (Math-primp expr)
1425 0
1426 (let ((h 0))
1427 (while (setq expr (cdr expr))
1428 (setq h (max h (math-expr-height (car expr)))))
d3896480 1429 (1+ h))))
136211a9
EZ
1430
1431
1432
1433
1434;;; Polynomial operations (to support the integrator and solve-for).
1435
1436(defun calcFunc-collect (expr base)
1437 (let ((p (math-is-polynomial expr base 50 t)))
1438 (if (cdr p)
1439 (math-normalize ; fix selection bug
1440 (math-build-polynomial-expr p base))
d3896480 1441 expr)))
136211a9
EZ
1442
1443;;; If expr is of the form "a + bx + cx^2 + ...", return the list (a b c ...),
0c908945
JB
1444;;; else return nil if not in polynomial form. If "loose" (math-is-poly-loose),
1445;;; coefficients may contain x, e.g., sin(x) + cos(x) x^2 is a loose polynomial in x.
1446
1447;; The variables math-is-poly-degree and math-is-poly-loose are local to
1448;; math-is-polynomial, but are used by math-is-poly-rec
1449(defvar math-is-poly-degree)
1450(defvar math-is-poly-loose)
1451
1452(defun math-is-polynomial (expr var &optional math-is-poly-degree math-is-poly-loose)
1453 (let* ((math-poly-base-variable (if math-is-poly-loose
1454 (if (eq math-is-poly-loose 'gen) var '(var XXX XXX))
136211a9
EZ
1455 math-poly-base-variable))
1456 (poly (math-is-poly-rec expr math-poly-neg-powers)))
0c908945
JB
1457 (and (or (null math-is-poly-degree)
1458 (<= (length poly) (1+ math-is-poly-degree)))
d3896480 1459 poly)))
136211a9
EZ
1460
1461(defun math-is-poly-rec (expr negpow)
1462 (math-poly-simplify
1463 (or (cond ((or (equal expr var)
1464 (eq (car-safe expr) '^))
1465 (let ((pow 1)
1466 (expr expr))
1467 (or (equal expr var)
1468 (setq pow (nth 2 expr)
1469 expr (nth 1 expr)))
1470 (or (eq math-poly-mult-powers 1)
1471 (setq pow (let ((m (math-is-multiple pow 1)))
1472 (and (eq (car-safe (car m)) 'cplx)
1473 (Math-zerop (nth 1 (car m)))
1474 (setq m (list (nth 2 (car m))
1475 (math-mul (nth 1 m)
1476 '(var i var-i)))))
1477 (and (if math-poly-mult-powers
1478 (equal math-poly-mult-powers
1479 (nth 1 m))
1480 (setq math-poly-mult-powers (nth 1 m)))
1481 (or (equal expr var)
1482 (eq math-poly-mult-powers 1))
1483 (car m)))))
1484 (if (consp pow)
1485 (progn
1486 (setq pow (math-to-simple-fraction pow))
1487 (and (eq (car-safe pow) 'frac)
1488 math-poly-frac-powers
1489 (equal expr var)
1490 (setq math-poly-frac-powers
1491 (calcFunc-lcm math-poly-frac-powers
1492 (nth 2 pow))))))
1493 (or (memq math-poly-frac-powers '(1 nil))
1494 (setq pow (math-mul pow math-poly-frac-powers)))
1495 (if (integerp pow)
1496 (if (and (= pow 1)
1497 (equal expr var))
1498 (list 0 1)
1499 (if (natnump pow)
1500 (let ((p1 (if (equal expr var)
1501 (list 0 1)
1502 (math-is-poly-rec expr nil)))
1503 (n pow)
1504 (accum (list 1)))
1505 (and p1
0c908945
JB
1506 (or (null math-is-poly-degree)
1507 (<= (* (1- (length p1)) n) math-is-poly-degree))
136211a9
EZ
1508 (progn
1509 (while (>= n 1)
1510 (setq accum (math-poly-mul accum p1)
1511 n (1- n)))
1512 accum)))
1513 (and negpow
1514 (math-is-poly-rec expr nil)
1515 (setq math-poly-neg-powers
1516 (cons (math-pow expr (- pow))
1517 math-poly-neg-powers))
1518 (list (list '^ expr pow))))))))
1519 ((Math-objectp expr)
1520 (list expr))
1521 ((memq (car expr) '(+ -))
1522 (let ((p1 (math-is-poly-rec (nth 1 expr) negpow)))
1523 (and p1
1524 (let ((p2 (math-is-poly-rec (nth 2 expr) negpow)))
1525 (and p2
1526 (math-poly-mix p1 1 p2
1527 (if (eq (car expr) '+) 1 -1)))))))
1528 ((eq (car expr) 'neg)
1529 (mapcar 'math-neg (math-is-poly-rec (nth 1 expr) negpow)))
1530 ((eq (car expr) '*)
1531 (let ((p1 (math-is-poly-rec (nth 1 expr) negpow)))
1532 (and p1
1533 (let ((p2 (math-is-poly-rec (nth 2 expr) negpow)))
1534 (and p2
0c908945
JB
1535 (or (null math-is-poly-degree)
1536 (<= (- (+ (length p1) (length p2)) 2)
1537 math-is-poly-degree))
136211a9
EZ
1538 (math-poly-mul p1 p2))))))
1539 ((eq (car expr) '/)
1540 (and (or (not (math-poly-depends (nth 2 expr) var))
1541 (and negpow
1542 (math-is-poly-rec (nth 2 expr) nil)
1543 (setq math-poly-neg-powers
1544 (cons (nth 2 expr) math-poly-neg-powers))))
1545 (not (Math-zerop (nth 2 expr)))
1546 (let ((p1 (math-is-poly-rec (nth 1 expr) negpow)))
1547 (mapcar (function (lambda (x) (math-div x (nth 2 expr))))
1548 p1))))
1549 ((and (eq (car expr) 'calcFunc-exp)
1550 (equal var '(var e var-e)))
1551 (math-is-poly-rec (list '^ var (nth 1 expr)) negpow))
1552 ((and (eq (car expr) 'calcFunc-sqrt)
1553 math-poly-frac-powers)
1554 (math-is-poly-rec (list '^ (nth 1 expr) '(frac 1 2)) negpow))
1555 (t nil))
1556 (and (or (not (math-poly-depends expr var))
0c908945 1557 math-is-poly-loose)
136211a9 1558 (not (eq (car expr) 'vec))
d3896480 1559 (list expr)))))
136211a9
EZ
1560
1561;;; Check if expr is a polynomial in var; if so, return its degree.
1562(defun math-polynomial-p (expr var)
1563 (cond ((equal expr var) 1)
1564 ((Math-primp expr) 0)
1565 ((memq (car expr) '(+ -))
1566 (let ((p1 (math-polynomial-p (nth 1 expr) var))
1567 p2)
1568 (and p1 (setq p2 (math-polynomial-p (nth 2 expr) var))
1569 (max p1 p2))))
1570 ((eq (car expr) '*)
1571 (let ((p1 (math-polynomial-p (nth 1 expr) var))
1572 p2)
1573 (and p1 (setq p2 (math-polynomial-p (nth 2 expr) var))
1574 (+ p1 p2))))
1575 ((eq (car expr) 'neg)
1576 (math-polynomial-p (nth 1 expr) var))
1577 ((and (eq (car expr) '/)
1578 (not (math-poly-depends (nth 2 expr) var)))
1579 (math-polynomial-p (nth 1 expr) var))
1580 ((and (eq (car expr) '^)
1581 (natnump (nth 2 expr)))
1582 (let ((p1 (math-polynomial-p (nth 1 expr) var)))
1583 (and p1 (* p1 (nth 2 expr)))))
1584 ((math-poly-depends expr var) nil)
d3896480 1585 (t 0)))
136211a9
EZ
1586
1587(defun math-poly-depends (expr var)
1588 (if math-poly-base-variable
1589 (math-expr-contains expr math-poly-base-variable)
d3896480 1590 (math-expr-depends expr var)))
136211a9
EZ
1591
1592;;; Find the variable (or sub-expression) which is the base of polynomial expr.
0c908945
JB
1593;; The variables math-poly-base-const-ok and math-poly-base-pred are
1594;; local to math-polynomial-base, but are used by math-polynomial-base-rec.
1595(defvar math-poly-base-const-ok)
1596(defvar math-poly-base-pred)
1597
885e6671
JB
1598;; The variable math-poly-base-top-expr is local to math-polynomial-base,
1599;; but is used by math-polynomial-p1 in calc-poly.el, which is called
1600;; by math-polynomial-base.
1601
1602(defun math-polynomial-base (math-poly-base-top-expr &optional math-poly-base-pred)
0c908945
JB
1603 (or math-poly-base-pred
1604 (setq math-poly-base-pred (function (lambda (base) (math-polynomial-p
885e6671 1605 math-poly-base-top-expr base)))))
0c908945 1606 (or (let ((math-poly-base-const-ok nil))
885e6671 1607 (math-polynomial-base-rec math-poly-base-top-expr))
0c908945 1608 (let ((math-poly-base-const-ok t))
885e6671 1609 (math-polynomial-base-rec math-poly-base-top-expr))))
136211a9
EZ
1610
1611(defun math-polynomial-base-rec (mpb-expr)
1612 (and (not (Math-objvecp mpb-expr))
1613 (or (and (memq (car mpb-expr) '(+ - *))
1614 (or (math-polynomial-base-rec (nth 1 mpb-expr))
1615 (math-polynomial-base-rec (nth 2 mpb-expr))))
1616 (and (memq (car mpb-expr) '(/ neg))
1617 (math-polynomial-base-rec (nth 1 mpb-expr)))
1618 (and (eq (car mpb-expr) '^)
1619 (math-polynomial-base-rec (nth 1 mpb-expr)))
1620 (and (eq (car mpb-expr) 'calcFunc-exp)
1621 (math-polynomial-base-rec '(var e var-e)))
0c908945
JB
1622 (and (or math-poly-base-const-ok (math-expr-contains-vars mpb-expr))
1623 (funcall math-poly-base-pred mpb-expr)
d3896480 1624 mpb-expr))))
136211a9
EZ
1625
1626;;; Return non-nil if expr refers to any variables.
1627(defun math-expr-contains-vars (expr)
1628 (or (eq (car-safe expr) 'var)
1629 (and (not (Math-primp expr))
1630 (progn
1631 (while (and (setq expr (cdr expr))
1632 (not (math-expr-contains-vars (car expr)))))
d3896480 1633 expr))))
136211a9
EZ
1634
1635;;; Simplify a polynomial in list form by stripping off high-end zeros.
1636;;; This always leaves the constant part, i.e., nil->nil and nonnil->nonnil.
1637(defun math-poly-simplify (p)
1638 (and p
1639 (if (Math-zerop (nth (1- (length p)) p))
1640 (let ((pp (copy-sequence p)))
1641 (while (and (cdr pp)
1642 (Math-zerop (nth (1- (length pp)) pp)))
1643 (setcdr (nthcdr (- (length pp) 2) pp) nil))
1644 pp)
d3896480 1645 p)))
136211a9
EZ
1646
1647;;; Compute ac*a + bc*b for polynomials in list form a, b and
1648;;; coefficients ac, bc. Result may be unsimplified.
1649(defun math-poly-mix (a ac b bc)
1650 (and (or a b)
1651 (cons (math-add (math-mul (or (car a) 0) ac)
1652 (math-mul (or (car b) 0) bc))
d3896480 1653 (math-poly-mix (cdr a) ac (cdr b) bc))))
136211a9
EZ
1654
1655(defun math-poly-zerop (a)
1656 (or (null a)
d3896480 1657 (and (null (cdr a)) (Math-zerop (car a)))))
136211a9
EZ
1658
1659;;; Multiply two polynomials in list form.
1660(defun math-poly-mul (a b)
1661 (and a b
1662 (math-poly-mix b (car a)
d3896480 1663 (math-poly-mul (cdr a) (cons 0 b)) 1)))
136211a9
EZ
1664
1665;;; Build an expression from a polynomial list.
1666(defun math-build-polynomial-expr (p var)
1667 (if p
1668 (if (Math-numberp var)
1669 (math-with-extra-prec 1
1670 (let* ((rp (reverse p))
1671 (accum (car rp)))
1672 (while (setq rp (cdr rp))
1673 (setq accum (math-add (car rp) (math-mul accum var))))
1674 accum))
1675 (let* ((rp (reverse p))
1676 (n (1- (length rp)))
1677 (accum (math-mul (car rp) (math-pow var n)))
1678 term)
1679 (while (setq rp (cdr rp))
1680 (setq n (1- n))
1681 (or (math-zerop (car rp))
1682 (setq accum (list (if (math-looks-negp (car rp)) '- '+)
1683 accum
1684 (math-mul (if (math-looks-negp (car rp))
1685 (math-neg (car rp))
1686 (car rp))
1687 (math-pow var n))))))
1688 accum))
d3896480 1689 0))
136211a9
EZ
1690
1691
1692(defun math-to-simple-fraction (f)
1693 (or (and (eq (car-safe f) 'float)
1694 (or (and (>= (nth 2 f) 0)
1695 (math-scale-int (nth 1 f) (nth 2 f)))
1696 (and (integerp (nth 1 f))
1697 (> (nth 1 f) -1000)
1698 (< (nth 1 f) 1000)
1699 (math-make-frac (nth 1 f)
1700 (math-scale-int 1 (- (nth 2 f)))))))
d3896480 1701 f))
136211a9 1702
41cf648d
JB
1703(provide 'calc-alg)
1704
ab5796a9 1705;;; arch-tag: 52e7dcdf-9688-464d-a02b-4bbe789348d0
d3896480 1706;;; calc-alg.el ends here