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