Fix typo in display-html-help
[maxima.git] / share / contrib / chebformax.lisp
blob9bed262f8315088ce0c8e2acfe5c6a0f54808d7f
1 ;;; -*- Mode: LISP; Package: Maxima; Syntax: Common-Lisp;
2 ;;; a package for chebyshev approximations. Comments at end
3 (in-package :maxima)
6 ;; tocheb computes all the a_j, j=0 to n-1 for the Maxima function f.
8 (defun $tocheb (f n)
9 (cons '($chebseries) (ajs f n)))
11 ;; compute a[j]s for Maxima this way
13 (defun ajs(f n)(loop for j from 0 to (1- n)
14 collect (aj f j n)))
17 ;; it turns out we will be re-using certain key values repeatedly,
18 ;; so we save them in a hash table.
20 (defvar *cosc* (make-hash-table)) ;; store useful values of cosine here.
22 (defun cachecos(r)(or (gethash r *cosc*)(setf (gethash r *cosc*) (cos r))))
24 (defun aj (f j n) ;; compute just one coefficient, a_j out of n for function f
25 (let ((in (/ 1.0d0 n))) ; inverse of n
26 (* in 2 (- 2 (if (= j n) 0 1))
27 (loop for k from 0 to (1- n) sum
28 (let ((h(* pi (+ k 0.5d0) in)))
29 (* (cachecos (* h j))
30 (mapply1 f (list (cachecos h)) f f)))))))
32 (defun $cheb_call(a x) ;; clenshaw algorithm
33 ;; evaluate p=sum'(a_nT_n(x), i=0 to N) a is chebseries
34 ;; sum' multiplies a_0 by 1/2
35 ;; works.
36 (declare (optimize (speed 3)(safety 0))
37 (double-float x))
38 (cond ((eq (caar a) '$chebseries)
39 (let* ((bj2 0.0d0)
40 (bj1 0.0d0)
41 (bj0 0.0d0))
42 (declare(double-float bj2 bj1 bj0))
43 (setf a (reverse(cdr a))) ;; could hack this away. maybe later
44 (loop while (cdr a) do
45 (setf bj0
46 (+ (* 2.0d0 x bj1)
47 (- bj2)
48 (the double-float (pop a))))
49 (setf bj2 bj1 bj1 bj0))
50 (+ (* x bj1) (* 0.5d0(pop a))(- bj2))))
52 (t (error "expecting chebseries,not ~s" a))))
54 (defun $chebadd(a b)
55 ;; a slower version, chebplus, is below
56 (let* ((ans nil))
57 (cond ((> (length a)(length b))
58 (setf a (append (cdr a) nil)) ;copy
59 (setf ans a)
60 (setf b (cdr b))
61 (while b (incf (car a)(pop b)) (pop a)))
63 (setf b (append (cdr b) nil)) ;copy
64 (setf ans b)
65 (setf a (cdr a))
66 (while a (incf (car b)(pop a)) (pop b))))
67 (cons '($chebseries) ans)))
70 (defun $chebmul(a b)
71 ;; assumes each is a chebseries. no error checking here.
72 ;; a slower version is below.
74 (let* ((aa (coerce (rest a) 'simple-array))
75 (bb (coerce (rest b) 'simple-array))
76 (la (length aa))
77 (lb (length bb))
78 (term 0.0d0)
79 (ans (make-array (+ la lb -1) :initial-element 0.0d0)))
80 (setf (aref aa 0)(* 0.5d0 (aref aa 0)))
81 (setf (aref bb 0)(* 0.5d0 (aref bb 0)))
82 (loop for i from 0 to (1- la) do
83 (loop for j from 0 to (1- lb) do
84 (setf term (* (aref aa i)(aref bb j)))
85 (incf (aref ans (+ i j)) term)
86 (incf (aref ans (abs(- i j))) term)
88 (loop for i from 1 to (+ la lb -2) do;; not ans[0]
89 (setf (aref ans i) (* (aref ans i)0.5d0))
91 (cons '($chebseries)(coerce ans 'list))))
94 ;; how about composition?
95 (defun $chebcomp(f g n)
96 ;; f, g are chebseries
97 ;; simple hack is to evaluate f(g(x)) as needed, e.g.
98 ($tocheb #'(lambda(r)($cheb_call f ($cheb_call g r)))
99 ;; how many points are justified though??
102 (defun $chebplus(f g)
103 ;; f, g are chebseries
104 ;; simple hack is to evaluate f and g as needed, e.g.
105 ($tocheb #'(lambda(r)(+($cheb_call f r) ($cheb_call g r)))
106 ;; how many points are justified though??
107 (max (length f)(length g))))
108 ;; this works
109 (defun $chebtimes(f g)
110 ;; f, g are chebseries
111 ;; simple hack is to evaluate f and g as needed, e.g.
112 ($tocheb #'(lambda(r)(*($cheb_call f r) ($cheb_call g r)))
113 ;; how many points are justified though??
114 (+ (length f)(length g) -1)))
116 (defun $chebinv(f n)
117 ;; f is a chebseries. Compute 1/f
118 ;; simple hack is to evaluate f and g as needed, e.g.
119 ($tocheb #'(lambda(r)(/ 1.0d0 ($cheb_call f r)))
120 ;; how many points are justified though??
123 (defun $chebapply(fun cs n) ;; apply any maxima function to a chebseries
124 ;; e.g. chebapply(lambda([r](exp(r^2+1)),chebs);
125 ;; constraint: fun must be a function of one float argument that
126 ;; returns a double-float.
127 ($tocheb #'(lambda(r)
128 (mapply1 fun (list r) fun fun)) cs
129 ;; how many points are justified though??
132 (defun $chebint(a) ;; indefinite integration of the function given by a.
133 ;;integrate(t[n](x),x) =
134 ;; if n=0 then t[1].
135 ;; if n=1 then 1/2*t[0] +1/4*t[2] else
136 ;; 1/2*(t[n+1]/(n+1) - t[n-1]/(n-1))
139 (let* ((aa (coerce (rest a) 'simple-array))
140 (la (length aa))
141 (term 0.0d0)
142 (ans (make-array (max 2(1+ la)) :initial-element 0.0d0)))
143 (setf (aref aa 0) (* 0.5d0 (aref aa 0)))
144 (setf (aref ans 1) (aref aa 0)) ;int(const)= const*x
145 (setf (aref ans 0) (* 0.25d0 (aref aa 1))) ;int(x) = x^2/2 =1/4*T[0]+
146 (setf (aref ans 2) (* 0.25d0 (aref aa 1))) ;...+ 1/4*T[2]
147 (loop for i from 2 to (1- la) do
148 (setf term (* 0.5 (aref aa i)))
149 (incf (aref ans (1+ i)) (/ term (1+ i)))
150 (decf (aref ans (1- i)) (/ term (1- i))))
151 (setf (aref ans 0)(* 0.5d0 (aref ans 0))) ;so sum' works
154 (cons '($chebseries)(coerce ans 'list))))
159 ;; elaboration: fix up the above programs to combine non-chebseries with
160 ;; chebseries. Compute the appropriate number of terms.
163 #| This file defines some Maxima functions for playing with
164 representation of functions of a single "real" variable
165 (double-precision floats, actually) by their Chebyshev series
166 coefficients. This particular version is set up for generation and
167 manipulation of functions defined on [-1,1].
169 We refer elsewhere (http://www2.maths.ox.ac.uk/chebfun) for a discussion
170 of the kinds of computations that can be considered, and the nature of functions
171 that can be appropriately modeled by a Chebyshev expansion.
173 The chebfun web site discusses a Matlab project which includes
174 facilities for functions being translated or scaled, or pasted together
175 piecewise.
177 A key piece (not included here), is a method for truncation of these chebyshev series,
178 based on the relative size of the trailing coefficients. Drop em if them are too small
179 to matter. Also, these series can be directly multiplied, added, composed. There
180 are neat ways of computing them for polynomials and rational functions, though not
181 as briefly as here. And there is a faster way of computing the coefficients from
182 the evaluation points using an FFT (or a Discrete Cosine Transform), which we do not
183 include because it would require other programs, and more debugging. These lisp
184 programs should be compiled for speed.
186 It has been said that "the Chebyshev polynomials are everywhere dense in numerical analysis."
188 examples
189 load("thisfile")
190 s: tocheb(lambda([x],sin(x)),20) ;
191 cheb_call(s,0.1234) ;
192 sin(0.1234) ;
193 gg(x):=sin(20*x^2+exp(x^5+sqrt(x^4+1))) ;
194 g:tocheb(gg,60);
195 gg(0.4) ;
196 cheb_call(g,0.4) ;
198 plot2d('[gg(x),cheb_call(g,x)],[x,0,1.025]) ; /* note they are the same until x>1 */
200 oh if you don't like
201 s: tocheb(lambda([x],sin(x)),20) ;
203 then we can do this:
204 afun(ex,x):=buildq([expr:ex,var:x],lambda([var],expr)) $
206 cheb3(expr,var,count):= tocheb(afun(expr,var),count)$
207 cheb3(sin(z),z,20) then is the same as tocheb(lambda([z],sin(z)),20) which happens also to be
208 the same as tocheb(sin,20).
210 Here are a few additional ideas.
211 Elaborate on chebseries so that they are callable. e.g.
212 (($chebseries) a b c) becomes #'(lambda(r)(cheb_call '((chebseries) a b c) r))
213 in effect. applying a chebseries to an argument becomes simpler.
214 include various limits (now default -1,1)
215 package up a piecewise function as the chebfun project does.
217 extract a coefficient from the series so that all coefficients are between -1 and 1.
218 e.g. [1,2,3] becomes 3* [1/3,2/3,1].
219 The max coefficient would then always be 1.
220 In fact, the coefficients could all be fixed point numbers between -.111111...
221 and +.11111. Low precision would look like .0000001.. . Given that float
222 arithmetic is ubiquitous and fast, this may not be a winner.
224 other advantage: a method for truncating the product of chebyshev series.
226 a= A* csa, where csa has max coefficient of +-1. [apparently not new,]
227 b= B* csb, similarly.
228 the product is then A*B* (csa*csb).
229 without loss of generality, consider only csa*csb.
231 We agree that if we know that all coefficients in the answer beyond
232 some N have magnitude less than epsilon (say, 1e-13) then we will drop
233 all those terms beyond N.
235 We will not necessarily know this to be the case
236 when we generate terms ab initio from some expression we are
237 evaluating at Gauss-Lobatto points, but if we assert the two cs to be
238 multiplied are in fact correct in all given terms, and furthermore,
239 all terms beyond those explicitly represented are exactly zero, then
240 we are doing about as well as can be expected with the information at
241 our disposal.
243 Typically the input cs will have rapidly declining coefficients,
244 especially just before they are cut off.
246 For purposes of being explicit, let us say that the coefficients start
247 with magnitude 1 and decrease by a factor of 10 for each coefficient.
248 that would suggest coefficients of magnitude
249 1,0.1, 0.01, ... 1e-12, 1e-13, 0.... in each input, and csa and csb are
250 both of length 13.
252 We know that any terms in the answer will be of magnitude 1e-13 or greater,
253 so there is not much point in accumulating answers that are 1e-7 times
254 terms in the other series that are 1e-7 or less. At worst, there will be
255 13 terms all of the same sign added together in a 13x13 multiply..
257 Consider
259 csa = csa_big + sqrt(eps/n)*csa_small =A1+sqrt(eps/n)A2 n is length of csa
260 csb = csb_big + sqrt(eps/m)*csb_small =B1+sqrt(eps/m)B2 m is length of csb
262 The product contains A1*B1+sqrt(eps/m)*A1*B2 +sqrt(eps/n)*A2*B1+ eps/sqrt(nm)*A2*B2.
263 This last component promises to be mostly negligible. Why multiply these?
264 So instead of computing 13^2 =169 terms to produce 26 coefficients, we compute about
265 3/4 of them, or about 127 terms. We will also produce about 13 coefficients.
268 maybe this cuts off too much? what if we use eps^2? a term of order eps^2 would not affect even the low order bits of a term of order eps, which is the smallest retained term, anyway.
270 how would terms of order eps^2 be generated -- hardly at all. ugh.
273 more thoughts, if we are going to make this into a generic system
274 for dealing with functions.
275 integral (just done)
276 derivative
277 zeros
278 (eh, maybe) positive
279 (eh, heuristic) test for equality
280 majorization? f>g, f<g, sometimes, always?
281 economization, remez?
283 rational or other powers. sqrt, power of 10.. maybe jcpmiller method?
288 another way of converting a polynomial in x of degree N, sum(a[i]*x^i,i,0,N) to chebyshev series,
289 based on CACM paper by Thacher, 1964.
291 (kill(c,phi), /* buggy */
292 c[q,N]:=sum(a[r]*phi[q,(r-q)/2,q],r,1,N),
293 phi[q,j]:=if j=0 then 2^(1-q) else (q+2*j)*(q+2*j-1)/(4*j*(q+j)*phi[q,j-1]))