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