* term/mac-win.el (ccl-encode-mac-roman-font)
[bpt/emacs.git] / lisp / calc / calc-alg.el
... / ...
CommitLineData
1;;; calc-alg.el --- algebraic functions for Calc
2
3;; Copyright (C) 1990, 1991, 1992, 1993, 2001 Free Software Foundation, Inc.
4
5;; Author: David Gillespie <daveg@synaptics.com>
6;; Maintainer: Jay Belanger <belanger@truman.edu>
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
25;;; Commentary:
26
27;;; Code:
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
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)
44 (calc-enter-result 1 "dsmp" (calc-top 1))))))
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)
52 (setq calc-simplify-mode (list calc-simplify-mode))))
53
54(defun calc-simplify ()
55 (interactive)
56 (calc-slow-wrapper
57 (calc-with-default-simplification
58 (calc-enter-result 1 "simp" (math-simplify (calc-top-n 1))))))
59
60(defun calc-simplify-extended ()
61 (interactive)
62 (calc-slow-wrapper
63 (calc-with-default-simplification
64 (calc-enter-result 1 "esmp" (math-simplify-extended (calc-top-n 1))))))
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)
72 (calc-enter-result 1 "expf"
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)
78 top))))))))
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)
85 arg)))
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))
93 (and n (list (prefix-numeric-value n)))))))
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)
106 var))))))
107
108(defun calc-apart (arg)
109 (interactive "P")
110 (calc-slow-wrapper
111 (calc-unary-op "aprt" 'calcFunc-apart arg)))
112
113(defun calc-normalize-rat (arg)
114 (interactive "P")
115 (calc-slow-wrapper
116 (calc-unary-op "nrat" 'calcFunc-nrat arg)))
117
118(defun calc-poly-gcd (arg)
119 (interactive "P")
120 (calc-slow-wrapper
121 (calc-binary-op "pgcd" 'calcFunc-pgcd arg)))
122
123
124(defun calc-poly-div (arg)
125 (interactive "P")
126 (calc-slow-wrapper
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)")))))))
137
138(defun calc-poly-rem (arg)
139 (interactive "P")
140 (calc-slow-wrapper
141 (calc-binary-op "prem" 'calcFunc-prem arg)))
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)
148 (calc-binary-op "pdvr" 'calcFunc-pdivrem arg))))
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)
177 (error "No occurrences found")))
178 (calc-enter-result num "sbst" (math-expr-subst expr old new)))))
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))
185 name))
186
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
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)
197 math-eval-rules-cache-tag (calc-var-value 'var-EvalRules)))
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)))
209 res))))
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)))))
265 (t (string-lessp (symbol-name (car a)) (symbol-name (car b))))))
266
267
268(defsubst math-simplify-extended (a)
269 (let ((math-living-dangerously t))
270 (math-simplify a)))
271
272(defalias 'calcFunc-esimplify 'math-simplify-extended)
273
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
278(defun math-simplify (top-expr)
279 (let ((math-simplifying t)
280 (math-top-only (consp calc-simplify-mode))
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)
293 (if math-top-only
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)))))
310 top-expr)
311
312(defalias 'calcFunc-simplify 'math-simplify)
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
320 (let ((aa (if (or math-top-only
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))))))
333 aa)))
334
335
336;; Placeholder, to synchronize autoloading.
337(defun math-need-std-simps ()
338 nil)
339
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
344(math-defsimplify (+ -)
345 (math-simplify-plus))
346
347(defun math-simplify-plus ()
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)
364 aaa temp)
365 (while (memq (car-safe (setq aaa (nth 1 aa))) '(+ -))
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))
369 (progn
370 (setcar (cdr (cdr math-simplify-expr)) temp)
371 (setcar math-simplify-expr '+)
372 (setcar (cdr (cdr aaa)) 0)))
373 (setq aa (nth 1 aa)))
374 (if (setq temp (math-combine-sum aaa (nth 2 math-simplify-expr)
375 nil (eq (car math-simplify-expr) '-) t))
376 (progn
377 (setcar (cdr (cdr math-simplify-expr)) temp)
378 (setcar math-simplify-expr '+)
379 (setcar (cdr aa) 0)))
380 math-simplify-expr))
381
382(math-defsimplify *
383 (math-simplify-times))
384
385(defun math-simplify-times ()
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)
400 aaa temp
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))))
404 (progn
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))))
408 (while (and (eq (car-safe (setq aaa (nth 2 aa))) '*)
409 safe)
410 (if (setq temp (math-combine-prod (nth 1 math-simplify-expr)
411 (nth 1 aaa) nil nil t))
412 (progn
413 (setcar (cdr math-simplify-expr) temp)
414 (setcar (cdr aaa) 1)))
415 (setq safe (or scalar (math-known-scalarp (nth 1 aaa) t))
416 aa (nth 2 aa)))
417 (if (and (setq temp (math-combine-prod aaa (nth 1 math-simplify-expr) nil nil t))
418 safe)
419 (progn
420 (setcar (cdr math-simplify-expr) temp)
421 (setcar (cdr (cdr aa)) 1)))
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)))
428
429(math-defsimplify /
430 (math-simplify-divide))
431
432(defun math-simplify-divide ()
433 (let ((np (cdr math-simplify-expr))
434 (nover nil)
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))))
438 n op)
439 (if nn
440 (progn
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))))
444 (if (and (eq (car-safe nn) 'frac) (eq (nth 1 nn) 1) (not n))
445 (progn
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))
450 (if (and (math-negp nn)
451 (setq op (assq (car math-simplify-expr) calc-tweak-eqn-table)))
452 (setcar math-simplify-expr (nth 1 op))))
453 (if (and n (not (eq (setq n (math-frac-gcd n nn)) 1)))
454 (progn
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))
459 (if (and (math-negp n)
460 (setq op (assq (car math-simplify-expr)
461 calc-tweak-eqn-table)))
462 (setcar math-simplify-expr (nth 1 op))))))))
463 (if (and (eq (car-safe (car np)) '/)
464 (math-known-scalarp (nth 2 math-simplify-expr) t))
465 (progn
466 (setq np (cdr (nth 1 math-simplify-expr)))
467 (while (eq (car-safe (setq n (car np))) '*)
468 (and (math-known-scalarp (nth 2 n) t)
469 (math-simplify-divisor (cdr n) (cdr (cdr math-simplify-expr)) nil t))
470 (setq np (cdr (cdr n))))
471 (math-simplify-divisor np (cdr (cdr math-simplify-expr)) nil t)
472 (setq nover t
473 np (cdr (cdr (nth 1 math-simplify-expr))))))
474 (while (eq (car-safe (setq n (car np))) '*)
475 (and (math-known-scalarp (nth 2 n) t)
476 (math-simplify-divisor (cdr n) (cdr (cdr math-simplify-expr)) nover t))
477 (setq np (cdr (cdr n))))
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)
486
487(defun math-simplify-divisor (np dp math-simplify-divisor-nover
488 math-simplify-divisor-dover)
489 (cond ((eq (car-safe (car dp)) '/)
490 (math-simplify-divisor np (cdr (car dp))
491 math-simplify-divisor-nover
492 math-simplify-divisor-dover)
493 (and (math-known-scalarp (nth 1 (car dp)) t)
494 (math-simplify-divisor np (cdr (cdr (car dp)))
495 math-simplify-divisor-nover
496 (not math-simplify-divisor-dover))))
497 ((or (or (eq (car math-simplify-expr) '/)
498 (let ((signs (math-possible-signs (car np))))
499 (or (memq signs '(1 4))
500 (and (memq (car math-simplify-expr) '(calcFunc-eq calcFunc-neq))
501 (eq signs 5))
502 math-living-dangerously)))
503 (math-numberp (car np)))
504 (let (d
505 (safe t)
506 (scalar (math-known-scalarp (car np))))
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
513 (math-simplify-one-divisor np dp))))))
514
515(defun math-simplify-one-divisor (np dp)
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))))))))
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))
554 (list 'frac 1 (math-abs (nth 2 expr))))))))))
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))
564 (math-div expr val))))
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))
577 (math-gcd (nth 2 a) (nth 2 b)))))))
578
579(math-defsimplify %
580 (math-simplify-mod))
581
582(defun math-simplify-mod ()
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)))
586 t1 t2 t3)
587 (or (and lin
588 (or (math-negp (car lin))
589 (not (Math-lessp (car lin) (nth 2 math-simplify-expr))))
590 (list '%
591 (list '+
592 (math-mul (nth 1 lin) (nth 2 lin))
593 (math-mod (car lin) (nth 2 math-simplify-expr)))
594 (nth 2 math-simplify-expr)))
595 (and lin
596 (not (math-equal-int (nth 1 lin) 1))
597 (math-num-integerp (nth 1 lin))
598 (math-num-integerp (nth 2 math-simplify-expr))
599 (setq t1 (calcFunc-gcd (nth 1 lin) (nth 2 math-simplify-expr)))
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)))
609 (math-div (nth 2 math-simplify-expr) t1))))
610 (and (math-equal-int (nth 2 math-simplify-expr) 1)
611 (math-known-integerp (if lin
612 (math-mul (nth 1 lin) (nth 2 lin))
613 (nth 1 math-simplify-expr)))
614 (if lin (math-mod (car lin) 1) 0))))))
615
616(math-defsimplify (calcFunc-eq calcFunc-neq calcFunc-lt
617 calcFunc-gt calcFunc-leq calcFunc-geq)
618 (if (= (length math-simplify-expr) 3)
619 (math-simplify-ineq)))
620
621(defun math-simplify-ineq ()
622 (let ((np (cdr math-simplify-expr))
623 n)
624 (while (memq (car-safe (setq n (car np))) '(+ -))
625 (math-simplify-add-term (cdr (cdr n)) (cdr (cdr math-simplify-expr))
626 (eq (car n) '-) nil)
627 (setq np (cdr n)))
628 (math-simplify-add-term np (cdr (cdr math-simplify-expr)) nil
629 (eq np (cdr math-simplify-expr)))
630 (math-simplify-divide)
631 (let ((signs (math-possible-signs (cons '- (cdr math-simplify-expr)))))
632 (or (cond ((eq (car math-simplify-expr) 'calcFunc-eq)
633 (or (and (eq signs 2) 1)
634 (and (memq signs '(1 4 5)) 0)))
635 ((eq (car math-simplify-expr) 'calcFunc-neq)
636 (or (and (eq signs 2) 0)
637 (and (memq signs '(1 4 5)) 1)))
638 ((eq (car math-simplify-expr) 'calcFunc-lt)
639 (or (and (eq signs 1) 1)
640 (and (memq signs '(2 4 6)) 0)))
641 ((eq (car math-simplify-expr) 'calcFunc-gt)
642 (or (and (eq signs 4) 1)
643 (and (memq signs '(1 2 3)) 0)))
644 ((eq (car math-simplify-expr) 'calcFunc-leq)
645 (or (and (eq signs 4) 0)
646 (and (memq signs '(1 2 3)) 1)))
647 ((eq (car math-simplify-expr) 'calcFunc-geq)
648 (or (and (eq signs 1) 0)
649 (and (memq signs '(2 4 6)) 1))))
650 math-simplify-expr))))
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)
679 (setcar dp (setq n (math-neg temp)))))))))
680
681(math-defsimplify calcFunc-sin
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)))))
686 (and (eq calc-angle-mode 'rad)
687 (let ((n (math-linear-in (nth 1 math-simplify-expr) '(var pi var-pi))))
688 (and n
689 (math-known-sin (car n) (nth 1 n) 120 0))))
690 (and (eq calc-angle-mode 'deg)
691 (let ((n (math-integer-plus (nth 1 math-simplify-expr))))
692 (and n
693 (math-known-sin (car n) (nth 1 n) '(frac 2 3) 0))))
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))
699 (list 'calcFunc-sqrt
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))))
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))
709 (list 'calcFunc-sin a))))))))
710
711(math-defsimplify calcFunc-cos
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))))
716 (and (eq calc-angle-mode 'rad)
717 (let ((n (math-linear-in (nth 1 math-simplify-expr) '(var pi var-pi))))
718 (and n
719 (math-known-sin (car n) (nth 1 n) 120 300))))
720 (and (eq calc-angle-mode 'deg)
721 (let ((n (math-integer-plus (nth 1 math-simplify-expr))))
722 (and n
723 (math-known-sin (car n) (nth 1 n) '(frac 2 3) 300))))
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)
728 (math-div 1
729 (list 'calcFunc-sqrt
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))))
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))
739 (list 'calcFunc-sin a))))))))
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)))
753 m)))
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)))
791 (t nil))))))
792
793(math-defsimplify calcFunc-tan
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)))))
798 (and (eq calc-angle-mode 'rad)
799 (let ((n (math-linear-in (nth 1 math-simplify-expr) '(var pi var-pi))))
800 (and n
801 (math-known-tan (car n) (nth 1 n) 120))))
802 (and (eq calc-angle-mode 'deg)
803 (let ((n (math-integer-plus (nth 1 math-simplify-expr))))
804 (and n
805 (math-known-tan (car n) (nth 1 n) '(frac 2 3)))))
806 (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-arcsin)
807 (math-div (nth 1 (nth 1 math-simplify-expr))
808 (list 'calcFunc-sqrt
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)
811 (math-div (list 'calcFunc-sqrt
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))))
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)))
819 (math-div (list 'calcFunc-sin (nth 1 math-simplify-expr))
820 (list 'calcFunc-cos (nth 1 math-simplify-expr))))))))
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))))
852 (t nil))))))
853
854(math-defsimplify calcFunc-sinh
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)
860 math-living-dangerously
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)
864 math-living-dangerously
865 (math-div (nth 1 (nth 1 math-simplify-expr))
866 (list 'calcFunc-sqrt
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)))
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))
876 (list 'calcFunc-sinh a)))))))))
877
878(math-defsimplify calcFunc-cosh
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)
884 math-living-dangerously
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)
888 math-living-dangerously
889 (math-div 1
890 (list 'calcFunc-sqrt
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)))
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))
900 (list 'calcFunc-sinh a)))))))))
901
902(math-defsimplify calcFunc-tanh
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)
908 math-living-dangerously
909 (math-div (nth 1 (nth 1 math-simplify-expr))
910 (list 'calcFunc-sqrt
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)
913 math-living-dangerously
914 (math-div (list 'calcFunc-sqrt
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)))
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)))
922 (math-div (list 'calcFunc-sinh (nth 1 math-simplify-expr))
923 (list 'calcFunc-cosh (nth 1 math-simplify-expr))))))))
924
925(math-defsimplify calcFunc-arcsin
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)
929 (math-quarter-circle t))
930 (and (equal (nth 1 math-simplify-expr) '(frac 1 2))
931 (math-div (math-half-circle t) 6))
932 (and math-living-dangerously
933 (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-sin)
934 (nth 1 (nth 1 math-simplify-expr)))
935 (and math-living-dangerously
936 (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-cos)
937 (math-sub (math-quarter-circle t)
938 (nth 1 (nth 1 math-simplify-expr))))))
939
940(math-defsimplify calcFunc-arccos
941 (or (and (eq (nth 1 math-simplify-expr) 0)
942 (math-quarter-circle t))
943 (and (eq (nth 1 math-simplify-expr) -1)
944 (math-half-circle t))
945 (and (equal (nth 1 math-simplify-expr) '(frac 1 2))
946 (math-div (math-half-circle t) 3))
947 (and (equal (nth 1 math-simplify-expr) '(frac -1 2))
948 (math-div (math-mul (math-half-circle t) 2) 3))
949 (and math-living-dangerously
950 (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-cos)
951 (nth 1 (nth 1 math-simplify-expr)))
952 (and math-living-dangerously
953 (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-sin)
954 (math-sub (math-quarter-circle t)
955 (nth 1 (nth 1 math-simplify-expr))))))
956
957(math-defsimplify calcFunc-arctan
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)
961 (math-div (math-half-circle t) 4))
962 (and math-living-dangerously
963 (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-tan)
964 (nth 1 (nth 1 math-simplify-expr)))))
965
966(math-defsimplify calcFunc-arcsinh
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)
970 (or math-living-dangerously
971 (math-known-realp (nth 1 (nth 1 math-simplify-expr))))
972 (nth 1 (nth 1 math-simplify-expr)))))
973
974(math-defsimplify calcFunc-arccosh
975 (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-cosh)
976 (or math-living-dangerously
977 (math-known-realp (nth 1 (nth 1 math-simplify-expr))))
978 (nth 1 (nth 1 math-simplify-expr))))
979
980(math-defsimplify calcFunc-arctanh
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)
984 (or math-living-dangerously
985 (math-known-realp (nth 1 (nth 1 math-simplify-expr))))
986 (nth 1 (nth 1 math-simplify-expr)))))
987
988(math-defsimplify calcFunc-sqrt
989 (math-simplify-sqrt))
990
991(defun math-simplify-sqrt ()
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)))))
1000 (and fac (not (eq fac 1))
1001 (math-mul (math-normalize (list 'calcFunc-sqrt fac))
1002 (math-normalize
1003 (list 'calcFunc-sqrt
1004 (math-cancel-common-factor
1005 (nth 1 math-simplify-expr) fac))))))
1006 (and math-living-dangerously
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))))
1012 'calcFunc-sin)
1013 (list 'calcFunc-cos
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))))
1016 'calcFunc-cos)
1017 (list 'calcFunc-sin
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))))
1025 'calcFunc-cosh)
1026 (list 'calcFunc-sinh
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))))
1031 (and (or (and (math-equal-int a 1)
1032 (setq a b b (nth 1 (nth 1 math-simplify-expr))))
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)))))))))
1041 (and (eq (car-safe (nth 1 math-simplify-expr)) '^)
1042 (list '^
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)))
1053 (let ((f (calcFunc-factors (calcFunc-expand
1054 (nth 1 math-simplify-expr)))))
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
1074 (math-mul sums rest))))))))))))
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))))
1087 fac)))
1088
1089(math-defsimplify calcFunc-exp
1090 (math-simplify-exp (nth 1 math-simplify-expr)))
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))
1118 (list '+ c (list '* s '(var i var-i))))))))
1119
1120(math-defsimplify calcFunc-ln
1121 (or (and (eq (car-safe (nth 1 math-simplify-expr)) 'calcFunc-exp)
1122 (or math-living-dangerously
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))
1127 (or math-living-dangerously
1128 (math-known-realp (nth 2 (nth 1 math-simplify-expr))))
1129 (nth 2 (nth 1 math-simplify-expr)))
1130 (and calc-symbolic-mode
1131 (math-known-negp (nth 1 math-simplify-expr))
1132 (math-add (list 'calcFunc-ln (math-neg (nth 1 math-simplify-expr)))
1133 '(* (var pi var-pi) (var i var-i))))
1134 (and calc-symbolic-mode
1135 (math-known-imagp (nth 1 math-simplify-expr))
1136 (let* ((ip (calcFunc-im (nth 1 math-simplify-expr)))
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))
1143 '(/ (* (var pi var-pi) (var i var-i)) 2))))))))
1144
1145(math-defsimplify ^
1146 (math-simplify-pow))
1147
1148(defun math-simplify-pow ()
1149 (or (and math-living-dangerously
1150 (or (and (eq (car-safe (nth 1 math-simplify-expr)) '^)
1151 (list '^
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)
1156 (list '^
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)
1171 (not math-integrating)
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))
1175 (math-imaginary-i)
1176 (math-num-integerp (nth 2 math-simplify-expr))
1177 (let ((x (math-mod (math-trunc (nth 2 math-simplify-expr)) 4)))
1178 (cond ((eq x 0) 1)
1179 ((eq x 1) (nth 1 math-simplify-expr))
1180 ((eq x 2) -1)
1181 ((eq x 3) (math-neg (nth 1 math-simplify-expr))))))
1182 (and math-integrating
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))
1188 (math-sub 1
1189 (math-sqr
1190 (list 'calcFunc-sin
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))
1195 (math-add 1
1196 (math-sqr
1197 (list 'calcFunc-sinh
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))))
1205 (and (not (Math-zerop flr))
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)
1210 (let ((temp (math-simplify-sqrt)))
1211 (and temp
1212 (list '^ temp (math-mul (nth 2 math-simplify-expr) 2)))))))
1213
1214(math-defsimplify calcFunc-log10
1215 (and (eq (car-safe (nth 1 math-simplify-expr)) '^)
1216 (math-equal-int (nth 1 (nth 1 math-simplify-expr)) 10)
1217 (or math-living-dangerously
1218 (math-known-realp (nth 2 (nth 1 math-simplify-expr))))
1219 (nth 2 (nth 1 math-simplify-expr))))
1220
1221
1222(math-defsimplify calcFunc-erf
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)))))))
1228
1229(math-defsimplify calcFunc-erfc
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)))))))
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))
1243 (and always (list expr 0))))
1244
1245(defun math-multiple-of (expr term)
1246 (let ((p (math-linear-in expr term)))
1247 (and p
1248 (math-zerop (car p))
1249 (nth 1 p))))
1250
1251; not perfect, but it'll do
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)))))
1263 (t nil)))
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
1286 (cons 0 coef)))))
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))
1312 (and always
1313 (list 1 expr)))))
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"))
1322 (cons 'vec res))))
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"))
1331 (cons 'vec res))))
1332
1333(defun calcFunc-islin (expr &optional var)
1334 (if (and (Math-objvecp expr) (not var))
1335 0
1336 (calcFunc-lin expr var)
1337 1))
1338
1339(defun calcFunc-islinnt (expr &optional var)
1340 (if (Math-objvecp expr)
1341 0
1342 (calcFunc-linnt expr var)
1343 1))
1344
1345
1346
1347
1348;;; Simple operations on expressions.
1349
1350;;; Return number of occurrences of thing in expr, or nil if none.
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)
1360 num)))))
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))))
1368 expr)))
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)))))
1377 thing))
1378
1379;;; Substitute all occurrences of old for new in expr (non-destructive).
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)
1387 (math-expr-subst-rec expr))
1388
1389(defalias 'calcFunc-subst 'math-expr-subst)
1390
1391(defun math-expr-subst-rec (expr)
1392 (cond ((equal expr math-expr-subst-old) math-expr-subst-new)
1393 ((Math-primp expr) expr)
1394 ((memq (car expr) '(calcFunc-deriv
1395 calcFunc-tderiv))
1396 (if (= (length expr) 2)
1397 (if (equal (nth 1 expr) math-expr-subst-old)
1398 (append expr (list math-expr-subst-new))
1399 expr)
1400 (list (car expr) (nth 1 expr)
1401 (math-expr-subst-rec (nth 2 expr)))))
1402 (t
1403 (cons (car expr)
1404 (mapcar 'math-expr-subst-rec (cdr expr))))))
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)))))
1413 w)))
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)))))
1421 (1+ h))))
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))
1433 expr)))
1434
1435;;; If expr is of the form "a + bx + cx^2 + ...", return the list (a b c ...),
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))
1447 math-poly-base-variable))
1448 (poly (math-is-poly-rec expr math-poly-neg-powers)))
1449 (and (or (null math-is-poly-degree)
1450 (<= (length poly) (1+ math-is-poly-degree)))
1451 poly)))
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
1498 (or (null math-is-poly-degree)
1499 (<= (* (1- (length p1)) n) math-is-poly-degree))
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
1527 (or (null math-is-poly-degree)
1528 (<= (- (+ (length p1) (length p2)) 2)
1529 math-is-poly-degree))
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))
1549 math-is-poly-loose)
1550 (not (eq (car expr) 'vec))
1551 (list expr)))))
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)
1577 (t 0)))
1578
1579(defun math-poly-depends (expr var)
1580 (if math-poly-base-variable
1581 (math-expr-contains expr math-poly-base-variable)
1582 (math-expr-depends expr var)))
1583
1584;;; Find the variable (or sub-expression) which is the base of polynomial expr.
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
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)
1595 (or math-poly-base-pred
1596 (setq math-poly-base-pred (function (lambda (base) (math-polynomial-p
1597 math-poly-base-top-expr base)))))
1598 (or (let ((math-poly-base-const-ok nil))
1599 (math-polynomial-base-rec math-poly-base-top-expr))
1600 (let ((math-poly-base-const-ok t))
1601 (math-polynomial-base-rec math-poly-base-top-expr))))
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)))
1614 (and (or math-poly-base-const-ok (math-expr-contains-vars mpb-expr))
1615 (funcall math-poly-base-pred mpb-expr)
1616 mpb-expr))))
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)))))
1625 expr))))
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)
1637 p)))
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))
1645 (math-poly-mix (cdr a) ac (cdr b) bc))))
1646
1647(defun math-poly-zerop (a)
1648 (or (null a)
1649 (and (null (cdr a)) (Math-zerop (car a)))))
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)
1655 (math-poly-mul (cdr a) (cons 0 b)) 1)))
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))
1681 0))
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)))))))
1693 f))
1694
1695;;; arch-tag: 52e7dcdf-9688-464d-a02b-4bbe789348d0
1696;;; calc-alg.el ends here