(math-do-integral-methods): Try linear, then non-linear, substitutions.
[bpt/emacs.git] / lisp / calc / calcalg2.el
1 ;;; calcalg2.el --- more 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 ;; Maintainers: D. Goel <deego@gnufans.org>
7 ;; Colin Walters <walters@debian.org>
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 (require 'calc-ext)
32
33 (require 'calc-macs)
34
35 (defun calc-Need-calc-alg-2 () nil)
36
37
38 (defun calc-derivative (var num)
39 (interactive "sDifferentiate with respect to: \np")
40 (calc-slow-wrapper
41 (when (< num 0)
42 (error "Order of derivative must be positive"))
43 (let ((func (if (calc-is-hyperbolic) 'calcFunc-tderiv 'calcFunc-deriv))
44 n expr)
45 (if (or (equal var "") (equal var "$"))
46 (setq n 2
47 expr (calc-top-n 2)
48 var (calc-top-n 1))
49 (setq var (math-read-expr var))
50 (when (eq (car-safe var) 'error)
51 (error "Bad format in expression: %s" (nth 1 var)))
52 (setq n 1
53 expr (calc-top-n 1)))
54 (while (>= (setq num (1- num)) 0)
55 (setq expr (list func expr var)))
56 (calc-enter-result n "derv" expr))))
57
58 (defun calc-integral (var)
59 (interactive "sIntegration variable: ")
60 (calc-slow-wrapper
61 (if (or (equal var "") (equal var "$"))
62 (calc-enter-result 2 "intg" (list 'calcFunc-integ
63 (calc-top-n 2)
64 (calc-top-n 1)))
65 (let ((var (math-read-expr var)))
66 (if (eq (car-safe var) 'error)
67 (error "Bad format in expression: %s" (nth 1 var)))
68 (calc-enter-result 1 "intg" (list 'calcFunc-integ
69 (calc-top-n 1)
70 var))))))
71
72 (defun calc-num-integral (&optional varname lowname highname)
73 (interactive "sIntegration variable: ")
74 (calc-tabular-command 'calcFunc-ninteg "Integration" "nint"
75 nil varname lowname highname))
76
77 (defun calc-summation (arg &optional varname lowname highname)
78 (interactive "P\nsSummation variable: ")
79 (calc-tabular-command 'calcFunc-sum "Summation" "sum"
80 arg varname lowname highname))
81
82 (defun calc-alt-summation (arg &optional varname lowname highname)
83 (interactive "P\nsSummation variable: ")
84 (calc-tabular-command 'calcFunc-asum "Summation" "asum"
85 arg varname lowname highname))
86
87 (defun calc-product (arg &optional varname lowname highname)
88 (interactive "P\nsIndex variable: ")
89 (calc-tabular-command 'calcFunc-prod "Index" "prod"
90 arg varname lowname highname))
91
92 (defun calc-tabulate (arg &optional varname lowname highname)
93 (interactive "P\nsIndex variable: ")
94 (calc-tabular-command 'calcFunc-table "Index" "tabl"
95 arg varname lowname highname))
96
97 (defun calc-tabular-command (func prompt prefix arg varname lowname highname)
98 (calc-slow-wrapper
99 (let (var (low nil) (high nil) (step nil) stepname stepnum (num 1) expr)
100 (if (consp arg)
101 (setq stepnum 1)
102 (setq stepnum 0))
103 (if (or (equal varname "") (equal varname "$") (null varname))
104 (setq high (calc-top-n (+ stepnum 1))
105 low (calc-top-n (+ stepnum 2))
106 var (calc-top-n (+ stepnum 3))
107 num (+ stepnum 4))
108 (setq var (if (stringp varname) (math-read-expr varname) varname))
109 (if (eq (car-safe var) 'error)
110 (error "Bad format in expression: %s" (nth 1 var)))
111 (or lowname
112 (setq lowname (read-string (concat prompt " variable: " varname
113 ", from: "))))
114 (if (or (equal lowname "") (equal lowname "$"))
115 (setq high (calc-top-n (+ stepnum 1))
116 low (calc-top-n (+ stepnum 2))
117 num (+ stepnum 3))
118 (setq low (if (stringp lowname) (math-read-expr lowname) lowname))
119 (if (eq (car-safe low) 'error)
120 (error "Bad format in expression: %s" (nth 1 low)))
121 (or highname
122 (setq highname (read-string (concat prompt " variable: " varname
123 ", from: " lowname
124 ", to: "))))
125 (if (or (equal highname "") (equal highname "$"))
126 (setq high (calc-top-n (+ stepnum 1))
127 num (+ stepnum 2))
128 (setq high (if (stringp highname) (math-read-expr highname)
129 highname))
130 (if (eq (car-safe high) 'error)
131 (error "Bad format in expression: %s" (nth 1 high)))
132 (if (consp arg)
133 (progn
134 (setq stepname (read-string (concat prompt " variable: "
135 varname
136 ", from: " lowname
137 ", to: " highname
138 ", step: ")))
139 (if (or (equal stepname "") (equal stepname "$"))
140 (setq step (calc-top-n 1)
141 num 2)
142 (setq step (math-read-expr stepname))
143 (if (eq (car-safe step) 'error)
144 (error "Bad format in expression: %s"
145 (nth 1 step)))))))))
146 (or step
147 (if (consp arg)
148 (setq step (calc-top-n 1))
149 (if arg
150 (setq step (prefix-numeric-value arg)))))
151 (setq expr (calc-top-n num))
152 (calc-enter-result num prefix (append (list func expr var low high)
153 (and step (list step)))))))
154
155 (defun calc-solve-for (var)
156 (interactive "sVariable to solve for: ")
157 (calc-slow-wrapper
158 (let ((func (if (calc-is-inverse)
159 (if (calc-is-hyperbolic) 'calcFunc-ffinv 'calcFunc-finv)
160 (if (calc-is-hyperbolic) 'calcFunc-fsolve 'calcFunc-solve))))
161 (if (or (equal var "") (equal var "$"))
162 (calc-enter-result 2 "solv" (list func
163 (calc-top-n 2)
164 (calc-top-n 1)))
165 (let ((var (if (and (string-match ",\\|[^ ] +[^ ]" var)
166 (not (string-match "\\[" var)))
167 (math-read-expr (concat "[" var "]"))
168 (math-read-expr var))))
169 (if (eq (car-safe var) 'error)
170 (error "Bad format in expression: %s" (nth 1 var)))
171 (calc-enter-result 1 "solv" (list func
172 (calc-top-n 1)
173 var)))))))
174
175 (defun calc-poly-roots (var)
176 (interactive "sVariable to solve for: ")
177 (calc-slow-wrapper
178 (if (or (equal var "") (equal var "$"))
179 (calc-enter-result 2 "prts" (list 'calcFunc-roots
180 (calc-top-n 2)
181 (calc-top-n 1)))
182 (let ((var (if (and (string-match ",\\|[^ ] +[^ ]" var)
183 (not (string-match "\\[" var)))
184 (math-read-expr (concat "[" var "]"))
185 (math-read-expr var))))
186 (if (eq (car-safe var) 'error)
187 (error "Bad format in expression: %s" (nth 1 var)))
188 (calc-enter-result 1 "prts" (list 'calcFunc-roots
189 (calc-top-n 1)
190 var))))))
191
192 (defun calc-taylor (var nterms)
193 (interactive "sTaylor expansion variable: \nNNumber of terms: ")
194 (calc-slow-wrapper
195 (let ((var (math-read-expr var)))
196 (if (eq (car-safe var) 'error)
197 (error "Bad format in expression: %s" (nth 1 var)))
198 (calc-enter-result 1 "tylr" (list 'calcFunc-taylor
199 (calc-top-n 1)
200 var
201 (prefix-numeric-value nterms))))))
202
203
204 (defun math-derivative (expr) ; uses global values: deriv-var, deriv-total.
205 (cond ((equal expr deriv-var)
206 1)
207 ((or (Math-scalarp expr)
208 (eq (car expr) 'sdev)
209 (and (eq (car expr) 'var)
210 (or (not deriv-total)
211 (math-const-var expr)
212 (progn
213 (math-setup-declarations)
214 (memq 'const (nth 1 (or (assq (nth 2 expr)
215 math-decls-cache)
216 math-decls-all)))))))
217 0)
218 ((eq (car expr) '+)
219 (math-add (math-derivative (nth 1 expr))
220 (math-derivative (nth 2 expr))))
221 ((eq (car expr) '-)
222 (math-sub (math-derivative (nth 1 expr))
223 (math-derivative (nth 2 expr))))
224 ((memq (car expr) '(calcFunc-eq calcFunc-neq calcFunc-lt
225 calcFunc-gt calcFunc-leq calcFunc-geq))
226 (list (car expr)
227 (math-derivative (nth 1 expr))
228 (math-derivative (nth 2 expr))))
229 ((eq (car expr) 'neg)
230 (math-neg (math-derivative (nth 1 expr))))
231 ((eq (car expr) '*)
232 (math-add (math-mul (nth 2 expr)
233 (math-derivative (nth 1 expr)))
234 (math-mul (nth 1 expr)
235 (math-derivative (nth 2 expr)))))
236 ((eq (car expr) '/)
237 (math-sub (math-div (math-derivative (nth 1 expr))
238 (nth 2 expr))
239 (math-div (math-mul (nth 1 expr)
240 (math-derivative (nth 2 expr)))
241 (math-sqr (nth 2 expr)))))
242 ((eq (car expr) '^)
243 (let ((du (math-derivative (nth 1 expr)))
244 (dv (math-derivative (nth 2 expr))))
245 (or (Math-zerop du)
246 (setq du (math-mul (nth 2 expr)
247 (math-mul (math-normalize
248 (list '^
249 (nth 1 expr)
250 (math-add (nth 2 expr) -1)))
251 du))))
252 (or (Math-zerop dv)
253 (setq dv (math-mul (math-normalize
254 (list 'calcFunc-ln (nth 1 expr)))
255 (math-mul expr dv))))
256 (math-add du dv)))
257 ((eq (car expr) '%)
258 (math-derivative (nth 1 expr))) ; a reasonable definition
259 ((eq (car expr) 'vec)
260 (math-map-vec 'math-derivative expr))
261 ((and (memq (car expr) '(calcFunc-conj calcFunc-re calcFunc-im))
262 (= (length expr) 2))
263 (list (car expr) (math-derivative (nth 1 expr))))
264 ((and (memq (car expr) '(calcFunc-subscr calcFunc-mrow calcFunc-mcol))
265 (= (length expr) 3))
266 (let ((d (math-derivative (nth 1 expr))))
267 (if (math-numberp d)
268 0 ; assume x and x_1 are independent vars
269 (list (car expr) d (nth 2 expr)))))
270 (t (or (and (symbolp (car expr))
271 (if (= (length expr) 2)
272 (let ((handler (get (car expr) 'math-derivative)))
273 (and handler
274 (let ((deriv (math-derivative (nth 1 expr))))
275 (if (Math-zerop deriv)
276 deriv
277 (math-mul (funcall handler (nth 1 expr))
278 deriv)))))
279 (let ((handler (get (car expr) 'math-derivative-n)))
280 (and handler
281 (funcall handler expr)))))
282 (and (not (eq deriv-symb 'pre-expand))
283 (let ((exp (math-expand-formula expr)))
284 (and exp
285 (or (let ((deriv-symb 'pre-expand))
286 (catch 'math-deriv (math-derivative expr)))
287 (math-derivative exp)))))
288 (if (or (Math-objvecp expr)
289 (eq (car expr) 'var)
290 (not (symbolp (car expr))))
291 (if deriv-symb
292 (throw 'math-deriv nil)
293 (list (if deriv-total 'calcFunc-tderiv 'calcFunc-deriv)
294 expr
295 deriv-var))
296 (let ((accum 0)
297 (arg expr)
298 (n 1)
299 derv)
300 (while (setq arg (cdr arg))
301 (or (Math-zerop (setq derv (math-derivative (car arg))))
302 (let ((func (intern (concat (symbol-name (car expr))
303 "'"
304 (if (> n 1)
305 (int-to-string n)
306 ""))))
307 (prop (cond ((= (length expr) 2)
308 'math-derivative-1)
309 ((= (length expr) 3)
310 'math-derivative-2)
311 ((= (length expr) 4)
312 'math-derivative-3)
313 ((= (length expr) 5)
314 'math-derivative-4)
315 ((= (length expr) 6)
316 'math-derivative-5))))
317 (setq accum
318 (math-add
319 accum
320 (math-mul
321 derv
322 (let ((handler (get func prop)))
323 (or (and prop handler
324 (apply handler (cdr expr)))
325 (if (and deriv-symb
326 (not (get func
327 'calc-user-defn)))
328 (throw 'math-deriv nil)
329 (cons func (cdr expr))))))))))
330 (setq n (1+ n)))
331 accum))))))
332
333 (defun calcFunc-deriv (expr deriv-var &optional deriv-value deriv-symb)
334 (let* ((deriv-total nil)
335 (res (catch 'math-deriv (math-derivative expr))))
336 (or (eq (car-safe res) 'calcFunc-deriv)
337 (null res)
338 (setq res (math-normalize res)))
339 (and res
340 (if deriv-value
341 (math-expr-subst res deriv-var deriv-value)
342 res))))
343
344 (defun calcFunc-tderiv (expr deriv-var &optional deriv-value deriv-symb)
345 (math-setup-declarations)
346 (let* ((deriv-total t)
347 (res (catch 'math-deriv (math-derivative expr))))
348 (or (eq (car-safe res) 'calcFunc-tderiv)
349 (null res)
350 (setq res (math-normalize res)))
351 (and res
352 (if deriv-value
353 (math-expr-subst res deriv-var deriv-value)
354 res))))
355
356 (put 'calcFunc-inv\' 'math-derivative-1
357 (function (lambda (u) (math-neg (math-div 1 (math-sqr u))))))
358
359 (put 'calcFunc-sqrt\' 'math-derivative-1
360 (function (lambda (u) (math-div 1 (math-mul 2 (list 'calcFunc-sqrt u))))))
361
362 (put 'calcFunc-deg\' 'math-derivative-1
363 (function (lambda (u) (math-div-float '(float 18 1) (math-pi)))))
364
365 (put 'calcFunc-rad\' 'math-derivative-1
366 (function (lambda (u) (math-pi-over-180))))
367
368 (put 'calcFunc-ln\' 'math-derivative-1
369 (function (lambda (u) (math-div 1 u))))
370
371 (put 'calcFunc-log10\' 'math-derivative-1
372 (function (lambda (u)
373 (math-div (math-div 1 (math-normalize '(calcFunc-ln 10)))
374 u))))
375
376 (put 'calcFunc-lnp1\' 'math-derivative-1
377 (function (lambda (u) (math-div 1 (math-add u 1)))))
378
379 (put 'calcFunc-log\' 'math-derivative-2
380 (function (lambda (x b)
381 (and (not (Math-zerop b))
382 (let ((lnv (math-normalize
383 (list 'calcFunc-ln b))))
384 (math-div 1 (math-mul lnv x)))))))
385
386 (put 'calcFunc-log\'2 'math-derivative-2
387 (function (lambda (x b)
388 (let ((lnv (list 'calcFunc-ln b)))
389 (math-neg (math-div (list 'calcFunc-log x b)
390 (math-mul lnv b)))))))
391
392 (put 'calcFunc-exp\' 'math-derivative-1
393 (function (lambda (u) (math-normalize (list 'calcFunc-exp u)))))
394
395 (put 'calcFunc-expm1\' 'math-derivative-1
396 (function (lambda (u) (math-normalize (list 'calcFunc-expm1 u)))))
397
398 (put 'calcFunc-sin\' 'math-derivative-1
399 (function (lambda (u) (math-to-radians-2 (math-normalize
400 (list 'calcFunc-cos u))))))
401
402 (put 'calcFunc-cos\' 'math-derivative-1
403 (function (lambda (u) (math-neg (math-to-radians-2
404 (math-normalize
405 (list 'calcFunc-sin u)))))))
406
407 (put 'calcFunc-tan\' 'math-derivative-1
408 (function (lambda (u) (math-to-radians-2
409 (math-div 1 (math-sqr
410 (math-normalize
411 (list 'calcFunc-cos u))))))))
412
413 (put 'calcFunc-arcsin\' 'math-derivative-1
414 (function (lambda (u)
415 (math-from-radians-2
416 (math-div 1 (math-normalize
417 (list 'calcFunc-sqrt
418 (math-sub 1 (math-sqr u)))))))))
419
420 (put 'calcFunc-arccos\' 'math-derivative-1
421 (function (lambda (u)
422 (math-from-radians-2
423 (math-div -1 (math-normalize
424 (list 'calcFunc-sqrt
425 (math-sub 1 (math-sqr u)))))))))
426
427 (put 'calcFunc-arctan\' 'math-derivative-1
428 (function (lambda (u) (math-from-radians-2
429 (math-div 1 (math-add 1 (math-sqr u)))))))
430
431 (put 'calcFunc-sinh\' 'math-derivative-1
432 (function (lambda (u) (math-normalize (list 'calcFunc-cosh u)))))
433
434 (put 'calcFunc-cosh\' 'math-derivative-1
435 (function (lambda (u) (math-normalize (list 'calcFunc-sinh u)))))
436
437 (put 'calcFunc-tanh\' 'math-derivative-1
438 (function (lambda (u) (math-div 1 (math-sqr
439 (math-normalize
440 (list 'calcFunc-cosh u)))))))
441
442 (put 'calcFunc-arcsinh\' 'math-derivative-1
443 (function (lambda (u)
444 (math-div 1 (math-normalize
445 (list 'calcFunc-sqrt
446 (math-add (math-sqr u) 1)))))))
447
448 (put 'calcFunc-arccosh\' 'math-derivative-1
449 (function (lambda (u)
450 (math-div 1 (math-normalize
451 (list 'calcFunc-sqrt
452 (math-add (math-sqr u) -1)))))))
453
454 (put 'calcFunc-arctanh\' 'math-derivative-1
455 (function (lambda (u) (math-div 1 (math-sub 1 (math-sqr u))))))
456
457 (put 'calcFunc-bern\'2 'math-derivative-2
458 (function (lambda (n x)
459 (math-mul n (list 'calcFunc-bern (math-add n -1) x)))))
460
461 (put 'calcFunc-euler\'2 'math-derivative-2
462 (function (lambda (n x)
463 (math-mul n (list 'calcFunc-euler (math-add n -1) x)))))
464
465 (put 'calcFunc-gammag\'2 'math-derivative-2
466 (function (lambda (a x) (math-deriv-gamma a x 1))))
467
468 (put 'calcFunc-gammaG\'2 'math-derivative-2
469 (function (lambda (a x) (math-deriv-gamma a x -1))))
470
471 (put 'calcFunc-gammaP\'2 'math-derivative-2
472 (function (lambda (a x) (math-deriv-gamma a x
473 (math-div
474 1 (math-normalize
475 (list 'calcFunc-gamma
476 a)))))))
477
478 (put 'calcFunc-gammaQ\'2 'math-derivative-2
479 (function (lambda (a x) (math-deriv-gamma a x
480 (math-div
481 -1 (math-normalize
482 (list 'calcFunc-gamma
483 a)))))))
484
485 (defun math-deriv-gamma (a x scale)
486 (math-mul scale
487 (math-mul (math-pow x (math-add a -1))
488 (list 'calcFunc-exp (math-neg x)))))
489
490 (put 'calcFunc-betaB\' 'math-derivative-3
491 (function (lambda (x a b) (math-deriv-beta x a b 1))))
492
493 (put 'calcFunc-betaI\' 'math-derivative-3
494 (function (lambda (x a b) (math-deriv-beta x a b
495 (math-div
496 1 (list 'calcFunc-beta
497 a b))))))
498
499 (defun math-deriv-beta (x a b scale)
500 (math-mul (math-mul (math-pow x (math-add a -1))
501 (math-pow (math-sub 1 x) (math-add b -1)))
502 scale))
503
504 (put 'calcFunc-erf\' 'math-derivative-1
505 (function (lambda (x) (math-div 2
506 (math-mul (list 'calcFunc-exp
507 (math-sqr x))
508 (if calc-symbolic-mode
509 '(calcFunc-sqrt
510 (var pi var-pi))
511 (math-sqrt-pi)))))))
512
513 (put 'calcFunc-erfc\' 'math-derivative-1
514 (function (lambda (x) (math-div -2
515 (math-mul (list 'calcFunc-exp
516 (math-sqr x))
517 (if calc-symbolic-mode
518 '(calcFunc-sqrt
519 (var pi var-pi))
520 (math-sqrt-pi)))))))
521
522 (put 'calcFunc-besJ\'2 'math-derivative-2
523 (function (lambda (v z) (math-div (math-sub (list 'calcFunc-besJ
524 (math-add v -1)
525 z)
526 (list 'calcFunc-besJ
527 (math-add v 1)
528 z))
529 2))))
530
531 (put 'calcFunc-besY\'2 'math-derivative-2
532 (function (lambda (v z) (math-div (math-sub (list 'calcFunc-besY
533 (math-add v -1)
534 z)
535 (list 'calcFunc-besY
536 (math-add v 1)
537 z))
538 2))))
539
540 (put 'calcFunc-sum 'math-derivative-n
541 (function
542 (lambda (expr)
543 (if (math-expr-contains (cons 'vec (cdr (cdr expr))) deriv-var)
544 (throw 'math-deriv nil)
545 (cons 'calcFunc-sum
546 (cons (math-derivative (nth 1 expr))
547 (cdr (cdr expr))))))))
548
549 (put 'calcFunc-prod 'math-derivative-n
550 (function
551 (lambda (expr)
552 (if (math-expr-contains (cons 'vec (cdr (cdr expr))) deriv-var)
553 (throw 'math-deriv nil)
554 (math-mul expr
555 (cons 'calcFunc-sum
556 (cons (math-div (math-derivative (nth 1 expr))
557 (nth 1 expr))
558 (cdr (cdr expr)))))))))
559
560 (put 'calcFunc-integ 'math-derivative-n
561 (function
562 (lambda (expr)
563 (if (= (length expr) 3)
564 (if (equal (nth 2 expr) deriv-var)
565 (nth 1 expr)
566 (math-normalize
567 (list 'calcFunc-integ
568 (math-derivative (nth 1 expr))
569 (nth 2 expr))))
570 (if (= (length expr) 5)
571 (let ((lower (math-expr-subst (nth 1 expr) (nth 2 expr)
572 (nth 3 expr)))
573 (upper (math-expr-subst (nth 1 expr) (nth 2 expr)
574 (nth 4 expr))))
575 (math-add (math-sub (math-mul upper
576 (math-derivative (nth 4 expr)))
577 (math-mul lower
578 (math-derivative (nth 3 expr))))
579 (if (equal (nth 2 expr) deriv-var)
580 0
581 (math-normalize
582 (list 'calcFunc-integ
583 (math-derivative (nth 1 expr)) (nth 2 expr)
584 (nth 3 expr) (nth 4 expr)))))))))))
585
586 (put 'calcFunc-if 'math-derivative-n
587 (function
588 (lambda (expr)
589 (and (= (length expr) 4)
590 (list 'calcFunc-if (nth 1 expr)
591 (math-derivative (nth 2 expr))
592 (math-derivative (nth 3 expr)))))))
593
594 (put 'calcFunc-subscr 'math-derivative-n
595 (function
596 (lambda (expr)
597 (and (= (length expr) 3)
598 (list 'calcFunc-subscr (nth 1 expr)
599 (math-derivative (nth 2 expr)))))))
600
601
602 (defvar math-integ-var '(var X ---))
603 (defvar math-integ-var-2 '(var Y ---))
604 (defvar math-integ-vars (list 'f math-integ-var math-integ-var-2))
605 (defvar math-integ-var-list (list math-integ-var))
606 (defvar math-integ-var-list-list (list math-integ-var-list))
607
608 (defmacro math-tracing-integral (&rest parts)
609 (list 'and
610 'trace-buffer
611 (list 'save-excursion
612 '(set-buffer trace-buffer)
613 '(goto-char (point-max))
614 (list 'and
615 '(bolp)
616 '(insert (make-string (- math-integral-limit
617 math-integ-level) 32)
618 (format "%2d " math-integ-depth)
619 (make-string math-integ-level 32)))
620 ;;(list 'condition-case 'err
621 (cons 'insert parts)
622 ;; '(error (insert (prin1-to-string err))))
623 '(sit-for 0))))
624
625 ;;; The following wrapper caches results and avoids infinite recursion.
626 ;;; Each cache entry is: ( A B ) Integral of A is B;
627 ;;; ( A N ) Integral of A failed at level N;
628 ;;; ( A busy ) Currently working on integral of A;
629 ;;; ( A parts ) Currently working, integ-by-parts;
630 ;;; ( A parts2 ) Currently working, integ-by-parts;
631 ;;; ( A cancelled ) Ignore this cache entry;
632 ;;; ( A [B] ) Same result as for cur-record = B.
633 (defun math-integral (expr &optional simplify same-as-above)
634 (let* ((simp cur-record)
635 (cur-record (assoc expr math-integral-cache))
636 (math-integ-depth (1+ math-integ-depth))
637 (val 'cancelled))
638 (math-tracing-integral "Integrating "
639 (math-format-value expr 1000)
640 "...\n")
641 (and cur-record
642 (progn
643 (math-tracing-integral "Found "
644 (math-format-value (nth 1 cur-record) 1000))
645 (and (consp (nth 1 cur-record))
646 (math-replace-integral-parts cur-record))
647 (math-tracing-integral " => "
648 (math-format-value (nth 1 cur-record) 1000)
649 "\n")))
650 (or (and cur-record
651 (not (eq (nth 1 cur-record) 'cancelled))
652 (or (not (integerp (nth 1 cur-record)))
653 (>= (nth 1 cur-record) math-integ-level)))
654 (and (math-integral-contains-parts expr)
655 (progn
656 (setq val nil)
657 t))
658 (unwind-protect
659 (progn
660 (let (math-integ-msg)
661 (if (eq calc-display-working-message 'lots)
662 (progn
663 (calc-set-command-flag 'clear-message)
664 (setq math-integ-msg (format
665 "Working... Integrating %s"
666 (math-format-flat-expr expr 0)))
667 (message math-integ-msg)))
668 (if cur-record
669 (setcar (cdr cur-record)
670 (if same-as-above (vector simp) 'busy))
671 (setq cur-record
672 (list expr (if same-as-above (vector simp) 'busy))
673 math-integral-cache (cons cur-record
674 math-integral-cache)))
675 (if (eq simplify 'yes)
676 (progn
677 (math-tracing-integral "Simplifying...")
678 (setq simp (math-simplify expr))
679 (setq val (if (equal simp expr)
680 (progn
681 (math-tracing-integral " no change\n")
682 (math-do-integral expr))
683 (math-tracing-integral " simplified\n")
684 (math-integral simp 'no t))))
685 (or (setq val (math-do-integral expr))
686 (eq simplify 'no)
687 (let ((simp (math-simplify expr)))
688 (or (equal simp expr)
689 (progn
690 (math-tracing-integral "Trying again after "
691 "simplification...\n")
692 (setq val (math-integral simp 'no t))))))))
693 (if (eq calc-display-working-message 'lots)
694 (message math-integ-msg)))
695 (setcar (cdr cur-record) (or val
696 (if (or math-enable-subst
697 (not math-any-substs))
698 math-integ-level
699 'cancelled)))))
700 (setq val cur-record)
701 (while (vectorp (nth 1 val))
702 (setq val (aref (nth 1 val) 0)))
703 (setq val (if (memq (nth 1 val) '(parts parts2))
704 (progn
705 (setcar (cdr val) 'parts2)
706 (list 'var 'PARTS val))
707 (and (consp (nth 1 val))
708 (nth 1 val))))
709 (math-tracing-integral "Integral of "
710 (math-format-value expr 1000)
711 " is "
712 (math-format-value val 1000)
713 "\n")
714 val))
715 (defvar math-integral-cache nil)
716 (defvar math-integral-cache-state nil)
717
718 (defun math-integral-contains-parts (expr)
719 (if (Math-primp expr)
720 (and (eq (car-safe expr) 'var)
721 (eq (nth 1 expr) 'PARTS)
722 (listp (nth 2 expr)))
723 (while (and (setq expr (cdr expr))
724 (not (math-integral-contains-parts (car expr)))))
725 expr))
726
727 (defun math-replace-integral-parts (expr)
728 (or (Math-primp expr)
729 (while (setq expr (cdr expr))
730 (and (consp (car expr))
731 (if (eq (car (car expr)) 'var)
732 (and (eq (nth 1 (car expr)) 'PARTS)
733 (consp (nth 2 (car expr)))
734 (if (listp (nth 1 (nth 2 (car expr))))
735 (progn
736 (setcar expr (nth 1 (nth 2 (car expr))))
737 (math-replace-integral-parts (cons 'foo expr)))
738 (setcar (cdr cur-record) 'cancelled)))
739 (math-replace-integral-parts (car expr)))))))
740
741 (defvar math-linear-subst-tried t
742 "Non-nil means that a linear substitution has been tried.")
743
744 (defun math-do-integral (expr)
745 (let ((math-linear-subst-tried nil)
746 t1 t2)
747 (or (cond ((not (math-expr-contains expr math-integ-var))
748 (math-mul expr math-integ-var))
749 ((equal expr math-integ-var)
750 (math-div (math-sqr expr) 2))
751 ((eq (car expr) '+)
752 (and (setq t1 (math-integral (nth 1 expr)))
753 (setq t2 (math-integral (nth 2 expr)))
754 (math-add t1 t2)))
755 ((eq (car expr) '-)
756 (and (setq t1 (math-integral (nth 1 expr)))
757 (setq t2 (math-integral (nth 2 expr)))
758 (math-sub t1 t2)))
759 ((eq (car expr) 'neg)
760 (and (setq t1 (math-integral (nth 1 expr)))
761 (math-neg t1)))
762 ((eq (car expr) '*)
763 (cond ((not (math-expr-contains (nth 1 expr) math-integ-var))
764 (and (setq t1 (math-integral (nth 2 expr)))
765 (math-mul (nth 1 expr) t1)))
766 ((not (math-expr-contains (nth 2 expr) math-integ-var))
767 (and (setq t1 (math-integral (nth 1 expr)))
768 (math-mul t1 (nth 2 expr))))
769 ((memq (car-safe (nth 1 expr)) '(+ -))
770 (math-integral (list (car (nth 1 expr))
771 (math-mul (nth 1 (nth 1 expr))
772 (nth 2 expr))
773 (math-mul (nth 2 (nth 1 expr))
774 (nth 2 expr)))
775 'yes t))
776 ((memq (car-safe (nth 2 expr)) '(+ -))
777 (math-integral (list (car (nth 2 expr))
778 (math-mul (nth 1 (nth 2 expr))
779 (nth 1 expr))
780 (math-mul (nth 2 (nth 2 expr))
781 (nth 1 expr)))
782 'yes t))))
783 ((eq (car expr) '/)
784 (cond ((and (not (math-expr-contains (nth 1 expr)
785 math-integ-var))
786 (not (math-equal-int (nth 1 expr) 1)))
787 (and (setq t1 (math-integral (math-div 1 (nth 2 expr))))
788 (math-mul (nth 1 expr) t1)))
789 ((not (math-expr-contains (nth 2 expr) math-integ-var))
790 (and (setq t1 (math-integral (nth 1 expr)))
791 (math-div t1 (nth 2 expr))))
792 ((and (eq (car-safe (nth 1 expr)) '*)
793 (not (math-expr-contains (nth 1 (nth 1 expr))
794 math-integ-var)))
795 (and (setq t1 (math-integral
796 (math-div (nth 2 (nth 1 expr))
797 (nth 2 expr))))
798 (math-mul t1 (nth 1 (nth 1 expr)))))
799 ((and (eq (car-safe (nth 1 expr)) '*)
800 (not (math-expr-contains (nth 2 (nth 1 expr))
801 math-integ-var)))
802 (and (setq t1 (math-integral
803 (math-div (nth 1 (nth 1 expr))
804 (nth 2 expr))))
805 (math-mul t1 (nth 2 (nth 1 expr)))))
806 ((and (eq (car-safe (nth 2 expr)) '*)
807 (not (math-expr-contains (nth 1 (nth 2 expr))
808 math-integ-var)))
809 (and (setq t1 (math-integral
810 (math-div (nth 1 expr)
811 (nth 2 (nth 2 expr)))))
812 (math-div t1 (nth 1 (nth 2 expr)))))
813 ((and (eq (car-safe (nth 2 expr)) '*)
814 (not (math-expr-contains (nth 2 (nth 2 expr))
815 math-integ-var)))
816 (and (setq t1 (math-integral
817 (math-div (nth 1 expr)
818 (nth 1 (nth 2 expr)))))
819 (math-div t1 (nth 2 (nth 2 expr)))))
820 ((eq (car-safe (nth 2 expr)) 'calcFunc-exp)
821 (math-integral
822 (math-mul (nth 1 expr)
823 (list 'calcFunc-exp
824 (math-neg (nth 1 (nth 2 expr)))))))))
825 ((eq (car expr) '^)
826 (cond ((not (math-expr-contains (nth 1 expr) math-integ-var))
827 (or (and (setq t1 (math-is-polynomial (nth 2 expr)
828 math-integ-var 1))
829 (math-div expr
830 (math-mul (nth 1 t1)
831 (math-normalize
832 (list 'calcFunc-ln
833 (nth 1 expr))))))
834 (math-integral
835 (list 'calcFunc-exp
836 (math-mul (nth 2 expr)
837 (math-normalize
838 (list 'calcFunc-ln
839 (nth 1 expr)))))
840 'yes t)))
841 ((not (math-expr-contains (nth 2 expr) math-integ-var))
842 (if (and (integerp (nth 2 expr)) (< (nth 2 expr) 0))
843 (math-integral
844 (list '/ 1 (math-pow (nth 1 expr) (- (nth 2 expr))))
845 nil t)
846 (or (and (setq t1 (math-is-polynomial (nth 1 expr)
847 math-integ-var
848 1))
849 (setq t2 (math-add (nth 2 expr) 1))
850 (math-div (math-pow (nth 1 expr) t2)
851 (math-mul t2 (nth 1 t1))))
852 (and (Math-negp (nth 2 expr))
853 (math-integral
854 (math-div 1
855 (math-pow (nth 1 expr)
856 (math-neg
857 (nth 2 expr))))
858 nil t))
859 nil))))))
860
861 ;; Integral of a polynomial.
862 (and (setq t1 (math-is-polynomial expr math-integ-var 20))
863 (let ((accum 0)
864 (n 1))
865 (while t1
866 (if (setq accum (math-add accum
867 (math-div (math-mul (car t1)
868 (math-pow
869 math-integ-var
870 n))
871 n))
872 t1 (cdr t1))
873 (setq n (1+ n))))
874 accum))
875
876 ;; Try looking it up!
877 (cond ((= (length expr) 2)
878 (and (symbolp (car expr))
879 (setq t1 (get (car expr) 'math-integral))
880 (progn
881 (while (and t1
882 (not (setq t2 (funcall (car t1)
883 (nth 1 expr)))))
884 (setq t1 (cdr t1)))
885 (and t2 (math-normalize t2)))))
886 ((= (length expr) 3)
887 (and (symbolp (car expr))
888 (setq t1 (get (car expr) 'math-integral-2))
889 (progn
890 (while (and t1
891 (not (setq t2 (funcall (car t1)
892 (nth 1 expr)
893 (nth 2 expr)))))
894 (setq t1 (cdr t1)))
895 (and t2 (math-normalize t2))))))
896
897 ;; Integral of a rational function.
898 (and (math-ratpoly-p expr math-integ-var)
899 (setq t1 (calcFunc-apart expr math-integ-var))
900 (not (equal t1 expr))
901 (math-integral t1))
902
903 ;; Try user-defined integration rules.
904 (and has-rules
905 (let ((math-old-integ (symbol-function 'calcFunc-integ))
906 (input (list 'calcFunc-integtry expr math-integ-var))
907 res part)
908 (unwind-protect
909 (progn
910 (fset 'calcFunc-integ 'math-sub-integration)
911 (setq res (math-rewrite input
912 '(var IntegRules var-IntegRules)
913 1))
914 (fset 'calcFunc-integ math-old-integ)
915 (and (not (equal res input))
916 (if (setq part (math-expr-calls
917 res '(calcFunc-integsubst)))
918 (and (memq (length part) '(3 4 5))
919 (let ((parts (mapcar
920 (function
921 (lambda (x)
922 (math-expr-subst
923 x (nth 2 part)
924 math-integ-var)))
925 (cdr part))))
926 (math-integrate-by-substitution
927 expr (car parts) t
928 (or (nth 2 parts)
929 (list 'calcFunc-integfailed
930 math-integ-var))
931 (nth 3 parts))))
932 (if (not (math-expr-calls res
933 '(calcFunc-integtry
934 calcFunc-integfailed)))
935 res))))
936 (fset 'calcFunc-integ math-old-integ))))
937
938 ;; See if the function is a symbolic derivative.
939 (and (string-match "'" (symbol-name (car expr)))
940 (let ((name (symbol-name (car expr)))
941 (p expr) (n 0) (which nil) (bad nil))
942 (while (setq n (1+ n) p (cdr p))
943 (if (equal (car p) math-integ-var)
944 (if which (setq bad t) (setq which n))
945 (if (math-expr-contains (car p) math-integ-var)
946 (setq bad t))))
947 (and which (not bad)
948 (let ((prime (if (= which 1) "'" (format "'%d" which))))
949 (and (string-match (concat prime "\\('['0-9]*\\|$\\)")
950 name)
951 (cons (intern
952 (concat
953 (substring name 0 (match-beginning 0))
954 (substring name (+ (match-beginning 0)
955 (length prime)))))
956 (cdr expr)))))))
957
958 ;; Try transformation methods (parts, substitutions).
959 (and (> math-integ-level 0)
960 (math-do-integral-methods expr))
961
962 ;; Try expanding the function's definition.
963 (let ((res (math-expand-formula expr)))
964 (and res
965 (math-integral res))))))
966
967 (defun math-sub-integration (expr &rest rest)
968 (or (if (or (not rest)
969 (and (< math-integ-level math-integral-limit)
970 (eq (car rest) math-integ-var)))
971 (math-integral expr)
972 (let ((res (apply math-old-integ expr rest)))
973 (and (or (= math-integ-level math-integral-limit)
974 (not (math-expr-calls res 'calcFunc-integ)))
975 res)))
976 (list 'calcFunc-integfailed expr)))
977
978 (defun math-do-integral-methods (expr)
979 (let ((so-far math-integ-var-list-list)
980 rat-in)
981
982 ;; Integration by substitution, for various likely sub-expressions.
983 ;; (In first pass, we look only for sub-exprs that are linear in X.)
984 (or (math-integ-try-linear-substitutions expr)
985 (math-integ-try-substitutions expr)
986
987 ;; If function has sines and cosines, try tan(x/2) substitution.
988 (and (let ((p (setq rat-in (math-expr-rational-in expr))))
989 (while (and p
990 (memq (car (car p)) '(calcFunc-sin
991 calcFunc-cos
992 calcFunc-tan))
993 (equal (nth 1 (car p)) math-integ-var))
994 (setq p (cdr p)))
995 (null p))
996 (or (and (math-integ-parts-easy expr)
997 (math-integ-try-parts expr t))
998 (math-integrate-by-good-substitution
999 expr (list 'calcFunc-tan (math-div math-integ-var 2)))))
1000
1001 ;; If function has sinh and cosh, try tanh(x/2) substitution.
1002 (and (let ((p rat-in))
1003 (while (and p
1004 (memq (car (car p)) '(calcFunc-sinh
1005 calcFunc-cosh
1006 calcFunc-tanh
1007 calcFunc-exp))
1008 (equal (nth 1 (car p)) math-integ-var))
1009 (setq p (cdr p)))
1010 (null p))
1011 (or (and (math-integ-parts-easy expr)
1012 (math-integ-try-parts expr t))
1013 (math-integrate-by-good-substitution
1014 expr (list 'calcFunc-tanh (math-div math-integ-var 2)))))
1015
1016 ;; If function has square roots, try sin, tan, or sec substitution.
1017 (and (let ((p rat-in))
1018 (setq t1 nil)
1019 (while (and p
1020 (or (equal (car p) math-integ-var)
1021 (and (eq (car (car p)) 'calcFunc-sqrt)
1022 (setq t1 (math-is-polynomial
1023 (nth 1 (setq t2 (car p)))
1024 math-integ-var 2)))))
1025 (setq p (cdr p)))
1026 (and (null p) t1))
1027 (if (cdr (cdr t1))
1028 (if (math-guess-if-neg (nth 2 t1))
1029 (let* ((c (math-sqrt (math-neg (nth 2 t1))))
1030 (d (math-div (nth 1 t1) (math-mul -2 c)))
1031 (a (math-sqrt (math-add (car t1) (math-sqr d)))))
1032 (math-integrate-by-good-substitution
1033 expr (list 'calcFunc-arcsin
1034 (math-div-thru
1035 (math-add (math-mul c math-integ-var) d)
1036 a))))
1037 (let* ((c (math-sqrt (nth 2 t1)))
1038 (d (math-div (nth 1 t1) (math-mul 2 c)))
1039 (aa (math-sub (car t1) (math-sqr d))))
1040 (if (and nil (not (and (eq d 0) (eq c 1))))
1041 (math-integrate-by-good-substitution
1042 expr (math-add (math-mul c math-integ-var) d))
1043 (if (math-guess-if-neg aa)
1044 (math-integrate-by-good-substitution
1045 expr (list 'calcFunc-arccosh
1046 (math-div-thru
1047 (math-add (math-mul c math-integ-var)
1048 d)
1049 (math-sqrt (math-neg aa)))))
1050 (math-integrate-by-good-substitution
1051 expr (list 'calcFunc-arcsinh
1052 (math-div-thru
1053 (math-add (math-mul c math-integ-var)
1054 d)
1055 (math-sqrt aa))))))))
1056 (math-integrate-by-good-substitution expr t2)) )
1057
1058 ;; Try integration by parts.
1059 (math-integ-try-parts expr)
1060
1061 ;; Give up.
1062 nil)))
1063
1064 (defun math-integ-parts-easy (expr)
1065 (cond ((Math-primp expr) t)
1066 ((memq (car expr) '(+ - *))
1067 (and (math-integ-parts-easy (nth 1 expr))
1068 (math-integ-parts-easy (nth 2 expr))))
1069 ((eq (car expr) '/)
1070 (and (math-integ-parts-easy (nth 1 expr))
1071 (math-atomic-factorp (nth 2 expr))))
1072 ((eq (car expr) '^)
1073 (and (natnump (nth 2 expr))
1074 (math-integ-parts-easy (nth 1 expr))))
1075 ((eq (car expr) 'neg)
1076 (math-integ-parts-easy (nth 1 expr)))
1077 (t t)))
1078
1079 (defun math-integ-try-parts (expr &optional math-good-parts)
1080 ;; Integration by parts:
1081 ;; integ(f(x) g(x),x) = f(x) h(x) - integ(h(x) f'(x),x)
1082 ;; where h(x) = integ(g(x),x).
1083 (or (let ((exp (calcFunc-expand expr)))
1084 (and (not (equal exp expr))
1085 (math-integral exp)))
1086 (and (eq (car expr) '*)
1087 (let ((first-bad (or (math-polynomial-p (nth 1 expr)
1088 math-integ-var)
1089 (equal (nth 2 expr) math-prev-parts-v))))
1090 (or (and first-bad ; so try this one first
1091 (math-integrate-by-parts (nth 1 expr) (nth 2 expr)))
1092 (math-integrate-by-parts (nth 2 expr) (nth 1 expr))
1093 (and (not first-bad)
1094 (math-integrate-by-parts (nth 1 expr) (nth 2 expr))))))
1095 (and (eq (car expr) '/)
1096 (math-expr-contains (nth 1 expr) math-integ-var)
1097 (let ((recip (math-div 1 (nth 2 expr))))
1098 (or (math-integrate-by-parts (nth 1 expr) recip)
1099 (math-integrate-by-parts recip (nth 1 expr)))))
1100 (and (eq (car expr) '^)
1101 (math-integrate-by-parts (math-pow (nth 1 expr)
1102 (math-sub (nth 2 expr) 1))
1103 (nth 1 expr)))))
1104
1105 (defun math-integrate-by-parts (u vprime)
1106 (let ((math-integ-level (if (or math-good-parts
1107 (math-polynomial-p u math-integ-var))
1108 math-integ-level
1109 (1- math-integ-level)))
1110 (math-doing-parts t)
1111 v temp)
1112 (and (>= math-integ-level 0)
1113 (unwind-protect
1114 (progn
1115 (setcar (cdr cur-record) 'parts)
1116 (math-tracing-integral "Integrating by parts, u = "
1117 (math-format-value u 1000)
1118 ", v' = "
1119 (math-format-value vprime 1000)
1120 "\n")
1121 (and (setq v (math-integral vprime))
1122 (setq temp (calcFunc-deriv u math-integ-var nil t))
1123 (setq temp (let ((math-prev-parts-v v))
1124 (math-integral (math-mul v temp) 'yes)))
1125 (setq temp (math-sub (math-mul u v) temp))
1126 (if (eq (nth 1 cur-record) 'parts)
1127 (calcFunc-expand temp)
1128 (setq v (list 'var 'PARTS cur-record)
1129 var-thing (list 'vec (math-sub v temp) v)
1130 temp (let (calc-next-why)
1131 (math-solve-for (math-sub v temp) 0 v nil)))
1132 (and temp (not (integerp temp))
1133 (math-simplify-extended temp)))))
1134 (setcar (cdr cur-record) 'busy)))))
1135
1136 ;;; This tries two different formulations, hoping the algebraic simplifier
1137 ;;; will be strong enough to handle at least one.
1138 (defun math-integrate-by-substitution (expr u &optional user uinv uinvprime)
1139 (and (> math-integ-level 0)
1140 (let ((math-integ-level (max (- math-integ-level 2) 0)))
1141 (math-integrate-by-good-substitution expr u user uinv uinvprime))))
1142
1143 (defun math-integrate-by-good-substitution (expr u &optional user
1144 uinv uinvprime)
1145 (let ((math-living-dangerously t)
1146 deriv temp)
1147 (and (setq uinv (if uinv
1148 (math-expr-subst uinv math-integ-var
1149 math-integ-var-2)
1150 (let (calc-next-why)
1151 (math-solve-for u
1152 math-integ-var-2
1153 math-integ-var nil))))
1154 (progn
1155 (math-tracing-integral "Integrating by substitution, u = "
1156 (math-format-value u 1000)
1157 "\n")
1158 (or (and (setq deriv (calcFunc-deriv u
1159 math-integ-var nil
1160 (not user)))
1161 (setq temp (math-integral (math-expr-subst
1162 (math-expr-subst
1163 (math-expr-subst
1164 (math-div expr deriv)
1165 u
1166 math-integ-var-2)
1167 math-integ-var
1168 uinv)
1169 math-integ-var-2
1170 math-integ-var)
1171 'yes)))
1172 (and (setq deriv (or uinvprime
1173 (calcFunc-deriv uinv
1174 math-integ-var-2
1175 math-integ-var
1176 (not user))))
1177 (setq temp (math-integral (math-mul
1178 (math-expr-subst
1179 (math-expr-subst
1180 (math-expr-subst
1181 expr
1182 u
1183 math-integ-var-2)
1184 math-integ-var
1185 uinv)
1186 math-integ-var-2
1187 math-integ-var)
1188 deriv)
1189 'yes)))))
1190 (math-simplify-extended
1191 (math-expr-subst temp math-integ-var u)))))
1192
1193 ;;; Look for substitutions of the form u = a x + b.
1194 (defun math-integ-try-linear-substitutions (sub-expr)
1195 (setq math-linear-subst-tried t)
1196 (and (not (Math-primp sub-expr))
1197 (or (and (not (memq (car sub-expr) '(+ - * / neg)))
1198 (not (and (eq (car sub-expr) '^)
1199 (integerp (nth 2 sub-expr))))
1200 (math-expr-contains sub-expr math-integ-var)
1201 (let ((res nil))
1202 (while (and (setq sub-expr (cdr sub-expr))
1203 (or (not (math-linear-in (car sub-expr)
1204 math-integ-var))
1205 (assoc (car sub-expr) so-far)
1206 (progn
1207 (setq so-far (cons (list (car sub-expr))
1208 so-far))
1209 (not (setq res
1210 (math-integrate-by-substitution
1211 expr (car sub-expr))))))))
1212 res))
1213 (let ((res nil))
1214 (while (and (setq sub-expr (cdr sub-expr))
1215 (not (setq res (math-integ-try-linear-substitutions
1216 (car sub-expr))))))
1217 res))))
1218
1219 ;;; Recursively try different substitutions based on various sub-expressions.
1220 (defun math-integ-try-substitutions (sub-expr &optional allow-rat)
1221 (and (not (Math-primp sub-expr))
1222 (not (assoc sub-expr so-far))
1223 (math-expr-contains sub-expr math-integ-var)
1224 (or (and (if (and (not (memq (car sub-expr) '(+ - * / neg)))
1225 (not (and (eq (car sub-expr) '^)
1226 (integerp (nth 2 sub-expr)))))
1227 (setq allow-rat t)
1228 (prog1 allow-rat (setq allow-rat nil)))
1229 (not (eq sub-expr expr))
1230 (or (math-integrate-by-substitution expr sub-expr)
1231 (and (eq (car sub-expr) '^)
1232 (integerp (nth 2 sub-expr))
1233 (< (nth 2 sub-expr) 0)
1234 (math-integ-try-substitutions
1235 (math-pow (nth 1 sub-expr) (- (nth 2 sub-expr)))
1236 t))))
1237 (let ((res nil))
1238 (setq so-far (cons (list sub-expr) so-far))
1239 (while (and (setq sub-expr (cdr sub-expr))
1240 (not (setq res (math-integ-try-substitutions
1241 (car sub-expr) allow-rat)))))
1242 res))))
1243
1244 (defun math-expr-rational-in (expr)
1245 (let ((parts nil))
1246 (math-expr-rational-in-rec expr)
1247 (mapcar 'car parts)))
1248
1249 (defun math-expr-rational-in-rec (expr)
1250 (cond ((Math-primp expr)
1251 (and (equal expr math-integ-var)
1252 (not (assoc expr parts))
1253 (setq parts (cons (list expr) parts))))
1254 ((or (memq (car expr) '(+ - * / neg))
1255 (and (eq (car expr) '^) (integerp (nth 2 expr))))
1256 (math-expr-rational-in-rec (nth 1 expr))
1257 (and (nth 2 expr) (math-expr-rational-in-rec (nth 2 expr))))
1258 ((and (eq (car expr) '^)
1259 (eq (math-quarter-integer (nth 2 expr)) 2))
1260 (math-expr-rational-in-rec (list 'calcFunc-sqrt (nth 1 expr))))
1261 (t
1262 (and (not (assoc expr parts))
1263 (math-expr-contains expr math-integ-var)
1264 (setq parts (cons (list expr) parts))))))
1265
1266 (defun math-expr-calls (expr funcs &optional arg-contains)
1267 (if (consp expr)
1268 (if (or (memq (car expr) funcs)
1269 (and (eq (car expr) '^) (eq (car funcs) 'calcFunc-sqrt)
1270 (eq (math-quarter-integer (nth 2 expr)) 2)))
1271 (and (or (not arg-contains)
1272 (math-expr-contains expr arg-contains))
1273 expr)
1274 (and (not (Math-primp expr))
1275 (let ((res nil))
1276 (while (and (setq expr (cdr expr))
1277 (not (setq res (math-expr-calls
1278 (car expr) funcs arg-contains)))))
1279 res)))))
1280
1281 (defun math-fix-const-terms (expr except-vars)
1282 (cond ((not (math-expr-depends expr except-vars)) 0)
1283 ((Math-primp expr) expr)
1284 ((eq (car expr) '+)
1285 (math-add (math-fix-const-terms (nth 1 expr) except-vars)
1286 (math-fix-const-terms (nth 2 expr) except-vars)))
1287 ((eq (car expr) '-)
1288 (math-sub (math-fix-const-terms (nth 1 expr) except-vars)
1289 (math-fix-const-terms (nth 2 expr) except-vars)))
1290 (t expr)))
1291
1292 ;; Command for debugging the Calculator's symbolic integrator.
1293 (defun calc-dump-integral-cache (&optional arg)
1294 (interactive "P")
1295 (let ((buf (current-buffer)))
1296 (unwind-protect
1297 (let ((p math-integral-cache)
1298 cur-record)
1299 (display-buffer (get-buffer-create "*Integral Cache*"))
1300 (set-buffer (get-buffer "*Integral Cache*"))
1301 (erase-buffer)
1302 (while p
1303 (setq cur-record (car p))
1304 (or arg (math-replace-integral-parts cur-record))
1305 (insert (math-format-flat-expr (car cur-record) 0)
1306 " --> "
1307 (if (symbolp (nth 1 cur-record))
1308 (concat "(" (symbol-name (nth 1 cur-record)) ")")
1309 (math-format-flat-expr (nth 1 cur-record) 0))
1310 "\n")
1311 (setq p (cdr p)))
1312 (goto-char (point-min)))
1313 (set-buffer buf))))
1314
1315 (defun math-try-integral (expr)
1316 (let ((math-integ-level math-integral-limit)
1317 (math-integ-depth 0)
1318 (math-integ-msg "Working...done")
1319 (cur-record nil) ; a technicality
1320 (math-integrating t)
1321 (calc-prefer-frac t)
1322 (calc-symbolic-mode t)
1323 (has-rules (calc-has-rules 'var-IntegRules)))
1324 (or (math-integral expr 'yes)
1325 (and math-any-substs
1326 (setq math-enable-subst t)
1327 (math-integral expr 'yes))
1328 (and (> math-max-integral-limit math-integral-limit)
1329 (setq math-integral-limit math-max-integral-limit
1330 math-integ-level math-integral-limit)
1331 (math-integral expr 'yes)))))
1332
1333 (defun calcFunc-integ (expr var &optional low high)
1334 (cond
1335 ;; Do these even if the parts turn out not to be integrable.
1336 ((eq (car-safe expr) '+)
1337 (math-add (calcFunc-integ (nth 1 expr) var low high)
1338 (calcFunc-integ (nth 2 expr) var low high)))
1339 ((eq (car-safe expr) '-)
1340 (math-sub (calcFunc-integ (nth 1 expr) var low high)
1341 (calcFunc-integ (nth 2 expr) var low high)))
1342 ((eq (car-safe expr) 'neg)
1343 (math-neg (calcFunc-integ (nth 1 expr) var low high)))
1344 ((and (eq (car-safe expr) '*)
1345 (not (math-expr-contains (nth 1 expr) var)))
1346 (math-mul (nth 1 expr) (calcFunc-integ (nth 2 expr) var low high)))
1347 ((and (eq (car-safe expr) '*)
1348 (not (math-expr-contains (nth 2 expr) var)))
1349 (math-mul (calcFunc-integ (nth 1 expr) var low high) (nth 2 expr)))
1350 ((and (eq (car-safe expr) '/)
1351 (not (math-expr-contains (nth 1 expr) var))
1352 (not (math-equal-int (nth 1 expr) 1)))
1353 (math-mul (nth 1 expr)
1354 (calcFunc-integ (math-div 1 (nth 2 expr)) var low high)))
1355 ((and (eq (car-safe expr) '/)
1356 (not (math-expr-contains (nth 2 expr) var)))
1357 (math-div (calcFunc-integ (nth 1 expr) var low high) (nth 2 expr)))
1358 ((and (eq (car-safe expr) '/)
1359 (eq (car-safe (nth 1 expr)) '*)
1360 (not (math-expr-contains (nth 1 (nth 1 expr)) var)))
1361 (math-mul (nth 1 (nth 1 expr))
1362 (calcFunc-integ (math-div (nth 2 (nth 1 expr)) (nth 2 expr))
1363 var low high)))
1364 ((and (eq (car-safe expr) '/)
1365 (eq (car-safe (nth 1 expr)) '*)
1366 (not (math-expr-contains (nth 2 (nth 1 expr)) var)))
1367 (math-mul (nth 2 (nth 1 expr))
1368 (calcFunc-integ (math-div (nth 1 (nth 1 expr)) (nth 2 expr))
1369 var low high)))
1370 ((and (eq (car-safe expr) '/)
1371 (eq (car-safe (nth 2 expr)) '*)
1372 (not (math-expr-contains (nth 1 (nth 2 expr)) var)))
1373 (math-div (calcFunc-integ (math-div (nth 1 expr) (nth 2 (nth 2 expr)))
1374 var low high)
1375 (nth 1 (nth 2 expr))))
1376 ((and (eq (car-safe expr) '/)
1377 (eq (car-safe (nth 2 expr)) '*)
1378 (not (math-expr-contains (nth 2 (nth 2 expr)) var)))
1379 (math-div (calcFunc-integ (math-div (nth 1 expr) (nth 1 (nth 2 expr)))
1380 var low high)
1381 (nth 2 (nth 2 expr))))
1382 ((eq (car-safe expr) 'vec)
1383 (cons 'vec (mapcar (function (lambda (x) (calcFunc-integ x var low high)))
1384 (cdr expr))))
1385 (t
1386 (let ((state (list calc-angle-mode
1387 ;;calc-symbolic-mode
1388 ;;calc-prefer-frac
1389 calc-internal-prec
1390 (calc-var-value 'var-IntegRules)
1391 (calc-var-value 'var-IntegSimpRules))))
1392 (or (equal state math-integral-cache-state)
1393 (setq math-integral-cache-state state
1394 math-integral-cache nil)))
1395 (let* ((math-max-integral-limit (or (and (boundp 'var-IntegLimit)
1396 (natnump var-IntegLimit)
1397 var-IntegLimit)
1398 3))
1399 (math-integral-limit 1)
1400 (sexpr (math-expr-subst expr var math-integ-var))
1401 (trace-buffer (get-buffer "*Trace*"))
1402 (calc-language (if (eq calc-language 'big) nil calc-language))
1403 (math-any-substs t)
1404 (math-enable-subst nil)
1405 (math-prev-parts-v nil)
1406 (math-doing-parts nil)
1407 (math-good-parts nil)
1408 (res
1409 (if trace-buffer
1410 (let ((calcbuf (current-buffer))
1411 (calcwin (selected-window)))
1412 (unwind-protect
1413 (progn
1414 (if (get-buffer-window trace-buffer)
1415 (select-window (get-buffer-window trace-buffer)))
1416 (set-buffer trace-buffer)
1417 (goto-char (point-max))
1418 (or (assq 'scroll-stop (buffer-local-variables))
1419 (progn
1420 (make-local-variable 'scroll-step)
1421 (setq scroll-step 3)))
1422 (insert "\n\n\n")
1423 (set-buffer calcbuf)
1424 (math-try-integral sexpr))
1425 (select-window calcwin)
1426 (set-buffer calcbuf)))
1427 (math-try-integral sexpr))))
1428 (if res
1429 (progn
1430 (if (calc-has-rules 'var-IntegAfterRules)
1431 (setq res (math-rewrite res '(var IntegAfterRules
1432 var-IntegAfterRules))))
1433 (math-simplify
1434 (if (and low high)
1435 (math-sub (math-expr-subst res math-integ-var high)
1436 (math-expr-subst res math-integ-var low))
1437 (setq res (math-fix-const-terms res math-integ-vars))
1438 (if low
1439 (math-expr-subst res math-integ-var low)
1440 (math-expr-subst res math-integ-var var)))))
1441 (append (list 'calcFunc-integ expr var)
1442 (and low (list low))
1443 (and high (list high))))))))
1444
1445
1446 (math-defintegral calcFunc-inv
1447 (math-integral (math-div 1 u)))
1448
1449 (math-defintegral calcFunc-conj
1450 (let ((int (math-integral u)))
1451 (and int
1452 (list 'calcFunc-conj int))))
1453
1454 (math-defintegral calcFunc-deg
1455 (let ((int (math-integral u)))
1456 (and int
1457 (list 'calcFunc-deg int))))
1458
1459 (math-defintegral calcFunc-rad
1460 (let ((int (math-integral u)))
1461 (and int
1462 (list 'calcFunc-rad int))))
1463
1464 (math-defintegral calcFunc-re
1465 (let ((int (math-integral u)))
1466 (and int
1467 (list 'calcFunc-re int))))
1468
1469 (math-defintegral calcFunc-im
1470 (let ((int (math-integral u)))
1471 (and int
1472 (list 'calcFunc-im int))))
1473
1474 (math-defintegral calcFunc-sqrt
1475 (and (equal u math-integ-var)
1476 (math-mul '(frac 2 3)
1477 (list 'calcFunc-sqrt (math-pow u 3)))))
1478
1479 (math-defintegral calcFunc-exp
1480 (or (and (equal u math-integ-var)
1481 (list 'calcFunc-exp u))
1482 (let ((p (math-is-polynomial u math-integ-var 2)))
1483 (and (nth 2 p)
1484 (let ((sqa (math-sqrt (math-neg (nth 2 p)))))
1485 (math-div
1486 (math-mul
1487 (math-mul (math-div (list 'calcFunc-sqrt '(var pi var-pi))
1488 sqa)
1489 (math-normalize
1490 (list 'calcFunc-exp
1491 (math-div (math-sub (math-mul (car p)
1492 (nth 2 p))
1493 (math-div
1494 (math-sqr (nth 1 p))
1495 4))
1496 (nth 2 p)))))
1497 (list 'calcFunc-erf
1498 (math-sub (math-mul sqa math-integ-var)
1499 (math-div (nth 1 p) (math-mul 2 sqa)))))
1500 2))))))
1501
1502 (math-defintegral calcFunc-ln
1503 (or (and (equal u math-integ-var)
1504 (math-sub (math-mul u (list 'calcFunc-ln u)) u))
1505 (and (eq (car u) '*)
1506 (math-integral (math-add (list 'calcFunc-ln (nth 1 u))
1507 (list 'calcFunc-ln (nth 2 u)))))
1508 (and (eq (car u) '/)
1509 (math-integral (math-sub (list 'calcFunc-ln (nth 1 u))
1510 (list 'calcFunc-ln (nth 2 u)))))
1511 (and (eq (car u) '^)
1512 (math-integral (math-mul (nth 2 u)
1513 (list 'calcFunc-ln (nth 1 u)))))))
1514
1515 (math-defintegral calcFunc-log10
1516 (and (equal u math-integ-var)
1517 (math-sub (math-mul u (list 'calcFunc-ln u))
1518 (math-div u (list 'calcFunc-ln 10)))))
1519
1520 (math-defintegral-2 calcFunc-log
1521 (math-integral (math-div (list 'calcFunc-ln u)
1522 (list 'calcFunc-ln v))))
1523
1524 (math-defintegral calcFunc-sin
1525 (or (and (equal u math-integ-var)
1526 (math-neg (math-from-radians-2 (list 'calcFunc-cos u))))
1527 (and (nth 2 (math-is-polynomial u math-integ-var 2))
1528 (math-integral (math-to-exponentials (list 'calcFunc-sin u))))))
1529
1530 (math-defintegral calcFunc-cos
1531 (or (and (equal u math-integ-var)
1532 (math-from-radians-2 (list 'calcFunc-sin u)))
1533 (and (nth 2 (math-is-polynomial u math-integ-var 2))
1534 (math-integral (math-to-exponentials (list 'calcFunc-cos u))))))
1535
1536 (math-defintegral calcFunc-tan
1537 (and (equal u math-integ-var)
1538 (math-neg (math-from-radians-2
1539 (list 'calcFunc-ln (list 'calcFunc-cos u))))))
1540
1541 (math-defintegral calcFunc-arcsin
1542 (and (equal u math-integ-var)
1543 (math-add (math-mul u (list 'calcFunc-arcsin u))
1544 (math-from-radians-2
1545 (list 'calcFunc-sqrt (math-sub 1 (math-sqr u)))))))
1546
1547 (math-defintegral calcFunc-arccos
1548 (and (equal u math-integ-var)
1549 (math-sub (math-mul u (list 'calcFunc-arccos u))
1550 (math-from-radians-2
1551 (list 'calcFunc-sqrt (math-sub 1 (math-sqr u)))))))
1552
1553 (math-defintegral calcFunc-arctan
1554 (and (equal u math-integ-var)
1555 (math-sub (math-mul u (list 'calcFunc-arctan u))
1556 (math-from-radians-2
1557 (math-div (list 'calcFunc-ln (math-add 1 (math-sqr u)))
1558 2)))))
1559
1560 (math-defintegral calcFunc-sinh
1561 (and (equal u math-integ-var)
1562 (list 'calcFunc-cosh u)))
1563
1564 (math-defintegral calcFunc-cosh
1565 (and (equal u math-integ-var)
1566 (list 'calcFunc-sinh u)))
1567
1568 (math-defintegral calcFunc-tanh
1569 (and (equal u math-integ-var)
1570 (list 'calcFunc-ln (list 'calcFunc-cosh u))))
1571
1572 (math-defintegral calcFunc-arcsinh
1573 (and (equal u math-integ-var)
1574 (math-sub (math-mul u (list 'calcFunc-arcsinh u))
1575 (list 'calcFunc-sqrt (math-add (math-sqr u) 1)))))
1576
1577 (math-defintegral calcFunc-arccosh
1578 (and (equal u math-integ-var)
1579 (math-sub (math-mul u (list 'calcFunc-arccosh u))
1580 (list 'calcFunc-sqrt (math-sub 1 (math-sqr u))))))
1581
1582 (math-defintegral calcFunc-arctanh
1583 (and (equal u math-integ-var)
1584 (math-sub (math-mul u (list 'calcFunc-arctan u))
1585 (math-div (list 'calcFunc-ln
1586 (math-add 1 (math-sqr u)))
1587 2))))
1588
1589 ;;; (Ax + B) / (ax^2 + bx + c)^n forms.
1590 (math-defintegral-2 /
1591 (math-integral-rational-funcs u v))
1592
1593 (defun math-integral-rational-funcs (u v)
1594 (let ((pu (math-is-polynomial u math-integ-var 1))
1595 (vpow 1) pv)
1596 (and pu
1597 (catch 'int-rat
1598 (if (and (eq (car-safe v) '^) (natnump (nth 2 v)))
1599 (setq vpow (nth 2 v)
1600 v (nth 1 v)))
1601 (and (setq pv (math-is-polynomial v math-integ-var 2))
1602 (let ((int (math-mul-thru
1603 (car pu)
1604 (math-integral-q02 (car pv) (nth 1 pv)
1605 (nth 2 pv) v vpow))))
1606 (if (cdr pu)
1607 (setq int (math-add int
1608 (math-mul-thru
1609 (nth 1 pu)
1610 (math-integral-q12
1611 (car pv) (nth 1 pv)
1612 (nth 2 pv) v vpow)))))
1613 int))))))
1614
1615 (defun math-integral-q12 (a b c v vpow)
1616 (let (q)
1617 (cond ((not c)
1618 (cond ((= vpow 1)
1619 (math-sub (math-div math-integ-var b)
1620 (math-mul (math-div a (math-sqr b))
1621 (list 'calcFunc-ln v))))
1622 ((= vpow 2)
1623 (math-div (math-add (list 'calcFunc-ln v)
1624 (math-div a v))
1625 (math-sqr b)))
1626 (t
1627 (let ((nm1 (math-sub vpow 1))
1628 (nm2 (math-sub vpow 2)))
1629 (math-div (math-sub
1630 (math-div a (math-mul nm1 (math-pow v nm1)))
1631 (math-div 1 (math-mul nm2 (math-pow v nm2))))
1632 (math-sqr b))))))
1633 ((math-zerop
1634 (setq q (math-sub (math-mul 4 (math-mul a c)) (math-sqr b))))
1635 (let ((part (math-div b (math-mul 2 c))))
1636 (math-mul-thru (math-pow c vpow)
1637 (math-integral-q12 part 1 nil
1638 (math-add math-integ-var part)
1639 (* vpow 2)))))
1640 ((= vpow 1)
1641 (and (math-ratp q) (math-negp q)
1642 (let ((calc-symbolic-mode t))
1643 (math-ratp (math-sqrt (math-neg q))))
1644 (throw 'int-rat nil)) ; should have used calcFunc-apart first
1645 (math-sub (math-div (list 'calcFunc-ln v) (math-mul 2 c))
1646 (math-mul-thru (math-div b (math-mul 2 c))
1647 (math-integral-q02 a b c v 1))))
1648 (t
1649 (let ((n (1- vpow)))
1650 (math-sub (math-neg (math-div
1651 (math-add (math-mul b math-integ-var)
1652 (math-mul 2 a))
1653 (math-mul n (math-mul q (math-pow v n)))))
1654 (math-mul-thru (math-div (math-mul b (1- (* 2 n)))
1655 (math-mul n q))
1656 (math-integral-q02 a b c v n))))))))
1657
1658 (defun math-integral-q02 (a b c v vpow)
1659 (let (q rq part)
1660 (cond ((not c)
1661 (cond ((= vpow 1)
1662 (math-div (list 'calcFunc-ln v) b))
1663 (t
1664 (math-div (math-pow v (- 1 vpow))
1665 (math-mul (- 1 vpow) b)))))
1666 ((math-zerop
1667 (setq q (math-sub (math-mul 4 (math-mul a c)) (math-sqr b))))
1668 (let ((part (math-div b (math-mul 2 c))))
1669 (math-mul-thru (math-pow c vpow)
1670 (math-integral-q02 part 1 nil
1671 (math-add math-integ-var part)
1672 (* vpow 2)))))
1673 ((progn
1674 (setq part (math-add (math-mul 2 (math-mul c math-integ-var)) b))
1675 (> vpow 1))
1676 (let ((n (1- vpow)))
1677 (math-add (math-div part (math-mul n (math-mul q (math-pow v n))))
1678 (math-mul-thru (math-div (math-mul (- (* 4 n) 2) c)
1679 (math-mul n q))
1680 (math-integral-q02 a b c v n)))))
1681 ((math-guess-if-neg q)
1682 (setq rq (list 'calcFunc-sqrt (math-neg q)))
1683 ;;(math-div-thru (list 'calcFunc-ln
1684 ;; (math-div (math-sub part rq)
1685 ;; (math-add part rq)))
1686 ;; rq)
1687 (math-div (math-mul -2 (list 'calcFunc-arctanh
1688 (math-div part rq)))
1689 rq))
1690 (t
1691 (setq rq (list 'calcFunc-sqrt q))
1692 (math-div (math-mul 2 (math-to-radians-2
1693 (list 'calcFunc-arctan
1694 (math-div part rq))))
1695 rq)))))
1696
1697
1698 (math-defintegral calcFunc-erf
1699 (and (equal u math-integ-var)
1700 (math-add (math-mul u (list 'calcFunc-erf u))
1701 (math-div 1 (math-mul (list 'calcFunc-exp (math-sqr u))
1702 (list 'calcFunc-sqrt
1703 '(var pi var-pi)))))))
1704
1705 (math-defintegral calcFunc-erfc
1706 (and (equal u math-integ-var)
1707 (math-sub (math-mul u (list 'calcFunc-erfc u))
1708 (math-div 1 (math-mul (list 'calcFunc-exp (math-sqr u))
1709 (list 'calcFunc-sqrt
1710 '(var pi var-pi)))))))
1711
1712
1713
1714
1715 (defvar math-tabulate-initial nil)
1716 (defvar math-tabulate-function nil)
1717 (defun calcFunc-table (expr var &optional low high step)
1718 (or low (setq low '(neg (var inf var-inf)) high '(var inf var-inf)))
1719 (or high (setq high low low 1))
1720 (and (or (math-infinitep low) (math-infinitep high))
1721 (not step)
1722 (math-scan-for-limits expr))
1723 (and step (math-zerop step) (math-reject-arg step 'nonzerop))
1724 (let ((known (+ (if (Math-objectp low) 1 0)
1725 (if (Math-objectp high) 1 0)
1726 (if (or (null step) (Math-objectp step)) 1 0)))
1727 (count '(var inf var-inf))
1728 vec)
1729 (or (= known 2) ; handy optimization
1730 (equal high '(var inf var-inf))
1731 (progn
1732 (setq count (math-div (math-sub high low) (or step 1)))
1733 (or (Math-objectp count)
1734 (setq count (math-simplify count)))
1735 (if (Math-messy-integerp count)
1736 (setq count (math-trunc count)))))
1737 (if (Math-negp count)
1738 (setq count -1))
1739 (if (integerp count)
1740 (let ((var-DUMMY nil)
1741 (vec math-tabulate-initial)
1742 (math-working-step-2 (1+ count))
1743 (math-working-step 0))
1744 (setq expr (math-evaluate-expr
1745 (math-expr-subst expr var '(var DUMMY var-DUMMY))))
1746 (while (>= count 0)
1747 (setq math-working-step (1+ math-working-step)
1748 var-DUMMY low
1749 vec (cond ((eq math-tabulate-function 'calcFunc-sum)
1750 (math-add vec (math-evaluate-expr expr)))
1751 ((eq math-tabulate-function 'calcFunc-prod)
1752 (math-mul vec (math-evaluate-expr expr)))
1753 (t
1754 (cons (math-evaluate-expr expr) vec)))
1755 low (math-add low (or step 1))
1756 count (1- count)))
1757 (if math-tabulate-function
1758 vec
1759 (cons 'vec (nreverse vec))))
1760 (if (Math-integerp count)
1761 (calc-record-why 'fixnump high)
1762 (if (Math-num-integerp low)
1763 (if (Math-num-integerp high)
1764 (calc-record-why 'integerp step)
1765 (calc-record-why 'integerp high))
1766 (calc-record-why 'integerp low)))
1767 (append (list (or math-tabulate-function 'calcFunc-table)
1768 expr var)
1769 (and (not (and (equal low '(neg (var inf var-inf)))
1770 (equal high '(var inf var-inf))))
1771 (list low high))
1772 (and step (list step))))))
1773
1774 (defun math-scan-for-limits (x)
1775 (cond ((Math-primp x))
1776 ((and (eq (car x) 'calcFunc-subscr)
1777 (Math-vectorp (nth 1 x))
1778 (math-expr-contains (nth 2 x) var))
1779 (let* ((calc-next-why nil)
1780 (low-val (math-solve-for (nth 2 x) 1 var nil))
1781 (high-val (math-solve-for (nth 2 x) (1- (length (nth 1 x)))
1782 var nil))
1783 temp)
1784 (and low-val (math-realp low-val)
1785 high-val (math-realp high-val))
1786 (and (Math-lessp high-val low-val)
1787 (setq temp low-val low-val high-val high-val temp))
1788 (setq low (math-max low (math-ceiling low-val))
1789 high (math-min high (math-floor high-val)))))
1790 (t
1791 (while (setq x (cdr x))
1792 (math-scan-for-limits (car x))))))
1793
1794
1795 (defvar math-disable-sums nil)
1796 (defun calcFunc-sum (expr var &optional low high step)
1797 (if math-disable-sums (math-reject-arg))
1798 (let* ((res (let* ((calc-internal-prec (+ calc-internal-prec 2)))
1799 (math-sum-rec expr var low high step)))
1800 (math-disable-sums t))
1801 (math-normalize res)))
1802
1803 (defun math-sum-rec (expr var &optional low high step)
1804 (or low (setq low '(neg (var inf var-inf)) high '(var inf var-inf)))
1805 (and low (not high) (setq high low low 1))
1806 (let (t1 t2 val)
1807 (setq val
1808 (cond
1809 ((not (math-expr-contains expr var))
1810 (math-mul expr (math-add (math-div (math-sub high low) (or step 1))
1811 1)))
1812 ((and step (not (math-equal-int step 1)))
1813 (if (math-negp step)
1814 (math-sum-rec expr var high low (math-neg step))
1815 (let ((lo (math-simplify (math-div low step))))
1816 (if (math-known-num-integerp lo)
1817 (math-sum-rec (math-normalize
1818 (math-expr-subst expr var
1819 (math-mul step var)))
1820 var lo (math-simplify (math-div high step)))
1821 (math-sum-rec (math-normalize
1822 (math-expr-subst expr var
1823 (math-add (math-mul step var)
1824 low)))
1825 var 0
1826 (math-simplify (math-div (math-sub high low)
1827 step)))))))
1828 ((memq (setq t1 (math-compare low high)) '(0 1))
1829 (if (eq t1 0)
1830 (math-expr-subst expr var low)
1831 0))
1832 ((setq t1 (math-is-polynomial expr var 20))
1833 (let ((poly nil)
1834 (n 0))
1835 (while t1
1836 (setq poly (math-poly-mix poly 1
1837 (math-sum-integer-power n) (car t1))
1838 n (1+ n)
1839 t1 (cdr t1)))
1840 (setq n (math-build-polynomial-expr poly high))
1841 (if (memq low '(0 1))
1842 n
1843 (math-sub n (math-build-polynomial-expr poly
1844 (math-sub low 1))))))
1845 ((and (memq (car expr) '(+ -))
1846 (setq t1 (math-sum-rec (nth 1 expr) var low high)
1847 t2 (math-sum-rec (nth 2 expr) var low high))
1848 (not (and (math-expr-calls t1 '(calcFunc-sum))
1849 (math-expr-calls t2 '(calcFunc-sum)))))
1850 (list (car expr) t1 t2))
1851 ((and (eq (car expr) '*)
1852 (setq t1 (math-sum-const-factors expr var)))
1853 (math-mul (car t1) (math-sum-rec (cdr t1) var low high)))
1854 ((and (eq (car expr) '*) (memq (car-safe (nth 1 expr)) '(+ -)))
1855 (math-sum-rec (math-add-or-sub (math-mul (nth 1 (nth 1 expr))
1856 (nth 2 expr))
1857 (math-mul (nth 2 (nth 1 expr))
1858 (nth 2 expr))
1859 nil (eq (car (nth 1 expr)) '-))
1860 var low high))
1861 ((and (eq (car expr) '*) (memq (car-safe (nth 2 expr)) '(+ -)))
1862 (math-sum-rec (math-add-or-sub (math-mul (nth 1 expr)
1863 (nth 1 (nth 2 expr)))
1864 (math-mul (nth 1 expr)
1865 (nth 2 (nth 2 expr)))
1866 nil (eq (car (nth 2 expr)) '-))
1867 var low high))
1868 ((and (eq (car expr) '/)
1869 (not (math-primp (nth 1 expr)))
1870 (setq t1 (math-sum-const-factors (nth 1 expr) var)))
1871 (math-mul (car t1)
1872 (math-sum-rec (math-div (cdr t1) (nth 2 expr))
1873 var low high)))
1874 ((and (eq (car expr) '/)
1875 (setq t1 (math-sum-const-factors (nth 2 expr) var)))
1876 (math-div (math-sum-rec (math-div (nth 1 expr) (cdr t1))
1877 var low high)
1878 (car t1)))
1879 ((eq (car expr) 'neg)
1880 (math-neg (math-sum-rec (nth 1 expr) var low high)))
1881 ((and (eq (car expr) '^)
1882 (not (math-expr-contains (nth 1 expr) var))
1883 (setq t1 (math-is-polynomial (nth 2 expr) var 1)))
1884 (let ((x (math-pow (nth 1 expr) (nth 1 t1))))
1885 (math-div (math-mul (math-sub (math-pow x (math-add 1 high))
1886 (math-pow x low))
1887 (math-pow (nth 1 expr) (car t1)))
1888 (math-sub x 1))))
1889 ((and (setq t1 (math-to-exponentials expr))
1890 (setq t1 (math-sum-rec t1 var low high))
1891 (not (math-expr-calls t1 '(calcFunc-sum))))
1892 (math-to-exps t1))
1893 ((memq (car expr) '(calcFunc-ln calcFunc-log10))
1894 (list (car expr) (calcFunc-prod (nth 1 expr) var low high)))
1895 ((and (eq (car expr) 'calcFunc-log)
1896 (= (length expr) 3)
1897 (not (math-expr-contains (nth 2 expr) var)))
1898 (list 'calcFunc-log
1899 (calcFunc-prod (nth 1 expr) var low high)
1900 (nth 2 expr)))))
1901 (if (equal val '(var nan var-nan)) (setq val nil))
1902 (or val
1903 (let* ((math-tabulate-initial 0)
1904 (math-tabulate-function 'calcFunc-sum))
1905 (calcFunc-table expr var low high)))))
1906
1907 (defun calcFunc-asum (expr var low &optional high step no-mul-flag)
1908 (or high (setq high low low 1))
1909 (if (and step (not (math-equal-int step 1)))
1910 (if (math-negp step)
1911 (math-mul (math-pow -1 low)
1912 (calcFunc-asum expr var high low (math-neg step) t))
1913 (let ((lo (math-simplify (math-div low step))))
1914 (if (math-num-integerp lo)
1915 (calcFunc-asum (math-normalize
1916 (math-expr-subst expr var
1917 (math-mul step var)))
1918 var lo (math-simplify (math-div high step)))
1919 (calcFunc-asum (math-normalize
1920 (math-expr-subst expr var
1921 (math-add (math-mul step var)
1922 low)))
1923 var 0
1924 (math-simplify (math-div (math-sub high low)
1925 step))))))
1926 (math-mul (if no-mul-flag 1 (math-pow -1 low))
1927 (calcFunc-sum (math-mul (math-pow -1 var) expr) var low high))))
1928
1929 (defun math-sum-const-factors (expr var)
1930 (let ((const nil)
1931 (not-const nil)
1932 (p expr))
1933 (while (eq (car-safe p) '*)
1934 (if (math-expr-contains (nth 1 p) var)
1935 (setq not-const (cons (nth 1 p) not-const))
1936 (setq const (cons (nth 1 p) const)))
1937 (setq p (nth 2 p)))
1938 (if (math-expr-contains p var)
1939 (setq not-const (cons p not-const))
1940 (setq const (cons p const)))
1941 (and const
1942 (cons (let ((temp (car const)))
1943 (while (setq const (cdr const))
1944 (setq temp (list '* (car const) temp)))
1945 temp)
1946 (let ((temp (or (car not-const) 1)))
1947 (while (setq not-const (cdr not-const))
1948 (setq temp (list '* (car not-const) temp)))
1949 temp)))))
1950
1951 (defvar math-sum-int-pow-cache (list '(0 1)))
1952 ;; Following is from CRC Math Tables, 27th ed, pp. 52-53.
1953 (defun math-sum-integer-power (pow)
1954 (let ((calc-prefer-frac t)
1955 (n (length math-sum-int-pow-cache)))
1956 (while (<= n pow)
1957 (let* ((new (list 0 0))
1958 (lin new)
1959 (pp (cdr (nth (1- n) math-sum-int-pow-cache)))
1960 (p 2)
1961 (sum 0)
1962 q)
1963 (while pp
1964 (setq q (math-div (car pp) p)
1965 new (cons (math-mul q n) new)
1966 sum (math-add sum q)
1967 p (1+ p)
1968 pp (cdr pp)))
1969 (setcar lin (math-sub 1 (math-mul n sum)))
1970 (setq math-sum-int-pow-cache
1971 (nconc math-sum-int-pow-cache (list (nreverse new)))
1972 n (1+ n))))
1973 (nth pow math-sum-int-pow-cache)))
1974
1975 (defun math-to-exponentials (expr)
1976 (and (consp expr)
1977 (= (length expr) 2)
1978 (let ((x (nth 1 expr))
1979 (pi (if calc-symbolic-mode '(var pi var-pi) (math-pi)))
1980 (i (if calc-symbolic-mode '(var i var-i) '(cplx 0 1))))
1981 (cond ((eq (car expr) 'calcFunc-exp)
1982 (list '^ '(var e var-e) x))
1983 ((eq (car expr) 'calcFunc-sin)
1984 (or (eq calc-angle-mode 'rad)
1985 (setq x (list '/ (list '* x pi) 180)))
1986 (list '/ (list '-
1987 (list '^ '(var e var-e) (list '* x i))
1988 (list '^ '(var e var-e)
1989 (list 'neg (list '* x i))))
1990 (list '* 2 i)))
1991 ((eq (car expr) 'calcFunc-cos)
1992 (or (eq calc-angle-mode 'rad)
1993 (setq x (list '/ (list '* x pi) 180)))
1994 (list '/ (list '+
1995 (list '^ '(var e var-e)
1996 (list '* x i))
1997 (list '^ '(var e var-e)
1998 (list 'neg (list '* x i))))
1999 2))
2000 ((eq (car expr) 'calcFunc-sinh)
2001 (list '/ (list '-
2002 (list '^ '(var e var-e) x)
2003 (list '^ '(var e var-e) (list 'neg x)))
2004 2))
2005 ((eq (car expr) 'calcFunc-cosh)
2006 (list '/ (list '+
2007 (list '^ '(var e var-e) x)
2008 (list '^ '(var e var-e) (list 'neg x)))
2009 2))
2010 (t nil)))))
2011
2012 (defun math-to-exps (expr)
2013 (cond (calc-symbolic-mode expr)
2014 ((Math-primp expr)
2015 (if (equal expr '(var e var-e)) (math-e) expr))
2016 ((and (eq (car expr) '^)
2017 (equal (nth 1 expr) '(var e var-e)))
2018 (list 'calcFunc-exp (nth 2 expr)))
2019 (t
2020 (cons (car expr) (mapcar 'math-to-exps (cdr expr))))))
2021
2022
2023 (defvar math-disable-prods nil)
2024 (defun calcFunc-prod (expr var &optional low high step)
2025 (if math-disable-prods (math-reject-arg))
2026 (let* ((res (let* ((calc-internal-prec (+ calc-internal-prec 2)))
2027 (math-prod-rec expr var low high step)))
2028 (math-disable-prods t))
2029 (math-normalize res)))
2030
2031 (defun math-prod-rec (expr var &optional low high step)
2032 (or low (setq low '(neg (var inf var-inf)) high '(var inf var-inf)))
2033 (and low (not high) (setq high '(var inf var-inf)))
2034 (let (t1 t2 t3 val)
2035 (setq val
2036 (cond
2037 ((not (math-expr-contains expr var))
2038 (math-pow expr (math-add (math-div (math-sub high low) (or step 1))
2039 1)))
2040 ((and step (not (math-equal-int step 1)))
2041 (if (math-negp step)
2042 (math-prod-rec expr var high low (math-neg step))
2043 (let ((lo (math-simplify (math-div low step))))
2044 (if (math-known-num-integerp lo)
2045 (math-prod-rec (math-normalize
2046 (math-expr-subst expr var
2047 (math-mul step var)))
2048 var lo (math-simplify (math-div high step)))
2049 (math-prod-rec (math-normalize
2050 (math-expr-subst expr var
2051 (math-add (math-mul step
2052 var)
2053 low)))
2054 var 0
2055 (math-simplify (math-div (math-sub high low)
2056 step)))))))
2057 ((and (memq (car expr) '(* /))
2058 (setq t1 (math-prod-rec (nth 1 expr) var low high)
2059 t2 (math-prod-rec (nth 2 expr) var low high))
2060 (not (and (math-expr-calls t1 '(calcFunc-prod))
2061 (math-expr-calls t2 '(calcFunc-prod)))))
2062 (list (car expr) t1 t2))
2063 ((and (eq (car expr) '^)
2064 (not (math-expr-contains (nth 2 expr) var)))
2065 (math-pow (math-prod-rec (nth 1 expr) var low high)
2066 (nth 2 expr)))
2067 ((and (eq (car expr) '^)
2068 (not (math-expr-contains (nth 1 expr) var)))
2069 (math-pow (nth 1 expr)
2070 (calcFunc-sum (nth 2 expr) var low high)))
2071 ((eq (car expr) 'sqrt)
2072 (math-normalize (list 'calcFunc-sqrt
2073 (list 'calcFunc-prod (nth 1 expr)
2074 var low high))))
2075 ((eq (car expr) 'neg)
2076 (math-mul (math-pow -1 (math-add (math-sub high low) 1))
2077 (math-prod-rec (nth 1 expr) var low high)))
2078 ((eq (car expr) 'calcFunc-exp)
2079 (list 'calcFunc-exp (calcFunc-sum (nth 1 expr) var low high)))
2080 ((and (setq t1 (math-is-polynomial expr var 1))
2081 (setq t2
2082 (cond
2083 ((or (and (math-equal-int (nth 1 t1) 1)
2084 (setq low (math-simplify
2085 (math-add low (car t1)))
2086 high (math-simplify
2087 (math-add high (car t1)))))
2088 (and (math-equal-int (nth 1 t1) -1)
2089 (setq t2 low
2090 low (math-simplify
2091 (math-sub (car t1) high))
2092 high (math-simplify
2093 (math-sub (car t1) t2)))))
2094 (if (or (math-zerop low) (math-zerop high))
2095 0
2096 (if (and (or (math-negp low) (math-negp high))
2097 (or (math-num-integerp low)
2098 (math-num-integerp high)))
2099 (if (math-posp high)
2100 0
2101 (math-mul (math-pow -1
2102 (math-add
2103 (math-add low high) 1))
2104 (list '/
2105 (list 'calcFunc-fact
2106 (math-neg low))
2107 (list 'calcFunc-fact
2108 (math-sub -1 high)))))
2109 (list '/
2110 (list 'calcFunc-fact high)
2111 (list 'calcFunc-fact (math-sub low 1))))))
2112 ((and (or (and (math-equal-int (nth 1 t1) 2)
2113 (setq t2 (math-simplify
2114 (math-add (math-mul low 2)
2115 (car t1)))
2116 t3 (math-simplify
2117 (math-add (math-mul high 2)
2118 (car t1)))))
2119 (and (math-equal-int (nth 1 t1) -2)
2120 (setq t2 (math-simplify
2121 (math-sub (car t1)
2122 (math-mul high 2)))
2123 t3 (math-simplify
2124 (math-sub (car t1)
2125 (math-mul low
2126 2))))))
2127 (or (math-integerp t2)
2128 (and (math-messy-integerp t2)
2129 (setq t2 (math-trunc t2)))
2130 (math-integerp t3)
2131 (and (math-messy-integerp t3)
2132 (setq t3 (math-trunc t3)))))
2133 (if (or (math-zerop t2) (math-zerop t3))
2134 0
2135 (if (or (math-evenp t2) (math-evenp t3))
2136 (if (or (math-negp t2) (math-negp t3))
2137 (if (math-posp high)
2138 0
2139 (list '/
2140 (list 'calcFunc-dfact
2141 (math-neg t2))
2142 (list 'calcFunc-dfact
2143 (math-sub -2 t3))))
2144 (list '/
2145 (list 'calcFunc-dfact t3)
2146 (list 'calcFunc-dfact
2147 (math-sub t2 2))))
2148 (if (math-negp t3)
2149 (list '*
2150 (list '^ -1
2151 (list '/ (list '- (list '- t2 t3)
2152 2)
2153 2))
2154 (list '/
2155 (list 'calcFunc-dfact
2156 (math-neg t2))
2157 (list 'calcFunc-dfact
2158 (math-sub -2 t3))))
2159 (if (math-posp t2)
2160 (list '/
2161 (list 'calcFunc-dfact t3)
2162 (list 'calcFunc-dfact
2163 (math-sub t2 2)))
2164 nil))))))))
2165 t2)))
2166 (if (equal val '(var nan var-nan)) (setq val nil))
2167 (or val
2168 (let* ((math-tabulate-initial 1)
2169 (math-tabulate-function 'calcFunc-prod))
2170 (calcFunc-table expr var low high)))))
2171
2172
2173
2174
2175 (defvar math-solve-ranges nil)
2176 ;;; Attempt to reduce lhs = rhs to solve-var = rhs', where solve-var appears
2177 ;;; in lhs but not in rhs or rhs'; return rhs'.
2178 ;;; Uses global values: solve-*.
2179 (defun math-try-solve-for (lhs rhs &optional sign no-poly)
2180 (let (t1 t2 t3)
2181 (cond ((equal lhs solve-var)
2182 (setq math-solve-sign sign)
2183 (if (eq solve-full 'all)
2184 (let ((vec (list 'vec (math-evaluate-expr rhs)))
2185 newvec var p)
2186 (while math-solve-ranges
2187 (setq p (car math-solve-ranges)
2188 var (car p)
2189 newvec (list 'vec))
2190 (while (setq p (cdr p))
2191 (setq newvec (nconc newvec
2192 (cdr (math-expr-subst
2193 vec var (car p))))))
2194 (setq vec newvec
2195 math-solve-ranges (cdr math-solve-ranges)))
2196 (math-normalize vec))
2197 rhs))
2198 ((Math-primp lhs)
2199 nil)
2200 ((and (eq (car lhs) '-)
2201 (eq (car-safe (nth 1 lhs)) (car-safe (nth 2 lhs)))
2202 (Math-zerop rhs)
2203 (= (length (nth 1 lhs)) 2)
2204 (= (length (nth 2 lhs)) 2)
2205 (setq t1 (get (car (nth 1 lhs)) 'math-inverse))
2206 (setq t2 (funcall t1 '(var SOLVEDUM SOLVEDUM)))
2207 (eq (math-expr-contains-count t2 '(var SOLVEDUM SOLVEDUM)) 1)
2208 (setq t3 (math-solve-above-dummy t2))
2209 (setq t1 (math-try-solve-for (math-sub (nth 1 (nth 1 lhs))
2210 (math-expr-subst
2211 t2 t3
2212 (nth 1 (nth 2 lhs))))
2213 0)))
2214 t1)
2215 ((eq (car lhs) 'neg)
2216 (math-try-solve-for (nth 1 lhs) (math-neg rhs)
2217 (and sign (- sign))))
2218 ((and (not (eq solve-full 't)) (math-try-solve-prod)))
2219 ((and (not no-poly)
2220 (setq t2 (math-decompose-poly lhs solve-var 15 rhs)))
2221 (setq t1 (cdr (nth 1 t2))
2222 t1 (let ((math-solve-ranges math-solve-ranges))
2223 (cond ((= (length t1) 5)
2224 (apply 'math-solve-quartic (car t2) t1))
2225 ((= (length t1) 4)
2226 (apply 'math-solve-cubic (car t2) t1))
2227 ((= (length t1) 3)
2228 (apply 'math-solve-quadratic (car t2) t1))
2229 ((= (length t1) 2)
2230 (apply 'math-solve-linear (car t2) sign t1))
2231 (solve-full
2232 (math-poly-all-roots (car t2) t1))
2233 (calc-symbolic-mode nil)
2234 (t
2235 (math-try-solve-for
2236 (car t2)
2237 (math-poly-any-root (reverse t1) 0 t)
2238 nil t)))))
2239 (if t1
2240 (if (eq (nth 2 t2) 1)
2241 t1
2242 (math-solve-prod t1 (math-try-solve-for (nth 2 t2) 0 nil t)))
2243 (calc-record-why "*Unable to find a symbolic solution")
2244 nil))
2245 ((and (math-solve-find-root-term lhs nil)
2246 (eq (math-expr-contains-count lhs t1) 1)) ; just in case
2247 (math-try-solve-for (math-simplify
2248 (math-sub (if (or t3 (math-evenp t2))
2249 (math-pow t1 t2)
2250 (math-neg (math-pow t1 t2)))
2251 (math-expand-power
2252 (math-sub (math-normalize
2253 (math-expr-subst
2254 lhs t1 0))
2255 rhs)
2256 t2 solve-var)))
2257 0))
2258 ((eq (car lhs) '+)
2259 (cond ((not (math-expr-contains (nth 1 lhs) solve-var))
2260 (math-try-solve-for (nth 2 lhs)
2261 (math-sub rhs (nth 1 lhs))
2262 sign))
2263 ((not (math-expr-contains (nth 2 lhs) solve-var))
2264 (math-try-solve-for (nth 1 lhs)
2265 (math-sub rhs (nth 2 lhs))
2266 sign))))
2267 ((eq (car lhs) 'calcFunc-eq)
2268 (math-try-solve-for (math-sub (nth 1 lhs) (nth 2 lhs))
2269 rhs sign no-poly))
2270 ((eq (car lhs) '-)
2271 (cond ((or (and (eq (car-safe (nth 1 lhs)) 'calcFunc-sin)
2272 (eq (car-safe (nth 2 lhs)) 'calcFunc-cos))
2273 (and (eq (car-safe (nth 1 lhs)) 'calcFunc-cos)
2274 (eq (car-safe (nth 2 lhs)) 'calcFunc-sin)))
2275 (math-try-solve-for (math-sub (nth 1 lhs)
2276 (list (car (nth 1 lhs))
2277 (math-sub
2278 (math-quarter-circle t)
2279 (nth 1 (nth 2 lhs)))))
2280 rhs))
2281 ((not (math-expr-contains (nth 1 lhs) solve-var))
2282 (math-try-solve-for (nth 2 lhs)
2283 (math-sub (nth 1 lhs) rhs)
2284 (and sign (- sign))))
2285 ((not (math-expr-contains (nth 2 lhs) solve-var))
2286 (math-try-solve-for (nth 1 lhs)
2287 (math-add rhs (nth 2 lhs))
2288 sign))))
2289 ((and (eq solve-full 't) (math-try-solve-prod)))
2290 ((and (eq (car lhs) '%)
2291 (not (math-expr-contains (nth 2 lhs) solve-var)))
2292 (math-try-solve-for (nth 1 lhs) (math-add rhs
2293 (math-solve-get-int
2294 (nth 2 lhs)))))
2295 ((eq (car lhs) 'calcFunc-log)
2296 (cond ((not (math-expr-contains (nth 2 lhs) solve-var))
2297 (math-try-solve-for (nth 1 lhs) (math-pow (nth 2 lhs) rhs)))
2298 ((not (math-expr-contains (nth 1 lhs) solve-var))
2299 (math-try-solve-for (nth 2 lhs) (math-pow
2300 (nth 1 lhs)
2301 (math-div 1 rhs))))))
2302 ((and (= (length lhs) 2)
2303 (symbolp (car lhs))
2304 (setq t1 (get (car lhs) 'math-inverse))
2305 (setq t2 (funcall t1 rhs)))
2306 (setq t1 (get (car lhs) 'math-inverse-sign))
2307 (math-try-solve-for (nth 1 lhs) (math-normalize t2)
2308 (and sign t1
2309 (if (integerp t1)
2310 (* t1 sign)
2311 (funcall t1 lhs sign)))))
2312 ((and (symbolp (car lhs))
2313 (setq t1 (get (car lhs) 'math-inverse-n))
2314 (setq t2 (funcall t1 lhs rhs)))
2315 t2)
2316 ((setq t1 (math-expand-formula lhs))
2317 (math-try-solve-for t1 rhs sign))
2318 (t
2319 (calc-record-why "*No inverse known" lhs)
2320 nil))))
2321
2322
2323 (defun math-try-solve-prod ()
2324 (cond ((eq (car lhs) '*)
2325 (cond ((not (math-expr-contains (nth 1 lhs) solve-var))
2326 (math-try-solve-for (nth 2 lhs)
2327 (math-div rhs (nth 1 lhs))
2328 (math-solve-sign sign (nth 1 lhs))))
2329 ((not (math-expr-contains (nth 2 lhs) solve-var))
2330 (math-try-solve-for (nth 1 lhs)
2331 (math-div rhs (nth 2 lhs))
2332 (math-solve-sign sign (nth 2 lhs))))
2333 ((Math-zerop rhs)
2334 (math-solve-prod (let ((math-solve-ranges math-solve-ranges))
2335 (math-try-solve-for (nth 2 lhs) 0))
2336 (math-try-solve-for (nth 1 lhs) 0)))))
2337 ((eq (car lhs) '/)
2338 (cond ((not (math-expr-contains (nth 1 lhs) solve-var))
2339 (math-try-solve-for (nth 2 lhs)
2340 (math-div (nth 1 lhs) rhs)
2341 (math-solve-sign sign (nth 1 lhs))))
2342 ((not (math-expr-contains (nth 2 lhs) solve-var))
2343 (math-try-solve-for (nth 1 lhs)
2344 (math-mul rhs (nth 2 lhs))
2345 (math-solve-sign sign (nth 2 lhs))))
2346 ((setq t1 (math-try-solve-for (math-sub (nth 1 lhs)
2347 (math-mul (nth 2 lhs)
2348 rhs))
2349 0))
2350 t1)))
2351 ((eq (car lhs) '^)
2352 (cond ((not (math-expr-contains (nth 1 lhs) solve-var))
2353 (math-try-solve-for
2354 (nth 2 lhs)
2355 (math-add (math-normalize
2356 (list 'calcFunc-log rhs (nth 1 lhs)))
2357 (math-div
2358 (math-mul 2
2359 (math-mul '(var pi var-pi)
2360 (math-solve-get-int
2361 '(var i var-i))))
2362 (math-normalize
2363 (list 'calcFunc-ln (nth 1 lhs)))))))
2364 ((not (math-expr-contains (nth 2 lhs) solve-var))
2365 (cond ((and (integerp (nth 2 lhs))
2366 (>= (nth 2 lhs) 2)
2367 (setq t1 (math-integer-log2 (nth 2 lhs))))
2368 (setq t2 rhs)
2369 (if (and (eq solve-full t)
2370 (math-known-realp (nth 1 lhs)))
2371 (progn
2372 (while (>= (setq t1 (1- t1)) 0)
2373 (setq t2 (list 'calcFunc-sqrt t2)))
2374 (setq t2 (math-solve-get-sign t2)))
2375 (while (>= (setq t1 (1- t1)) 0)
2376 (setq t2 (math-solve-get-sign
2377 (math-normalize
2378 (list 'calcFunc-sqrt t2))))))
2379 (math-try-solve-for
2380 (nth 1 lhs)
2381 (math-normalize t2)))
2382 ((math-looks-negp (nth 2 lhs))
2383 (math-try-solve-for
2384 (list '^ (nth 1 lhs) (math-neg (nth 2 lhs)))
2385 (math-div 1 rhs)))
2386 ((and (eq solve-full t)
2387 (Math-integerp (nth 2 lhs))
2388 (math-known-realp (nth 1 lhs)))
2389 (setq t1 (math-normalize
2390 (list 'calcFunc-nroot rhs (nth 2 lhs))))
2391 (if (math-evenp (nth 2 lhs))
2392 (setq t1 (math-solve-get-sign t1)))
2393 (math-try-solve-for
2394 (nth 1 lhs) t1
2395 (and sign
2396 (math-oddp (nth 2 lhs))
2397 (math-solve-sign sign (nth 2 lhs)))))
2398 (t (math-try-solve-for
2399 (nth 1 lhs)
2400 (math-mul
2401 (math-normalize
2402 (list 'calcFunc-exp
2403 (if (Math-realp (nth 2 lhs))
2404 (math-div (math-mul
2405 '(var pi var-pi)
2406 (math-solve-get-int
2407 '(var i var-i)
2408 (and (integerp (nth 2 lhs))
2409 (math-abs
2410 (nth 2 lhs)))))
2411 (math-div (nth 2 lhs) 2))
2412 (math-div (math-mul
2413 2
2414 (math-mul
2415 '(var pi var-pi)
2416 (math-solve-get-int
2417 '(var i var-i)
2418 (and (integerp (nth 2 lhs))
2419 (math-abs
2420 (nth 2 lhs))))))
2421 (nth 2 lhs)))))
2422 (math-normalize
2423 (list 'calcFunc-nroot
2424 rhs
2425 (nth 2 lhs))))
2426 (and sign
2427 (math-oddp (nth 2 lhs))
2428 (math-solve-sign sign (nth 2 lhs)))))))))
2429 (t nil)))
2430
2431 (defun math-solve-prod (lsoln rsoln)
2432 (cond ((null lsoln)
2433 rsoln)
2434 ((null rsoln)
2435 lsoln)
2436 ((eq solve-full 'all)
2437 (cons 'vec (append (cdr lsoln) (cdr rsoln))))
2438 (solve-full
2439 (list 'calcFunc-if
2440 (list 'calcFunc-gt (math-solve-get-sign 1) 0)
2441 lsoln
2442 rsoln))
2443 (t lsoln)))
2444
2445 ;;; This deals with negative, fractional, and symbolic powers of "x".
2446 (defun math-solve-poly-funny-powers (sub-rhs) ; uses "t1", "t2"
2447 (setq t1 lhs)
2448 (let ((pp math-poly-neg-powers)
2449 fac)
2450 (while pp
2451 (setq fac (math-pow (car pp) (or math-poly-mult-powers 1))
2452 t1 (math-mul t1 fac)
2453 rhs (math-mul rhs fac)
2454 pp (cdr pp))))
2455 (if sub-rhs (setq t1 (math-sub t1 rhs)))
2456 (let ((math-poly-neg-powers nil))
2457 (setq t2 (math-mul (or math-poly-mult-powers 1)
2458 (let ((calc-prefer-frac t))
2459 (math-div 1 math-poly-frac-powers)))
2460 t1 (math-is-polynomial (math-simplify (calcFunc-expand t1)) b 50))))
2461
2462 ;;; This converts "a x^8 + b x^5 + c x^2" to "(a (x^3)^2 + b (x^3) + c) * x^2".
2463 (defun math-solve-crunch-poly (max-degree) ; uses "t1", "t3"
2464 (let ((count 0))
2465 (while (and t1 (Math-zerop (car t1)))
2466 (setq t1 (cdr t1)
2467 count (1+ count)))
2468 (and t1
2469 (let* ((degree (1- (length t1)))
2470 (scale degree))
2471 (while (and (> scale 1) (= (car t3) 1))
2472 (and (= (% degree scale) 0)
2473 (let ((p t1)
2474 (n 0)
2475 (new-t1 nil)
2476 (okay t))
2477 (while (and p okay)
2478 (if (= (% n scale) 0)
2479 (setq new-t1 (nconc new-t1 (list (car p))))
2480 (or (Math-zerop (car p))
2481 (setq okay nil)))
2482 (setq p (cdr p)
2483 n (1+ n)))
2484 (if okay
2485 (setq t3 (cons scale (cdr t3))
2486 t1 new-t1))))
2487 (setq scale (1- scale)))
2488 (setq t3 (list (math-mul (car t3) t2) (math-mul count t2)))
2489 (<= (1- (length t1)) max-degree)))))
2490
2491 (defun calcFunc-poly (expr var &optional degree)
2492 (if degree
2493 (or (natnump degree) (math-reject-arg degree 'fixnatnump))
2494 (setq degree 50))
2495 (let ((p (math-is-polynomial expr var degree 'gen)))
2496 (if p
2497 (if (equal p '(0))
2498 (list 'vec)
2499 (cons 'vec p))
2500 (math-reject-arg expr "Expected a polynomial"))))
2501
2502 (defun calcFunc-gpoly (expr var &optional degree)
2503 (if degree
2504 (or (natnump degree) (math-reject-arg degree 'fixnatnump))
2505 (setq degree 50))
2506 (let* ((math-poly-base-variable var)
2507 (d (math-decompose-poly expr var degree nil)))
2508 (if d
2509 (cons 'vec d)
2510 (math-reject-arg expr "Expected a polynomial"))))
2511
2512 (defun math-decompose-poly (lhs solve-var degree sub-rhs)
2513 (let ((rhs (or sub-rhs 1))
2514 t1 t2 t3)
2515 (setq t2 (math-polynomial-base
2516 lhs
2517 (function
2518 (lambda (b)
2519 (let ((math-poly-neg-powers '(1))
2520 (math-poly-mult-powers nil)
2521 (math-poly-frac-powers 1)
2522 (math-poly-exp-base t))
2523 (and (not (equal b lhs))
2524 (or (not (memq (car-safe b) '(+ -))) sub-rhs)
2525 (setq t3 '(1 0) t2 1
2526 t1 (math-is-polynomial lhs b 50))
2527 (if (and (equal math-poly-neg-powers '(1))
2528 (memq math-poly-mult-powers '(nil 1))
2529 (eq math-poly-frac-powers 1)
2530 sub-rhs)
2531 (setq t1 (cons (math-sub (car t1) rhs)
2532 (cdr t1)))
2533 (math-solve-poly-funny-powers sub-rhs))
2534 (math-solve-crunch-poly degree)
2535 (or (math-expr-contains b solve-var)
2536 (math-expr-contains (car t3) solve-var))))))))
2537 (if t2
2538 (list (math-pow t2 (car t3))
2539 (cons 'vec t1)
2540 (if sub-rhs
2541 (math-pow t2 (nth 1 t3))
2542 (math-div (math-pow t2 (nth 1 t3)) rhs))))))
2543
2544 (defun math-solve-linear (var sign b a)
2545 (math-try-solve-for var
2546 (math-div (math-neg b) a)
2547 (math-solve-sign sign a)
2548 t))
2549
2550 (defun math-solve-quadratic (var c b a)
2551 (math-try-solve-for
2552 var
2553 (if (math-looks-evenp b)
2554 (let ((halfb (math-div b 2)))
2555 (math-div
2556 (math-add
2557 (math-neg halfb)
2558 (math-solve-get-sign
2559 (math-normalize
2560 (list 'calcFunc-sqrt
2561 (math-add (math-sqr halfb)
2562 (math-mul (math-neg c) a))))))
2563 a))
2564 (math-div
2565 (math-add
2566 (math-neg b)
2567 (math-solve-get-sign
2568 (math-normalize
2569 (list 'calcFunc-sqrt
2570 (math-add (math-sqr b)
2571 (math-mul 4 (math-mul (math-neg c) a)))))))
2572 (math-mul 2 a)))
2573 nil t))
2574
2575 (defun math-solve-cubic (var d c b a)
2576 (let* ((p (math-div b a))
2577 (q (math-div c a))
2578 (r (math-div d a))
2579 (psqr (math-sqr p))
2580 (aa (math-sub q (math-div psqr 3)))
2581 (bb (math-add r
2582 (math-div (math-sub (math-mul 2 (math-mul psqr p))
2583 (math-mul 9 (math-mul p q)))
2584 27)))
2585 m)
2586 (if (Math-zerop aa)
2587 (math-try-solve-for (math-pow (math-add var (math-div p 3)) 3)
2588 (math-neg bb) nil t)
2589 (if (Math-zerop bb)
2590 (math-try-solve-for
2591 (math-mul (math-add var (math-div p 3))
2592 (math-add (math-sqr (math-add var (math-div p 3)))
2593 aa))
2594 0 nil t)
2595 (setq m (math-mul 2 (list 'calcFunc-sqrt (math-div aa -3))))
2596 (math-try-solve-for
2597 var
2598 (math-sub
2599 (math-normalize
2600 (math-mul
2601 m
2602 (list 'calcFunc-cos
2603 (math-div
2604 (math-sub (list 'calcFunc-arccos
2605 (math-div (math-mul 3 bb)
2606 (math-mul aa m)))
2607 (math-mul 2
2608 (math-mul
2609 (math-add 1 (math-solve-get-int
2610 1 3))
2611 (math-half-circle
2612 calc-symbolic-mode))))
2613 3))))
2614 (math-div p 3))
2615 nil t)))))
2616
2617 (defun math-solve-quartic (var d c b a aa)
2618 (setq a (math-div a aa))
2619 (setq b (math-div b aa))
2620 (setq c (math-div c aa))
2621 (setq d (math-div d aa))
2622 (math-try-solve-for
2623 var
2624 (let* ((asqr (math-sqr a))
2625 (asqr4 (math-div asqr 4))
2626 (y (let ((solve-full nil)
2627 calc-next-why)
2628 (math-solve-cubic solve-var
2629 (math-sub (math-sub
2630 (math-mul 4 (math-mul b d))
2631 (math-mul asqr d))
2632 (math-sqr c))
2633 (math-sub (math-mul a c)
2634 (math-mul 4 d))
2635 (math-neg b)
2636 1)))
2637 (rsqr (math-add (math-sub asqr4 b) y))
2638 (r (list 'calcFunc-sqrt rsqr))
2639 (sign1 (math-solve-get-sign 1))
2640 (de (list 'calcFunc-sqrt
2641 (math-add
2642 (math-sub (math-mul 3 asqr4)
2643 (math-mul 2 b))
2644 (if (Math-zerop rsqr)
2645 (math-mul
2646 2
2647 (math-mul sign1
2648 (list 'calcFunc-sqrt
2649 (math-sub (math-sqr y)
2650 (math-mul 4 d)))))
2651 (math-sub
2652 (math-mul sign1
2653 (math-div
2654 (math-sub (math-sub
2655 (math-mul 4 (math-mul a b))
2656 (math-mul 8 c))
2657 (math-mul asqr a))
2658 (math-mul 4 r)))
2659 rsqr))))))
2660 (math-normalize
2661 (math-sub (math-add (math-mul sign1 (math-div r 2))
2662 (math-solve-get-sign (math-div de 2)))
2663 (math-div a 4))))
2664 nil t))
2665
2666 (defvar math-symbolic-solve nil)
2667 (defvar math-int-coefs nil)
2668 (defun math-poly-all-roots (var p &optional math-factoring)
2669 (catch 'ouch
2670 (let* ((math-symbolic-solve calc-symbolic-mode)
2671 (roots nil)
2672 (deg (1- (length p)))
2673 (orig-p (reverse p))
2674 (math-int-coefs nil)
2675 (math-int-scale nil)
2676 (math-double-roots nil)
2677 (math-int-factors nil)
2678 (math-int-threshold nil)
2679 (pp p))
2680 ;; If rational coefficients, look for exact rational factors.
2681 (while (and pp (Math-ratp (car pp)))
2682 (setq pp (cdr pp)))
2683 (if pp
2684 (if (or math-factoring math-symbolic-solve)
2685 (throw 'ouch nil))
2686 (let ((lead (car orig-p))
2687 (calc-prefer-frac t)
2688 (scale (apply 'math-lcm-denoms p)))
2689 (setq math-int-scale (math-abs (math-mul scale lead))
2690 math-int-threshold (math-div '(float 5 -2) math-int-scale)
2691 math-int-coefs (cdr (math-div (cons 'vec orig-p) lead)))))
2692 (if (> deg 4)
2693 (let ((calc-prefer-frac nil)
2694 (calc-symbolic-mode nil)
2695 (pp p)
2696 (def-p (copy-sequence orig-p)))
2697 (while pp
2698 (if (Math-numberp (car pp))
2699 (setq pp (cdr pp))
2700 (throw 'ouch nil)))
2701 (while (> deg (if math-symbolic-solve 2 4))
2702 (let* ((x (math-poly-any-root def-p '(float 0 0) nil))
2703 b c pp)
2704 (if (and (eq (car-safe x) 'cplx)
2705 (math-nearly-zerop (nth 2 x) (nth 1 x)))
2706 (setq x (calcFunc-re x)))
2707 (or math-factoring
2708 (setq roots (cons x roots)))
2709 (or (math-numberp x)
2710 (setq x (math-evaluate-expr x)))
2711 (setq pp def-p
2712 b (car def-p))
2713 (while (setq pp (cdr pp))
2714 (setq c (car pp))
2715 (setcar pp b)
2716 (setq b (math-add (math-mul x b) c)))
2717 (setq def-p (cdr def-p)
2718 deg (1- deg))))
2719 (setq p (reverse def-p))))
2720 (if (> deg 1)
2721 (let ((solve-var '(var DUMMY var-DUMMY))
2722 (math-solve-sign nil)
2723 (math-solve-ranges nil)
2724 (solve-full 'all))
2725 (if (= (length p) (length math-int-coefs))
2726 (setq p (reverse math-int-coefs)))
2727 (setq roots (append (cdr (apply (cond ((= deg 2)
2728 'math-solve-quadratic)
2729 ((= deg 3)
2730 'math-solve-cubic)
2731 (t
2732 'math-solve-quartic))
2733 solve-var p))
2734 roots)))
2735 (if (> deg 0)
2736 (setq roots (cons (math-div (math-neg (car p)) (nth 1 p))
2737 roots))))
2738 (if math-factoring
2739 (progn
2740 (while roots
2741 (math-poly-integer-root (car roots))
2742 (setq roots (cdr roots)))
2743 (list math-int-factors (nreverse math-int-coefs) math-int-scale))
2744 (let ((vec nil) res)
2745 (while roots
2746 (let ((root (car roots))
2747 (solve-full (and solve-full 'all)))
2748 (if (math-floatp root)
2749 (setq root (math-poly-any-root orig-p root t)))
2750 (setq vec (append vec
2751 (cdr (or (math-try-solve-for var root nil t)
2752 (throw 'ouch nil))))))
2753 (setq roots (cdr roots)))
2754 (setq vec (cons 'vec (nreverse vec)))
2755 (if math-symbolic-solve
2756 (setq vec (math-normalize vec)))
2757 (if (eq solve-full t)
2758 (list 'calcFunc-subscr
2759 vec
2760 (math-solve-get-int 1 (1- (length orig-p)) 1))
2761 vec))))))
2762
2763 (defun math-lcm-denoms (&rest fracs)
2764 (let ((den 1))
2765 (while fracs
2766 (if (eq (car-safe (car fracs)) 'frac)
2767 (setq den (calcFunc-lcm den (nth 2 (car fracs)))))
2768 (setq fracs (cdr fracs)))
2769 den))
2770
2771 (defun math-poly-any-root (p x polish) ; p is a reverse poly coeff list
2772 (let* ((newt (if (math-zerop x)
2773 (math-poly-newton-root
2774 p '(cplx (float 123 -6) (float 1 -4)) 4)
2775 (math-poly-newton-root p x 4)))
2776 (res (if (math-zerop (cdr newt))
2777 (car newt)
2778 (if (and (math-lessp (cdr newt) '(float 1 -3)) (not polish))
2779 (setq newt (math-poly-newton-root p (car newt) 30)))
2780 (if (math-zerop (cdr newt))
2781 (car newt)
2782 (math-poly-laguerre-root p x polish)))))
2783 (and math-symbolic-solve (math-floatp res)
2784 (throw 'ouch nil))
2785 res))
2786
2787 (defun math-poly-newton-root (p x iters)
2788 (let* ((calc-prefer-frac nil)
2789 (calc-symbolic-mode nil)
2790 (try-integer math-int-coefs)
2791 (dx x) b d)
2792 (while (and (> (setq iters (1- iters)) 0)
2793 (let ((pp p))
2794 (math-working "newton" x)
2795 (setq b (car p)
2796 d 0)
2797 (while (setq pp (cdr pp))
2798 (setq d (math-add (math-mul x d) b)
2799 b (math-add (math-mul x b) (car pp))))
2800 (not (math-zerop d)))
2801 (progn
2802 (setq dx (math-div b d)
2803 x (math-sub x dx))
2804 (if try-integer
2805 (let ((adx (math-abs-approx dx)))
2806 (and (math-lessp adx math-int-threshold)
2807 (let ((iroot (math-poly-integer-root x)))
2808 (if iroot
2809 (setq x iroot dx 0)
2810 (setq try-integer nil))))))
2811 (or (not (or (eq dx 0)
2812 (math-nearly-zerop dx (math-abs-approx x))))
2813 (progn (setq dx 0) nil)))))
2814 (cons x (if (math-zerop x)
2815 1 (math-div (math-abs-approx dx) (math-abs-approx x))))))
2816
2817 (defun math-poly-integer-root (x)
2818 (and (math-lessp (calcFunc-xpon (math-abs-approx x)) calc-internal-prec)
2819 math-int-coefs
2820 (let* ((calc-prefer-frac t)
2821 (xre (calcFunc-re x))
2822 (xim (calcFunc-im x))
2823 (xresq (math-sqr xre))
2824 (ximsq (math-sqr xim)))
2825 (if (math-lessp ximsq (calcFunc-scf xresq -1))
2826 ;; Look for linear factor
2827 (let* ((rnd (math-div (math-round (math-mul xre math-int-scale))
2828 math-int-scale))
2829 (icp math-int-coefs)
2830 (rem (car icp))
2831 (newcoef nil))
2832 (while (setq icp (cdr icp))
2833 (setq newcoef (cons rem newcoef)
2834 rem (math-add (car icp)
2835 (math-mul rem rnd))))
2836 (and (math-zerop rem)
2837 (progn
2838 (setq math-int-coefs (nreverse newcoef)
2839 math-int-factors (cons (list (math-neg rnd))
2840 math-int-factors))
2841 rnd)))
2842 ;; Look for irreducible quadratic factor
2843 (let* ((rnd1 (math-div (math-round
2844 (math-mul xre (math-mul -2 math-int-scale)))
2845 math-int-scale))
2846 (sqscale (math-sqr math-int-scale))
2847 (rnd0 (math-div (math-round (math-mul (math-add xresq ximsq)
2848 sqscale))
2849 sqscale))
2850 (rem1 (car math-int-coefs))
2851 (icp (cdr math-int-coefs))
2852 (rem0 (car icp))
2853 (newcoef nil)
2854 (found (assoc (list rnd0 rnd1 (math-posp xim))
2855 math-double-roots))
2856 this)
2857 (if found
2858 (setq math-double-roots (delq found math-double-roots)
2859 rem0 0 rem1 0)
2860 (while (setq icp (cdr icp))
2861 (setq this rem1
2862 newcoef (cons rem1 newcoef)
2863 rem1 (math-sub rem0 (math-mul this rnd1))
2864 rem0 (math-sub (car icp) (math-mul this rnd0)))))
2865 (and (math-zerop rem0)
2866 (math-zerop rem1)
2867 (let ((aa (math-div rnd1 -2)))
2868 (or found (setq math-int-coefs (reverse newcoef)
2869 math-double-roots (cons (list
2870 (list
2871 rnd0 rnd1
2872 (math-negp xim)))
2873 math-double-roots)
2874 math-int-factors (cons (cons rnd0 rnd1)
2875 math-int-factors)))
2876 (math-add aa
2877 (let ((calc-symbolic-mode math-symbolic-solve))
2878 (math-mul (math-sqrt (math-sub (math-sqr aa)
2879 rnd0))
2880 (if (math-negp xim) -1 1)))))))))))
2881
2882 ;;; The following routine is from Numerical Recipes, section 9.5.
2883 (defun math-poly-laguerre-root (p x polish)
2884 (let* ((calc-prefer-frac nil)
2885 (calc-symbolic-mode nil)
2886 (iters 0)
2887 (m (1- (length p)))
2888 (try-newt (not polish))
2889 (tried-newt nil)
2890 b d f x1 dx dxold)
2891 (while
2892 (and (or (< (setq iters (1+ iters)) 50)
2893 (math-reject-arg x "*Laguerre's method failed to converge"))
2894 (let ((err (math-abs-approx (car p)))
2895 (abx (math-abs-approx x))
2896 (pp p))
2897 (setq b (car p)
2898 d 0 f 0)
2899 (while (setq pp (cdr pp))
2900 (setq f (math-add (math-mul x f) d)
2901 d (math-add (math-mul x d) b)
2902 b (math-add (math-mul x b) (car pp))
2903 err (math-add (math-abs-approx b) (math-mul abx err))))
2904 (math-lessp (calcFunc-scf err (- -2 calc-internal-prec))
2905 (math-abs-approx b)))
2906 (or (not (math-zerop d))
2907 (not (math-zerop f))
2908 (progn
2909 (setq x (math-pow (math-neg b) (list 'frac 1 m)))
2910 nil))
2911 (let* ((g (math-div d b))
2912 (g2 (math-sqr g))
2913 (h (math-sub g2 (math-mul 2 (math-div f b))))
2914 (sq (math-sqrt
2915 (math-mul (1- m) (math-sub (math-mul m h) g2))))
2916 (gp (math-add g sq))
2917 (gm (math-sub g sq)))
2918 (if (math-lessp (calcFunc-abssqr gp) (calcFunc-abssqr gm))
2919 (setq gp gm))
2920 (setq dx (math-div m gp)
2921 x1 (math-sub x dx))
2922 (if (and try-newt
2923 (math-lessp (math-abs-approx dx)
2924 (calcFunc-scf (math-abs-approx x) -3)))
2925 (let ((newt (math-poly-newton-root p x1 7)))
2926 (setq tried-newt t
2927 try-newt nil)
2928 (if (math-zerop (cdr newt))
2929 (setq x (car newt) x1 x)
2930 (if (math-lessp (cdr newt) '(float 1 -6))
2931 (let ((newt2 (math-poly-newton-root
2932 p (car newt) 20)))
2933 (if (math-zerop (cdr newt2))
2934 (setq x (car newt2) x1 x)
2935 (setq x (car newt))))))))
2936 (not (or (eq x x1)
2937 (math-nearly-equal x x1))))
2938 (let ((cdx (math-abs-approx dx)))
2939 (setq x x1
2940 tried-newt nil)
2941 (prog1
2942 (or (<= iters 6)
2943 (math-lessp cdx dxold)
2944 (progn
2945 (if polish
2946 (let ((digs (calcFunc-xpon
2947 (math-div (math-abs-approx x) cdx))))
2948 (calc-record-why
2949 "*Could not attain full precision")
2950 (if (natnump digs)
2951 (let ((calc-internal-prec (max 3 digs)))
2952 (setq x (math-normalize x))))))
2953 nil))
2954 (setq dxold cdx)))
2955 (or polish
2956 (math-lessp (calcFunc-scf (math-abs-approx x)
2957 (- calc-internal-prec))
2958 dxold))))
2959 (or (and (math-floatp x)
2960 (math-poly-integer-root x))
2961 x)))
2962
2963 (defun math-solve-above-dummy (x)
2964 (and (not (Math-primp x))
2965 (if (and (equal (nth 1 x) '(var SOLVEDUM SOLVEDUM))
2966 (= (length x) 2))
2967 x
2968 (let ((res nil))
2969 (while (and (setq x (cdr x))
2970 (not (setq res (math-solve-above-dummy (car x))))))
2971 res))))
2972
2973 (defun math-solve-find-root-term (x neg) ; sets "t2", "t3"
2974 (if (math-solve-find-root-in-prod x)
2975 (setq t3 neg
2976 t1 x)
2977 (and (memq (car-safe x) '(+ -))
2978 (or (math-solve-find-root-term (nth 1 x) neg)
2979 (math-solve-find-root-term (nth 2 x)
2980 (if (eq (car x) '-) (not neg) neg))))))
2981
2982 (defun math-solve-find-root-in-prod (x)
2983 (and (consp x)
2984 (math-expr-contains x solve-var)
2985 (or (and (eq (car x) 'calcFunc-sqrt)
2986 (setq t2 2))
2987 (and (eq (car x) '^)
2988 (or (and (memq (math-quarter-integer (nth 2 x)) '(1 2 3))
2989 (setq t2 2))
2990 (and (eq (car-safe (nth 2 x)) 'frac)
2991 (eq (nth 2 (nth 2 x)) 3)
2992 (setq t2 3))))
2993 (and (memq (car x) '(* /))
2994 (or (and (not (math-expr-contains (nth 1 x) solve-var))
2995 (math-solve-find-root-in-prod (nth 2 x)))
2996 (and (not (math-expr-contains (nth 2 x) solve-var))
2997 (math-solve-find-root-in-prod (nth 1 x))))))))
2998
2999
3000 (defun math-solve-system (exprs solve-vars solve-full)
3001 (setq exprs (mapcar 'list (if (Math-vectorp exprs)
3002 (cdr exprs)
3003 (list exprs)))
3004 solve-vars (if (Math-vectorp solve-vars)
3005 (cdr solve-vars)
3006 (list solve-vars)))
3007 (or (let ((math-solve-simplifying nil))
3008 (math-solve-system-rec exprs solve-vars nil))
3009 (let ((math-solve-simplifying t))
3010 (math-solve-system-rec exprs solve-vars nil))))
3011
3012 ;;; The following backtracking solver works by choosing a variable
3013 ;;; and equation, and trying to solve the equation for the variable.
3014 ;;; If it succeeds it calls itself recursively with that variable and
3015 ;;; equation removed from their respective lists, and with the solution
3016 ;;; added to solns as well as being substituted into all existing
3017 ;;; equations. The algorithm terminates when any solution path
3018 ;;; manages to remove all the variables from var-list.
3019
3020 ;;; To support calcFunc-roots, entries in eqn-list and solns are
3021 ;;; actually lists of equations.
3022
3023 (defun math-solve-system-rec (eqn-list var-list solns)
3024 (if var-list
3025 (let ((v var-list)
3026 (res nil))
3027
3028 ;; Try each variable in turn.
3029 (while
3030 (and
3031 v
3032 (let* ((vv (car v))
3033 (e eqn-list)
3034 (elim (eq (car-safe vv) 'calcFunc-elim)))
3035 (if elim
3036 (setq vv (nth 1 vv)))
3037
3038 ;; Try each equation in turn.
3039 (while
3040 (and
3041 e
3042 (let ((e2 (car e))
3043 (eprev nil)
3044 res2)
3045 (setq res nil)
3046
3047 ;; Try to solve for vv the list of equations e2.
3048 (while (and e2
3049 (setq res2 (or (and (eq (car e2) eprev)
3050 res2)
3051 (math-solve-for (car e2) 0 vv
3052 solve-full))))
3053 (setq eprev (car e2)
3054 res (cons (if (eq solve-full 'all)
3055 (cdr res2)
3056 (list res2))
3057 res)
3058 e2 (cdr e2)))
3059 (if e2
3060 (setq res nil)
3061
3062 ;; Found a solution. Now try other variables.
3063 (setq res (nreverse res)
3064 res (math-solve-system-rec
3065 (mapcar
3066 'math-solve-system-subst
3067 (delq (car e)
3068 (copy-sequence eqn-list)))
3069 (delq (car v) (copy-sequence var-list))
3070 (let ((math-solve-simplifying nil)
3071 (s (mapcar
3072 (function
3073 (lambda (x)
3074 (cons
3075 (car x)
3076 (math-solve-system-subst
3077 (cdr x)))))
3078 solns)))
3079 (if elim
3080 s
3081 (cons (cons vv (apply 'append res))
3082 s)))))
3083 (not res))))
3084 (setq e (cdr e)))
3085 (not res)))
3086 (setq v (cdr v)))
3087 res)
3088
3089 ;; Eliminated all variables, so now put solution into the proper format.
3090 (setq solns (sort solns
3091 (function
3092 (lambda (x y)
3093 (not (memq (car x) (memq (car y) solve-vars)))))))
3094 (if (eq solve-full 'all)
3095 (math-transpose
3096 (math-normalize
3097 (cons 'vec
3098 (if solns
3099 (mapcar (function (lambda (x) (cons 'vec (cdr x)))) solns)
3100 (mapcar (function (lambda (x) (cons 'vec x))) eqn-list)))))
3101 (math-normalize
3102 (cons 'vec
3103 (if solns
3104 (mapcar (function (lambda (x) (cons 'calcFunc-eq x))) solns)
3105 (mapcar 'car eqn-list)))))))
3106
3107 (defun math-solve-system-subst (x) ; uses "res" and "v"
3108 (let ((accum nil)
3109 (res2 res))
3110 (while x
3111 (setq accum (nconc accum
3112 (mapcar (function
3113 (lambda (r)
3114 (if math-solve-simplifying
3115 (math-simplify
3116 (math-expr-subst (car x) vv r))
3117 (math-expr-subst (car x) vv r))))
3118 (car res2)))
3119 x (cdr x)
3120 res2 (cdr res2)))
3121 accum))
3122
3123
3124 (defun math-get-from-counter (name)
3125 (let ((ctr (assq name calc-command-flags)))
3126 (if ctr
3127 (setcdr ctr (1+ (cdr ctr)))
3128 (setq ctr (cons name 1)
3129 calc-command-flags (cons ctr calc-command-flags)))
3130 (cdr ctr)))
3131
3132 (defun math-solve-get-sign (val)
3133 (setq val (math-simplify val))
3134 (if (and (eq (car-safe val) '*)
3135 (Math-numberp (nth 1 val)))
3136 (list '* (nth 1 val) (math-solve-get-sign (nth 2 val)))
3137 (and (eq (car-safe val) 'calcFunc-sqrt)
3138 (eq (car-safe (nth 1 val)) '^)
3139 (setq val (math-normalize (list '^
3140 (nth 1 (nth 1 val))
3141 (math-div (nth 2 (nth 1 val)) 2)))))
3142 (if solve-full
3143 (if (and (calc-var-value 'var-GenCount)
3144 (Math-natnump var-GenCount)
3145 (not (eq solve-full 'all)))
3146 (prog1
3147 (math-mul (list 'calcFunc-as var-GenCount) val)
3148 (setq var-GenCount (math-add var-GenCount 1))
3149 (calc-refresh-evaltos 'var-GenCount))
3150 (let* ((var (concat "s" (int-to-string (math-get-from-counter 'solve-sign))))
3151 (var2 (list 'var (intern var) (intern (concat "var-" var)))))
3152 (if (eq solve-full 'all)
3153 (setq math-solve-ranges (cons (list var2 1 -1)
3154 math-solve-ranges)))
3155 (math-mul var2 val)))
3156 (calc-record-why "*Choosing positive solution")
3157 val)))
3158
3159 (defun math-solve-get-int (val &optional range first)
3160 (if solve-full
3161 (if (and (calc-var-value 'var-GenCount)
3162 (Math-natnump var-GenCount)
3163 (not (eq solve-full 'all)))
3164 (prog1
3165 (math-mul val (list 'calcFunc-an var-GenCount))
3166 (setq var-GenCount (math-add var-GenCount 1))
3167 (calc-refresh-evaltos 'var-GenCount))
3168 (let* ((var (concat "n" (int-to-string
3169 (math-get-from-counter 'solve-int))))
3170 (var2 (list 'var (intern var) (intern (concat "var-" var)))))
3171 (if (and range (eq solve-full 'all))
3172 (setq math-solve-ranges (cons (cons var2
3173 (cdr (calcFunc-index
3174 range (or first 0))))
3175 math-solve-ranges)))
3176 (math-mul val var2)))
3177 (calc-record-why "*Choosing 0 for arbitrary integer in solution")
3178 0))
3179
3180 (defun math-solve-sign (sign expr)
3181 (and sign
3182 (let ((s1 (math-possible-signs expr)))
3183 (cond ((memq s1 '(4 6))
3184 sign)
3185 ((memq s1 '(1 3))
3186 (- sign))))))
3187
3188 (defun math-looks-evenp (expr)
3189 (if (Math-integerp expr)
3190 (math-evenp expr)
3191 (if (memq (car expr) '(* /))
3192 (math-looks-evenp (nth 1 expr)))))
3193
3194 (defun math-solve-for (lhs rhs solve-var solve-full &optional sign)
3195 (if (math-expr-contains rhs solve-var)
3196 (math-solve-for (math-sub lhs rhs) 0 solve-var solve-full)
3197 (and (math-expr-contains lhs solve-var)
3198 (math-with-extra-prec 1
3199 (let* ((math-poly-base-variable solve-var)
3200 (res (math-try-solve-for lhs rhs sign)))
3201 (if (and (eq solve-full 'all)
3202 (math-known-realp solve-var))
3203 (let ((old-len (length res))
3204 new-len)
3205 (setq res (delq nil
3206 (mapcar (function
3207 (lambda (x)
3208 (and (not (memq (car-safe x)
3209 '(cplx polar)))
3210 x)))
3211 res))
3212 new-len (length res))
3213 (if (< new-len old-len)
3214 (calc-record-why (if (= new-len 1)
3215 "*All solutions were complex"
3216 (format
3217 "*Omitted %d complex solutions"
3218 (- old-len new-len)))))))
3219 res)))))
3220
3221 (defun math-solve-eqn (expr var full)
3222 (if (memq (car-safe expr) '(calcFunc-neq calcFunc-lt calcFunc-gt
3223 calcFunc-leq calcFunc-geq))
3224 (let ((res (math-solve-for (cons '- (cdr expr))
3225 0 var full
3226 (if (eq (car expr) 'calcFunc-neq) nil 1))))
3227 (and res
3228 (if (eq math-solve-sign 1)
3229 (list (car expr) var res)
3230 (if (eq math-solve-sign -1)
3231 (list (car expr) res var)
3232 (or (eq (car expr) 'calcFunc-neq)
3233 (calc-record-why
3234 "*Can't determine direction of inequality"))
3235 (and (memq (car expr) '(calcFunc-neq calcFunc-lt calcFunc-gt))
3236 (list 'calcFunc-neq var res))))))
3237 (let ((res (math-solve-for expr 0 var full)))
3238 (and res
3239 (list 'calcFunc-eq var res)))))
3240
3241 (defun math-reject-solution (expr var func)
3242 (if (math-expr-contains expr var)
3243 (or (equal (car calc-next-why) '(* "Unable to find a symbolic solution"))
3244 (calc-record-why "*Unable to find a solution")))
3245 (list func expr var))
3246
3247 (defun calcFunc-solve (expr var)
3248 (or (if (or (Math-vectorp expr) (Math-vectorp var))
3249 (math-solve-system expr var nil)
3250 (math-solve-eqn expr var nil))
3251 (math-reject-solution expr var 'calcFunc-solve)))
3252
3253 (defun calcFunc-fsolve (expr var)
3254 (or (if (or (Math-vectorp expr) (Math-vectorp var))
3255 (math-solve-system expr var t)
3256 (math-solve-eqn expr var t))
3257 (math-reject-solution expr var 'calcFunc-fsolve)))
3258
3259 (defun calcFunc-roots (expr var)
3260 (let ((math-solve-ranges nil))
3261 (or (if (or (Math-vectorp expr) (Math-vectorp var))
3262 (math-solve-system expr var 'all)
3263 (math-solve-for expr 0 var 'all))
3264 (math-reject-solution expr var 'calcFunc-roots))))
3265
3266 (defun calcFunc-finv (expr var)
3267 (let ((res (math-solve-for expr math-integ-var var nil)))
3268 (if res
3269 (math-normalize (math-expr-subst res math-integ-var var))
3270 (math-reject-solution expr var 'calcFunc-finv))))
3271
3272 (defun calcFunc-ffinv (expr var)
3273 (let ((res (math-solve-for expr math-integ-var var t)))
3274 (if res
3275 (math-normalize (math-expr-subst res math-integ-var var))
3276 (math-reject-solution expr var 'calcFunc-finv))))
3277
3278
3279 (put 'calcFunc-inv 'math-inverse
3280 (function (lambda (x) (math-div 1 x))))
3281 (put 'calcFunc-inv 'math-inverse-sign -1)
3282
3283 (put 'calcFunc-sqrt 'math-inverse
3284 (function (lambda (x) (math-sqr x))))
3285
3286 (put 'calcFunc-conj 'math-inverse
3287 (function (lambda (x) (list 'calcFunc-conj x))))
3288
3289 (put 'calcFunc-abs 'math-inverse
3290 (function (lambda (x) (math-solve-get-sign x))))
3291
3292 (put 'calcFunc-deg 'math-inverse
3293 (function (lambda (x) (list 'calcFunc-rad x))))
3294 (put 'calcFunc-deg 'math-inverse-sign 1)
3295
3296 (put 'calcFunc-rad 'math-inverse
3297 (function (lambda (x) (list 'calcFunc-deg x))))
3298 (put 'calcFunc-rad 'math-inverse-sign 1)
3299
3300 (put 'calcFunc-ln 'math-inverse
3301 (function (lambda (x) (list 'calcFunc-exp x))))
3302 (put 'calcFunc-ln 'math-inverse-sign 1)
3303
3304 (put 'calcFunc-log10 'math-inverse
3305 (function (lambda (x) (list 'calcFunc-exp10 x))))
3306 (put 'calcFunc-log10 'math-inverse-sign 1)
3307
3308 (put 'calcFunc-lnp1 'math-inverse
3309 (function (lambda (x) (list 'calcFunc-expm1 x))))
3310 (put 'calcFunc-lnp1 'math-inverse-sign 1)
3311
3312 (put 'calcFunc-exp 'math-inverse
3313 (function (lambda (x) (math-add (math-normalize (list 'calcFunc-ln x))
3314 (math-mul 2
3315 (math-mul '(var pi var-pi)
3316 (math-solve-get-int
3317 '(var i var-i))))))))
3318 (put 'calcFunc-exp 'math-inverse-sign 1)
3319
3320 (put 'calcFunc-expm1 'math-inverse
3321 (function (lambda (x) (math-add (math-normalize (list 'calcFunc-lnp1 x))
3322 (math-mul 2
3323 (math-mul '(var pi var-pi)
3324 (math-solve-get-int
3325 '(var i var-i))))))))
3326 (put 'calcFunc-expm1 'math-inverse-sign 1)
3327
3328 (put 'calcFunc-sin 'math-inverse
3329 (function (lambda (x) (let ((n (math-solve-get-int 1)))
3330 (math-add (math-mul (math-normalize
3331 (list 'calcFunc-arcsin x))
3332 (math-pow -1 n))
3333 (math-mul (math-half-circle t)
3334 n))))))
3335
3336 (put 'calcFunc-cos 'math-inverse
3337 (function (lambda (x) (math-add (math-solve-get-sign
3338 (math-normalize
3339 (list 'calcFunc-arccos x)))
3340 (math-solve-get-int
3341 (math-full-circle t))))))
3342
3343 (put 'calcFunc-tan 'math-inverse
3344 (function (lambda (x) (math-add (math-normalize (list 'calcFunc-arctan x))
3345 (math-solve-get-int
3346 (math-half-circle t))))))
3347
3348 (put 'calcFunc-arcsin 'math-inverse
3349 (function (lambda (x) (math-normalize (list 'calcFunc-sin x)))))
3350
3351 (put 'calcFunc-arccos 'math-inverse
3352 (function (lambda (x) (math-normalize (list 'calcFunc-cos x)))))
3353
3354 (put 'calcFunc-arctan 'math-inverse
3355 (function (lambda (x) (math-normalize (list 'calcFunc-tan x)))))
3356
3357 (put 'calcFunc-sinh 'math-inverse
3358 (function (lambda (x) (let ((n (math-solve-get-int 1)))
3359 (math-add (math-mul (math-normalize
3360 (list 'calcFunc-arcsinh x))
3361 (math-pow -1 n))
3362 (math-mul (math-half-circle t)
3363 (math-mul
3364 '(var i var-i)
3365 n)))))))
3366 (put 'calcFunc-sinh 'math-inverse-sign 1)
3367
3368 (put 'calcFunc-cosh 'math-inverse
3369 (function (lambda (x) (math-add (math-solve-get-sign
3370 (math-normalize
3371 (list 'calcFunc-arccosh x)))
3372 (math-mul (math-full-circle t)
3373 (math-solve-get-int
3374 '(var i var-i)))))))
3375
3376 (put 'calcFunc-tanh 'math-inverse
3377 (function (lambda (x) (math-add (math-normalize
3378 (list 'calcFunc-arctanh x))
3379 (math-mul (math-half-circle t)
3380 (math-solve-get-int
3381 '(var i var-i)))))))
3382 (put 'calcFunc-tanh 'math-inverse-sign 1)
3383
3384 (put 'calcFunc-arcsinh 'math-inverse
3385 (function (lambda (x) (math-normalize (list 'calcFunc-sinh x)))))
3386 (put 'calcFunc-arcsinh 'math-inverse-sign 1)
3387
3388 (put 'calcFunc-arccosh 'math-inverse
3389 (function (lambda (x) (math-normalize (list 'calcFunc-cosh x)))))
3390
3391 (put 'calcFunc-arctanh 'math-inverse
3392 (function (lambda (x) (math-normalize (list 'calcFunc-tanh x)))))
3393 (put 'calcFunc-arctanh 'math-inverse-sign 1)
3394
3395
3396
3397 (defun calcFunc-taylor (expr var num)
3398 (let ((x0 0) (v var))
3399 (if (memq (car-safe var) '(+ - calcFunc-eq))
3400 (setq x0 (if (eq (car var) '+) (math-neg (nth 2 var)) (nth 2 var))
3401 v (nth 1 var)))
3402 (or (and (eq (car-safe v) 'var)
3403 (math-expr-contains expr v)
3404 (natnump num)
3405 (let ((accum (math-expr-subst expr v x0))
3406 (var2 (if (eq (car var) 'calcFunc-eq)
3407 (cons '- (cdr var))
3408 var))
3409 (n 0)
3410 (nfac 1)
3411 (fprime expr))
3412 (while (and (<= (setq n (1+ n)) num)
3413 (setq fprime (calcFunc-deriv fprime v nil t)))
3414 (setq fprime (math-simplify fprime)
3415 nfac (math-mul nfac n)
3416 accum (math-add accum
3417 (math-div (math-mul (math-pow var2 n)
3418 (math-expr-subst
3419 fprime v x0))
3420 nfac))))
3421 (and fprime
3422 (math-normalize accum))))
3423 (list 'calcFunc-taylor expr var num))))
3424
3425 ;;; arch-tag: f2932ec8-dd63-418b-a542-11a644b9d4c4
3426 ;;; calcalg2.el ends here