Merge from emacs--rel--22
[bpt/emacs.git] / lisp / calc / calcalg3.el
1 ;;; calcalg3.el --- more algebraic functions for Calc
2
3 ;; Copyright (C) 1990, 1991, 1992, 1993, 2001, 2002, 2003, 2004,
4 ;; 2005, 2006, 2007 Free Software Foundation, Inc.
5
6 ;; Author: David Gillespie <daveg@synaptics.com>
7 ;; Maintainer: Jay Belanger <jay.p.belanger@gmail.com>
8
9 ;; This file is part of GNU Emacs.
10
11 ;; GNU Emacs is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 3, or (at your option)
14 ;; any later version.
15
16 ;; GNU Emacs is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
20
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
23 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 ;; Boston, MA 02110-1301, USA.
25
26 ;;; Commentary:
27
28 ;;; Code:
29
30 ;; This file is autoloaded from calc-ext.el.
31
32 (require 'calc-ext)
33 (require 'calc-macs)
34
35 (defun calc-find-root (var)
36 (interactive "sVariable(s) to solve for: ")
37 (calc-slow-wrapper
38 (let ((func (if (calc-is-hyperbolic) 'calcFunc-wroot 'calcFunc-root)))
39 (if (or (equal var "") (equal var "$"))
40 (calc-enter-result 2 "root" (list func
41 (calc-top-n 3)
42 (calc-top-n 1)
43 (calc-top-n 2)))
44 (let ((var (if (and (string-match ",\\|[^ ] +[^ ]" var)
45 (not (string-match "\\[" var)))
46 (math-read-expr (concat "[" var "]"))
47 (math-read-expr var))))
48 (if (eq (car-safe var) 'error)
49 (error "Bad format in expression: %s" (nth 1 var)))
50 (calc-enter-result 1 "root" (list func
51 (calc-top-n 2)
52 var
53 (calc-top-n 1))))))))
54
55 (defun calc-find-minimum (var)
56 (interactive "sVariable(s) to minimize over: ")
57 (calc-slow-wrapper
58 (let ((func (if (calc-is-inverse)
59 (if (calc-is-hyperbolic)
60 'calcFunc-wmaximize 'calcFunc-maximize)
61 (if (calc-is-hyperbolic)
62 'calcFunc-wminimize 'calcFunc-minimize)))
63 (tag (if (calc-is-inverse) "max" "min")))
64 (if (or (equal var "") (equal var "$"))
65 (calc-enter-result 2 tag (list func
66 (calc-top-n 3)
67 (calc-top-n 1)
68 (calc-top-n 2)))
69 (let ((var (if (and (string-match ",\\|[^ ] +[^ ]" var)
70 (not (string-match "\\[" var)))
71 (math-read-expr (concat "[" var "]"))
72 (math-read-expr var))))
73 (if (eq (car-safe var) 'error)
74 (error "Bad format in expression: %s" (nth 1 var)))
75 (calc-enter-result 1 tag (list func
76 (calc-top-n 2)
77 var
78 (calc-top-n 1))))))))
79
80 (defun calc-find-maximum (var)
81 (interactive "sVariable to maximize over: ")
82 (calc-invert-func)
83 (calc-find-minimum var))
84
85
86 (defun calc-poly-interp (arg)
87 (interactive "P")
88 (calc-slow-wrapper
89 (let ((data (calc-top 2)))
90 (if (or (consp arg) (eq arg 0) (eq arg 2))
91 (setq data (cons 'vec (calc-top-list 2 2)))
92 (or (null arg)
93 (error "Bad prefix argument")))
94 (if (calc-is-hyperbolic)
95 (calc-enter-result 1 "rati" (list 'calcFunc-ratint data (calc-top 1)))
96 (calc-enter-result 1 "poli" (list 'calcFunc-polint data
97 (calc-top 1)))))))
98
99 ;; The variables calc-curve-nvars, calc-curve-varnames, calc-curve-model and calc-curve-coefnames are local to calc-curve-fit, but are
100 ;; used by calc-get-fit-variables which is called by calc-curve-fit.
101 (defvar calc-curve-nvars)
102 (defvar calc-curve-varnames)
103 (defvar calc-curve-model)
104 (defvar calc-curve-coefnames)
105
106 (defvar calc-curve-fit-history nil
107 "History for calc-curve-fit.")
108
109 (defun calc-curve-fit (arg &optional calc-curve-model
110 calc-curve-coefnames calc-curve-varnames)
111 (interactive "P")
112 (calc-slow-wrapper
113 (setq calc-aborted-prefix nil)
114 (let ((func (if (calc-is-inverse) 'calcFunc-xfit
115 (if (calc-is-hyperbolic) 'calcFunc-efit
116 'calcFunc-fit)))
117 key (which 0)
118 (nonlinear nil)
119 (plot nil)
120 n calc-curve-nvars temp data
121 (homog nil)
122 (msgs '( "(Press ? for help)"
123 "1 = linear or multilinear"
124 "2-9 = polynomial fits; i = interpolating polynomial"
125 "p = a x^b, ^ = a b^x"
126 "e = a exp(b x), x = exp(a + b x), l = a + b ln(x)"
127 "E = a 10^(b x), X = 10^(a + b x), L = a + b log10(x)"
128 "q = a + b (x-c)^2"
129 "g = (a/b sqrt(2 pi)) exp(-0.5*((x-c)/b)^2)"
130 "s = a/(1 + exp(b (x - c)))"
131 "b = a exp(b (x - c))/(1 + exp(b (x - c)))^2"
132 "o = (y/x) = a (1 - x/b)"
133 "h prefix = homogeneous model (no constant term)"
134 "P prefix = plot result"
135 "' = alg entry, $ = stack, u = Model1, U = Model2")))
136 (while (not calc-curve-model)
137 (message
138 "Fit to model: %s:%s%s"
139 (nth which msgs)
140 (if plot "P" " ")
141 (if homog "h" ""))
142 (setq key (read-char))
143 (cond ((= key ?\C-g)
144 (keyboard-quit))
145 ((= key ??)
146 (setq which (% (1+ which) (length msgs))))
147 ((memq key '(?h ?H))
148 (setq homog (not homog)))
149 ((= key ?P)
150 (if plot
151 (setq plot nil)
152 (let ((data (calc-top 1)))
153 (if (or
154 (calc-is-hyperbolic)
155 (calc-is-inverse)
156 (not (= (length data) 3)))
157 (setq plot "Can't plot")
158 (setq plot data)))))
159 ((progn
160 (if (eq key ?\$)
161 (setq n 1)
162 (setq n 0))
163 (cond ((null arg)
164 (setq n (1+ n)
165 data (calc-top n)))
166 ((or (consp arg) (eq arg 0))
167 (setq n (+ n 2)
168 data (calc-top n)
169 data (if (math-matrixp data)
170 (append data (list (calc-top (1- n))))
171 (list 'vec data (calc-top (1- n))))))
172 ((> (setq arg (prefix-numeric-value arg)) 0)
173 (setq data (cons 'vec (calc-top-list arg (1+ n)))
174 n (+ n arg)))
175 (t (error "Bad prefix argument")))
176 (or (math-matrixp data) (not (cdr (cdr data)))
177 (error "Data matrix is not a matrix!"))
178 (setq calc-curve-nvars (- (length data) 2)
179 calc-curve-coefnames nil
180 calc-curve-varnames nil)
181 nil))
182 ((= key ?1) ; linear or multilinear
183 (calc-get-fit-variables calc-curve-nvars
184 (1+ calc-curve-nvars) (and homog 0))
185 (setq calc-curve-model
186 (math-mul calc-curve-coefnames
187 (cons 'vec (cons 1 (cdr calc-curve-varnames))))))
188 ((and (>= key ?2) (<= key ?9)) ; polynomial
189 (calc-get-fit-variables 1 (- key ?0 -1) (and homog 0))
190 (setq calc-curve-model
191 (math-build-polynomial-expr (cdr calc-curve-coefnames)
192 (nth 1 calc-curve-varnames))))
193 ((= key ?i) ; exact polynomial
194 (calc-get-fit-variables 1 (1- (length (nth 1 data)))
195 (and homog 0))
196 (setq calc-curve-model
197 (math-build-polynomial-expr (cdr calc-curve-coefnames)
198 (nth 1 calc-curve-varnames))))
199 ((= key ?p) ; power law
200 (calc-get-fit-variables calc-curve-nvars
201 (1+ calc-curve-nvars) (and homog 1))
202 (setq calc-curve-model
203 (math-mul
204 (nth 1 calc-curve-coefnames)
205 (calcFunc-reduce
206 '(var mul var-mul)
207 (calcFunc-map
208 '(var pow var-pow)
209 calc-curve-varnames
210 (cons 'vec (cdr (cdr calc-curve-coefnames))))))))
211 ((= key ?^) ; exponential law
212 (calc-get-fit-variables calc-curve-nvars
213 (1+ calc-curve-nvars) (and homog 1))
214 (setq calc-curve-model
215 (math-mul (nth 1 calc-curve-coefnames)
216 (calcFunc-reduce
217 '(var mul var-mul)
218 (calcFunc-map
219 '(var pow var-pow)
220 (cons 'vec (cdr (cdr calc-curve-coefnames)))
221 calc-curve-varnames)))))
222 ((= key ?s)
223 (setq nonlinear t)
224 (setq calc-curve-model t)
225 (require 'calc-nlfit)
226 (calc-fit-s-shaped-logistic-curve func))
227 ((= key ?b)
228 (setq nonlinear t)
229 (setq calc-curve-model t)
230 (require 'calc-nlfit)
231 (calc-fit-bell-shaped-logistic-curve func))
232 ((= key ?o)
233 (setq nonlinear t)
234 (setq calc-curve-model t)
235 (require 'calc-nlfit)
236 (if (and plot (not (stringp plot)))
237 (setq plot
238 (list 'vec
239 (nth 1 plot)
240 (cons
241 'vec
242 (mapcar* 'calcFunc-div
243 (cdr (nth 2 plot))
244 (cdr (nth 1 plot)))))))
245 (calc-fit-hubbert-linear-curve func))
246 ((memq key '(?e ?E))
247 (calc-get-fit-variables calc-curve-nvars
248 (1+ calc-curve-nvars) (and homog 1))
249 (setq calc-curve-model
250 (math-mul (nth 1 calc-curve-coefnames)
251 (calcFunc-reduce
252 '(var mul var-mul)
253 (calcFunc-map
254 (if (eq key ?e)
255 '(var exp var-exp)
256 '(calcFunc-lambda
257 (var a var-a)
258 (^ 10 (var a var-a))))
259 (calcFunc-map
260 '(var mul var-mul)
261 (cons 'vec (cdr (cdr calc-curve-coefnames)))
262 calc-curve-varnames))))))
263 ((memq key '(?x ?X))
264 (calc-get-fit-variables calc-curve-nvars
265 (1+ calc-curve-nvars) (and homog 0))
266 (setq calc-curve-model
267 (math-mul calc-curve-coefnames
268 (cons 'vec (cons 1 (cdr calc-curve-varnames)))))
269 (setq calc-curve-model (if (eq key ?x)
270 (list 'calcFunc-exp calc-curve-model)
271 (list '^ 10 calc-curve-model))))
272 ((memq key '(?l ?L))
273 (calc-get-fit-variables calc-curve-nvars
274 (1+ calc-curve-nvars) (and homog 0))
275 (setq calc-curve-model
276 (math-mul calc-curve-coefnames
277 (cons 'vec
278 (cons 1 (cdr (calcFunc-map
279 (if (eq key ?l)
280 '(var ln var-ln)
281 '(var log10
282 var-log10))
283 calc-curve-varnames)))))))
284 ((= key ?q)
285 (calc-get-fit-variables calc-curve-nvars
286 (1+ (* 2 calc-curve-nvars)) (and homog 0))
287 (let ((c calc-curve-coefnames)
288 (v calc-curve-varnames))
289 (setq calc-curve-model (nth 1 c))
290 (while (setq v (cdr v) c (cdr (cdr c)))
291 (setq calc-curve-model (math-add
292 calc-curve-model
293 (list '*
294 (car c)
295 (list '^
296 (list '- (car v) (nth 1 c))
297 2)))))))
298 ((= key ?g)
299 (setq
300 calc-curve-model
301 (math-read-expr
302 "(AFit / BFit sqrt(2 pi)) exp(-0.5 * ((XFit - CFit) / BFit)^2)")
303 calc-curve-varnames '(vec (var XFit var-XFit))
304 calc-curve-coefnames '(vec (var AFit var-AFit)
305 (var BFit var-BFit)
306 (var CFit var-CFit)))
307 (calc-get-fit-variables 1 (1- (length calc-curve-coefnames))
308 (and homog 1)))
309 ((memq key '(?\$ ?\' ?u ?U))
310 (let* ((defvars nil)
311 (record-entry nil))
312 (if (eq key ?\')
313 (let* ((calc-dollar-values calc-arg-values)
314 (calc-dollar-used 0)
315 (calc-hashes-used 0))
316 (setq calc-curve-model
317 (calc-do-alg-entry "" "Model formula: "
318 nil 'calc-curve-fit-history))
319 (if (/= (length calc-curve-model) 1)
320 (error "Bad format"))
321 (setq calc-curve-model (car calc-curve-model)
322 record-entry t)
323 (if (> calc-dollar-used 0)
324 (setq calc-curve-coefnames
325 (cons 'vec
326 (nthcdr (- (length calc-arg-values)
327 calc-dollar-used)
328 (reverse calc-arg-values))))
329 (if (> calc-hashes-used 0)
330 (setq calc-curve-coefnames
331 (cons 'vec (calc-invent-args
332 calc-hashes-used))))))
333 (progn
334 (setq calc-curve-model (cond ((eq key ?u)
335 (calc-var-value 'var-Model1))
336 ((eq key ?U)
337 (calc-var-value 'var-Model2))
338 (t (calc-top 1))))
339 (or calc-curve-model (error "User model not yet defined"))
340 (if (math-vectorp calc-curve-model)
341 (if (and (memq (length calc-curve-model) '(3 4))
342 (not (math-objvecp (nth 1 calc-curve-model)))
343 (math-vectorp (nth 2 calc-curve-model))
344 (or (null (nth 3 calc-curve-model))
345 (math-vectorp (nth 3 calc-curve-model))))
346 (setq calc-curve-varnames (nth 2 calc-curve-model)
347 calc-curve-coefnames
348 (or (nth 3 calc-curve-model)
349 (cons 'vec
350 (math-all-vars-but
351 calc-curve-model
352 calc-curve-varnames)))
353 calc-curve-model (nth 1 calc-curve-model))
354 (error "Incorrect model specifier")))))
355 (or calc-curve-varnames
356 (let ((with-y
357 (eq (car-safe calc-curve-model) 'calcFunc-eq)))
358 (if calc-curve-coefnames
359 (calc-get-fit-variables
360 (if with-y (1+ calc-curve-nvars) calc-curve-nvars)
361 (1- (length calc-curve-coefnames))
362 (math-all-vars-but
363 calc-curve-model calc-curve-coefnames)
364 nil with-y)
365 (let* ((coefs (math-all-vars-but calc-curve-model nil))
366 (vars nil)
367 (n (-
368 (length coefs)
369 calc-curve-nvars
370 (if with-y 2 1)))
371 p)
372 (if (< n 0)
373 (error "Not enough variables in model"))
374 (setq p (nthcdr n coefs))
375 (setq vars (cdr p))
376 (setcdr p nil)
377 (calc-get-fit-variables
378 (if with-y (1+ calc-curve-nvars) calc-curve-nvars)
379 (length coefs)
380 vars coefs with-y)))))
381 (if record-entry
382 (calc-record (list 'vec calc-curve-model
383 calc-curve-varnames calc-curve-coefnames)
384 "modl"))))
385 (t (beep))))
386 (unless nonlinear
387 (let ((calc-fit-to-trail t))
388 (calc-enter-result n (substring (symbol-name func) 9)
389 (list func calc-curve-model
390 (if (= (length calc-curve-varnames) 2)
391 (nth 1 calc-curve-varnames)
392 calc-curve-varnames)
393 (if (= (length calc-curve-coefnames) 2)
394 (nth 1 calc-curve-coefnames)
395 calc-curve-coefnames)
396 data))
397 (if (consp calc-fit-to-trail)
398 (calc-record (calc-normalize calc-fit-to-trail) "parm"))))
399 (when plot
400 (if (stringp plot)
401 (message plot)
402 (let ((calc-graph-no-auto-view t))
403 (calc-graph-delete t)
404 (calc-graph-add-curve
405 (calc-graph-lookup (nth 1 plot))
406 (calc-graph-lookup (nth 2 plot)))
407 (unless (math-contains-sdev-p (nth 2 data))
408 (calc-graph-set-styles nil nil)
409 (calc-graph-point-style nil))
410 (setq plot (cdr (nth 1 plot)))
411 (setq plot
412 (list 'intv
413 3
414 (math-sub
415 (math-min-list (car plot) (cdr plot))
416 '(float 5 -1))
417 (math-add
418 '(float 5 -1)
419 (math-max-list (car plot) (cdr plot)))))
420 (calc-graph-add-curve (calc-graph-lookup plot)
421 (calc-graph-lookup (calc-top-n 1)))
422 (calc-graph-plot nil)))))))
423
424 (defun calc-invent-independent-variables (n &optional but)
425 (calc-invent-variables n but '(x y z t) "x"))
426
427 (defun calc-invent-parameter-variables (n &optional but)
428 (calc-invent-variables n but '(a b c d) "a"))
429
430 (defun calc-invent-variables (num but names base)
431 (let ((vars nil)
432 (n num) (nn 0)
433 var)
434 (while (and (> n 0) names)
435 (setq var (math-build-var-name (if (consp names)
436 (car names)
437 (concat base (int-to-string
438 (setq nn (1+ nn)))))))
439 (or (math-expr-contains (cons 'vec but) var)
440 (setq vars (cons var vars)
441 n (1- n)))
442 (or (symbolp names) (setq names (cdr names))))
443 (if (= n 0)
444 (nreverse vars)
445 (calc-invent-variables num but t base))))
446
447 (defun calc-get-fit-variables (nv nc &optional defv defc with-y homog)
448 (or (= nv (if with-y (1+ calc-curve-nvars) calc-curve-nvars))
449 (error "Wrong number of data vectors for this type of model"))
450 (if (integerp defv)
451 (setq homog defv
452 defv nil))
453 (if homog
454 (setq nc (1- nc)))
455 (or defv
456 (setq defv (calc-invent-independent-variables nv)))
457 (or defc
458 (setq defc (calc-invent-parameter-variables nc defv)))
459 (let ((vars (read-string (format "Fitting variables (default %s; %s): "
460 (mapconcat 'symbol-name
461 (mapcar (function (lambda (v)
462 (nth 1 v)))
463 defv)
464 ",")
465 (mapconcat 'symbol-name
466 (mapcar (function (lambda (v)
467 (nth 1 v)))
468 defc)
469 ","))))
470 (coefs nil))
471 (setq vars (if (string-match "\\[" vars)
472 (math-read-expr vars)
473 (math-read-expr (concat "[" vars "]"))))
474 (if (eq (car-safe vars) 'error)
475 (error "Bad format in expression: %s" (nth 2 vars)))
476 (or (math-vectorp vars)
477 (error "Expected a variable or vector of variables"))
478 (if (equal vars '(vec))
479 (setq vars (cons 'vec defv)
480 coefs (cons 'vec defc))
481 (if (math-vectorp (nth 1 vars))
482 (if (and (= (length vars) 3)
483 (math-vectorp (nth 2 vars)))
484 (setq coefs (nth 2 vars)
485 vars (nth 1 vars))
486 (error
487 "Expected independent variables vector, then parameters vector"))
488 (setq coefs (cons 'vec defc))))
489 (or (= nv (1- (length vars)))
490 (and (not with-y) (= (1+ nv) (1- (length vars))))
491 (error "Expected %d independent variable%s" nv (if (= nv 1) "" "s")))
492 (or (= nc (1- (length coefs)))
493 (error "Expected %d parameter variable%s" nc (if (= nc 1) "" "s")))
494 (if homog
495 (setq coefs (cons 'vec (cons homog (cdr coefs)))))
496 (if calc-curve-varnames
497 (setq calc-curve-model (math-multi-subst calc-curve-model (cdr calc-curve-varnames) (cdr vars))))
498 (if calc-curve-coefnames
499 (setq calc-curve-model (math-multi-subst calc-curve-model (cdr calc-curve-coefnames) (cdr coefs))))
500 (setq calc-curve-varnames vars
501 calc-curve-coefnames coefs)))
502
503
504
505
506 ;;; The following algorithms are from Numerical Recipes chapter 9.
507
508 ;;; "rtnewt" with safety kludges
509
510 (defvar var-DUMMY)
511
512 (defun math-newton-root (expr deriv guess orig-guess limit)
513 (math-working "newton" guess)
514 (let* ((var-DUMMY guess)
515 next dval)
516 (setq next (math-evaluate-expr expr)
517 dval (math-evaluate-expr deriv))
518 (if (and (Math-numberp next)
519 (Math-numberp dval)
520 (not (Math-zerop dval)))
521 (progn
522 (setq next (math-sub guess (math-div next dval)))
523 (if (math-nearly-equal guess (setq next (math-float next)))
524 (progn
525 (setq var-DUMMY next)
526 (list 'vec next (math-evaluate-expr expr)))
527 (if (Math-lessp (math-abs-approx (math-sub next orig-guess))
528 limit)
529 (math-newton-root expr deriv next orig-guess limit)
530 (math-reject-arg next "*Newton's method failed to converge"))))
531 (math-reject-arg next "*Newton's method encountered a singularity"))))
532
533 ;;; Inspired by "rtsafe"
534 (defun math-newton-search-root (expr deriv guess vguess ostep oostep
535 low vlow high vhigh)
536 (let ((var-DUMMY guess)
537 (better t)
538 pos step next vnext)
539 (if guess
540 (math-working "newton" (list 'intv 0 low high))
541 (math-working "bisect" (list 'intv 0 low high))
542 (setq ostep (math-mul-float (math-sub-float high low)
543 '(float 5 -1))
544 guess (math-add-float low ostep)
545 var-DUMMY guess
546 vguess (math-evaluate-expr expr))
547 (or (Math-realp vguess)
548 (progn
549 (setq ostep (math-mul-float ostep '(float 6 -1))
550 guess (math-add-float low ostep)
551 var-DUMMY guess
552 vguess (math-evaluate-expr expr))
553 (or (math-realp vguess)
554 (progn
555 (setq ostep (math-mul-float ostep '(float 123456 -5))
556 guess (math-add-float low ostep)
557 var-DUMMY guess
558 vguess nil))))))
559 (or vguess
560 (setq vguess (math-evaluate-expr expr)))
561 (or (Math-realp vguess)
562 (math-reject-arg guess "*Newton's method encountered a singularity"))
563 (setq vguess (math-float vguess))
564 (if (eq (Math-negp vlow) (setq pos (Math-posp vguess)))
565 (setq high guess
566 vhigh vguess)
567 (if (eq (Math-negp vhigh) pos)
568 (setq low guess
569 vlow vguess)
570 (setq better nil)))
571 (if (or (Math-zerop vguess)
572 (math-nearly-equal low high))
573 (list 'vec guess vguess)
574 (setq step (math-evaluate-expr deriv))
575 (if (and (Math-realp step)
576 (not (Math-zerop step))
577 (setq step (math-div-float vguess (math-float step))
578 next (math-sub-float guess step))
579 (not (math-lessp-float high next))
580 (not (math-lessp-float next low)))
581 (progn
582 (setq var-DUMMY next
583 vnext (math-evaluate-expr expr))
584 (if (or (Math-zerop vnext)
585 (math-nearly-equal next guess))
586 (list 'vec next vnext)
587 (if (and better
588 (math-lessp-float (math-abs (or oostep
589 (math-sub-float
590 high low)))
591 (math-abs
592 (math-mul-float '(float 2 0)
593 step))))
594 (math-newton-search-root expr deriv nil nil nil ostep
595 low vlow high vhigh)
596 (math-newton-search-root expr deriv next vnext step ostep
597 low vlow high vhigh))))
598 (if (or (and (Math-posp vlow) (Math-posp vhigh))
599 (and (Math-negp vlow) (Math-negp vhigh)))
600 (math-search-root expr deriv low vlow high vhigh)
601 (math-newton-search-root expr deriv nil nil nil ostep
602 low vlow high vhigh))))))
603
604 ;;; Search for a root in an interval with no overt zero crossing.
605
606 ;; The variable math-root-widen is local to math-find-root, but
607 ;; is used by math-search-root, which is called (directly and
608 ;; indirectly) by math-find-root.
609 (defvar math-root-widen)
610
611 (defun math-search-root (expr deriv low vlow high vhigh)
612 (let (found)
613 (if math-root-widen
614 (let ((iters 0)
615 (iterlim (if (eq math-root-widen 'point)
616 (+ calc-internal-prec 10)
617 20))
618 (factor (if (eq math-root-widen 'point)
619 '(float 9 0)
620 '(float 16 -1)))
621 (prev nil) vprev waslow
622 diff)
623 (while (or (and (math-posp vlow) (math-posp vhigh))
624 (and (math-negp vlow) (math-negp vhigh)))
625 (math-working "widen" (list 'intv 0 low high))
626 (if (> (setq iters (1+ iters)) iterlim)
627 (math-reject-arg (list 'intv 0 low high)
628 "*Unable to bracket root"))
629 (if (= iters calc-internal-prec)
630 (setq factor '(float 16 -1)))
631 (setq diff (math-mul-float (math-sub-float high low) factor))
632 (if (Math-zerop diff)
633 (setq high (calcFunc-incr high 10))
634 (if (math-lessp-float (math-abs vlow) (math-abs vhigh))
635 (setq waslow t
636 prev low
637 low (math-sub low diff)
638 var-DUMMY low
639 vprev vlow
640 vlow (math-evaluate-expr expr))
641 (setq waslow nil
642 prev high
643 high (math-add high diff)
644 var-DUMMY high
645 vprev vhigh
646 vhigh (math-evaluate-expr expr)))))
647 (if prev
648 (if waslow
649 (setq high prev vhigh vprev)
650 (setq low prev vlow vprev)))
651 (setq found t))
652 (or (Math-realp vlow)
653 (math-reject-arg vlow 'realp))
654 (or (Math-realp vhigh)
655 (math-reject-arg vhigh 'realp))
656 (let ((xvals (list low high))
657 (yvals (list vlow vhigh))
658 (pos (Math-posp vlow))
659 (levels 0)
660 (step (math-sub-float high low))
661 xp yp var-DUMMY)
662 (while (and (<= (setq levels (1+ levels)) 5)
663 (not found))
664 (setq xp xvals
665 yp yvals
666 step (math-mul-float step '(float 497 -3)))
667 (while (and (cdr xp) (not found))
668 (if (Math-realp (car yp))
669 (setq low (car xp)
670 vlow (car yp)))
671 (setq high (math-add-float (car xp) step)
672 var-DUMMY high
673 vhigh (math-evaluate-expr expr))
674 (math-working "search" high)
675 (if (and (Math-realp vhigh)
676 (eq (math-negp vhigh) pos))
677 (setq found t)
678 (setcdr xp (cons high (cdr xp)))
679 (setcdr yp (cons vhigh (cdr yp)))
680 (setq xp (cdr (cdr xp))
681 yp (cdr (cdr yp))))))))
682 (if found
683 (if (Math-zerop vhigh)
684 (list 'vec high vhigh)
685 (if (Math-zerop vlow)
686 (list 'vec low vlow)
687 (if deriv
688 (math-newton-search-root expr deriv nil nil nil nil
689 low vlow high vhigh)
690 (math-bisect-root expr low vlow high vhigh))))
691 (math-reject-arg (list 'intv 3 low high)
692 "*Unable to find a sign change in this interval"))))
693
694 ;;; "rtbis" (but we should be using Brent's method)
695 (defun math-bisect-root (expr low vlow high vhigh)
696 (let ((step (math-sub-float high low))
697 (pos (Math-posp vhigh))
698 var-DUMMY
699 mid vmid)
700 (while (not (or (math-nearly-equal low
701 (setq step (math-mul-float
702 step '(float 5 -1))
703 mid (math-add-float low step)))
704 (progn
705 (setq var-DUMMY mid
706 vmid (math-evaluate-expr expr))
707 (Math-zerop vmid))))
708 (math-working "bisect" mid)
709 (if (eq (Math-posp vmid) pos)
710 (setq high mid
711 vhigh vmid)
712 (setq low mid
713 vlow vmid)))
714 (list 'vec mid vmid)))
715
716 ;;; "mnewt"
717
718 (defvar math-root-vars [(var DUMMY var-DUMMY)])
719
720 (defun math-newton-multi (expr jacob n guess orig-guess limit)
721 (let ((m -1)
722 (p guess)
723 p2 expr-val jacob-val next)
724 (while (< (setq p (cdr p) m (1+ m)) n)
725 (set (nth 2 (aref math-root-vars m)) (car p)))
726 (setq expr-val (math-evaluate-expr expr)
727 jacob-val (math-evaluate-expr jacob))
728 (unless (and (math-constp expr-val)
729 (math-constp jacob-val))
730 (math-reject-arg guess "*Newton's method encountered a singularity"))
731 (setq next (math-add guess (math-div (math-float (math-neg expr-val))
732 (math-float jacob-val)))
733 p guess p2 next)
734 (math-working "newton" next)
735 (while (and (setq p (cdr p) p2 (cdr p2))
736 (math-nearly-equal (car p) (car p2))))
737 (if p
738 (if (Math-lessp (math-abs-approx (math-sub next orig-guess))
739 limit)
740 (math-newton-multi expr jacob n next orig-guess limit)
741 (math-reject-arg nil "*Newton's method failed to converge"))
742 (list 'vec next expr-val))))
743
744
745 (defun math-find-root (expr var guess math-root-widen)
746 (if (eq (car-safe expr) 'vec)
747 (let ((n (1- (length expr)))
748 (calc-symbolic-mode nil)
749 (var-DUMMY nil)
750 (jacob (list 'vec))
751 p p2 m row)
752 (unless (eq (car-safe var) 'vec)
753 (math-reject-arg var 'vectorp))
754 (unless (= (length var) (1+ n))
755 (math-dimension-error))
756 (setq expr (copy-sequence expr))
757 (while (>= n (length math-root-vars))
758 (let ((symb (intern (concat "math-root-v"
759 (int-to-string
760 (length math-root-vars))))))
761 (setq math-root-vars (vconcat math-root-vars
762 (vector (list 'var symb symb))))))
763 (setq m -1)
764 (while (< (setq m (1+ m)) n)
765 (set (nth 2 (aref math-root-vars m)) nil))
766 (setq m -1 p var)
767 (while (setq m (1+ m) p (cdr p))
768 (or (eq (car-safe (car p)) 'var)
769 (math-reject-arg var "*Expected a variable"))
770 (setq p2 expr)
771 (while (setq p2 (cdr p2))
772 (setcar p2 (math-expr-subst (car p2) (car p)
773 (aref math-root-vars m)))))
774 (unless (eq (car-safe guess) 'vec)
775 (math-reject-arg guess 'vectorp))
776 (unless (= (length guess) (1+ n))
777 (math-dimension-error))
778 (setq guess (copy-sequence guess)
779 p guess)
780 (while (setq p (cdr p))
781 (or (Math-numberp (car guess))
782 (math-reject-arg guess 'numberp))
783 (setcar p (math-float (car p))))
784 (setq p expr)
785 (while (setq p (cdr p))
786 (if (assq (car-safe (car p)) calc-tweak-eqn-table)
787 (setcar p (math-sub (nth 1 (car p)) (nth 2 (car p)))))
788 (setcar p (math-evaluate-expr (car p)))
789 (setq row (list 'vec)
790 m -1)
791 (while (< (setq m (1+ m)) n)
792 (nconc row (list (math-evaluate-expr
793 (or (calcFunc-deriv (car p)
794 (aref math-root-vars m)
795 nil t)
796 (math-reject-arg
797 expr
798 "*Formulas must be differentiable"))))))
799 (nconc jacob (list row)))
800 (setq m (math-abs-approx guess))
801 (math-newton-multi expr jacob n guess guess
802 (if (math-zerop m) '(float 1 3) (math-mul m 10))))
803 (unless (eq (car-safe var) 'var)
804 (math-reject-arg var "*Expected a variable"))
805 (unless (math-expr-contains expr var)
806 (math-reject-arg expr "*Formula does not contain specified variable"))
807 (if (assq (car expr) calc-tweak-eqn-table)
808 (setq expr (math-sub (nth 1 expr) (nth 2 expr))))
809 (math-with-extra-prec 2
810 (setq expr (math-expr-subst expr var '(var DUMMY var-DUMMY)))
811 (let* ((calc-symbolic-mode nil)
812 (var-DUMMY nil)
813 (expr (math-evaluate-expr expr))
814 (deriv (calcFunc-deriv expr '(var DUMMY var-DUMMY) nil t))
815 low high vlow vhigh)
816 (and deriv (setq deriv (math-evaluate-expr deriv)))
817 (setq guess (math-float guess))
818 (if (and (math-numberp guess)
819 deriv)
820 (math-newton-root expr deriv guess guess
821 (if (math-zerop guess) '(float 1 6)
822 (math-mul (math-abs-approx guess) 100)))
823 (if (Math-realp guess)
824 (setq low guess
825 high guess
826 var-DUMMY guess
827 vlow (math-evaluate-expr expr)
828 vhigh vlow
829 math-root-widen 'point)
830 (if (eq (car guess) 'intv)
831 (progn
832 (or (math-constp guess) (math-reject-arg guess 'constp))
833 (setq low (nth 2 guess)
834 high (nth 3 guess))
835 (if (memq (nth 1 guess) '(0 1))
836 (setq low (calcFunc-incr low 1 high)))
837 (if (memq (nth 1 guess) '(0 2))
838 (setq high (calcFunc-incr high -1 low)))
839 (setq var-DUMMY low
840 vlow (math-evaluate-expr expr)
841 var-DUMMY high
842 vhigh (math-evaluate-expr expr)))
843 (if (math-complexp guess)
844 (math-reject-arg "*Complex root finder must have derivative")
845 (math-reject-arg guess 'realp))))
846 (if (Math-zerop vlow)
847 (list 'vec low vlow)
848 (if (Math-zerop vhigh)
849 (list 'vec high vhigh)
850 (if (and deriv (Math-numberp vlow) (Math-numberp vhigh))
851 (math-newton-search-root expr deriv nil nil nil nil
852 low vlow high vhigh)
853 (if (or (and (Math-posp vlow) (Math-posp vhigh))
854 (and (Math-negp vlow) (Math-negp vhigh))
855 (not (Math-numberp vlow))
856 (not (Math-numberp vhigh)))
857 (math-search-root expr deriv low vlow high vhigh)
858 (math-bisect-root expr low vlow high vhigh))))))))))
859
860 (defun calcFunc-root (expr var guess)
861 (math-find-root expr var guess nil))
862
863 (defun calcFunc-wroot (expr var guess)
864 (math-find-root expr var guess t))
865
866
867
868
869 ;;; The following algorithms come from Numerical Recipes, chapter 10.
870
871 (defvar math-min-vars [(var DUMMY var-DUMMY)])
872
873 (defun math-min-eval (expr a)
874 (if (Math-vectorp a)
875 (let ((m -1))
876 (while (setq m (1+ m) a (cdr a))
877 (set (nth 2 (aref math-min-vars m)) (car a))))
878 (setq var-DUMMY a))
879 (setq a (math-evaluate-expr expr))
880 (if (Math-ratp a)
881 (math-float a)
882 (if (eq (car a) 'float)
883 a
884 (math-reject-arg a 'realp))))
885
886 (defvar math-min-or-max "minimum")
887
888 ;;; A bracket for a minimum is a < b < c where f(b) < f(a) and f(b) < f(c).
889
890 ;;; "mnbrak"
891 (defun math-widen-min (expr a b)
892 (let ((done nil)
893 (iters 30)
894 incr c va vb vc u vu r q ulim bc ba qr)
895 (or b (setq b (math-mul a '(float 101 -2))))
896 (setq va (math-min-eval expr a)
897 vb (math-min-eval expr b))
898 (if (math-lessp-float va vb)
899 (setq u a a b b u
900 vu va va vb vb vu))
901 (setq c (math-add-float b (math-mul-float '(float 161803 -5)
902 (math-sub-float b a)))
903 vc (math-min-eval expr c))
904 (while (and (not done) (math-lessp-float vc vb))
905 (math-working "widen" (list 'intv 0 a c))
906 (if (= (setq iters (1- iters)) 0)
907 (math-reject-arg nil (format "*Unable to find a %s near the interval"
908 math-min-or-max)))
909 (setq bc (math-sub-float b c)
910 ba (math-sub-float b a)
911 r (math-mul-float ba (math-sub-float vb vc))
912 q (math-mul-float bc (math-sub-float vb va))
913 qr (math-sub-float q r))
914 (if (math-lessp-float (math-abs qr) '(float 1 -20))
915 (setq qr (if (math-negp qr) '(float -1 -20) '(float 1 -20))))
916 (setq u (math-sub-float
917 b
918 (math-div-float (math-sub-float (math-mul-float bc q)
919 (math-mul-float ba r))
920 (math-mul-float '(float 2 0) qr)))
921 ulim (math-add-float b (math-mul-float '(float -1 2) bc))
922 incr (math-negp bc))
923 (if (if incr (math-lessp-float b u) (math-lessp-float u b))
924 (if (if incr (math-lessp-float u c) (math-lessp-float c u))
925 (if (math-lessp-float (setq vu (math-min-eval expr u)) vc)
926 (setq a b va vb
927 b u vb vu
928 done t)
929 (if (math-lessp-float vb vu)
930 (setq c u vc vu
931 done t)
932 (setq u (math-add-float c (math-mul-float '(float -161803 -5)
933 bc))
934 vu (math-min-eval expr u))))
935 (if (if incr (math-lessp-float u ulim) (math-lessp-float ulim u))
936 (if (math-lessp-float (setq vu (math-min-eval expr u)) vc)
937 (setq b c vb vc
938 c u vc vu
939 u (math-add-float c (math-mul-float
940 '(float -161803 -5)
941 (math-sub-float b c)))
942 vu (math-min-eval expr u)))
943 (setq u ulim
944 vu (math-min-eval expr u))))
945 (setq u (math-add-float c (math-mul-float '(float -161803 -5)
946 bc))
947 vu (math-min-eval expr u)))
948 (setq a b va vb
949 b c vb vc
950 c u vc vu))
951 (if (math-lessp-float a c)
952 (list a va b vb c vc)
953 (list c vc b vb a va))))
954
955 (defun math-narrow-min (expr a c intv)
956 (let ((xvals (list a c))
957 (yvals (list (math-min-eval expr a)
958 (math-min-eval expr c)))
959 (levels 0)
960 (step (math-sub-float c a))
961 (found nil)
962 xp yp b)
963 (while (and (<= (setq levels (1+ levels)) 5)
964 (not found))
965 (setq xp xvals
966 yp yvals
967 step (math-mul-float step '(float 497 -3)))
968 (while (and (cdr xp) (not found))
969 (setq b (math-add-float (car xp) step))
970 (math-working "search" b)
971 (setcdr xp (cons b (cdr xp)))
972 (setcdr yp (cons (math-min-eval expr b) (cdr yp)))
973 (if (and (math-lessp-float (nth 1 yp) (car yp))
974 (math-lessp-float (nth 1 yp) (nth 2 yp)))
975 (setq found t)
976 (setq xp (cdr xp)
977 yp (cdr yp))
978 (if (and (cdr (cdr yp))
979 (math-lessp-float (nth 1 yp) (car yp))
980 (math-lessp-float (nth 1 yp) (nth 2 yp)))
981 (setq found t)
982 (setq xp (cdr xp)
983 yp (cdr yp))))))
984 (if found
985 (list (car xp) (car yp)
986 (nth 1 xp) (nth 1 yp)
987 (nth 2 xp) (nth 2 yp))
988 (or (if (math-lessp-float (car yvals) (nth 1 yvals))
989 (and (memq (nth 1 intv) '(2 3))
990 (let ((min (car yvals)))
991 (while (and (setq yvals (cdr yvals))
992 (math-lessp-float min (car yvals))))
993 (and (not yvals)
994 (list (nth 2 intv) min))))
995 (and (memq (nth 1 intv) '(1 3))
996 (setq yvals (nreverse yvals))
997 (let ((min (car yvals)))
998 (while (and (setq yvals (cdr yvals))
999 (math-lessp-float min (car yvals))))
1000 (and (not yvals)
1001 (list (nth 3 intv) min)))))
1002 (math-reject-arg nil (format "*Unable to find a %s in the interval"
1003 math-min-or-max))))))
1004
1005 ;;; "brent"
1006 (defun math-brent-min (expr prec a va x vx b vb)
1007 (let ((iters (+ 20 (* 5 prec)))
1008 (w x)
1009 (vw vx)
1010 (v x)
1011 (vv vx)
1012 (tol (list 'float 1 (- -1 prec)))
1013 (zeps (list 'float 1 (- -5 prec)))
1014 (e '(float 0 0))
1015 d u vu xm tol1 tol2 etemp p q r xv xw)
1016 (while (progn
1017 (setq xm (math-mul-float '(float 5 -1)
1018 (math-add-float a b))
1019 tol1 (math-add-float
1020 zeps
1021 (math-mul-float tol (math-abs x)))
1022 tol2 (math-mul-float tol1 '(float 2 0)))
1023 (math-lessp-float (math-sub-float tol2
1024 (math-mul-float
1025 '(float 5 -1)
1026 (math-sub-float b a)))
1027 (math-abs (math-sub-float x xm))))
1028 (if (= (setq iters (1- iters)) 0)
1029 (math-reject-arg nil (format "*Unable to converge on a %s"
1030 math-min-or-max)))
1031 (math-working "brent" x)
1032 (if (math-lessp-float (math-abs e) tol1)
1033 (setq e (if (math-lessp-float x xm)
1034 (math-sub-float b x)
1035 (math-sub-float a x))
1036 d (math-mul-float '(float 381966 -6) e))
1037 (setq xw (math-sub-float x w)
1038 r (math-mul-float xw (math-sub-float vx vv))
1039 xv (math-sub-float x v)
1040 q (math-mul-float xv (math-sub-float vx vw))
1041 p (math-sub-float (math-mul-float xv q)
1042 (math-mul-float xw r))
1043 q (math-mul-float '(float 2 0) (math-sub-float q r)))
1044 (if (math-posp q)
1045 (setq p (math-neg-float p))
1046 (setq q (math-neg-float q)))
1047 (setq etemp e
1048 e d)
1049 (if (and (math-lessp-float (math-abs p)
1050 (math-abs (math-mul-float
1051 '(float 5 -1)
1052 (math-mul-float q etemp))))
1053 (math-lessp-float (math-mul-float
1054 q (math-sub-float a x)) p)
1055 (math-lessp-float p (math-mul-float
1056 q (math-sub-float b x))))
1057 (progn
1058 (setq d (math-div-float p q)
1059 u (math-add-float x d))
1060 (if (or (math-lessp-float (math-sub-float u a) tol2)
1061 (math-lessp-float (math-sub-float b u) tol2))
1062 (setq d (if (math-lessp-float xm x)
1063 (math-neg-float tol1)
1064 tol1))))
1065 (setq e (if (math-lessp-float x xm)
1066 (math-sub-float b x)
1067 (math-sub-float a x))
1068 d (math-mul-float '(float 381966 -6) e))))
1069 (setq u (math-add-float x
1070 (if (math-lessp-float (math-abs d) tol1)
1071 (if (math-negp d)
1072 (math-neg-float tol1)
1073 tol1)
1074 d))
1075 vu (math-min-eval expr u))
1076 (if (math-lessp-float vx vu)
1077 (progn
1078 (if (math-lessp-float u x)
1079 (setq a u)
1080 (setq b u))
1081 (if (or (equal w x)
1082 (not (math-lessp-float vw vu)))
1083 (setq v w vv vw
1084 w u vw vu)
1085 (if (or (equal v x)
1086 (equal v w)
1087 (not (math-lessp-float vv vu)))
1088 (setq v u vv vu))))
1089 (if (math-lessp-float u x)
1090 (setq b x)
1091 (setq a x))
1092 (setq v w vv vw
1093 w x vw vx
1094 x u vx vu)))
1095 (list 'vec x vx)))
1096
1097 ;;; "powell"
1098 (defun math-powell-min (expr n guesses prec)
1099 (let* ((f1dim (math-line-min-func expr n))
1100 (xi (calcFunc-idn 1 n))
1101 (p (cons 'vec (mapcar 'car guesses)))
1102 (pt p)
1103 (ftol (list 'float 1 (- prec)))
1104 (fret (math-min-eval expr p))
1105 fp ptt fptt xit i ibig del diff res)
1106 (while (progn
1107 (setq fp fret
1108 ibig 0
1109 del '(float 0 0)
1110 i 0)
1111 (while (<= (setq i (1+ i)) n)
1112 (setq fptt fret
1113 res (math-line-min f1dim p
1114 (math-mat-col xi i)
1115 n prec)
1116 p (let ((calc-internal-prec prec))
1117 (math-normalize (car res)))
1118 fret (nth 2 res)
1119 diff (math-abs (math-sub-float fptt fret)))
1120 (if (math-lessp-float del diff)
1121 (setq del diff
1122 ibig i)))
1123 (math-lessp-float
1124 (math-mul-float ftol
1125 (math-add-float (math-abs fp)
1126 (math-abs fret)))
1127 (math-mul-float '(float 2 0)
1128 (math-abs (math-sub-float fp
1129 fret)))))
1130 (setq ptt (math-sub (math-mul '(float 2 0) p) pt)
1131 xit (math-sub p pt)
1132 pt p
1133 fptt (math-min-eval expr ptt))
1134 (if (and (math-lessp-float fptt fp)
1135 (math-lessp-float
1136 (math-mul-float
1137 (math-mul-float '(float 2 0)
1138 (math-add-float
1139 (math-sub-float fp
1140 (math-mul-float '(float 2 0)
1141 fret))
1142 fptt))
1143 (math-sqr-float (math-sub-float
1144 (math-sub-float fp fret) del)))
1145 (math-mul-float del
1146 (math-sqr-float (math-sub-float fp fptt)))))
1147 (progn
1148 (setq res (math-line-min f1dim p xit n prec)
1149 p (car res)
1150 fret (nth 2 res)
1151 i 0)
1152 (while (<= (setq i (1+ i)) n)
1153 (setcar (nthcdr ibig (nth i xi))
1154 (nth i (nth 1 res)))))))
1155 (list 'vec p fret)))
1156
1157 (defun math-line-min-func (expr n)
1158 (let ((m -1))
1159 (while (< (setq m (1+ m)) n)
1160 (set (nth 2 (aref math-min-vars m))
1161 (list '+
1162 (list '*
1163 '(var DUMMY var-DUMMY)
1164 (list 'calcFunc-mrow '(var line-xi line-xi) (1+ m)))
1165 (list 'calcFunc-mrow '(var line-p line-p) (1+ m)))))
1166 (math-evaluate-expr expr)))
1167
1168 (defun math-line-min (f1dim line-p line-xi n prec)
1169 (let* ((var-DUMMY nil)
1170 (expr (math-evaluate-expr f1dim))
1171 (params (math-widen-min expr '(float 0 0) '(float 1 0)))
1172 (res (apply 'math-brent-min expr prec params))
1173 (xi (math-mul (nth 1 res) line-xi)))
1174 (list (math-add line-p xi) xi (nth 2 res))))
1175
1176
1177 (defun math-find-minimum (expr var guess min-widen)
1178 (let* ((calc-symbolic-mode nil)
1179 (n 0)
1180 (var-DUMMY nil)
1181 (isvec (math-vectorp var))
1182 g guesses)
1183 (or (math-vectorp var)
1184 (setq var (list 'vec var)))
1185 (or (math-vectorp guess)
1186 (setq guess (list 'vec guess)))
1187 (or (= (length var) (length guess))
1188 (math-dimension-error))
1189 (while (setq var (cdr var) guess (cdr guess))
1190 (or (eq (car-safe (car var)) 'var)
1191 (math-reject-arg (car var) "*Expected a variable"))
1192 (or (math-expr-contains expr (car var))
1193 (math-reject-arg (car var)
1194 "*Formula does not contain specified variable"))
1195 (while (>= (1+ n) (length math-min-vars))
1196 (let ((symb (intern (concat "math-min-v"
1197 (int-to-string
1198 (length math-min-vars))))))
1199 (setq math-min-vars (vconcat math-min-vars
1200 (vector (list 'var symb symb))))))
1201 (set (nth 2 (aref math-min-vars n)) nil)
1202 (set (nth 2 (aref math-min-vars (1+ n))) nil)
1203 (if (math-complexp (car guess))
1204 (setq expr (math-expr-subst expr
1205 (car var)
1206 (list '+ (aref math-min-vars n)
1207 (list '*
1208 (aref math-min-vars (1+ n))
1209 '(cplx 0 1))))
1210 guesses (let ((g (math-float (math-complex (car guess)))))
1211 (cons (list (nth 2 g) nil nil)
1212 (cons (list (nth 1 g) nil nil t)
1213 guesses)))
1214 n (+ n 2))
1215 (setq expr (math-expr-subst expr
1216 (car var)
1217 (aref math-min-vars n))
1218 guesses (cons (if (math-realp (car guess))
1219 (list (math-float (car guess)) nil nil)
1220 (if (and (eq (car-safe (car guess)) 'intv)
1221 (math-constp (car guess)))
1222 (list (math-mul
1223 (math-add (nth 2 (car guess))
1224 (nth 3 (car guess)))
1225 '(float 5 -1))
1226 (math-float (nth 2 (car guess)))
1227 (math-float (nth 3 (car guess)))
1228 (car guess))
1229 (math-reject-arg (car guess) 'realp)))
1230 guesses)
1231 n (1+ n))))
1232 (setq guesses (nreverse guesses)
1233 expr (math-evaluate-expr expr))
1234 (if (= n 1)
1235 (let* ((params (if (nth 1 (car guesses))
1236 (if min-widen
1237 (math-widen-min expr
1238 (nth 1 (car guesses))
1239 (nth 2 (car guesses)))
1240 (math-narrow-min expr
1241 (nth 1 (car guesses))
1242 (nth 2 (car guesses))
1243 (nth 3 (car guesses))))
1244 (math-widen-min expr
1245 (car (car guesses))
1246 nil)))
1247 (prec calc-internal-prec)
1248 (res (if (cdr (cdr params))
1249 (math-with-extra-prec (+ calc-internal-prec 2)
1250 (apply 'math-brent-min expr prec params))
1251 (cons 'vec params))))
1252 (if isvec
1253 (list 'vec (list 'vec (nth 1 res)) (nth 2 res))
1254 res))
1255 (let* ((prec calc-internal-prec)
1256 (res (math-with-extra-prec (+ calc-internal-prec 2)
1257 (math-powell-min expr n guesses prec)))
1258 (p (nth 1 res))
1259 (vec (list 'vec)))
1260 (while (setq p (cdr p))
1261 (if (nth 3 (car guesses))
1262 (progn
1263 (nconc vec (list (math-normalize
1264 (list 'cplx (car p) (nth 1 p)))))
1265 (setq p (cdr p)
1266 guesses (cdr guesses)))
1267 (nconc vec (list (car p))))
1268 (setq guesses (cdr guesses)))
1269 (if isvec
1270 (list 'vec vec (nth 2 res))
1271 (list 'vec (nth 1 vec) (nth 2 res)))))))
1272
1273 (defun calcFunc-minimize (expr var guess)
1274 (let ((calc-internal-prec (max (/ calc-internal-prec 2) 3))
1275 (math-min-or-max "minimum"))
1276 (math-find-minimum (math-normalize expr)
1277 (math-normalize var)
1278 (math-normalize guess) nil)))
1279
1280 (defun calcFunc-wminimize (expr var guess)
1281 (let ((calc-internal-prec (max (/ calc-internal-prec 2) 3))
1282 (math-min-or-max "minimum"))
1283 (math-find-minimum (math-normalize expr)
1284 (math-normalize var)
1285 (math-normalize guess) t)))
1286
1287 (defun calcFunc-maximize (expr var guess)
1288 (let* ((calc-internal-prec (max (/ calc-internal-prec 2) 3))
1289 (math-min-or-max "maximum")
1290 (res (math-find-minimum (math-normalize (math-neg expr))
1291 (math-normalize var)
1292 (math-normalize guess) nil)))
1293 (list 'vec (nth 1 res) (math-neg (nth 2 res)))))
1294
1295 (defun calcFunc-wmaximize (expr var guess)
1296 (let* ((calc-internal-prec (max (/ calc-internal-prec 2) 3))
1297 (math-min-or-max "maximum")
1298 (res (math-find-minimum (math-normalize (math-neg expr))
1299 (math-normalize var)
1300 (math-normalize guess) t)))
1301 (list 'vec (nth 1 res) (math-neg (nth 2 res)))))
1302
1303
1304
1305
1306 ;;; The following algorithms come from Numerical Recipes, chapter 3.
1307
1308 (defun calcFunc-polint (data x)
1309 (or (math-matrixp data) (math-reject-arg data 'matrixp))
1310 (or (= (length data) 3)
1311 (math-reject-arg data "*Wrong number of data rows"))
1312 (or (> (length (nth 1 data)) 2)
1313 (math-reject-arg data "*Too few data points"))
1314 (if (and (math-vectorp x) (or (math-constp x) math-expand-formulas))
1315 (cons 'vec (mapcar (function (lambda (x) (calcFunc-polint data x)))
1316 (cdr x)))
1317 (or (math-objectp x) math-expand-formulas (math-reject-arg x 'objectp))
1318 (math-with-extra-prec 2
1319 (cons 'vec (math-poly-interp (cdr (nth 1 data)) (cdr (nth 2 data)) x
1320 nil)))))
1321 (put 'calcFunc-polint 'math-expandable t)
1322
1323
1324 (defun calcFunc-ratint (data x)
1325 (or (math-matrixp data) (math-reject-arg data 'matrixp))
1326 (or (= (length data) 3)
1327 (math-reject-arg data "*Wrong number of data rows"))
1328 (or (> (length (nth 1 data)) 2)
1329 (math-reject-arg data "*Too few data points"))
1330 (if (and (math-vectorp x) (or (math-constp x) math-expand-formulas))
1331 (cons 'vec (mapcar (function (lambda (x) (calcFunc-ratint data x)))
1332 (cdr x)))
1333 (or (math-objectp x) math-expand-formulas (math-reject-arg x 'objectp))
1334 (math-with-extra-prec 2
1335 (cons 'vec (math-poly-interp (cdr (nth 1 data)) (cdr (nth 2 data)) x
1336 (cdr (cdr (cdr (nth 1 data)))))))))
1337 (put 'calcFunc-ratint 'math-expandable t)
1338
1339
1340 (defun math-poly-interp (xa ya x ratp)
1341 (let ((n (length xa))
1342 (dif nil)
1343 (ns nil)
1344 (xax nil)
1345 (c (copy-sequence ya))
1346 (d (copy-sequence ya))
1347 (i 0)
1348 (m 0)
1349 y dy (xp xa) xpm cp dp temp)
1350 (while (<= (setq i (1+ i)) n)
1351 (setq xax (cons (math-sub (car xp) x) xax)
1352 xp (cdr xp)
1353 temp (math-abs (car xax)))
1354 (if (or (null dif) (math-lessp temp dif))
1355 (setq dif temp
1356 ns i)))
1357 (setq xax (nreverse xax)
1358 ns (1- ns)
1359 y (nth ns ya))
1360 (if (math-zerop dif)
1361 (list y 0)
1362 (while (< (setq m (1+ m)) n)
1363 (setq i 0
1364 xp xax
1365 xpm (nthcdr m xax)
1366 cp c
1367 dp d)
1368 (while (<= (setq i (1+ i)) (- n m))
1369 (if ratp
1370 (let ((t2 (math-div (math-mul (car xp) (car dp)) (car xpm))))
1371 (setq temp (math-div (math-sub (nth 1 cp) (car dp))
1372 (math-sub t2 (nth 1 cp))))
1373 (setcar dp (math-mul (nth 1 cp) temp))
1374 (setcar cp (math-mul t2 temp)))
1375 (if (math-equal (car xp) (car xpm))
1376 (math-reject-arg (cons 'vec xa) "*Duplicate X values"))
1377 (setq temp (math-div (math-sub (nth 1 cp) (car dp))
1378 (math-sub (car xp) (car xpm))))
1379 (setcar dp (math-mul (car xpm) temp))
1380 (setcar cp (math-mul (car xp) temp)))
1381 (setq cp (cdr cp)
1382 dp (cdr dp)
1383 xp (cdr xp)
1384 xpm (cdr xpm)))
1385 (if (< (+ ns ns) (- n m))
1386 (setq dy (nth ns c))
1387 (setq ns (1- ns)
1388 dy (nth ns d)))
1389 (setq y (math-add y dy)))
1390 (list y dy))))
1391
1392
1393
1394 ;;; The following algorithms come from Numerical Recipes, chapter 4.
1395
1396 (defun calcFunc-ninteg (expr var lo hi)
1397 (setq lo (math-evaluate-expr lo)
1398 hi (math-evaluate-expr hi))
1399 (or (math-numberp lo) (math-infinitep lo) (math-reject-arg lo 'numberp))
1400 (or (math-numberp hi) (math-infinitep hi) (math-reject-arg hi 'numberp))
1401 (if (math-lessp hi lo)
1402 (math-neg (calcFunc-ninteg expr var hi lo))
1403 (setq expr (math-expr-subst expr var '(var DUMMY var-DUMMY)))
1404 (let ((var-DUMMY nil)
1405 (calc-symbolic-mode nil)
1406 (calc-prefer-frac nil)
1407 (sum 0))
1408 (setq expr (math-evaluate-expr expr))
1409 (if (equal lo '(neg (var inf var-inf)))
1410 (let ((thi (if (math-lessp hi '(float -2 0))
1411 hi '(float -2 0))))
1412 (setq sum (math-ninteg-romberg
1413 'math-ninteg-midpoint expr
1414 (math-float lo) (math-float thi) 'inf)
1415 lo thi)))
1416 (if (equal hi '(var inf var-inf))
1417 (let ((tlo (if (math-lessp '(float 2 0) lo)
1418 lo '(float 2 0))))
1419 (setq sum (math-add sum
1420 (math-ninteg-romberg
1421 'math-ninteg-midpoint expr
1422 (math-float tlo) (math-float hi) 'inf))
1423 hi tlo)))
1424 (or (math-equal lo hi)
1425 (setq sum (math-add sum
1426 (math-ninteg-romberg
1427 'math-ninteg-midpoint expr
1428 (math-float lo) (math-float hi) nil))))
1429 sum)))
1430
1431
1432 ;;; Open Romberg method; "qromo" in section 4.4.
1433
1434 ;; The variable math-ninteg-temp is local to math-ninteg-romberg,
1435 ;; but is used by math-ninteg-midpoint, which is used by
1436 ;; math-ninteg-romberg.
1437 (defvar math-ninteg-temp)
1438
1439 (defun math-ninteg-romberg (func expr lo hi mode)
1440 (let ((curh '(float 1 0))
1441 (h nil)
1442 (s nil)
1443 (j 0)
1444 (ss nil)
1445 (prec calc-internal-prec)
1446 (math-ninteg-temp nil))
1447 (math-with-extra-prec 2
1448 ;; Limit on "j" loop must be 14 or less to keep "it" from overflowing.
1449 (or (while (and (null ss) (<= (setq j (1+ j)) 8))
1450 (setq s (nconc s (list (funcall func expr lo hi mode)))
1451 h (nconc h (list curh)))
1452 (if (>= j 3)
1453 (let ((res (math-poly-interp h s '(float 0 0) nil)))
1454 (if (math-lessp (math-abs (nth 1 res))
1455 (calcFunc-scf (math-abs (car res))
1456 (- prec)))
1457 (setq ss (car res)))))
1458 (if (>= j 5)
1459 (setq s (cdr s)
1460 h (cdr h)))
1461 (setq curh (math-div-float curh '(float 9 0))))
1462 ss
1463 (math-reject-arg nil (format "*Integral failed to converge"))))))
1464
1465
1466 (defun math-ninteg-evaluate (expr x mode)
1467 (if (eq mode 'inf)
1468 (setq x (math-div '(float 1 0) x)))
1469 (let* ((var-DUMMY x)
1470 (res (math-evaluate-expr expr)))
1471 (or (Math-numberp res)
1472 (math-reject-arg res "*Integrand does not evaluate to a number"))
1473 (if (eq mode 'inf)
1474 (setq res (math-mul res (math-sqr x))))
1475 res))
1476
1477
1478 (defun math-ninteg-midpoint (expr lo hi mode) ; uses "math-ninteg-temp"
1479 (if (eq mode 'inf)
1480 (let ((math-infinite-mode t) temp)
1481 (setq temp (math-div 1 lo)
1482 lo (math-div 1 hi)
1483 hi temp)))
1484 (if math-ninteg-temp
1485 (let* ((it3 (* 3 (car math-ninteg-temp)))
1486 (math-working-step-2 (* 2 (car math-ninteg-temp)))
1487 (math-working-step 0)
1488 (range (math-sub hi lo))
1489 (del (math-div range (math-float it3)))
1490 (del2 (math-add del del))
1491 (del3 (math-add del del2))
1492 (x (math-add lo (math-mul '(float 5 -1) del)))
1493 (sum '(float 0 0))
1494 (j 0) temp)
1495 (while (<= (setq j (1+ j)) (car math-ninteg-temp))
1496 (setq math-working-step (1+ math-working-step)
1497 temp (math-ninteg-evaluate expr x mode)
1498 math-working-step (1+ math-working-step)
1499 sum (math-add sum (math-add temp (math-ninteg-evaluate
1500 expr (math-add x del2)
1501 mode)))
1502 x (math-add x del3)))
1503 (setq math-ninteg-temp (list it3
1504 (math-add (math-div (nth 1 math-ninteg-temp)
1505 '(float 3 0))
1506 (math-mul sum del)))))
1507 (setq math-ninteg-temp (list 1 (math-mul
1508 (math-sub hi lo)
1509 (math-ninteg-evaluate
1510 expr
1511 (math-mul (math-add lo hi) '(float 5 -1))
1512 mode)))))
1513 (nth 1 math-ninteg-temp))
1514
1515
1516
1517
1518
1519 ;;; The following algorithms come from Numerical Recipes, chapter 14.
1520
1521 (defvar math-dummy-vars [(var DUMMY var-DUMMY)])
1522 (defvar math-dummy-counter 0)
1523 (defun math-dummy-variable ()
1524 (if (= math-dummy-counter (length math-dummy-vars))
1525 (let ((symb (intern (format "math-dummy-%d" math-dummy-counter))))
1526 (setq math-dummy-vars (vconcat math-dummy-vars
1527 (vector (list 'var symb symb))))))
1528 (set (nth 2 (aref math-dummy-vars math-dummy-counter)) nil)
1529 (prog1
1530 (aref math-dummy-vars math-dummy-counter)
1531 (setq math-dummy-counter (1+ math-dummy-counter))))
1532
1533 (defvar math-in-fit 0)
1534 (defvar calc-fit-to-trail nil)
1535
1536 (defun calcFunc-fit (expr vars &optional coefs data)
1537 (let ((math-in-fit 10))
1538 (math-with-extra-prec 2
1539 (math-general-fit expr vars coefs data nil))))
1540
1541 (defun calcFunc-efit (expr vars &optional coefs data)
1542 (let ((math-in-fit 10))
1543 (math-with-extra-prec 2
1544 (math-general-fit expr vars coefs data 'sdev))))
1545
1546 (defun calcFunc-xfit (expr vars &optional coefs data)
1547 (let ((math-in-fit 10))
1548 (math-with-extra-prec 2
1549 (math-general-fit expr vars coefs data 'full))))
1550
1551 ;; The variables math-fit-first-var, math-fit-first-coef and
1552 ;; math-fit-new-coefs are local to math-general-fit, but are used by
1553 ;; calcFunc-fitvar, calcFunc-fitparam and calcFunc-fitdummy
1554 ;; (respectively), which are used by math-general-fit.
1555 (defvar math-fit-first-var)
1556 (defvar math-fit-first-coef)
1557 (defvar math-fit-new-coefs)
1558
1559 (defun math-general-fit (expr vars coefs data mode)
1560 (let ((calc-simplify-mode nil)
1561 (math-dummy-counter math-dummy-counter)
1562 (math-in-fit 1)
1563 (extended (eq mode 'full))
1564 (math-fit-first-coef math-dummy-counter)
1565 math-fit-first-var
1566 (plain-expr expr)
1567 orig-expr
1568 have-sdevs need-chisq chisq
1569 (x-funcs nil)
1570 (y-filter nil)
1571 y-dummy
1572 (coef-filters nil)
1573 math-fit-new-coefs
1574 (xy-values nil)
1575 (weights nil)
1576 (var-YVAL nil) (var-YVALX nil)
1577 covar beta
1578 n nn m mm v dummy p)
1579
1580 ;; Validate and parse arguments.
1581 (or data
1582 (if coefs
1583 (setq data coefs
1584 coefs nil)
1585 (if (math-vectorp expr)
1586 (if (memq (length expr) '(3 4))
1587 (setq data vars
1588 vars (nth 2 expr)
1589 coefs (nth 3 expr)
1590 expr (nth 1 expr))
1591 (math-dimension-error))
1592 (setq data vars
1593 vars nil
1594 coefs nil))))
1595 (or (math-matrixp data) (math-reject-arg data 'matrixp))
1596 (setq v (1- (length data))
1597 n (1- (length (nth 1 data))))
1598 (or (math-vectorp vars) (null vars)
1599 (setq vars (list 'vec vars)))
1600 (or (math-vectorp coefs) (null coefs)
1601 (setq coefs (list 'vec coefs)))
1602 (or coefs
1603 (setq coefs (cons 'vec (math-all-vars-but expr vars))))
1604 (or vars
1605 (if (<= (1- (length coefs)) v)
1606 (math-reject-arg coefs "*Not enough variables in model")
1607 (setq coefs (copy-sequence coefs))
1608 (let ((p (nthcdr (- (length coefs) v
1609 (if (eq (car-safe expr) 'calcFunc-eq) 1 0))
1610 coefs)))
1611 (setq vars (cons 'vec (cdr p)))
1612 (setcdr p nil))))
1613 (or (= (1- (length vars)) v)
1614 (= (length vars) v)
1615 (math-reject-arg vars "*Number of variables does not match data"))
1616 (setq m (1- (length coefs)))
1617 (if (< m 1)
1618 (math-reject-arg coefs "*Need at least one parameter"))
1619
1620 ;; Rewrite expr in terms of fitparam and fitvar, make into an equation.
1621 (setq p coefs)
1622 (while (setq p (cdr p))
1623 (or (eq (car-safe (car p)) 'var)
1624 (math-reject-arg (car p) "*Expected a variable"))
1625 (setq dummy (math-dummy-variable)
1626 expr (math-expr-subst expr (car p)
1627 (list 'calcFunc-fitparam
1628 (- math-dummy-counter math-fit-first-coef)))))
1629 (setq math-fit-first-var math-dummy-counter
1630 p vars)
1631 (while (setq p (cdr p))
1632 (or (eq (car-safe (car p)) 'var)
1633 (math-reject-arg (car p) "*Expected a variable"))
1634 (setq dummy (math-dummy-variable)
1635 expr (math-expr-subst expr (car p)
1636 (list 'calcFunc-fitvar
1637 (- math-dummy-counter math-fit-first-var)))))
1638 (if (< math-dummy-counter (+ math-fit-first-var v))
1639 (setq dummy (math-dummy-variable))) ; dependent variable may be unnamed
1640 (setq y-dummy dummy
1641 orig-expr expr)
1642 (or (eq (car-safe expr) 'calcFunc-eq)
1643 (setq expr (list 'calcFunc-eq (list 'calcFunc-fitvar v) expr)))
1644
1645 (let ((calc-symbolic-mode nil))
1646
1647 ;; Apply rewrites to put expr into a linear-like form.
1648 (setq expr (math-evaluate-expr expr)
1649 expr (math-rewrite (list 'calcFunc-fitmodel expr)
1650 '(var FitRules var-FitRules))
1651 math-in-fit 2
1652 expr (math-evaluate-expr expr))
1653 (or (and (eq (car-safe expr) 'calcFunc-fitsystem)
1654 (= (length expr) 4)
1655 (math-vectorp (nth 2 expr))
1656 (math-vectorp (nth 3 expr))
1657 (> (length (nth 2 expr)) 1)
1658 (= (length (nth 3 expr)) (1+ m)))
1659 (math-reject-arg plain-expr "*Model expression is too complex"))
1660 (setq y-filter (nth 1 expr)
1661 x-funcs (vconcat (cdr (nth 2 expr)))
1662 coef-filters (nth 3 expr)
1663 mm (length x-funcs))
1664 (if (equal y-filter y-dummy)
1665 (setq y-filter nil))
1666
1667 ;; Build the (square) system of linear equations to be solved.
1668 (setq beta (cons 'vec (make-list mm 0))
1669 covar (cons 'vec (mapcar 'copy-sequence (make-list mm beta))))
1670 (let* ((ptrs (vconcat (cdr data)))
1671 (isigsq 1)
1672 (xvals (make-vector mm 0))
1673 (i 0)
1674 j k xval yval sigmasqr wt covj covjk covk betaj lud)
1675 (while (<= (setq i (1+ i)) n)
1676
1677 ;; Assign various independent variables for this data point.
1678 (setq j 0
1679 sigmasqr nil)
1680 (while (< j v)
1681 (aset ptrs j (cdr (aref ptrs j)))
1682 (setq xval (car (aref ptrs j)))
1683 (if (= j (1- v))
1684 (if sigmasqr
1685 (progn
1686 (if (eq (car-safe xval) 'sdev)
1687 (setq sigmasqr (math-add (math-sqr (nth 2 xval))
1688 sigmasqr)
1689 xval (nth 1 xval)))
1690 (if y-filter
1691 (setq xval (math-make-sdev xval
1692 (math-sqrt sigmasqr))))))
1693 (if (eq (car-safe xval) 'sdev)
1694 (setq sigmasqr (math-add (math-sqr (nth 2 xval))
1695 (or sigmasqr 0))
1696 xval (nth 1 xval))))
1697 (set (nth 2 (aref math-dummy-vars (+ math-fit-first-var j))) xval)
1698 (setq j (1+ j)))
1699
1700 ;; Compute Y value for this data point.
1701 (if y-filter
1702 (setq yval (math-evaluate-expr y-filter))
1703 (setq yval (symbol-value (nth 2 y-dummy))))
1704 (if (eq (car-safe yval) 'sdev)
1705 (setq sigmasqr (math-sqr (nth 2 yval))
1706 yval (nth 1 yval)))
1707 (if (= i 1)
1708 (setq have-sdevs sigmasqr
1709 need-chisq (or extended
1710 (and (eq mode 'sdev) (not have-sdevs)))))
1711 (if have-sdevs
1712 (if sigmasqr
1713 (progn
1714 (setq isigsq (math-div 1 sigmasqr))
1715 (if need-chisq
1716 (setq weights (cons isigsq weights))))
1717 (math-reject-arg yval "*Mixed error forms and plain numbers"))
1718 (if sigmasqr
1719 (math-reject-arg yval "*Mixed error forms and plain numbers")))
1720
1721 ;; Compute X values for this data point and update covar and beta.
1722 (if (eq (car-safe xval) 'sdev)
1723 (set (nth 2 y-dummy) (nth 1 xval)))
1724 (setq j 0
1725 covj covar
1726 betaj beta)
1727 (while (< j mm)
1728 (setq wt (math-evaluate-expr (aref x-funcs j)))
1729 (aset xvals j wt)
1730 (setq wt (math-mul wt isigsq)
1731 betaj (cdr betaj)
1732 covjk (car (setq covj (cdr covj)))
1733 k 0)
1734 (while (<= k j)
1735 (setq covjk (cdr covjk))
1736 (setcar covjk (math-add (car covjk)
1737 (math-mul wt (aref xvals k))))
1738 (setq k (1+ k)))
1739 (setcar betaj (math-add (car betaj) (math-mul wt yval)))
1740 (setq j (1+ j)))
1741 (if need-chisq
1742 (setq xy-values (cons (append xvals (list yval)) xy-values))))
1743
1744 ;; Fill in symmetric half of covar matrix.
1745 (setq j 0
1746 covj covar)
1747 (while (< j (1- mm))
1748 (setq k j
1749 j (1+ j)
1750 covjk (nthcdr j (car (setq covj (cdr covj))))
1751 covk (nthcdr j covar))
1752 (while (< (setq k (1+ k)) mm)
1753 (setq covjk (cdr covjk)
1754 covk (cdr covk))
1755 (setcar covjk (nth j (car covk))))))
1756
1757 ;; Solve the linear system.
1758 (if mode
1759 (progn
1760 (setq covar (math-matrix-inv-raw covar))
1761 (if covar
1762 (setq beta (math-mul covar beta))
1763 (if (math-zerop (math-abs beta))
1764 (setq covar (calcFunc-diag 0 (1- (length beta))))
1765 (math-reject-arg orig-expr "*Singular matrix")))
1766 (or (math-vectorp covar)
1767 (setq covar (list 'vec (list 'vec covar)))))
1768 (setq beta (math-div beta covar)))
1769
1770 ;; Compute chi-square statistic if necessary.
1771 (if need-chisq
1772 (let (bp xp sum)
1773 (setq chisq 0)
1774 (while xy-values
1775 (setq bp beta
1776 xp (car xy-values)
1777 sum 0)
1778 (while (setq bp (cdr bp))
1779 (setq sum (math-add sum (math-mul (car bp) (car xp)))
1780 xp (cdr xp)))
1781 (setq sum (math-sqr (math-sub (car xp) sum)))
1782 (if weights (setq sum (math-mul sum (car weights))))
1783 (setq chisq (math-add chisq sum)
1784 weights (cdr weights)
1785 xy-values (cdr xy-values)))))
1786
1787 ;; Convert coefficients back into original terms.
1788 (setq math-fit-new-coefs (copy-sequence beta))
1789 (let* ((bp math-fit-new-coefs)
1790 (cp covar)
1791 (sigdat 1)
1792 (math-in-fit 3)
1793 (j 0))
1794 (and mode (not have-sdevs)
1795 (setq sigdat (if (<= n mm)
1796 0
1797 (math-div chisq (- n mm)))))
1798 (if mode
1799 (while (setq bp (cdr bp))
1800 (setcar bp (math-make-sdev
1801 (car bp)
1802 (math-sqrt (math-mul (nth (setq j (1+ j))
1803 (car (setq cp (cdr cp))))
1804 sigdat))))))
1805 (setq math-fit-new-coefs (math-evaluate-expr coef-filters))
1806 (if calc-fit-to-trail
1807 (let ((bp math-fit-new-coefs)
1808 (cp coefs)
1809 (vec nil))
1810 (while (setq bp (cdr bp) cp (cdr cp))
1811 (setq vec (cons (list 'calcFunc-eq (car cp) (car bp)) vec)))
1812 (setq calc-fit-to-trail (cons 'vec (nreverse vec)))))))
1813
1814 ;; Substitute best-fit coefficients back into original formula.
1815 (setq expr (math-multi-subst
1816 orig-expr
1817 (let ((n v)
1818 (vec nil))
1819 (while (>= n 1)
1820 (setq vec (cons (list 'calcFunc-fitvar n) vec)
1821 n (1- n)))
1822 (setq n m)
1823 (while (>= n 1)
1824 (setq vec (cons (list 'calcFunc-fitparam n) vec)
1825 n (1- n)))
1826 vec)
1827 (append (cdr math-fit-new-coefs) (cdr vars))))
1828
1829 ;; Package the result.
1830 (math-normalize
1831 (if extended
1832 (list 'vec expr beta covar
1833 (let ((p coef-filters)
1834 (n 0))
1835 (while (and (setq n (1+ n) p (cdr p))
1836 (eq (car-safe (car p)) 'calcFunc-fitdummy)
1837 (eq (nth 1 (car p)) n)))
1838 (if p
1839 coef-filters
1840 (list 'vec)))
1841 chisq
1842 (if (and have-sdevs (> n mm))
1843 (list 'calcFunc-utpc chisq (- n mm))
1844 '(var nan var-nan)))
1845 expr))))
1846
1847
1848 (defun calcFunc-fitvar (x)
1849 (if (>= math-in-fit 2)
1850 (progn
1851 (setq x (aref math-dummy-vars (+ math-fit-first-var x -1)))
1852 (or (calc-var-value (nth 2 x)) x))
1853 (math-reject-arg x)))
1854
1855 (defun calcFunc-fitparam (x)
1856 (if (>= math-in-fit 2)
1857 (progn
1858 (setq x (aref math-dummy-vars (+ math-fit-first-coef x -1)))
1859 (or (calc-var-value (nth 2 x)) x))
1860 (math-reject-arg x)))
1861
1862 (defun calcFunc-fitdummy (x)
1863 (if (= math-in-fit 3)
1864 (nth x math-fit-new-coefs)
1865 (math-reject-arg x)))
1866
1867 (defun calcFunc-hasfitvars (expr)
1868 (if (Math-primp expr)
1869 0
1870 (if (eq (car expr) 'calcFunc-fitvar)
1871 (nth 1 expr)
1872 (apply 'max (mapcar 'calcFunc-hasfitvars (cdr expr))))))
1873
1874 (defun calcFunc-hasfitparams (expr)
1875 (if (Math-primp expr)
1876 0
1877 (if (eq (car expr) 'calcFunc-fitparam)
1878 (nth 1 expr)
1879 (apply 'max (mapcar 'calcFunc-hasfitparams (cdr expr))))))
1880
1881
1882 (defun math-all-vars-but (expr but)
1883 (let* ((vars (math-all-vars-in expr))
1884 (p but))
1885 (while p
1886 (setq vars (delq (assoc (car-safe p) vars) vars)
1887 p (cdr p)))
1888 (sort (mapcar 'car vars)
1889 (function (lambda (x y) (string< (nth 1 x) (nth 1 y)))))))
1890
1891 ;; The variables math-all-vars-vars (the vars for math-all-vars) and
1892 ;; math-all-vars-found are local to math-all-vars-in, but are used by
1893 ;; math-all-vars-rec which is called by math-all-vars-in.
1894 (defvar math-all-vars-vars)
1895 (defvar math-all-vars-found)
1896
1897 (defun math-all-vars-in (expr)
1898 (let ((math-all-vars-vars nil)
1899 math-all-vars-found)
1900 (math-all-vars-rec expr)
1901 math-all-vars-vars))
1902
1903 (defun math-all-vars-rec (expr)
1904 (if (Math-primp expr)
1905 (if (eq (car-safe expr) 'var)
1906 (or (math-const-var expr)
1907 (if (setq math-all-vars-found (assoc expr math-all-vars-vars))
1908 (setcdr math-all-vars-found (1+ (cdr math-all-vars-found)))
1909 (setq math-all-vars-vars (cons (cons expr 1) math-all-vars-vars)))))
1910 (while (setq expr (cdr expr))
1911 (math-all-vars-rec (car expr)))))
1912
1913 (provide 'calcalg3)
1914
1915 ;;; arch-tag: ff9f2920-8111-48b5-b3fa-b0682c3e44a6
1916 ;;; calcalg3.el ends here