~ubuntu-branches/ubuntu/karmic/maxima/karmic

« back to all changes in this revision

Viewing changes to share/orthopoly/orthopoly.lisp

  • Committer: Bazaar Package Importer
  • Author(s): Barry deFreese
  • Date: 2006-07-06 17:04:52 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20060706170452-j9ypoqc1kjfnz221
Tags: 5.9.3-1ubuntu1
* Re-sync with Debian
* Comment out backward-delete-char-untabify in maxima.el (Closes Malone #5273)
* debian/control: build-dep automake -> automake1.9 (Closes BTS: #374663)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
;; 8/8 | 5/5 
 
2
;; Copyright (C) 2000, 2001, 2003 Barton Willis
 
3
 
 
4
;; Maxima code for evaluating orthogonal polynomials listed in Chapter 22 
 
5
;; of Abramowitz and Stegun (A & S). 
 
6
 
 
7
;; Author: Barton Willis, University of Nebraska at Kearney (aka UNK).
 
8
;; License: see README. The user of this code assumes all risk 
 
9
;; for its use. It has no warranty. If you don't know the meaning 
 
10
;; of "no warranty," don't use this code. :-)
 
11
 
 
12
(in-package :maxima)
 
13
($put '$orthopoly 1.0 '$version)
 
14
 
 
15
;; A while loop taken from nset.lisp. Someday it should be placed
 
16
;; in a file with other Maxima macros and deleted from here and from nset.
 
17
 
 
18
(defmacro while (cond &rest body)
 
19
  `(do ()
 
20
       ((not ,cond))
 
21
     ,@body))
 
22
 
 
23
;; If the input can be evaluated to a floating point number (either
 
24
;; real or complex), convert the input to a Common Lisp complex number.
 
25
;; When the input doesn't evaluate to a float, return the input.
 
26
 
 
27
(defun maxima-to-lisp-complex-float (a)
 
28
  (let* (($ratprint nil)
 
29
         (b ($rectform a))
 
30
         (br ($float ($realpart b)))
 
31
         (bi ($float ($imagpart b))))
 
32
    (cond ((and (numberp br) (numberp bi))
 
33
           (if (= bi 0) (float br 1.0L0)
 
34
             (complex (float br 1.0L0) 
 
35
                      (float bi 1.0L0))))
 
36
          (t a))))
 
37
 
 
38
;; Return true iff a is a float or a complex number with either a
 
39
;; real or imaginary part that is a float.
 
40
 
 
41
(defun xcomplexp (a)
 
42
  (or (floatp a)
 
43
      (and (complexp a) (or (floatp (realpart a)) (floatp (imagpart a))))))
 
44
 
 
45
;; Convert a Lisp complex number into a Maxima complex number. When the
 
46
;; input isn't a Lisp complex number, return the argument.
 
47
 
 
48
(defun lisp-complex-to-maxima (x)
 
49
  (if (complexp x) (add (realpart x) (mul '$%i (imagpart x))) x))
 
50
   
 
51
;; When orthopoly_returns_intervals is true, floating point evaluation 
 
52
;; returns an interval using the form (($interval) c r), where c is the 
 
53
;; center of the interval and r is its radius.  We don't provide the user
 
54
;; with any tools for working with intervals; if a user wants
 
55
 
 
56
(defmvar $orthopoly_returns_intervals t)
 
57
 
 
58
(defun orthopoly-return-handler (d f e)
 
59
  (cond ((or (floatp f) (complexp f))
 
60
         (let ((df (maxima-to-lisp-complex-float d))
 
61
               (ef))
 
62
           (setq f (lisp-complex-to-maxima
 
63
                    (if (numberp df) (* df f) (mul d f))))
 
64
           (setq ef (if (and (numberp df) (numberp e)) (abs (* df e)) nil))
 
65
           (cond ((and $orthopoly_returns_intervals (floatp ef))
 
66
                  `(($interval simp) ,f ,ef))
 
67
                 (t f))))
 
68
        (t (mul d f))))
 
69
                             
 
70
;; When a user requests the derivative of an a function in this package
 
71
;; with respect to the order or some other parameter, return a form 
 
72
;; ((unk) input from user). We "simplify" this form by printing an error.
 
73
 
 
74
(defprop unk simp-unk operators)
 
75
 
 
76
(defun simp-unk (x y z)
 
77
  (declare (ignore y z))
 
78
  (merror "Maxima doesn't know the derivative of ~:M with respect the ~:M argument" (nth 2 x) (nth 1 x)))
 
79
 
 
80
;; A left continuous unit step function; thus 
 
81
;;
 
82
;;       unit_step(x) = 0 for x <= 0 and 1 for x > 0.  
 
83
;;
 
84
;; This function differs from (1 + signum(x))/2 which isn't left or right
 
85
;; continuous at 0.
 
86
 
 
87
(defprop $unit_step simp-unit-step operators)
 
88
(defprop $unit_step "\\Theta" texword)
 
89
 
 
90
(defun simp-unit-step (a y z)
 
91
  (oneargcheck a)
 
92
  (setq y (simpcheck (cadr a) z))
 
93
  (let ((s (csign y)))
 
94
    (cond ((or (eq s '$nz) (eq s '$zero) (eq s '$neg)) 0)
 
95
          ((eq s '$pos) 1)
 
96
          (t `(($unit_step simp) ,y)))))
 
97
 
 
98
;; We barely support intervals; these functions aren't for user-level use.
 
99
;; The function intervalp returns true iff its argument is an interval.
 
100
 
 
101
(defun $intervalp (a)
 
102
  (and (consp a) (consp (car a)) (eq (caar a) '$interval)))
 
103
 
 
104
;; Multiply x by a, where x isn't an interval and a might be an 
 
105
;; interval.  When a isn't an interval or x is an interval, return
 
106
;; x * a.  The optional argument dx is an upper bound for the 
 
107
;; relative error in x.
 
108
 
 
109
(defun interval-mult (x a &optional dx)
 
110
  (if (null dx) (setq dx 0))
 
111
  (cond ((and ($intervalp a) (not ($intervalp x)))
 
112
         (let ((p (nth 1 a))
 
113
               (q (nth 2 a)))
 
114
           (if (or (floatp p) (floatp q)) 
 
115
               (setq x ($float ($rectform x))))
 
116
           (setq p ($expand (mult x p)))
 
117
           (setq q ($expand (mult x (add q (simplify `((mabs) ,(mul p dx)))))))
 
118
           (setq q (simplify `((mabs) ,q)))
 
119
           `(($interval) ,p ,q)))
 
120
        (t (mult x a))))
 
121
           
 
122
;; TeX a function with subscripts and superscripts.  The string fn is the
 
123
;; function name, the list sub holds the positions of the subscripts, the list
 
124
;; sup holds the positions of the superscripts, and i is the position of the 
 
125
;; function argument.  When b1 is true, the subscript is surrounded by parens;
 
126
;; when b2 is true, the superscript is surrounded by parens.  The lists sub and
 
127
;; sup may be nil, but the function must have at least on argument.
 
128
 
 
129
(defun tex-sub-and-super-scripted-function (fn sub b1 sup b2 i x l r)
 
130
  (setq x (cdr x))
 
131
  (let ((lo) (hi) (s1) (s2))
 
132
    (setq s1 (if b1 `("\\left(")  nil))
 
133
    (setq s2 (if b1 `("\\right)") nil))
 
134
    (dolist (i sub)
 
135
      (setq lo (cons (nth i x) lo)))
 
136
    (setq lo (if lo (tex-list (nreverse lo) s1 s2 ",") nil))
 
137
    (setq s1 (if b2 `("\\left(")  nil))
 
138
    (setq s2 (if b2 `("\\right)") nil))
 
139
    (dolist (i sup)
 
140
      (setq hi (cons (nth i x) hi)))
 
141
    (setq hi (if hi (tex-list (nreverse hi) s1 s2 ",") nil))
 
142
    (append l `(,fn)
 
143
            (if lo `("_{",@lo "}") nil)
 
144
            (if hi `("^{" ,@hi "}") nil)           
 
145
            `(,@(tex-list (nthcdr i x) `("\\left(") `("\\right)") ","))
 
146
            r)))
 
147
            
 
148
(defun dimension-sub-and-super-scripted-function (fn sub sup b2 k x)
 
149
  (let ((lo) (hi) (form))
 
150
    (dolist (i sub)
 
151
      (setq lo (cons (nth i x) lo)))
 
152
    (setq lo (nreverse lo))
 
153
    (dolist (i sup)
 
154
      (setq hi (cons (nth i x) hi)))
 
155
    (setq hi (nreverse hi))
 
156
    (cond ((null hi)
 
157
           (setq form `((,fn simp array) ,@lo)))
 
158
          (b2
 
159
           (setq form `((mexpt) ((,fn simp array) ,@lo) (("") ,@hi))))
 
160
          (t
 
161
           (setq form `((mexpt) ((,fn simp array) ,@lo) ,@hi))))
 
162
    `((,form simp) ,@(nthcdr k x))))
 
163
 
 
164
;; Return true iff 
 
165
;;   (1) each member of the list a evaluates to a floating
 
166
;;       point number (using $float) and 
 
167
;;   (2) at least one member of a has a real or imaginary part that is a 
 
168
;;       floating point number *or* a bigfloat.
 
169
;; When we find an member of a that doesn't evaluate to a float, 
 
170
;; immediately bail out and return nil.
 
171
 
 
172
(defun use-float (&rest a)
 
173
  (let ((xr) (xi) (float-found nil) (okay t))
 
174
    (dolist (x a)
 
175
      (setq x ($rectform x))
 
176
      (setq xr ($realpart x))
 
177
      (setq xi ($imagpart x))
 
178
      (setq float-found (or float-found (floatp xr) (floatp xi)
 
179
                            ($bfloatp xr) ($bfloatp xi)))
 
180
      (setq okay (and (floatp ($float xr)) (floatp ($float xi))))
 
181
      (if (not okay) (return)))
 
182
    (and okay float-found)))
 
183
         
 
184
;; When n is a nonnegative integer, return 1F1(a,b,x); that is return
 
185
;; sum(pochhammer(a,k) * x^k /pochhammer(b,k),k,0,n). Regardless of the
 
186
;; value of n,  when x = 0, immediately return 1.
 
187
 
 
188
;; Any orthopoly function that calls hypergeo should check that n is an
 
189
;; integer with n > -1; thus the summation code shouldn't get called for
 
190
;; any orthopoly function.  It wouldn't be terrible if it happened -- I
 
191
;; think the summation form isn't useful and a user can get into trouble
 
192
;; with things like subst(0,x,sum(x^k,k,0,n)).
 
193
 
 
194
(defun $hypergeo11 (a b x n)
 
195
  (cond ((like x 0) 1)
 
196
        ((and (integerp n) (> n -1))
 
197
         (cond ((and (like a (- n)) (use-float b x))
 
198
                (let ((f) (e))
 
199
                  (multiple-value-setq (f e)
 
200
                    (hypergeo11-float (- n) (maxima-to-lisp-complex-float b)
 
201
                                      (maxima-to-lisp-complex-float x)))
 
202
                  (values f e)))
 
203
               (t
 
204
                (let ((sum 1) (cf 1))
 
205
                  (dotimes (i n sum)
 
206
                    (setq cf (div (mul cf (add i a) x) (mul (add i b) (+ 1 i))))
 
207
                    (setq sum (add cf sum)))))))
 
208
        (t
 
209
         `((%sum )
 
210
           ((mtimes) ((mexpt) ((mfactorial) ,$genindex) -1)
 
211
            (($pochhammer) ,a ,$genindex)
 
212
            ((mexpt) (($pochhammer ) ,b ,$genindex) -1) 
 
213
            ((mexpt) ,x ,$genindex)) ,$genindex 0 ,n))))
 
214
 
 
215
;; return the F[2,1] hypergeometic sum from 0 to n. Use genindex as the 
 
216
;; sum index; genindex is defined in asum.lisp
 
217
 
 
218
(defun $hypergeo21 (a b c x n)
 
219
  (cond ((like x 0) 1)
 
220
        ((and (integerp n) (> n -1))
 
221
         (cond ((and (like a (- n)) (use-float b c x))
 
222
                (let ((f) (e))
 
223
                  (multiple-value-setq (f e)
 
224
                    (hypergeo21-float (- n) 
 
225
                                      (maxima-to-lisp-complex-float b)
 
226
                                      (maxima-to-lisp-complex-float c)
 
227
                                      (maxima-to-lisp-complex-float x)))
 
228
                  (values f e)))
 
229
               (t
 
230
                (let ((sum 1) (cf 1))
 
231
                  (dotimes (i n sum)
 
232
                    (setq cf (div (mul cf (add i a) (add i b) x) (mul (+ 1 i) 
 
233
                                                                      (add i c))))
 
234
                    (setq sum (add cf sum)))))))
 
235
        
 
236
        (t
 
237
         `((%sum)
 
238
           ((mtimes) (($pochhammer) ,a ,$genindex) (($pochhammer) ,b ,$genindex)
 
239
            ((mexpt) (($pochhammer) ,c ,$genindex) -1)
 
240
            ((mexpt) ((mfactorial) ,$genindex) -1)
 
241
            ((mexpt) ,x ,$genindex)) 
 
242
           ,$genindex 0 ,n))))
 
243
   
 
244
;; When n is an integer with n > -1, return the product 
 
245
;; x (x + 1) (x + 2) ... (x + n - 1).  This is the same as
 
246
;; gamma(x + n) / gamma(x).  See A&S 6.1.22, page 256.  When
 
247
;; n isn't an integer or n < 0, return the form (($pochhammer) x n).
 
248
;; Also notice that pochhammer(1,n) = n!.
 
249
 
 
250
;; We trap the case x is a complex float; otherwise, Maxima has to..
 
251
 
 
252
(defmvar $pochhammer_max_index 100)
 
253
 
 
254
(defun $pochhammer (x n)
 
255
  (cond ((mminusp n)
 
256
         (div (power -1 n) ($pochhammer (sub 1 x) (neg n))))
 
257
 
 
258
        ((and (integerp n) (use-float x))
 
259
         (let ((acc 1.0d0))
 
260
           (setq x (maxima-to-lisp-complex-float x))
 
261
           (dotimes (i n (lisp-float-to-maxima-float acc))
 
262
             (setq acc (* acc (+ i x))))))
 
263
 
 
264
        ((and (integerp n) (<= n $pochhammer_max_index))
 
265
         (let ((acc 1))
 
266
           (dotimes (i n acc)
 
267
             (setq acc (mul acc (add i x))))))
 
268
 
 
269
        (t `(($pochhammer simp) ,x ,n))))
 
270
 
 
271
(putprop '$pochhammer
 
272
         '((x n)
 
273
           ((mtimes) (($pochhammer) x n)
 
274
            ((mplus) ((mtimes) -1 ((mqapply) (($psi array) 0) x))
 
275
             ((mqapply) (($psi array) 0) ((mplus) n x)))) 
 
276
           ((mtimes) (($pochhammer) x n)
 
277
            ((mqapply) (($psi array) 0) ((mplus) n x))))
 
278
         'grad)
 
279
 
 
280
(defprop $pochhammer tex-pochhammer tex)
 
281
 
 
282
(defun tex-pochhammer (x l r)
 
283
  (setq x (mapcar #'(lambda (s) (tex s nil nil nil nil)) (cdr x)))
 
284
  (append l 
 
285
          `("\\left(")
 
286
          (nth 0 x)
 
287
          `("\\right)_{")
 
288
          (nth 1 x)
 
289
          `("}")
 
290
          r))
 
291
 
 
292
(setf (get '$pochhammer 'dimension) 'dimension-pochhammer)
 
293
 
 
294
(defun dimension-pochhammer (form result)
 
295
  (setq form `(( (("") ,(nth 1 form)) simp array) ,(nth 2 form)))
 
296
  (dimension-array form result))
 
297
 
 
298
;; pochhammer-quotient(a b x n) returns pochhammer( a,n) / pochhammer(b,n).  
 
299
;; Only when one of a, b, or x  is a floating point number and the others are 
 
300
;; numeric types (that is when (use-float a b x) evaluates to true) does this 
 
301
;; function differ from using (div ($pochhammer a n) ($pochhammer b n)).  
 
302
;; In the floating point case, we arrange the operations to reduce rounding 
 
303
;; errors and to reduce over and underflows.
 
304
 
 
305
(defun pochhammer-quotient (a b x n)
 
306
  (cond ((mminusp n)
 
307
         (pochhammer-quotient b a x (neg n)))
 
308
        ((and (integerp n) (use-float a b x))
 
309
         (let ((acc 1.0d0))
 
310
           (setq a (maxima-to-lisp-complex-float a))
 
311
           (setq b (maxima-to-lisp-complex-float b))
 
312
           (dotimes (i n (lisp-float-to-maxima-float acc))
 
313
             (setq acc (* acc (/ (+ i a) (+ i b)))))))
 
314
        (t (div ($pochhammer a n) ($pochhammer b n)))))
 
315
  
 
316
(defun use-hypergeo (n x)
 
317
  (declare (ignore x))
 
318
  (or (and (integerp n) (> n -1))
 
319
      ($featurep n '$integer)))
 
320
;      (and ($featurep n '$integer) ($ratnump x))))
 
321
 
 
322
;; See A&S 22.5.42, page 779. For integer n, use the identity
 
323
;;     binomial(n+a,n) = pochhammer(a+1,n)/pochhammer(1,n)
 
324
 
 
325
;; The condition number of the pochhammer function is 
 
326
;;     |1 + x/(x+1) + x/(x+2) + ... + x/(x+n-1)| <= n.
 
327
;; The relative floating point error in computing the pochhammer 
 
328
;; function is bounded by 3 n eps.  Putting these errors together,
 
329
;; the error in d is bounded 4 n |d| eps.
 
330
 
 
331
;; We're looking at (d +|- 4 n eps |d|)(f +|- e) = d (f +|- (e + 4 n eps |f|)) + 
 
332
;; O(eps^2). 
 
333
 
 
334
(defun $jacobi_p (n a b x)
 
335
  (cond ((use-hypergeo n x)
 
336
         (let ((f) (d) (e))
 
337
           ;(setq d (div ($pochhammer (add a 1) n) ($pochhammer 1 n)))
 
338
           (setq d (pochhammer-quotient (add a 1) 1 x n))
 
339
           (multiple-value-setq (f e)
 
340
             ($hypergeo21 (mul -1 n) (add n a b 1) (add a 1)
 
341
                          (div (add 1 (mul -1 x)) 2) n))
 
342
           (setq e (if e (+ e (* 4 n (abs f) double-float-epsilon)) nil))
 
343
           (orthopoly-return-handler d f e)))
 
344
        (t `(($jacobi_p simp) ,n ,a ,b ,x))))
 
345
 
 
346
(putprop '$jacobi_p
 
347
         '((n a b x)
 
348
           ((unk) "$first" "$jacobi_p")
 
349
           ((unk) "$second" "$jacobi_p")
 
350
           ((unk) "$third" "$jacobi_p")
 
351
 
 
352
           ((mtimes)
 
353
            ((mexpt) ((mplus ) a b ((mtimes ) 2 n)) -1)
 
354
            ((mplus)
 
355
             ((mtimes) 2
 
356
              (($unit_step) n)
 
357
              ((mplus) a n) ((mplus) b n)
 
358
              (($jacobi_p) ((mplus) -1 n) a b x))
 
359
             ((mtimes) n (($jacobi_p) n a b x)
 
360
              ((mplus) a ((mtimes ) -1 b)
 
361
               ((mtimes)
 
362
                ((mplus) ((mtimes) -1 a) ((mtimes ) -1 b)
 
363
                 ((mtimes) -2 n)) x))))
 
364
            ((mexpt) ((mplus) 1 ((mtimes) -1 ((mexpt ) x 2))) -1)))
 
365
         'grad)
 
366
           
 
367
(defprop $jacobi_p tex-jacobi-poly tex)
 
368
 
 
369
(defun tex-jacobi-poly (x l r)
 
370
  (tex-sub-and-super-scripted-function "P" `(0) nil `(1 2) t 3 x l r))
 
371
 
 
372
(setf (get '$jacobi_p 'dimension) 'dimension-jacobi-p)
 
373
 
 
374
(defun dimension-jacobi-p (form result)
 
375
  (dimension-function
 
376
   (dimension-sub-and-super-scripted-function "P" `(1) `(2 3) t 4 form)
 
377
   result))
 
378
          
 
379
;; See A&S 22.5.46, page 779.
 
380
 
 
381
(defun $ultraspherical (n a x)
 
382
  (cond ((use-hypergeo n x)
 
383
         (let ((f) (d) (e))
 
384
           ;(setq d (div ($pochhammer (mul 2 a) n) ($pochhammer 1 n)))
 
385
           (setq d (pochhammer-quotient (mul 2 a) 1 x n))
 
386
           (multiple-value-setq (f e)
 
387
             ($hypergeo21 (mul -1 n) (add n (mul 2 a)) (add a (div 1 2))
 
388
                          (div (add 1 (mul -1 x)) 2) n))
 
389
           (setq e (if e (+ e (* 4 n (abs f) double-float-epsilon)) nil))
 
390
           (orthopoly-return-handler d f e)))
 
391
        (t `(($ultraspherical simp) ,n ,a ,x))))
 
392
 
 
393
(putprop '$ultraspherical 
 
394
         '((n a x)
 
395
           ((unk) "$first" "$ultraspherical")
 
396
           ((unk) "$second" "$ultrapsherical")
 
397
           ((mtimes)
 
398
            ((mplus)
 
399
             ((mtimes)
 
400
              (($unit_step) n)
 
401
              ((mplus) -1 ((mtimes) 2 a) n)
 
402
              (($ultraspherical) ((mplus) -1 n) a x))
 
403
             ((mtimes) -1 n (($ultraspherical) n a x) x))
 
404
            ((mexpt) ((mplus) 1 ((mtimes) -1 ((mexpt) x 2))) -1)))
 
405
         'grad)            
 
406
 
 
407
(defprop $ultraspherical tex-ultraspherical tex)
 
408
 
 
409
(defun tex-ultraspherical (x l r)
 
410
  (tex-sub-and-super-scripted-function "C" `(0) nil `(1) t 2 x l r))
 
411
 
 
412
(setf (get '$ultraspherical 'dimension) 'dimension-ultraspherical)
 
413
 
 
414
(defun dimension-ultraspherical (form result)
 
415
    (dimension-function
 
416
     (dimension-sub-and-super-scripted-function "C" `(1) `(2) t 3 form)
 
417
     result))
 
418
  
 
419
(defun $chebyshev_t (n x)
 
420
  (cond ((use-hypergeo n x)
 
421
         (let ((f) (e))
 
422
           (multiple-value-setq (f e)
 
423
             ($hypergeo21 (mul -1 n) n (rat 1 2) (div (add 1 (mul -1 x)) 2) n))
 
424
           (orthopoly-return-handler 1 f e)))
 
425
        (t `(($chebyshev_t simp) ,n ,x))))
 
426
 
 
427
(putprop '$chebyshev_t 
 
428
         '((n x)
 
429
           ((unk) "$first" "$chebyshev_t")
 
430
           ((mtimes)
 
431
            ((mplus)
 
432
             ((mtimes) n (($chebyshev_t) ((mplus ) -1 n) x))
 
433
             ((mtimes ) -1 n (($chebyshev_t) n x) x))
 
434
            ((mexpt) ((mplus ) 1 ((mtimes) -1 ((mexpt) x 2))) -1)))
 
435
           'grad)
 
436
 
 
437
(defprop $chebyshev_t tex-chebyshev-t tex)
 
438
 
 
439
(defun tex-chebyshev-t (x l r)
 
440
  (tex-sub-and-super-scripted-function "T" `(0) nil nil nil 1 x l r))
 
441
 
 
442
(setf (get '$chebyshev_t 'dimension) 'dimension-chebyshev-t)
 
443
 
 
444
(defun dimension-chebyshev-t (form result)
 
445
  (dimension-function
 
446
   (dimension-sub-and-super-scripted-function "T" `(1) nil nil 2 form)
 
447
   result))
 
448
 
 
449
;; See A & S 22.5.48, page 779.
 
450
 
 
451
(defun $chebyshev_u (n x)
 
452
  (cond ((use-hypergeo n x)
 
453
         (let ((f) (d) (e))
 
454
           (setq d (add 1 n)) 
 
455
           (multiple-value-setq (f e)
 
456
             ($hypergeo21 (mul -1 n) (add 2 n) (rat 3 2)
 
457
                          (div (add 1 (mul -1 x)) 2) n))
 
458
           (orthopoly-return-handler d f e)))
 
459
        (t `(($chebyshev_u simp) ,n ,x))))
 
460
 
 
461
(putprop '$chebyshev_u
 
462
         '((n x)
 
463
           ((unk) "$first" "$chebyshev_u")
 
464
           ((mtimes)
 
465
            ((mplus)
 
466
             ((mtimes)
 
467
              (($unit_step) n)
 
468
              ((mplus) 1 n) (($chebyshev_u) ((mplus) -1 n) x))
 
469
             ((mtimes) -1 n (($chebyshev_u) n x) x))
 
470
            ((mexpt) ((mplus ) 1 ((mtimes) -1 ((mexpt) x 2))) -1)))
 
471
         'grad) 
 
472
 
 
473
(defprop $chebyshev_u tex-chebyshev-u tex)
 
474
 
 
475
(defun tex-chebyshev-u (x l r)
 
476
  (tex-sub-and-super-scripted-function "U" `(0) nil nil nil 1 x l r))
 
477
 
 
478
(setf (get '$chebyshev_u 'dimension) 'dimension-chebyshev-u)
 
479
 
 
480
(defun dimension-chebyshev-u (form result)
 
481
  (dimension-function
 
482
   (dimension-sub-and-super-scripted-function "U" `(1) nil nil 2 form)
 
483
   result))
 
484
 
 
485
;; See A & S 22.5.35, page 779.  We evaluate the legendre polynomials
 
486
;; as jacobi_p(n,0,0,x).  Eat less exercise more.
 
487
 
 
488
(defun $legendre_p (n x)
 
489
  (cond ((use-hypergeo n x) 
 
490
         ($jacobi_p n 0 0 x))
 
491
        (t `(($legendre_p simp) ,n ,x))))
 
492
 
 
493
(putprop '$legendre_p 
 
494
         '((n x) 
 
495
           ((unk) "$first" "$legendre_p")
 
496
           ((mtimes)
 
497
             ((mplus)
 
498
              ((mtimes) n (($legendre_p) ((mplus) -1 n) x))
 
499
              ((mtimes) -1 n (($legendre_p) n x) x))
 
500
             ((mexpt) ((mplus) 1 ((mtimes) -1 ((mexpt) x 2))) -1)))
 
501
         'grad)
 
502
 
 
503
(defprop $legendre_p tex-legendre-p tex)
 
504
 
 
505
(defun tex-legendre-p (x l r)
 
506
  (tex-sub-and-super-scripted-function "P" `(0) nil nil nil 1 x l r))
 
507
 
 
508
(setf (get '$legendre_p 'dimension) 'dimension-legendre-p)
 
509
 
 
510
(defun dimension-legendre-p (form result)
 
511
  (dimension-function
 
512
   (dimension-sub-and-super-scripted-function "P" `(1) nil nil 2 form)
 
513
   result))
 
514
  
 
515
(defun $legendre_q (n x)
 
516
  (if (and (integerp n) (> n -1)) 
 
517
      ($assoc_legendre_q n 0 x)
 
518
    `(($legendre_q simp) ,n ,x)))
 
519
 
 
520
(putprop '$legendre_q 
 
521
         '((n x) 
 
522
           ((unk) "$first" "$legendre_p")
 
523
           ((mplus)
 
524
            ((mtimes) -1 (($kron_delta) 0 n)
 
525
             ((mexpt) ((mplus) -1 ((mexpt) x 2)) -1)) 
 
526
            ((mtimes)
 
527
             ((mplus)
 
528
              ((mtimes) n (($legendre_q) ((mplus) -1 n) x))
 
529
              ((mtimes) -1 n (($legendre_q) n x) x))
 
530
             ((mexpt) ((mplus) 1 ((mtimes) -1 ((mexpt) x 2))) -1))))
 
531
         'grad)
 
532
 
 
533
(defprop $legendre_q tex-legendre-q tex)
 
534
 
 
535
(defun tex-legendre-q (x l r)
 
536
  (tex-sub-and-super-scripted-function "Q" `(0) nil nil nil 1 x l r))
 
537
 
 
538
(setf (get '$legendre_q 'dimension) 'dimension-legendre-q)
 
539
 
 
540
(defun dimension-legendre-q (form result)
 
541
 (dimension-function
 
542
   (dimension-sub-and-super-scripted-function "Q" `(1) nil nil 2 form)
 
543
   result))
 
544
         
 
545
;; See A & S 8.6.7 and 8.2.6 pages 333 and 334. I chose the 
 
546
;; definition that is real valued on (-1,1).  
 
547
 
 
548
;; For negative m, A & S 8.2.6 page 333 and  G & R 8.706 page 1000
 
549
;; disagree; the factor of exp(i m pi) in A & S 8.1.6 suggests to me that
 
550
;; A & S  8.2.6 is bogus.  As further evidence, Macsyma 2.4 seems to 
 
551
;; agree with G & R 8.706. I'll use G & R.
 
552
 
 
553
;; Return assoc_legendre(0,m,x). This isn't a user-level function; we 
 
554
;; don't check that m is a positive integer.
 
555
 
 
556
(defun q0m (m x)
 
557
  (cond ((< m 0)
 
558
         (merror "function q0m called with negative order. File a bug report"))
 
559
        ((= m 0)
 
560
         (div (simplify `((%log) ,(div (add 1 x) (sub 1 x)))) 2))
 
561
        (t
 
562
         (mul (factorial (- m 1)) `((rat simp) 1 2)
 
563
              (if (oddp m) -1 1) (power (sub 1 (mult x x)) (div m 2))
 
564
              (add 
 
565
               (mul (if (oddp m) 1 -1) (power (add 1 x) (neg m)))
 
566
               (power (sub 1 x) (neg m)))))))
 
567
  
 
568
;; Return assoc_legendre(1,m,x).  This isn't a user-level function; we 
 
569
;; don't check that m is a positive integer; we don't check that m is 
 
570
;; a positive integer.
 
571
 
 
572
(defun q1m (m x)
 
573
  (cond ((< m 0)
 
574
         (merror "function q1m called with negative order. File a bug report"))
 
575
        ((= m 0)
 
576
         (sub (mul x (q0m 0 x)) 1))
 
577
        ((= m 1)
 
578
         (mul -1 (power (sub 1 (mult x x)) `((rat simp) 1 2))
 
579
              (sub (q0m 0 x) (div x (sub (mul x x) 1)))))
 
580
        (t
 
581
         (mul (if (oddp m) -1 1) (power (sub 1 (mult x x)) (div m 2))
 
582
              (add
 
583
               (mul (factorial (- m 2)) `((rat simp) 1 2) (if (oddp m) -1 1)
 
584
                    (sub (power (add x 1) (sub 1 m))
 
585
                         (power (sub x 1) (sub 1 m))))
 
586
               
 
587
               (mul (factorial (- m 1)) `((rat simp) 1 2) (if (oddp m) -1 1)
 
588
                    (add (power (add x 1) (neg m)) 
 
589
                         (power (sub x 1) (neg m)))))))))
 
590
 
 
591
;; Return assoc_legendre_q(n,n,x). I don't have a reference that gives
 
592
;; a formula for assoc_legendre_q(n,n,x). To figure one out,  I used
 
593
;; A&S 8.2.1 and a formula for assoc_legendre_p(n,n,x).  
 
594
 
 
595
;; After finishing the while loop, q = int(1/(1-t^2)^(n+1),t,0,x). 
 
596
 
 
597
(defun assoc-legendre-q-nn (n x)
 
598
  (let ((q) 
 
599
        (z (sub 1 (mul x x))) 
 
600
        (i 1))
 
601
    (setq q (div (simplify `((%log) ,(div (add 1 x) (sub 1 x)))) 2))
 
602
    (while (<= i n)
 
603
      (setq q (add (mul (sub 1 `((rat) 1 ,(* 2 i))) q)
 
604
                   (div x (mul 2 i (power z i)))))
 
605
      (incf i))
 
606
    (mul (^ -2 n) (factorial n) (power z (div n 2)) q)))
 
607
 
 
608
;; Use degree recursion to find the assoc_legendre_q function. 
 
609
;; See A&S 8.5.3. When i = m in the while loop, we have a special
 
610
;; case.  For negative order, see A&S 8.2.6.
 
611
 
 
612
(defun $assoc_legendre_q (n m x)
 
613
  (cond ((and (integerp n) (> n -1) (integerp m) (<= (abs m) n))
 
614
         (cond ((< m 0)
 
615
                (mul (div (factorial (+ n m)) (factorial (- n m)))
 
616
                     ($assoc_legendre_q n (- m) x)))
 
617
               (t
 
618
                (if (not (or (floatp x) ($bfloatp x))) (setq x ($rat x)))
 
619
                (let* ((q0 (q0m m x))
 
620
                       (q1 (if (= n 0) q0 (q1m m x)))
 
621
                       (q) (i 2)
 
622
                       (use-rat (or ($ratp x) (floatp x) ($bfloatp x))))
 
623
                  
 
624
                  (while (<= i n)
 
625
                    (setq q (if (= i m) (assoc-legendre-q-nn i x) 
 
626
                              (div (sub (mul (- (* 2 i) 1) x q1) 
 
627
                                        (mul (+ i -1 m) q0)) (- i m))))
 
628
                    (setq q0 q1)
 
629
                    (setq q1 q)
 
630
                    (incf i))
 
631
                  (if use-rat q1 ($ratsimp q1))))))
 
632
        (t `(($assoc_legendre_q simp) ,n ,m ,x))))
 
633
 
 
634
;; See G & R, 8.733, page 1005 first equation.
 
635
 
 
636
(putprop '$assoc_legendre_q
 
637
         '((n m x)
 
638
           ((unk) "$first" "$assoc_legendre_q")
 
639
           ((unk) "$second" "$assoc_legendre_q")
 
640
           
 
641
           ((mplus)
 
642
            ((mtimes)
 
643
             ((mplus)
 
644
              ((mtimes) -1 ((mplus) 1 ((mtimes) -1 m) n)
 
645
               (($assoc_legendre_q ) ((mplus ) 1 n) m x))
 
646
              ((mtimes) ((mplus) 1 n)
 
647
               (($assoc_legendre_q ) n m x) x))
 
648
             ((mexpt) ((mplus) 1 ((mtimes) -1 ((mexpt) x 2))) -1))))
 
649
         'grad) 
 
650
            
 
651
(defprop $assoc_legendre_q tex-assoc-legendre-q tex)
 
652
 
 
653
(defun tex-assoc-legendre-q (x l r)
 
654
  (tex-sub-and-super-scripted-function "Q" `(0) nil `(1) nil 2 x l r))
 
655
 
 
656
(setf (get '$assoc_legendre_q 'dimension) 'dimension-assoc-legendre-q)
 
657
 
 
658
(defun dimension-assoc-legendre-q (form result)
 
659
 (dimension-function
 
660
   (dimension-sub-and-super-scripted-function "Q" `(1) `(2) nil 3 form)
 
661
   result))
 
662
 
 
663
;; See A & S 22.5.37 page 779, A & S 8.6.6 (second equation) page 334, and 
 
664
;; A & S 8.2.5 page 333.  For n < 0, see A&S 8.2.1 page 333.
 
665
 
 
666
(defun $assoc_legendre_p (n m x)
 
667
  (let ((f) (d) (dx 0))
 
668
    (cond ((and (integerp n) (integerp m))
 
669
           (cond ((> (abs m) n)
 
670
                  (setq f 0)
 
671
                  (setq d 1))
 
672
                 ((< m 0)
 
673
                  (setq f ($assoc_legendre_p n (neg m) x))
 
674
                  (setq d (div (factorial (+ n m)) (factorial (- n m))))
 
675
                  (setq dx 1))
 
676
                 (t
 
677
                  (cond ((eq m 0)
 
678
                         (setq d 1))
 
679
                        (t
 
680
                         (setq d (simplify  
 
681
                                  `((%genfact) ,(- (* 2 m) 1) ,(- m 1) 2)))
 
682
                         (setq d (mul d (if (oddp m) -1 1)))
 
683
                         (setq d (mul d (power (sub 1 (mul x x)) (div m 2))))))
 
684
                  (setq dx 4)
 
685
                  (setq f 
 
686
                        ($ultraspherical (- n m) (add m (rat 1 2)) x)))))
 
687
          (t
 
688
           (setq d 1)
 
689
           (setq f `(($assoc_legendre_p simp) ,n ,m ,x))))
 
690
    (interval-mult d f (* double-float-epsilon dx))))
 
691
 
 
692
 
 
693
;; For the derivative of the associated legendre p function, see
 
694
;; A & S 8.5.4 page 334.
 
695
 
 
696
(putprop `$assoc_legendre_p
 
697
         '((n m x)
 
698
           ((unk) "$first" "$assoc_legendre_p")
 
699
           ((unk) "$second" "$assoc_legendre_p")
 
700
           ((mtimes simp)
 
701
            ((mplus simp)
 
702
             ((mtimes simp) -1 ((mplus simp) m n) (($unit_step) n)
 
703
              (($assoc_legendre_p simp) ((mplus simp) -1 n) m x))
 
704
             ((mtimes simp) n (($assoc_legendre_p simp) n m x) x))
 
705
            ((mexpt simp) ((mplus simp) -1 ((mexpt simp) x 2)) -1))) 
 
706
           'grad) 
 
707
           
 
708
(defprop $assoc_legendre_p tex-assoc-legendre-p tex)
 
709
 
 
710
(defun tex-assoc-legendre-p (x l r)
 
711
  (tex-sub-and-super-scripted-function "P" `(0) nil `(1) nil 2 x l r))
 
712
 
 
713
(setf (get '$assoc_legendre_p 'dimension) 'dimension-assoc-legendre-p)
 
714
 
 
715
(defun dimension-assoc-legendre-p (form result)
 
716
  (dimension-function
 
717
   (dimension-sub-and-super-scripted-function "P" `(1) `(2) nil 3 form)
 
718
   result))
 
719
                                
 
720
;; See A&S 22.5.55 and 22.5.56, page 780.
 
721
 
 
722
(defun $hermite (n x)
 
723
  (cond ((integerp n)
 
724
         (let ((f) (d) (e))
 
725
           (cond (($evenp n)
 
726
                  (setq n (/ n 2))
 
727
                  (multiple-value-setq (f e)  
 
728
                    ($hypergeo11 (- n) (rat 1 2) (mul x x) n))
 
729
                  (setq d (mul (if (oddp n) -1 1) (factorial (* 2 n))
 
730
                               (div 1 (factorial n)))))
 
731
                 (($oddp n)
 
732
                  (setq n (/ (- n 1) 2))
 
733
                  (multiple-value-setq (f e)
 
734
                    ($hypergeo11 (- n) (rat 3 2) (mul x x) n))
 
735
                  (setq d (mul (if (oddp n) -1 1) (factorial (+ 1 (* 2 n))) 2 x
 
736
                               (div 1 (factorial n))))))
 
737
           (orthopoly-return-handler d f e))) 
 
738
        (t `(($hermite) ,n ,x))))
 
739
 
 
740
(putprop '$hermite
 
741
         '((n x)
 
742
           ((unk) "$first" "$hermite")
 
743
           ((mtimes) 2 n (($hermite) ((mplus) -1 n) x)))
 
744
         'grad)
 
745
 
 
746
(defprop $hermite tex-hermite tex)
 
747
 
 
748
(defun tex-hermite (x l r)
 
749
  (tex-sub-and-super-scripted-function "H" `(0) nil nil nil 1 x l r))
 
750
 
 
751
(setf (get '$hermite 'dimension) 'dimension-hermite)
 
752
 
 
753
(defun dimension-hermite (form result)
 
754
 (dimension-function
 
755
   (dimension-sub-and-super-scripted-function "H" `(1) nil nil 2 form)
 
756
   result))
 
757
 
 
758
;; See A & S 22.5.54, page 780.  For integer n, use the identity
 
759
;;     binomial(n+a,n) = pochhammer(a+1,n)/pochhammer(1,n)
 
760
 
 
761
(defun $gen_laguerre (n a x)
 
762
  (cond ((use-hypergeo n x)
 
763
         (let ((f) (d) (e))
 
764
           ;(setq d (div ($pochhammer (add a 1) n) ($pochhammer 1 n)))
 
765
           (setq d (pochhammer-quotient (add a 1) 1 x n))
 
766
           (multiple-value-setq (f e)
 
767
             ($hypergeo11 (mul -1 n) (add 1 a) x n))
 
768
           (setq e (if e (+ e (* 4 (abs f) double-float-epsilon n)) nil))
 
769
           (orthopoly-return-handler d f e)))
 
770
        (t
 
771
         `(($gen_laguerre) ,n ,a ,x))))
 
772
 
 
773
(putprop '$gen_laguerre
 
774
         '((n a x)
 
775
           ((unk) "$first" "$gen_laguerre")
 
776
           ((unk) "$second" "$gen_laguerre")
 
777
           ((mtimes)
 
778
            ((mplus)
 
779
             ((mtimes) -1 ((mplus) a n)
 
780
              (($unit_step) n) (($gen_laguerre) ((mplus) -1 n) a x))
 
781
             ((mtimes) n (($gen_laguerre) n a x)))
 
782
            ((mexpt) x -1)))
 
783
         'grad)
 
784
                 
 
785
(defprop $gen_laguerre tex-gen-laguerre tex)
 
786
 
 
787
(defun tex-gen-laguerre (x l r)
 
788
  (tex-sub-and-super-scripted-function "L" `(0) nil `(1) t 1 x l r))
 
789
 
 
790
(setf (get '$gen_laguerre 'dimension) 'dimension-gen-laguerre)
 
791
 
 
792
(defun dimension-gen-laguerre (form result)
 
793
  (dimension-function
 
794
   (dimension-sub-and-super-scripted-function "L" `(1) `(2) t 3 form)
 
795
   result))
 
796
 
 
797
;; See A & S 22.5.16, page 778.
 
798
 
 
799
(defun $laguerre (n x)
 
800
  (cond ((use-hypergeo n x)
 
801
         (let ((f) (e))
 
802
           (multiple-value-setq (f e) ($hypergeo11 (mul -1 n) 1 x n))
 
803
           (orthopoly-return-handler 1 f e)))
 
804
        (t
 
805
         `(($laguerre) ,n ,x))))
 
806
 
 
807
(putprop '$laguerre
 
808
         '((n x)
 
809
           ((unk) "$first" "$laguerre")
 
810
           ((mtimes)
 
811
            ((mplus)
 
812
             ((mtimes) -1 n (($laguerre) ((mplus) -1 n) x))
 
813
             ((mtimes) n (($laguerre) n x)))
 
814
            ((mexpt) x -1)))
 
815
         'grad)
 
816
         
 
817
(defprop $laguerre tex-laguerre tex)
 
818
 
 
819
(defun tex-laguerre (x l r)
 
820
  (tex-sub-and-super-scripted-function "L" `(0) nil nil nil 1 x l r))
 
821
 
 
822
(setf (get '$laguerre 'dimension) 'dimension-laguerre)
 
823
 
 
824
(defun dimension-laguerre (form result)
 
825
  (dimension-function
 
826
   (dimension-sub-and-super-scripted-function "L" `(1) nil nil 2 form)
 
827
   result))
 
828
 
 
829
(defun $spherical_hankel1 (n x)
 
830
  (let ((f) (d) (e))
 
831
    (cond ((and (integerp n) (< n 0))
 
832
           (setq d (mul '$%i (if (oddp n) 1 -1)))
 
833
           (multiple-value-setq (f e)
 
834
             ($spherical_hankel1 (add -1 (mul -1 n)) x))
 
835
           (orthopoly-return-handler d f e))
 
836
          ((use-hypergeo n x)
 
837
           (multiple-value-setq (f e)
 
838
             ($hypergeo11 (mul -1 n) (mul -2 n) (mul -2 '$%i x) n))
 
839
           (setq d (mul '$%i (if (= 0 n) 1 
 
840
                               (simplify `((%genfact) ,(add (mul 2 n) -1) 
 
841
                                           ,(add n (rat -1 2)) 2)))
 
842
                        (power '$%e (mul '$%i x)) (div -1 (power x (add 1 n)))))
 
843
           (orthopoly-return-handler d f e))
 
844
          (t 
 
845
           `(($spherical_hankel1) ,n ,x)))))
 
846
 
 
847
(putprop '$spherical_hankel1
 
848
         '((n x)
 
849
           ((unk) "$first" "$spherical_hankel1")
 
850
           ((mplus simp) (($spherical_hankel1) ((mplus) -1 n) x)
 
851
            ((mtimes simp) -1 ((mplus) 1 n)
 
852
             (($spherical_hankel1) n x) ((mexpt) x -1))))
 
853
         'grad)
 
854
 
 
855
(defprop $spherical_hankel1 tex-spherical-hankel-1 tex)
 
856
 
 
857
(defun tex-spherical-hankel-1 (x l r)
 
858
  (tex-sub-and-super-scripted-function "h^{(1)}" `(0) nil nil nil 1 x l r))
 
859
 
 
860
(setf (get '$spherical_hankel1 'dimension) 'dimension-spherical-hankel-1)
 
861
 
 
862
(defun dimension-spherical-hankel-1 (form result)
 
863
  (let ((form1 `((mexpt) (($\h simp array) ,(nth 1 form)) 
 
864
                 (1))))
 
865
    (dimension-function `((,form1 simp) ,(nth 2 form)) result)))
 
866
 
 
867
;; See A & S 10.1.36.
 
868
 
 
869
(defun $spherical_hankel2 (n x)
 
870
  (cond ((integerp n)
 
871
         (setq x (mul x (power '$%e (mul '$%i '$%pi (add (mul 2 n) 1)))))
 
872
         (let ((f))
 
873
           (setq f ($spherical_hankel1 n x))
 
874
           (if (oddp n) (interval-mult -1 f) f)))
 
875
        (t `(($spherical_hankel2) ,n ,x))))
 
876
 
 
877
(putprop '$spherical_hankel2
 
878
         '((n x)
 
879
           ((unk) "$first" "$spherical_hankel2")
 
880
           ((mplus simp) (($spherical_hankel2) ((mplus) -1 n) x)
 
881
            ((mtimes simp) -1 ((mplus) 1 n)
 
882
             (($spherical_hankel2) n x) ((mexpt) x -1))))
 
883
         'grad)
 
884
 
 
885
(defprop $spherical_hankel2 tex-spherical-hankel-2 tex)
 
886
 
 
887
(defun tex-spherical-hankel-2 (x l r)
 
888
  (tex-sub-and-super-scripted-function "h^{(2)}" `(0) nil nil nil 1 x l r))
 
889
 
 
890
(setf (get '$spherical_hankel2 'dimension) 'dimension-spherical-hankel-2)
 
891
 
 
892
(defun dimension-spherical-hankel-2 (form result)
 
893
  (let ((form1 `((mexpt) (($\h simp array) ,(nth 1 form))  (2))))
 
894
    (dimension-function `((,form1 simp) ,(nth 2 form)) result)))
 
895
  
 
896
;;---------------------------------------------------------------------
 
897
;; The spherical_bessel functions use the functions p-fun and q-fun.
 
898
;; See A&S 10.1.8 and 10.1.9 page 437.
 
899
 
 
900
(defun p-fun (n x)
 
901
  (let ((s 1) (w 1) 
 
902
        (n1 (floor (/ n 2)))
 
903
        (x2 (mul x x)) (m2))
 
904
    (dotimes (m n1 s)
 
905
      (setq m2 (* 2 m))
 
906
      (setq w (div (mul w `((rat) ,(* -1 (+ n m2 2) (+ n m2 1) 
 
907
                                      (- n m2) (- n (+ m2 1)))
 
908
                            ,(* 4 (+ m2 1) (+ m2 2)))) x2))
 
909
      (setq s (add s w)))))
 
910
 
 
911
(defun q-fun (n x)
 
912
  (let ((s (if (= 0 n) 0 1))
 
913
        (w 1) (m2) (x2 (mul x x))
 
914
        (n1 (floor (/ (- n 1) 2))))
 
915
    (dotimes (m n1 (div (mul n (+ n 1) s) (mul 2 x)))
 
916
      (setq m2 (* 2 m))
 
917
      (setq w (div (mul w `((rat) ,(* -1 (+ n m2 3) (+ n m2 2) 
 
918
                                      (- n (+ m2 1)) (- n (+ m2 2)))
 
919
                            ,(* 4 (+ m2 3) (+ m2 2)))) x2))
 
920
      (setq s (add s w)))))
 
921
 
 
922
 
 
923
;; See A&S 10.1.8 page 437 and A&S 10.1.15 page 439.  When the order
 
924
;; is an integer and x is a float or a bigfloat, use the slatec code
 
925
;; for numerical evaluation.  Yes, we coerce bigfloats to floats and
 
926
;; return a float.
 
927
 
 
928
;; For numerical evaluation, we do our own analytic continuation -- otherwise
 
929
;; we get factors exp(%i n %pi / 2) that should evaluate to 1,%i,-1,-%, but
 
930
;; numerically have "fuzz" in their values.  The fuzz can cause the spherical
 
931
;; bessel functions to have nonzero (but small) imaginary values on the
 
932
;; negative real axis. See A&S 10.1.34
 
933
 
 
934
(defun $spherical_bessel_j (n x)
 
935
  (cond ((and (eq '$zero (csign ($ratdisrep x)))
 
936
              (or (integerp n) ($featurep n '$integer)))
 
937
         `(($kron_delta) 0 ,n))
 
938
 
 
939
        ((and (use-float x) (integerp n))
 
940
         (let ((d 1) (xr) (xi) (z))
 
941
           (setq x ($rectform ($float x)))
 
942
           (setq xr ($realpart x))
 
943
           (setq xi ($imagpart x))
 
944
           (setq z (complex xr xi))
 
945
           (cond ((< xr 0.0)
 
946
                  (setq d (if (oddp n) -1 1))
 
947
                  (setq x (mul -1 x))
 
948
                  (setq z (* -1 z))))
 
949
           (setq n (+ 0.5L0 ($float n)))
 
950
           (setq d (* d (sqrt (/ pi (* 2 z)))))
 
951
           (setq d (lisp-float-to-maxima-float d))
 
952
           ($expand (mul ($rectform d) ($bessel x n)))))
 
953
 
 
954
        ((and (integerp n) (> n -1))
 
955
         (let ((xt (sub x (div (mul n '$%pi) 2))))
 
956
           (div (add
 
957
                 (mul (p-fun n x) (simplify `((%sin) ,xt)))
 
958
                 (mul (q-fun n x) (simplify `((%cos) ,xt)))) x)))
 
959
 
 
960
        ((integerp n)
 
961
         (mul (if (oddp n) -1 1) ($spherical_bessel_y (- (+ n 1)) x)))
 
962
 
 
963
        (t 
 
964
         `(($spherical_bessel_j) ,n ,x))))
 
965
         
 
966
(putprop '$spherical_bessel_j
 
967
         '((n x)
 
968
           ((unk) "$first" "$spherical_bessel_j")
 
969
           ((mtimes) ((mexpt) ((mplus) 1 ((mtimes) 2 n)) -1)
 
970
            ((mplus)
 
971
             ((mtimes) n (($spherical_bessel_j) ((mplus) -1 n) x))
 
972
             ((mtimes) -1 ((mplus) 1 n)
 
973
              (($spherical_bessel_j) ((mplus) 1 n) x)))))
 
974
         'grad)
 
975
 
 
976
(defprop $spherical_bessel_j tex-spherical-bessel-j tex)
 
977
 
 
978
(defun tex-spherical-bessel-j (x l r)
 
979
  (tex-sub-and-super-scripted-function "j^{(2)}" `(0) nil nil nil 1 x l r))
 
980
 
 
981
(setf (get '$spherical_bessel_j 'dimension) 'dimension-spherical-bessel-j)
 
982
 
 
983
(defun dimension-spherical-bessel-j (form result)
 
984
  (let ((form1 `(($\j simp array) ,(nth 1 form)))) 
 
985
    (dimension-function `((,form1 simp) ,(nth 2 form)) result)))
 
986
 
 
987
;; For analytic continuation, see A&S 10.1.35.
 
988
 
 
989
(defun $spherical_bessel_y (n x)
 
990
  (cond ((and (use-float x) (integerp n))
 
991
         (let ((d 1) (xr) (xi) (z))
 
992
           (setq x ($rectform ($float x)))
 
993
           (setq xr ($realpart x))
 
994
           (setq xi ($imagpart x))
 
995
           (setq z (complex xr xi))
 
996
           (cond ((< xr 0.0)
 
997
                  (setq d (if (oddp n) 1 -1))
 
998
                  (setq x (mul -1 x))
 
999
                  (setq z (* -1 z))))
 
1000
           (setq n (+ 0.5L0 ($float n)))
 
1001
           (setq d (* d (sqrt (/ pi (* 2 z)))))
 
1002
           (setq d (lisp-float-to-maxima-float d))
 
1003
           ($expand (mul ($rectform d) ($bessel_y n x)))))
 
1004
 
 
1005
        ((and (integerp n) (> n -1))
 
1006
         (let ((xt (add x (div (mul n '$%pi) 2))))
 
1007
           (mul (if (oddp n) 1 -1)
 
1008
                (div (sub
 
1009
                      (mul (p-fun n x) (simplify `((%cos) ,xt)))
 
1010
                      (mul (q-fun n x) (simplify `((%sin) ,xt)))) x))))
 
1011
 
 
1012
        ((integerp n)
 
1013
         (mul (if (oddp n) 1 -1) ($spherical_bessel_j (- (+ n 1)) x)))
 
1014
        (t  `(($spherical_bessel_y) ,n ,x))))
 
1015
 
 
1016
(putprop '$spherical_bessel_y
 
1017
         '((n x)
 
1018
           ((unk) "$first" "$spherical_bessel_y")
 
1019
           ((mtimes) ((mexpt) ((mplus) 1 ((mtimes) 2 n)) -1)
 
1020
            ((mplus)
 
1021
             ((mtimes) n (($spherical_bessel_y) ((mplus) -1 n) x))
 
1022
             ((mtimes) -1 ((mplus) 1 n)
 
1023
              (($spherical_bessel_y) ((mplus) 1 n) x)))))
 
1024
         'grad)
 
1025
 
 
1026
(defprop $spherical_bessel_y tex-spherical-bessel-y tex)
 
1027
 
 
1028
(defun tex-spherical-bessel-y (x l r)
 
1029
  (tex-sub-and-super-scripted-function "y^{(2)}" `(0) nil nil nil 1 x l r))
 
1030
 
 
1031
 (setf (get '$spherical_bessel_y 'dimension) 'dimension-spherical-bessel-y)
 
1032
 
 
1033
(defun dimension-spherical-bessel-y (form result)
 
1034
  (let ((form1 `(($\y simp array) ,(nth 1 form)))) 
 
1035
    (dimension-function `((,form1 simp) ,(nth 2 form)) result)))
 
1036
 
 
1037
;; Compute P_n^m(cos(theta)).  See Merzbacher, 9.59 page 184
 
1038
;; and 9.64 page 185, and A & S 22.5.37 page 779.  This function
 
1039
;; lacks error checking; it should only be called by spherical_harmonic.
 
1040
 
 
1041
;; We need to be careful -- for the spherical harmonics we can't use
 
1042
;; assoc_legendre_p(n,m,cos(x)).  If we did, we'd get factors 
 
1043
;; (1 - cos^2(x))^(m/2) that simplify to |sin(x)|^m but we want them
 
1044
;; to simplify to sin^m(x).  Oh my!
 
1045
 
 
1046
(defun assoc-leg-cos (n m x)
 
1047
  (interval-mult
 
1048
   (if (= m 0) 1 (mul (simplify 
 
1049
                       `((%genfact) ,(add (mul 2 m) -1) ,(add m (div 1 2)) 2))
 
1050
                      (power (simplify `((%sin) ,x)) m)))
 
1051
   ($ultraspherical (sub n m) (add m `((rat) 1 2)) 
 
1052
                    (simplify `((%cos) ,x)))))
 
1053
 
 
1054
(defun $spherical_harmonic (n m th p)
 
1055
  (cond ((and (integerp n) (integerp m) (> n -1))
 
1056
         (cond ((> (abs m) n)
 
1057
                0)
 
1058
               ((< m 0)
 
1059
                (interval-mult (if (oddp m) -1 1) 
 
1060
                               ($spherical_harmonic n (- m) th (mul -1 p))))
 
1061
               (t
 
1062
                (interval-mult
 
1063
                 (mul (simplify ($exp (mul '$%i m p)))
 
1064
                      (power (div (* (+ (* 2 n) 1) (factorial (- n m)))
 
1065
                                  (mul '$%pi (* 4 (factorial (+ n m))))) 
 
1066
                             `((rat) 1 2)))
 
1067
                 (assoc-leg-cos n m th)))))
 
1068
        (t
 
1069
         `(($spherical_harmonic) ,n ,m ,th ,p))))
 
1070
 
 
1071
(defprop $spherical_harmonic tex-spherical-harmonic tex)
 
1072
 
 
1073
(defun tex-spherical-harmonic (x l r)
 
1074
  (tex-sub-and-super-scripted-function "Y" `(0) nil `(1) nil 2 x l r))
 
1075
 
 
1076
(setf (get '$spherical_harmonic 'dimension) 'dimension-spherical-harmonic)
 
1077
 
 
1078
(defun dimension-spherical-harmonic (form result)
 
1079
 (dimension-function
 
1080
  (dimension-sub-and-super-scripted-function "Y" `(1) `(2) nil 3 form)
 
1081
  result))
 
1082
 
 
1083
(putprop '$spherical_harmonic
 
1084
         '((n m theta phi)
 
1085
           ((unk) "$first" "$spherical_harmonic")
 
1086
           ((unk) "$second" "$spherical_harmonic")
 
1087
           ((mplus)
 
1088
            ((mtimes) ((rat ) -1 2)
 
1089
             ((mexpt)
 
1090
              ((mtimes) ((mplus) ((mtimes) -1 m) n)
 
1091
               ((mplus) 1 m n))
 
1092
              ((rat) 1 2))
 
1093
             (($spherical_harmonic) n ((mplus) 1 m) theta phi)
 
1094
             ((mexpt) $%e ((mtimes) -1 $%i phi)))
 
1095
            ((mtimes) ((rat) 1 2)
 
1096
             ((mexpt)
 
1097
              ((mtimes) ((mplus) 1 ((mtimes) -1 m) n)
 
1098
               ((mplus) m n))
 
1099
              ((rat) 1 2))
 
1100
             (($spherical_harmonic) n ((mplus) -1 m) theta phi)
 
1101
             ((mexpt) $%e ((mtimes) $%i phi)))) 
 
1102
           
 
1103
           ((mtimes) $%i m (($spherical_harmonic) n m theta phi)))
 
1104
         'grad)
 
1105
                                                                        
 
1106
(defun maxima-float-to-lisp-float (y)
 
1107
  (let* ((x ($rectform y))
 
1108
         (xr ($realpart x))
 
1109
         (xi ($imagpart x)))
 
1110
    (cond ((or (floatp xr) (floatp xi))
 
1111
           (setq xr (float xr 1.0d0)
 
1112
                 xi (float xi 1.0d0))
 
1113
           (if (= 0.0 xi) xr (complex xr xi)))
 
1114
          (t
 
1115
           y))))
 
1116
 
 
1117
(defun lisp-float-to-maxima-float (x)
 
1118
  (if (complexp x)
 
1119
      (add (realpart x) (mul '$%i (imagpart x)))
 
1120
    x))
 
1121
     
 
1122
(defun hypergeo11-float (n b x)
 
1123
  (let ((f0) (fm1) (f) (i 0) (k) (dk) (ak) (bk) (err)
 
1124
        (as (make-array (- 1 n) 
 
1125
                        :initial-element 0.0d0))
 
1126
        (bs (make-array (- 1 n) 
 
1127
                        :initial-element 0.0d0))
 
1128
        (fs (make-array (- 1 n)
 
1129
                        :initial-element 0.0d0))
 
1130
        (u) (u0) (um1))
 
1131
 
 
1132
    (setq f0 1.0d0)
 
1133
    (setq fm1 0.0d0)
 
1134
    (setq x (- b x))
 
1135
    (setq n (- n))
 
1136
    (while (< i n)
 
1137
      (setf (aref fs i) f0)
 
1138
      (setq dk (+ b i))
 
1139
      (setq ak (/ (+ (* 2 i) x) dk))
 
1140
      (setq bk (/ (- i) dk))
 
1141
      (setq f (+ (* ak f0) (* bk fm1)))
 
1142
      (setf (aref as i) ak)
 
1143
      (setf (aref bs i) bk)
 
1144
      (setq fm1 f0)
 
1145
      (setq f0 f)
 
1146
      (incf i))
 
1147
    (setf (aref fs i) f0)
 
1148
    (setq i 1)
 
1149
    (setq err 1.0d0)
 
1150
    (setq u0 1.0d0)
 
1151
    (setq um1 0.0d0)
 
1152
    (while (< i n)
 
1153
      (setq k (- n i))
 
1154
      (setq u (+ (* (aref as k) u0)
 
1155
                 (* (aref bs (+ 1 k)) um1)))
 
1156
      (setq um1 u0)
 
1157
      (setq u0 u)
 
1158
      (setq err (+ err (abs (* u0 (aref fs k)))))
 
1159
      (incf i))
 
1160
    (values f0 (* 12 double-float-epsilon err))))
 
1161
    
 
1162
(defun hypergeo21-float (n b c x)
 
1163
  (let ((f0) (fm1) (f) (i 0) (k) (dk) (ak) (bk) (err)
 
1164
        (as (make-array (- 1 n) 
 
1165
                        :initial-element 0.0d0))
 
1166
        (bs (make-array (- 1 n) 
 
1167
                        :initial-element 0.0d0))
 
1168
        (fs (make-array (- 1 n)
 
1169
                        :initial-element 0.0d0))
 
1170
        (u) (u0) (um1))
 
1171
 
 
1172
    (setq f0 1.0d0)
 
1173
    (setq fm1 0.0d0)
 
1174
    (setq n (- n))
 
1175
    (while (< i n)
 
1176
      (setf (aref fs i) f0)
 
1177
      (setq dk (+ c i))
 
1178
      (setq ak (/ (+ (* 2 i) c (- (* x (+ b i)))) dk))
 
1179
      (setq bk (/ (* i (- x 1)) dk))
 
1180
      (setq f (+ (* ak f0) (* bk fm1)))
 
1181
      (setf (aref as i) ak)
 
1182
      (setf (aref bs i) bk)
 
1183
      (setq fm1 f0)
 
1184
      (setq f0 f)
 
1185
      (incf i))
 
1186
    (setf (aref fs i) f0)
 
1187
    (setq i 1)
 
1188
    (setq err 1.0d0)
 
1189
    (setq u0 1.0d0)
 
1190
    (setq um1 0.0d0)
 
1191
    (while (< i n)
 
1192
      (setq k (- n i))
 
1193
      (setq u (+ (* (aref as k) u0)
 
1194
                 (* (aref bs (+ 1 k)) um1)))
 
1195
      (setq um1 u0)
 
1196
      (setq u0 u)
 
1197
      (incf i)
 
1198
      (setq err (+ err (abs (* (aref fs k) u0)))))
 
1199
    (values f0 (* 12 double-float-epsilon err))))
 
1200
    
 
1201
;; For recursion relations, see A & S 22.7 page 782. 
 
1202
 
 
1203
;;  jacobi_p(n+1,a,b,x) = (((2*n+a+b+1)*(a^2-b^2) + 
 
1204
;;    x*pochhammer(2*n+a+b,3)) * jacobi_p(n,a,b,x) - 
 
1205
;;    2*(n+a)*(n+b)*(2*n+a+b+2)*jacobi_p(n-1,a,b,x))/(2*(n+1)*(n+a+b+1)*(2*n+a+b))
 
1206
 
 
1207
;; ultraspherical(n+1,a,x) = (2*(n+a)*x * ultraspherical(n,a,x) - 
 
1208
;;    (n+2*a+1)*ultraspherical(n-1,a,x))/(n+1)
 
1209
 
 
1210
;; chebyshev_t(n+1,x) = 2*x*chebyshev_t(n,x) -chebyshev_t(n-1,x)
 
1211
 
 
1212
;; chebyshev_u(n+1,x) = 2*x*chebyshev_u(n,x) -chebyshev_u(n-1,x)
 
1213
 
 
1214
;;  laguerre(n+1,x) = (((2*n+1) - x)*laguerre(n,x)  -(n)*laguerre(n-1,x))/(n+1)
 
1215
 
 
1216
;; gen_laguerre(n+1,a,x) = (((2*n+a+1) - x)*gen_laguerre(n,a,x)  
 
1217
;;  -(n+a)*gen_laguerre(n-1,a,x))/(n+1)
 
1218
 
 
1219
;; hermite(n+1,x) = 2*x*hermite(n,x) +2*n*hermite(n-1,x)
 
1220
 
 
1221
;; See G & R 8.733.2; A & S 22.7.11 might be wrong -- or maybe I need
 
1222
;; reading glasses.
 
1223
 
 
1224
;; (2*n+1)*x*assoc_legendre_p(n,m,x) = (n-m+1)*assoc_legendre_p(n+1,m,x) 
 
1225
;; + (n+m)*assoc_legendre_p(n-1,m,x)
 
1226
 
 
1227
;; For the half-integer bessel functions, See A & S 10.1.19
 
1228
 
 
1229
;; fn(n-1,x) + fn(n+1,x) = (2*n+1)*fn(n,x)/x;
 
1230
 
 
1231
(defun check-arg-length (fn n m)
 
1232
  (if (not (= n m))
 
1233
      (merror "Function ~:M needs ~:M arguments, instead it received ~:M"
 
1234
              fn n m)))
 
1235
 
 
1236
(defun $orthopoly_recur (fn arg)
 
1237
  (if (not ($listp arg)) 
 
1238
      (merror "The second argument to orthopoly_recur must be a list"))
 
1239
  (cond ((eq fn '$jacobi_p)
 
1240
         (check-arg-length fn 4 (- (length arg) 1))
 
1241
         (let ((n (nth 1 arg))
 
1242
               (a (nth 2 arg))
 
1243
               (b (nth 3 arg))
 
1244
               (x (nth 4 arg)))
 
1245
           (simplify
 
1246
            `((mequal) (($jacobi_p ) ((mplus) 1 ,n) ,a ,b ,x)
 
1247
              ((mtimes) ((rat) 1 2) ((mexpt) ((mplus) 1 ,n) -1)
 
1248
               ((mexpt) ((mplus) 1 ,a ,b ,n) -1)
 
1249
               ((mexpt) ((mplus) ,a ,b ((mtimes) 2 ,n)) -1)
 
1250
               ((mplus)
 
1251
                ((mtimes) -2 ((mplus) ,a ,n) ((mplus) ,b ,n)
 
1252
                 ((mplus) 2 ,a ,b ((mtimes) 2 ,n))
 
1253
                 (($jacobi_p ) ((mplus) -1 ,n) ,a ,b ,x))
 
1254
                ((mtimes) (($jacobi_p ) ,n ,a ,b ,x)
 
1255
                 ((mplus)
 
1256
                 ((mtimes)
 
1257
                  ((mplus) ((mexpt) ,a 2)
 
1258
                   ((mtimes) -1 ((mexpt) ,b 2)))
 
1259
                  ((mplus) 1 ,a ,b ((mtimes) 2 ,n)))
 
1260
                 ((mtimes) ((mplus) ,a ,b ((mtimes) 2 ,n))
 
1261
                  ((mplus) 1 ,a ,b ((mtimes) 2 ,n))
 
1262
                  ((mplus) 2 ,a ,b ((mtimes) 2 ,n)) ,x)))))))))
 
1263
 
 
1264
        ((eq fn '$ultraspherical)
 
1265
         (check-arg-length fn 3 (- (length arg) 1))
 
1266
         (let ((n (nth 1 arg))
 
1267
               (a (nth 2 arg))
 
1268
               (x (nth 3 arg)))
 
1269
           (simplify
 
1270
            `((mequal) (($ultraspherical) ((mplus) 1 ,n) ,a ,x)
 
1271
             ((mtimes) ((mexpt) ((mplus) 1 ,n) -1)
 
1272
              ((mplus)
 
1273
               ((mtimes) -1 ((mplus) -1 ((mtimes) 2 ,a) ,n)
 
1274
                (($ultraspherical) ((mplus) -1 ,n) ,a ,x))
 
1275
               ((mtimes) 2 ((mplus) ,a ,n)
 
1276
                (($ultraspherical) ,n ,a ,x) ,x)))))))
 
1277
 
 
1278
        ((member fn  `($chebyshev_t $chebyshev_u) :test 'eq)
 
1279
         (check-arg-length fn 2 (- (length arg) 1))
 
1280
         (let ((n (nth 1 arg))
 
1281
               (x (nth 2 arg)))
 
1282
          (simplify
 
1283
           `((mequal ) ((,fn) ((mplus ) 1 ,n) ,x)
 
1284
            ((mplus )
 
1285
             ((mtimes ) -1 ((,fn) ((mplus ) -1 ,n) ,x))
 
1286
             ((mtimes ) 2 ((,fn) ,n ,x) ,x))))))
 
1287
 
 
1288
        ((member fn '($legendre_p $legendre_q) :test 'eq)
 
1289
         (check-arg-length fn 2 (- (length arg) 1))
 
1290
         (let* ((n (nth 1 arg))
 
1291
               (x (nth 2 arg))
 
1292
               (z (if (eq fn '$legendre_q) 
 
1293
                      `((mtimes) -1 (($kron_delta) ,n 1)) 0))) 
 
1294
           (simplify
 
1295
             `((mequal) ((,fn) ,n ,x)
 
1296
               ((mplus)
 
1297
                ((mtimes) ((mexpt) ,n -1)
 
1298
                 ((mplus)
 
1299
                  ((mtimes) ((mplus) 1 ((mtimes) -1 ,n))
 
1300
                   ((,fn) ((mplus) -2 ,n) ,x))
 
1301
                  ((mtimes) ((mplus) -1 ((mtimes) 2 ,n))
 
1302
                   ((,fn) ((mplus) -1 ,n) ,x) ,x)))
 
1303
                ,z)))))
 
1304
 
 
1305
        ((member fn '($assoc_legendre_p $assoc_legendre_q) :test 'eq)
 
1306
         (check-arg-length fn 3 (- (length arg) 1))
 
1307
         (let ((n (nth 1 arg))
 
1308
               (m (nth 2 arg))
 
1309
               (x (nth 3 arg)))
 
1310
           (simplify
 
1311
            `((mequal) ((,fn) ((mplus) 1 ,n) ,m ,x)
 
1312
              ((mtimes)
 
1313
               ((mexpt) ((mplus) 1 ((mtimes) -1 ,m) ,n) -1)
 
1314
               ((mplus)
 
1315
                ((mtimes)
 
1316
                 ((mplus) ((mtimes) -1 ,m)
 
1317
                  ((mtimes) -1 ,n))
 
1318
                 ((,fn) ((mplus) -1 ,n) ,m ,x))
 
1319
                ((mtimes) ((mplus) 1 ((mtimes) 2 ,n))
 
1320
                 ((,fn) ,n ,m ,x) ,x))))))) 
 
1321
        
 
1322
        ((eq fn '$laguerre)
 
1323
         (check-arg-length fn 2 (- (length arg) 1))
 
1324
         (let ((n (nth 1 arg))
 
1325
               (x (nth 2 arg)))
 
1326
           (simplify
 
1327
            `((mequal ) (($laguerre ) ((mplus ) 1 ,n) ,x)
 
1328
              ((mtimes ) ((mexpt ) ((mplus ) 1 ,n) -1)
 
1329
               ((mplus )
 
1330
                ((mtimes ) -1 ,n (($laguerre ) ((mplus ) -1 ,n) ,x))
 
1331
                ((mtimes ) (($laguerre ) ,n ,x)
 
1332
                 ((mplus ) 1 ((mtimes ) 2 ,n) ((mtimes ) -1 ,x))))))))) 
 
1333
 
 
1334
        ((eq fn '$gen_laguerre)
 
1335
         (check-arg-length fn 3 (- (length arg) 1))
 
1336
         (let ((n (nth 1 arg))
 
1337
               (a (nth 2 arg))
 
1338
               (x (nth 3 arg)))
 
1339
           (simplify
 
1340
            `((mequal) (($gen_laguerre) ((mplus) 1 ,n) ,a ,x)
 
1341
              ((mtimes) ((mexpt ) ((mplus) 1 ,n) -1)
 
1342
               ((mplus)
 
1343
                ((mtimes) -1 ((mplus) ,a ,n)
 
1344
                 (($gen_laguerre) ((mplus) -1 ,n) ,a ,x))
 
1345
                ((mtimes) (($gen_laguerre) ,n ,a ,x)
 
1346
                 ((mplus) 1 ,a ((mtimes) 2 ,n) ((mtimes ) -1 ,x))))))))) 
 
1347
 
 
1348
        ((eq fn '$hermite)
 
1349
         (check-arg-length fn 2 (- (length arg) 1))
 
1350
         (let ((n (nth 1 arg))
 
1351
               (x (nth 2 arg)))
 
1352
           (simplify
 
1353
            `((mequal) (($hermite) ((mplus) 1 ,n) ,x)
 
1354
              ((mplus)
 
1355
               ((mtimes) -2 ,n (($hermite) ((mplus) -1 ,n) ,x))
 
1356
               ((mtimes) 2 (($hermite) ,n ,x) ,x))))))
 
1357
 
 
1358
        ((member fn `($spherical_bessel_j $spherical_bessel_y
 
1359
                                          $spherical_hankel1 $spherical_hankel2)
 
1360
                 :test 'eq)
 
1361
         (check-arg-length fn 2 (- (length arg) 1))
 
1362
         (let ((n (nth 1 arg))
 
1363
               (x (nth 2 arg)))
 
1364
           (simplify
 
1365
            `((mequal) ((,fn) ((mplus) 1 ,n) ,x)
 
1366
              ((mplus) ((mtimes) -1 ((,fn ) ((mplus) -1 ,n) ,x))
 
1367
               ((mtimes) ((,fn) ,n ,x) ((mexpt) ,x -1))
 
1368
               ((mtimes) 2 ,n ((,fn ) ,n ,x) ((mexpt) ,x -1)))))))
 
1369
         
 
1370
        (t (merror "A recursion relation for ~:M isn't known to Maxima" fn))))
 
1371
    
 
1372
;; See A & S Table 2.2, page 774.
 
1373
 
 
1374
(defun $orthopoly_weight (fn arg)
 
1375
  (if (not ($listp arg)) 
 
1376
      (merror "The second argument to orthopoly_weight must be a list"))
 
1377
 
 
1378
  (if (not (or ($symbolp (car (last arg))) ($subvarp (car (last arg)))))
 
1379
      (merror "The last element of the second argument to orthopoly_weight must
 
1380
be a symbol or a subscripted symbol, instead found ~:M" (car (last arg))))
 
1381
 
 
1382
  (if (not (every #'(lambda (s) 
 
1383
                      ($freeof (car (last arg)) s)) (butlast (cdr arg))))
 
1384
      (merror "Only the last element of ~:M may depend on the integration
 
1385
variable ~:M" arg (car (last arg))))
 
1386
 
 
1387
  (cond ((eq fn '$jacobi_p)
 
1388
         (check-arg-length fn 4 (- (length arg) 1))
 
1389
         (let ((a (nth 2 arg))
 
1390
               (b (nth 3 arg))
 
1391
               (x (nth 4 arg)))
 
1392
           (simplify
 
1393
            `((mlist)
 
1394
              ((mtimes) ((mexpt) ((mplus) 1 ((mtimes) -1 ,x)) ,a)
 
1395
               ((mexpt) ((mplus ) 1 ,x) ,b))
 
1396
              -1 1))))
 
1397
        
 
1398
        ((eq fn '$ultraspherical)
 
1399
         (check-arg-length fn 3 (- (length arg) 1))
 
1400
         (let ((a (nth 2 arg))
 
1401
               (x (nth 3 arg)))
 
1402
           (simplify
 
1403
            `((mlist)
 
1404
              ((mexpt) ((mplus) 1 ((mtimes) -1 ((mexpt) ,x 2)))
 
1405
               ((mplus) ((rat) -1 2) ,a)) -1 1))))
 
1406
 
 
1407
        ((eq fn '$chebyshev_t)
 
1408
         (check-arg-length fn 2 (- (length arg) 1))
 
1409
         (let ((x (nth 2 arg)))
 
1410
           (simplify
 
1411
            `((mlist)
 
1412
              ((mexpt) ((mplus) 1 ((mtimes) -1 ((mexpt) ,x 2)))
 
1413
               ((rat) -1 2)) -1 1)))) 
 
1414
          
 
1415
        ((eq fn '$chebyshev_u)
 
1416
         (check-arg-length fn 2 (- (length arg) 1))
 
1417
         (let ((x (nth 2 arg)))
 
1418
           (simplify
 
1419
            `((mlist)
 
1420
              ((mexpt) ((mplus) 1  ((mtimes) -1 ((mexpt) ,x 2)))
 
1421
               ((rat) 1 2)) -1 1))))
 
1422
 
 
1423
        ((eq fn '$legendre_p)
 
1424
         (check-arg-length fn 2 (- (length arg) 1))
 
1425
         `((mlist) 1 -1 1))
 
1426
 
 
1427
        ((eq fn '$laguerre)
 
1428
         (check-arg-length fn 2 (- (length arg) 1))
 
1429
         (let ((x (nth 2 arg)))
 
1430
           (simplify
 
1431
            `((mlist) ((mexpt) $%e ((mtimes) -1 ,x)) 0 $inf))))
 
1432
 
 
1433
        ((eq fn '$gen_laguerre)
 
1434
         (check-arg-length fn 3 (- (length arg) 1))
 
1435
         (let ((a (nth 2 arg))
 
1436
               (x (nth 3 arg)))
 
1437
           (simplify
 
1438
            `((mlist)
 
1439
              ((mtimes) ((mexpt) ,x ,a)
 
1440
               ((mexpt) $%e ((mtimes) -1 ,x))) 0 $inf))))
 
1441
 
 
1442
        ((eq fn '$hermite)
 
1443
         (check-arg-length fn 2 (- (length arg) 1))
 
1444
         (let ((x (nth 2 arg)))
 
1445
           (simplify
 
1446
            `((mlist) ((mexpt) $%e ((mtimes) -1 ((mexpt) ,x 2)))
 
1447
              ((mtimes ) -1 $inf) $inf))))
 
1448
 
 
1449
        (t (merror "a weight for ~:m isn't known to maxima" fn))))
 
1450
    
 
1451
 
 
1452
    
 
1453
 
 
1454
 
 
1455