1 ;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;; The data in this file contains enhancments. ;;;;;
5 ;;; Copyright (c) 1984,1987 by William Schelter,University of Texas ;;;;;
6 ;;; All rights reserved ;;;;;
7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
11 (declare-top (special $hypergeometric_representation
))
13 ;; When non-NIL, the Bessel functions of half-integral order are
14 ;; expanded in terms of elementary functions.
16 (defmvar $besselexpand nil
)
18 ;; When T Bessel functions with an integer order are reduced to order 0 and 1
19 (defmvar $bessel_reduce nil
)
21 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
23 ;;; Helper functions for this file
25 ;; If E is a maxima ratio with a denominator of DEN, return the ratio
26 ;; as a Lisp rational. Otherwise NIL.
27 (defun max-numeric-ratio-p (e den
)
31 (integerp (second e
)))
32 (/ (second e
) (third e
))
35 (defun bessel-numerical-eval-p (order arg
)
36 ;; Return non-NIL if we should numerically evaluate a bessel
37 ;; function. Basically, both args have to be numbers. If both args
38 ;; are integers, we don't evaluate unless $numer is true.
39 (or (and (numberp order
) (complex-number-p arg
)
41 (floatp ($realpart arg
))
42 (floatp ($imagpart arg
))))
43 (and $numer
(numberp order
)
44 (complex-number-p arg
))))
46 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
48 ;;; Implementation of the Bessel J function
50 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
52 (defmfun $bessel_j
(v z
)
53 (simplify (list '(%bessel_j
) v z
)))
55 (defprop $bessel_j %bessel_j alias
)
56 (defprop $bessel_j %bessel_j verb
)
57 (defprop %bessel_j $bessel_j reversealias
)
58 (defprop %bessel_j $bessel_j noun
)
60 ;; Bessel J is a simplifying function.
62 (defprop %bessel_j simp-bessel-j operators
)
64 ;; Bessel J distributes over lists, matrices, and equations
66 (defprop %bessel_j
(mlist $matrix mequal
) distribute_over
)
68 ;; Derivatives of the Bessel function.
71 ;; Derivative wrt to order n. A&S 9.1.64. Do we really want to
72 ;; do this? It's quite messy.
75 ;; - (x/2)^n*sum((-1)^k*psi(n+k+1)/gamma(n+k+1)*(x^2/4)^k/k!,k,0,inf)
79 ((%log
) ((mtimes) ((rat) 1 2) x
)))
81 ((mexpt) ((mtimes) x
((rat) 1 2)) n
)
83 ((mtimes) ((mexpt) -
1 $%k
)
84 ((mexpt) ((mfactorial) $%k
) -
1)
85 ((mqapply) (($psi array
) 0) ((mplus) 1 $%k n
))
86 ((mexpt) ((%gamma
) ((mplus) 1 $%k n
)) -
1)
87 ((mexpt) ((mtimes) x x
((rat) 1 4)) $%k
))
90 ;; Derivative wrt to arg x.
91 ;; A&S 9.1.27; changed from 9.1.30 so that taylor works on Bessel functions
94 ((%bessel_j
) ((mplus) -
1 n
) x
)
95 ((mtimes) -
1 ((%bessel_j
) ((mplus) 1 n
) x
)))
99 ;; Integral of the Bessel function wrt z
100 (defun bessel-j-integral-2 (v z
)
103 ;; integrate(bessel_j(0,z),z)
104 ;; = (1/2)*z*(%pi*bessel_j(1,z)*struve_h(0,z)
105 ;; +bessel_j(0,z)*(2-%pi*struve_h(1,z)))
106 `((mtimes) ((rat) 1 2) ,z
113 ((mplus) 2 ((mtimes) -
1 $%pi
((%struve_h
) 1 ,z
)))))))
115 ;; integrate(bessel_j(1,z),z) = -bessel_j(0,z)
116 `((mtimes) -
1 ((%bessel_j
) 0 ,z
)))
118 ;; http://functions.wolfram.com/03.01.21.0002.01
119 ;; integrate(bessel_j(v,z),z)
120 ;; = 2^(-v-1)*z^(v+1)*gamma(v/2+1/2)
121 ;; * hypergeometric_regularized([v/2+1/2],[v+1,v/2+3/2],-z^2/4)
122 ;; = 2^(-v)*z^(v+1)*hypergeometric([v/2+1/2],[v+1,v/2+3/2],-z^2/4)
127 ((mplus) ((rat) 1 2) ((mtimes) ((rat) 1 2) ,v
)))
129 ((mplus) ((rat) 3 2) ((mtimes) ((rat) 1 2) ,v
))
131 ((mtimes) ((rat) -
1 4) ((mexpt) ,z
2)))
132 ((mexpt) 2 ((mtimes) -
1 ,v
))
133 ((mexpt) ((%gamma
) ((mplus) 2 ,v
)) -
1)
134 ((mexpt) z
((mplus) 1 ,v
))))))
136 (putprop '%bessel_j
`((v z
) nil
,#'bessel-j-integral-2
) 'integral
)
138 ;; Support a simplim%bessel_j function to handle specific limits
140 (defprop %bessel_j simplim%bessel_j simplim%function
)
142 (defun simplim%bessel_j
(expr var val
)
143 ;; Look for the limit of the arguments.
144 (let ((v (limit (cadr expr
) var val
'think
))
145 (z (limit (caddr expr
) var val
'think
)))
147 ;; Handle an argument 0 at this place.
151 (let ((sgn ($sign
($realpart v
))))
152 (cond ((and (eq sgn
'$neg
)
153 (not (maxima-integerp v
)))
154 ;; bessel_j(v,0), Re(v)<0 and v not an integer
156 ((and (eq sgn
'$zero
)
158 ;; bessel_j(v,0), Re(v)=0 and v #0
160 ;; Call the simplifier of the function.
161 (t (simplify (list '(%bessel_j
) v z
))))))
164 ;; bessel_j(v,inf) or bessel_j(v,minf)
167 ;; All other cases are handled by the simplifier of the function.
168 (simplify (list '(%bessel_j
) v z
))))))
170 (defun simp-bessel-j (expr ignored z
)
171 (declare (ignore ignored
))
173 (let ((order (simpcheck (cadr expr
) z
))
174 (arg (simpcheck (caddr expr
) z
))
178 ;; We handle the different case for zero arg carefully.
179 (let ((sgn ($sign
($realpart order
))))
180 (cond ((and (eq sgn
'$zero
)
181 (zerop1 ($imagpart order
)))
183 (cond ((or ($bfloatp order
) ($bfloatp arg
)) ($bfloat
1))
184 ((or (floatp order
) (floatp arg
)) 1.0)
187 (maxima-integerp order
))
188 ;; bessel_j(v,0) and Re(v)>0 or v an integer
189 (cond ((or ($bfloatp order
) ($bfloatp arg
)) ($bfloat
0))
190 ((or (floatp order
) (floatp arg
)) 0.0)
193 (not (maxima-integerp order
)))
194 ;; bessel_j(v,0) and Re(v)<0 and v not an integer
196 (intl:gettext
"bessel_j: bessel_j(~:M,~:M) is undefined.")
198 ((and (eq sgn
'$zero
)
199 (not (zerop1 ($imagpart order
))))
200 ;; bessel_j(v,0) and Re(v)=0 and v # 0
202 (intl:gettext
"bessel_j: bessel_j(~:M,~:M) is undefined.")
205 ;; No information about the sign of the order
206 (eqtest (list '(%bessel_j
) order arg
) expr
)))))
208 ((complex-float-numerical-eval-p order arg
)
209 ;; We have numeric order and arg and $numer is true, or we have either
210 ;; the order or arg being floating-point, so let's evaluate it
212 ;; The numerical routine bessel-j returns a CL number, so we have
213 ;; to add the conversion to a Maxima-complex-number.
214 (cond ((= 0 ($imagpart order
))
215 ;; order is real, arg is real or complex
216 (complexify (bessel-j ($float order
)
217 (complex ($float
($realpart arg
))
218 ($float
($imagpart arg
))))))
220 ;; order is complex, arg is real or complex
223 (order ($float order
))
227 (bessel-j-hypergeometric order arg
)))))))
229 ((and (integerp order
) (minusp order
))
230 ;; Some special cases when the order is an integer.
231 ;; A&S 9.1.5: J[-n](x) = (-1)^n*J[n](x)
233 (take '(%bessel_j
) (- order
) arg
)
234 (mul -
1 (take '(%bessel_j
) (- order
) arg
))))
237 (setq rat-order
(max-numeric-ratio-p order
2)))
238 ;; When order is a fraction with a denominator of 2, we
239 ;; can express the result in terms of elementary functions.
240 (bessel-j-half-order rat-order arg
))
243 (and (integerp order
)
246 ;; Reduce a bessel function of order > 2 to order 1 and 0.
247 ;; A&S 9.1.27: bessel_j(v,z) = 2*(v-1)/z*bessel_j(v-1,z)-bessel_j(v-2,z)
251 (take '(%bessel_j
) (- order
1) arg
))
252 (take '(%bessel_j
) (- order
2) arg
)))
254 ((and $%iargs
(multiplep arg
'$%i
))
255 ;; bessel_j(v, %i*x) = (%i*x)^v/(x^v) * bessel_i(v, x)
256 ;; (From http://functions.wolfram.com/03.01.27.0002.01)
257 (let ((x (coeff arg
'$%i
1)))
258 (mul (power (mul '$%i x
) order
)
259 (inv (power x order
))
260 (take '(%bessel_i
) order x
))))
262 ($hypergeometric_representation
263 (bessel-j-hypergeometric order arg
))
266 (eqtest (list '(%bessel_j
) order arg
) expr
)))))
268 ;; Returns the hypergeometric representation of bessel_j
269 (defun bessel-j-hypergeometric (order arg
)
270 ;; A&S 9.1.69 / http://functions.wolfram.com/03.01.26.0002.01
271 ;; hypergeometric([],[v+1],-z^2/4)*(z/2)^v/gamma(v+1)
272 (mul (inv (take '(%gamma
) (add order
1)))
273 (power (div arg
2) order
)
274 (take '($hypergeometric
)
276 (list '(mlist) (add order
1))
277 (neg (div (mul arg arg
) 4)))))
279 ;; Compute value of Bessel function of the first kind of order ORDER.
280 (defun bessel-j (order arg
)
282 ((zerop (imagpart arg
))
283 ;; We have numeric args and the arg is purely real.
284 ;; Call the real-valued Bessel function when possible.
285 (let ((arg (realpart arg
)))
288 (slatec:dbesj0
(float arg
)))
290 (slatec:dbesj1
(float arg
)))
292 (cond ((zerop (nth-value 1 (truncate order
)))
293 ;; The order is a negative integer. We use A&S 9.1.5:
294 ;; J[-n](z) = (-1)^n*J[n](z)
295 ;; and not the Hankel functions.
296 (if (evenp (floor order
))
297 (bessel-j (- order
) arg
)
298 (- (bessel-j (- order
) arg
))))
300 ;; Bessel function of negative order. We use the Hankel
301 ;; functions to compute this:
302 ;; J[v](z) = (H1[v](z) + H2[v](z)) / 2.
303 ;; This works for negative and positive arg and handles
304 ;; special cases correctly.
305 (let ((result (* 0.5 (+ (hankel-1 order arg
) (hankel-2 order arg
)))))
306 (cond ((= (nth-value 1 (floor order
)) 1/2)
307 ;; ORDER is a half-integral-value or a float
308 ;; representation, thereof.
310 ;; arg is negative, the result is purely imaginary
311 (complex 0 (imagpart result
))
312 ;; arg is positive, the result is purely real
314 ;; in all other cases general complex result
317 ;; We have a real arg and order > 0 and order not 0 or 1
318 ;; for this case we can call the function dbesj
319 (multiple-value-bind (n alpha
) (floor (float order
))
320 (let ((jvals (make-array (1+ n
) :element-type
'flonum
)))
321 (slatec:dbesj
(abs (float arg
)) alpha
(1+ n
) jvals
0)
325 ;; Use analytic continuation formula A&S 9.1.35:
326 ;; J[v](z*exp(m*%pi*%i)) = exp(m*%pi*%i*v)*J[v](z)
327 ;; for an integer m. In particular, for m = 1:
328 ;; J[v](-x) = exp(v*%pi*%i)*J[v](x)
329 ;; and handle special cases
330 (cond ((zerop (nth-value 1 (truncate order
)))
331 ;; order is an integer
332 (if (evenp (floor order
))
335 ((= (nth-value 1 (floor order
)) 1/2)
336 ;; Order is a half-integral-value and we know that
337 ;; arg < 0, so the result is purely imginary.
338 (if (evenp (floor order
))
339 (complex 0 (aref jvals n
))
340 (complex 0 (- (aref jvals n
)))))
341 ;; In all other cases a general complex result
343 (* (cis (* order pi
))
344 (aref jvals n
))))))))))))
346 ;; The arg is complex. Use the complex-valued Bessel function.
347 (cond ((mminusp order
)
348 ;; Bessel function of negative order. We use the Hankel function to
349 ;; compute this, because A&S 9.1.3 and 9.1.4 say
350 ;; H1[v](z) = J[v](z) + %i * Y[v](z)
352 ;; H2[v](z) = J[v](z) - %i * Y[v](z).
354 ;; J[v](z) = (H1[v](z) + H2[v](z)) / 2.
355 ;; Not the most efficient way, but perhaps good enough for maxima.
356 (* 0.5 (+ (hankel-1 order arg
) (hankel-2 order arg
))))
358 (multiple-value-bind (n alpha
) (floor (float order
))
359 (let ((cyr (make-array (1+ n
) :element-type
'flonum
))
360 (cyi (make-array (1+ n
) :element-type
'flonum
)))
361 (multiple-value-bind (v-zr v-zi v-fnu v-kode v-n
362 v-cyr v-cyi v-nz v-ierr
)
363 (slatec:zbesj
(float (realpart arg
))
364 (float (imagpart arg
))
365 alpha
1 (1+ n
) cyr cyi
0 0)
366 (declare (ignore v-zr v-zi v-fnu v-kode v-n v-cyr v-cyi v-nz
))
368 ;; Should check the return status in v-ierr of this routine.
370 (format t
"zbesj ierr = ~A~%" v-ierr
))
371 (complex (aref cyr n
) (aref cyi n
))))))))))
373 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
375 ;;; Implementation of the Bessel Y function
377 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
379 (defmfun $bessel_y
(v z
)
380 (simplify (list '(%bessel_y
) v z
)))
382 (defprop $bessel_y %bessel_y alias
)
383 (defprop $bessel_y %bessel_y verb
)
384 (defprop %bessel_y $bessel_y reversealias
)
385 (defprop %bessel_y $bessel_y noun
)
387 (defprop %bessel_y simp-bessel-y operators
)
389 ;; Bessel Y distributes over lists, matrices, and equations
391 (defprop %bessel_y
(mlist $matrix mequal
) distribute_over
)
395 ;; Derivative wrt order n. A&S 9.1.65.
397 ;; cot(n*%pi)*[diff(bessel_j(n,x),n)-%pi*bessel_y(n,x)]
398 ;; - csc(n*%pi)*diff(bessel_j(-n,x),n)-%pi*bessel_j(n,x)
400 ((mtimes) -
1 $%pi
((%bessel_j
) n x
))
403 ((%csc
) ((mtimes) $%pi n
))
404 ((%derivative
) ((%bessel_j
) ((mtimes) -
1 n
) x
) n
1))
406 ((%cot
) ((mtimes) $%pi n
))
408 ((mtimes) -
1 $%pi
((%bessel_y
) n x
))
409 ((%derivative
) ((%bessel_j
) n x
) n
1))))
411 ;; Derivative wrt to arg x. A&S 9.1.27; changed from A&S 9.1.30
412 ;; to be consistent with bessel_j.
415 ((%bessel_y
)((mplus) -
1 n
) x
)
416 ((mtimes) -
1 ((%bessel_y
) ((mplus) 1 n
) x
)))
420 ;; Integral of the Bessel Y function wrt z
421 ;; http://functions.wolfram.com/Bessel-TypeFunctions/BesselY/21/01/01/
422 (defun bessel-y-integral-2 (n z
)
424 ((and ($integerp n
) (<= 0 n
))
427 ;; integrate(bessel_y(2*N+1,z),z) , N > 0
428 ;; = -bessel_y(0,z) - 2 * sum(bessel_y(2*k,z),k,1,N)
430 (answer `((mplus) ((mtimes) -
1 ((%bessel_y
) 0 ,z
))
432 ((%sum
) ((%bessel_y
) ((mtimes) 2 ,k
) ,z
) ,k
1
433 ((mtimes) ((rat) 1 2) ((mplus) -
1 ,n
)))))))
434 ;; Expand out the sum if n < 10. Otherwise fix up the indices
436 (meval `(($ev
) ,answer $sum
)) ; Is there a better way?
437 (simplify ($niceindices answer
)))))
439 ;; integrate(bessel_y(2*N,z),z) , N > 0
440 ;; = (1/2)*%pi*z*(bessel_y(0,z)*struve_h(-1,z)
441 ;; +bessel_y(1,z)*struve_h(0,z))
442 ;; - 2 * sum(bessel_y(2*k+1,z),k,0,N-1)
448 ((%bessel_y
) ((mplus) 1 ((mtimes) 2 ,k
)) ,z
)
452 ((mtimes) ((rat) 1 2) ,n
))))
453 ((mtimes) ((rat) 1 2) $%pi
,z
460 ((%struve_h
) 0 ,z
)))))))
461 ;; Expand out the sum if n < 10. Otherwise fix up the indices
463 (meval `(($ev
) ,answer $sum
)) ; Is there a better way?
464 (simplify ($niceindices answer
)))))))
467 (putprop '%bessel_y
`((n z
) nil
,#'bessel-y-integral-2
) 'integral
)
469 ;; Support a simplim%bessel_y function to handle specific limits
471 (defprop %bessel_y simplim%bessel_y simplim%function
)
473 (defun simplim%bessel_y
(expr var val
)
474 ;; Look for the limit of the arguments.
475 (let ((v (limit (cadr expr
) var val
'think
))
476 (z (limit (caddr expr
) var val
'think
)))
478 ;; Handle an argument 0 at this place.
486 ;; bessel_y(n,0), n an integer
487 (cond ((evenp v
) '$minf
)
488 (t (cond ((eq z
'$zeroa
) '$minf
)
489 ((eq z
'$zerob
) '$inf
)
491 ((not (zerop1 ($realpart v
)))
492 ;; bessel_y(v,0), Re(v)#0
494 ((and (zerop1 ($realpart v
))
496 ;; bessel_y(v,0), Re(v)=0 and v#0
498 ;; Call the simplifier of the function.
499 (t (simplify (list '(%bessel_y
) v z
)))))
502 ;; bessel_y(v,inf) or bessel_y(v,minf)
505 ;; All other cases are handled by the simplifier of the function.
506 (simplify (list '(%bessel_y
) v z
))))))
508 (defun simp-bessel-y (expr ignored z
)
509 (declare (ignore ignored
))
511 (let ((order (simpcheck (cadr expr
) z
))
512 (arg (simpcheck (caddr expr
) z
))
516 ;; Domain error for a zero argument.
518 (intl:gettext
"bessel_y: bessel_y(~:M,~:M) is undefined.") order arg
))
520 ((complex-float-numerical-eval-p order arg
)
521 ;; We have numeric order and arg and $numer is true, or
522 ;; we have either the order or arg being floating-point,
523 ;; so let's evaluate it numerically.
524 (cond ((= 0 ($imagpart order
))
525 ;; order is real, arg is real or complex
526 (complexify (bessel-y ($float order
)
527 (complex ($float
($realpart arg
))
528 ($float
($imagpart arg
))))))
530 ;; order is complex, arg is real or complex
533 (order ($float order
))
537 (bessel-y-hypergeometric order arg
)))))))
539 ((and (integerp order
) (minusp order
))
540 ;; Special case when the order is an integer.
541 ;; A&S 9.1.5: Y[-n](x) = (-1)^n*Y[n](x)
543 (take '(%bessel_y
) (- order
) arg
)
544 (mul -
1 (take '(%bessel_y
) (- order
) arg
))))
547 (setq rat-order
(max-numeric-ratio-p order
2)))
548 ;; When order is a fraction with a denominator of 2, we
549 ;; can express the result in terms of elementary functions.
550 ;; From A&S 10.1.1, 10.1.11-12 and 10.1.15:
552 ;; Y[1/2](z) = -J[-1/2](z) is a function of cos(z).
553 ;; Y[-1/2](z) = J[1/2](z) is a function of sin(z).
554 (bessel-y-half-order rat-order arg
))
557 (and (integerp order
)
560 ;; Reduce a bessel function of order > 2 to order 1 and 0.
561 ;; A&S 9.1.27: bessel_y(v,z) = 2*(v-1)/z*bessel_y(v-1,z)-bessel_y(v-2,z)
565 (take '(%bessel_y
) (- order
1) arg
))
566 (take '(%bessel_y
) (- order
2) arg
)))
568 ($hypergeometric_representation
569 (bessel-y-hypergeometric order arg
))
572 (eqtest (list '(%bessel_y
) order arg
) expr
)))))
574 ;; Returns the hypergeometric representation of bessel_y
575 (defun bessel-y-hypergeometric (order arg
)
576 ;; http://functions.wolfram.com/03.03.26.0002.01
577 ;; -hypergeometric([],[1-v],-z^2/4)*(2/z)^v*gamma(v)/%pi
578 ;; - hypergeometric([],[v+1],-z^2/4)*gamma(-v)*cos(%pi*v)*(z/2)^v/%pi
581 (inv (power arg order
))
582 (take '(%gamma
) order
)
584 (take '($hypergeometric
)
586 (list '(mlist) (sub 1 order
))
587 (neg (div (mul arg arg
) 4))))
589 (inv (power 2 order
))
591 (take '(%cos
) (mul order
'$%pi
))
592 (take '(%gamma
) (neg order
))
594 (take '($hypergeometric
)
596 (list '(mlist) (add 1 order
))
597 (neg (div (mul arg arg
) 4))))))
599 ;; Bessel function of the second kind, Y[n](z), for real or complex z
600 (defun bessel-y (order arg
)
602 ((zerop (imagpart arg
))
603 ;; We have numeric args and the first arg is purely
604 ;; real. Call the real-valued Bessel function.
606 ;; For negative values, use the analytic continuation formula
609 ;; Y[v](z*exp(m*%pi*%i)) = exp(-v*m*%pi*%i) * Y[v](z)
610 ;; + 2*%i*sin(m*v*%pi)*cot(v*%pi)*J[v](z)
612 ;; In particular for m = 1:
613 ;; Y[v](-z) = exp(-v*%pi*%i) * Y[v](z) + 2*%i*cos(v*%pi)*J[v](z)
614 (let ((arg (realpart arg
)))
618 (slatec:dbesy0
(float arg
)))
620 ;; For v = 0, this simplifies to
621 ;; Y[0](-z) = Y[0](z) + 2*%i*J[0](z)
622 ;; the return value has to be a CL number
623 (+ (slatec:dbesy0
(float (- arg
)))
624 (complex 0 (* 2 (slatec:dbesj0
(float (- arg
)))))))))
627 (slatec:dbesy1
(float arg
)))
629 ;; For v = 1, this simplifies to
630 ;; Y[1](-z) = -Y[1](z) - 2*%i*J[1](v)
631 ;; the return value has to be a CL number
632 (+ (- (slatec:dbesy1
(float (- arg
))))
633 (complex 0 (* -
2 (slatec:dbesj1
(float (- arg
)))))))))
635 (cond ((zerop (nth-value 1 (truncate order
)))
636 ;; Order is a negative integer or float representation.
637 ;; Use A&S 9.1.5: Y[-n](z) = (-1)^n*Y[n](z).
638 (if (evenp (floor order
))
639 (bessel-y (- order
) arg
)
640 (- (bessel-y (- order
) arg
))))
642 ;; Bessel function of negative order. We use the Hankel
643 ;; functions to compute this:
644 ;; Y[v](z) = (H1[v](z) - H2[v](z)) / 2 / %i
645 (let ((result (/ (- (hankel-1 order arg
)
646 (hankel-2 order arg
))
648 (cond ((= (nth-value 1 (floor order
)) 1/2)
649 ;; ORDER is half-integral-value or a float
650 ;; representation thereof.
652 ;; arg is negative, the result is purely imaginary
653 (complex 0 (imagpart result
))
654 ;; arg is positive, the result is purely real
656 ;; in all other cases general complex result
659 (multiple-value-bind (n alpha
) (floor (float order
))
660 (let ((jvals (make-array (1+ n
) :element-type
'flonum
)))
661 ;; First we do the calculation for an positive argument.
662 (slatec:dbesy
(abs (float arg
)) alpha
(1+ n
) jvals
)
664 ;; Now we look at the sign of the argument
668 (let* ((dpi (coerce pi
'flonum
))
669 (s1 (cis (- (* order dpi
))))
670 (s2 (* #c
(0 2) (cos (* order dpi
)))))
671 (let ((result (+ (* s1
(aref jvals n
))
672 (* s2
(bessel-j order
(- arg
))))))
673 (cond ((zerop (nth-value 1 (truncate order
)))
674 ;; ORDER is an integer or a float representation
675 ;; of an integer, and the arg is positive the
676 ;; result is general complex.
678 ((= (nth-value 1 (floor order
)) 1/2)
679 ;; ORDER is a half-integral-value or an float
680 ;; representation and we have arg < 0. The
681 ;; result is purely imaginary.
682 (complex 0 (imagpart result
)))
683 ;; in all other cases general complex result
684 (t result
))))))))))))
686 (cond ((minusp order
)
687 ;; Bessel function of negative order. We use the Hankel function to
688 ;; compute this, because A&S 9.1.3 and 9.1.4 say
689 ;; H1[v](z) = J[v](z) + %i * Y[v](z)
691 ;; H2[v](z) = J[v](z) - %i * Y[v](z).
693 ;; Y[v](z) = (H1[v](z) - H2[v](z)) / 2 / %i
694 (/ (- (hankel-1 order arg
) (hankel-2 order arg
))
697 (multiple-value-bind (n alpha
) (floor (float order
))
698 (let ((cyr (make-array (1+ n
) :element-type
'flonum
))
699 (cyi (make-array (1+ n
) :element-type
'flonum
))
700 (cwrkr (make-array (1+ n
) :element-type
'flonum
))
701 (cwrki (make-array (1+ n
) :element-type
'flonum
)))
702 (multiple-value-bind (v-zr v-zi v-fnu v-kode v-n v-cyr v-cyi
703 v-nz v-cwrkr v-cwrki v-ierr
)
704 (slatec::zbesy
(float (realpart arg
))
705 (float (imagpart arg
))
706 alpha
1 (1+ n
) cyr cyi
0 cwrkr cwrki
0)
707 (declare (ignore v-zr v-zi v-fnu v-kode v-n
708 v-cyr v-cyi v-cwrkr v-cwrki v-nz
))
710 ;; We should check for errors based on the value of v-ierr.
712 (format t
"zbesy ierr = ~A~%" v-ierr
))
714 (complex (aref cyr n
) (aref cyi n
))))))))))
716 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
718 ;;; Implementation of the Bessel I function
720 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
722 (defmfun $bessel_i
(v z
)
723 (simplify (list '(%bessel_i
) v z
)))
725 (defprop $bessel_i %bessel_i alias
)
726 (defprop $bessel_i %bessel_i verb
)
727 (defprop %bessel_i $bessel_i reversealias
)
728 (defprop %bessel_i $bessel_i noun
)
730 (defprop %bessel_i simp-bessel-i operators
)
732 ;; Bessel I distributes over lists, matrices, and equations
734 (defprop %bessel_i
(mlist $matrix mequal
) distribute_over
)
738 ;; Derivative wrt order n. A&S 9.6.42.
741 ;; - (x/2)^n*sum(psi(n+k+1)/gamma(n+k+1)*(x^2/4)^k/k!,k,0,inf)
745 ((%log
) ((mtimes) ((rat) 1 2) x
)))
747 ((mexpt) ((mtimes) x
((rat) 1 2)) n
)
750 ((mexpt) ((mfactorial) $%k
) -
1)
751 ((mqapply) (($psi array
) 0) ((mplus) 1 $%k n
))
752 ((mexpt) ((%gamma
) ((mplus) 1 $%k n
)) -
1)
753 ((mexpt) ((mtimes) x x
((rat) 1 4)) $%k
))
755 ;; Derivative wrt to x. A&S 9.6.29.
757 ((mplus) ((%bessel_i
) ((mplus) -
1 n
) x
)
758 ((%bessel_i
) ((mplus) 1 n
) x
))
762 ;; Integral of the Bessel I function wrt z
763 ;; http://functions.wolfram.com/Bessel-TypeFunctions/BesselI/21/01/01/
764 (defun bessel-i-integral-2 (v z
)
767 ;; integrate(bessel_i(0,z),z)
768 ;; = (1/2)*z*(bessel_i(0,z)*(%pi*struve_l(1,z)+2)
769 ;; -%pi*bessel_i(1,z)*struve_l(0,z))
770 `((mtimes) ((rat) 1 2) ,z
778 ((mtimes) $%pi
((%struve_l
) 1 ,z
)))))))
780 ;; integrate(bessel_i(1,z),z) = bessel_i(0,z)
783 ;; http://functions.wolfram.com/03.02.21.0002.01
784 ;; integrate(bessel_i(v,z),z)
785 ;; = 2^(-v-1)*z^(v+1)*gamma(v/2+1/2)
786 ;; * hypergeometric_regularized([v/2+1/2],[v+1,v/2+3/2],z^2/4)
787 ;; = 2^(-v)*z^(v+1)*hypergeometric([v/2+1/2],[v+1,v/2+3/2],z^2/4)
792 ((mplus) ((rat) 1 2) ((mtimes) ((rat) 1 2) ,v
)))
794 ((mplus) ((rat) 3 2) ((mtimes) ((rat) 1 2) ,v
))
796 ((mtimes) ((rat) 1 4) ((mexpt) ,z
2)))
797 ((mexpt) 2 ((mtimes) -
1 ,v
))
798 ((mexpt) ((%gamma
) ((mplus) 2 ,v
)) -
1)
799 ((mexpt) z
((mplus) 1 ,v
))))))
801 (putprop '%bessel_i
`((v z
) nil
,#'bessel-i-integral-2
) 'integral
)
803 ;; Support a simplim%bessel_i function to handle specific limits
805 (defprop %bessel_i simplim%bessel_i simplim%function
)
807 (defun simplim%bessel_i
(expr var val
)
808 ;; Look for the limit of the arguments.
809 (let ((v (limit (cadr expr
) var val
'think
))
810 (z (limit (caddr expr
) var val
'think
)))
812 ;; Handle an argument 0 at this place.
816 (let ((sgn ($sign
($realpart v
))))
817 (cond ((and (eq sgn
'$neg
)
818 (not (maxima-integerp v
)))
819 ;; bessel_i(v,0), Re(v)<0 and v not an integer
821 ((and (eq sgn
'$zero
)
823 ;; bessel_i(v,0), Re(v)=0 and v #0
825 ;; Call the simplifier of the function.
826 (t (simplify (list '(%bessel_i
) v z
))))))
834 ;; All other cases are handled by the simplifier of the function.
835 (simplify (list '(%bessel_i
) v z
))))))
837 (defun simp-bessel-i (expr ignored z
)
838 (declare (ignore ignored
))
840 (let ((order (simpcheck (cadr expr
) z
))
841 (arg (simpcheck (caddr expr
) z
))
845 ;; We handle the different case for zero arg carefully.
846 (let ((sgn ($sign
($realpart order
))))
847 (cond ((and (eq sgn
'$zero
)
848 (zerop1 ($imagpart order
)))
850 (cond ((or ($bfloatp order
) ($bfloatp arg
)) ($bfloat
1))
851 ((or (floatp order
) (floatp arg
)) 1.0)
854 (maxima-integerp order
))
855 ;; bessel_i(v,0) and Re(v)>0 or v an integer
856 (cond ((or ($bfloatp order
) ($bfloatp arg
)) ($bfloat
0))
857 ((or (floatp order
) (floatp arg
)) 0.0)
860 (not (maxima-integerp order
)))
861 ;; bessel_i(v,0) and Re(v)<0 and v not an integer
863 (intl:gettext
"bessel_i: bessel_i(~:M,~:M) is undefined.")
865 ((and (eq sgn
'$zero
)
866 (not (zerop1 ($imagpart order
))))
867 ;; bessel_i(v,0) and Re(v)=0 and v # 0
869 (intl:gettext
"bessel_i: bessel_i(~:M,~:M) is undefined.")
872 ;; No information about the sign of the order
873 (eqtest (list '(%bessel_i
) order arg
) expr
)))))
875 ((complex-float-numerical-eval-p order arg
)
876 (cond ((= 0 ($imagpart order
))
877 ;; order is real, arg is real or complex
878 (complexify (bessel-i ($float order
)
879 (complex ($float
($realpart arg
))
880 ($float
($imagpart arg
))))))
882 ;; order is complex, arg is real or complex
885 (order ($float order
))
889 (bessel-i-hypergeometric order arg
)))))))
891 ((and (integerp order
) (minusp order
))
892 ;; Some special cases when the order is an integer
893 ;; A&S 9.6.6: I[-n](x) = I[n](x)
894 (take '(%bessel_i
) (- order
) arg
))
896 ((and $besselexpand
(setq rat-order
(max-numeric-ratio-p order
2)))
897 ;; When order is a fraction with a denominator of 2, we
898 ;; can express the result in terms of elementary functions.
899 ;; From A&S 10.2.13 and 10.2.14:
901 ;; I[1/2](z) = sqrt(2/%pi/z)*sinh(z)
902 ;; I[-1/2](z) = sqrt(2/%pi/z)*cosh(z)
903 (bessel-i-half-order rat-order arg
))
906 (and (integerp order
)
909 ;; Reduce a bessel function of order > 2 to order 1 and 0.
910 ;; A&S 9.6.26: bessel_i(v,z) = -2*(v-1)/z*bessel_i(v-1,z)+bessel_i(v-2,z)
914 (take '(%bessel_i
) (- order
1) arg
))
915 (take '(%bessel_i
) (- order
2) arg
)))
917 ((and $%iargs
(multiplep arg
'$%i
))
918 ;; bessel_i(v, %i*x) = (%i*x)^v/(x^v) * bessel_j(v, x)
919 ;; (From http://functions.wolfram.com/03.02.27.0002.01)
920 (let ((x (coeff arg
'$%i
1)))
921 (mul (power (mul '$%i x
) order
)
922 (inv (power x order
))
923 (take '(%bessel_j
) order x
))))
925 ($hypergeometric_representation
926 (bessel-i-hypergeometric order arg
))
929 (eqtest (list '(%bessel_i
) order arg
) expr
)))))
931 ;; Returns the hypergeometric representation of bessel_i
932 (defun bessel-i-hypergeometric (order arg
)
933 ;; A&S 9.6.47 / http://functions.wolfram.com/03.02.26.0002.01
934 ;; hypergeometric([],[v+1],z^2/4)*(z/2)^v/gamma(v+1)
935 (mul (inv (take '(%gamma
) (add order
1)))
936 (power (div arg
2) order
)
937 (take '($hypergeometric
)
939 (list '(mlist) (add order
1))
940 (div (mul arg arg
) 4))))
942 ;; Compute value of Modified Bessel function of the first kind of order ORDER
943 (defun bessel-i (order arg
)
945 ((zerop (imagpart arg
))
946 ;; We have numeric args and the first arg is purely
947 ;; real. Call the real-valued Bessel function. Use special
948 ;; routines for order 0 and 1, when possible
949 (let ((arg (realpart arg
)))
952 (slatec:dbesi0
(float arg
)))
954 (slatec:dbesi1
(float arg
)))
955 ((or (minusp order
) (< arg
0))
956 (multiple-value-bind (order-int order-frac
) (floor order
)
957 (cond ((zerop order-frac
)
958 ;; Order is an integer. From A&S 9.6.6 and 9.6.30 we have
959 ;; I[-n](z) = I[n](z)
961 ;; I[n](-z) = (-1)^n*I[n](z)
963 (if (evenp order-int
)
964 (bessel-i (abs order
) (abs arg
))
965 (- (bessel-i (abs order
) (abs arg
))))
966 (bessel-i (abs order
) arg
)))
968 ;; Order or arg is negative and order is not an integer, use
969 ;; the bessel-j function for calculation. We know from
970 ;; the definition I[v](x) = x^v/(%i*x)^v * J[v](%i*x).
971 (let* ((arg (float arg
))
972 (result (* (expt arg order
)
973 (expt (complex 0 arg
) (- order
))
974 (bessel-j order
(complex 0 arg
)))))
975 ;; Try to clean up result if we know the result is
976 ;; purely real or purely imaginary.
978 ;; Result is purely real for arg >= 0
981 ;; Order is an integer or a float representation of
982 ;; an integer, the result is purely real.
985 ;; Order is half-integral-value or a float
986 ;; representation and arg < 0, the result
987 ;; is purely imaginary.
988 (complex 0 (imagpart result
)))
991 ;; Now the case order > 0 and arg >= 0
992 (multiple-value-bind (n alpha
) (floor (float order
))
993 (let ((jvals (make-array (1+ n
) :element-type
'flonum
)))
994 (slatec:dbesi
(float (realpart arg
)) alpha
1 (1+ n
) jvals
0)
997 ((and (zerop (realpart arg
))
998 (zerop (rem order
1)))
999 ;; Handle the case for a pure imaginary arg and integer order.
1000 ;; In this case, the result is purely real or purely imaginary,
1001 ;; so we want to make sure that happens.
1003 ;; bessel_i(n, %i*x) = (%i*x)^n/x^n * bessel_j(n,x)
1004 ;; = %i^n * bessel_j(n,x)
1005 (let* ((n (floor order
))
1006 (result (bessel-j (float n
) (imagpart arg
))))
1008 ;; %i^(2*m) = (-1)^m, where n=2*m
1013 ;; %i^(2*m+1) = %i*(-1)^m, where n = 2*m+1
1014 (if (evenp (floor n
2))
1016 (complex 0 (- result
)))))))
1019 ;; The arg is complex. Use the complex-valued Bessel function.
1020 (multiple-value-bind (n alpha
) (floor (abs (float order
)))
1021 ;; Evaluate the function for positive order and fixup the result later.
1022 (let ((cyr (make-array (1+ n
) :element-type
'flonum
))
1023 (cyi (make-array (1+ n
) :element-type
'flonum
)))
1024 (multiple-value-bind (v-zr v-zi v-fnu v-kode v-n
1025 v-cyr v-cyi v-nz v-ierr
)
1026 (slatec::zbesi
(float (realpart arg
))
1027 (float (imagpart arg
))
1028 alpha
1 (1+ n
) cyr cyi
0 0)
1029 (declare (ignore v-zr v-zi v-fnu v-kode v-n v-cyr v-cyi v-nz
))
1030 ;; We should check for errors here based on the value of v-ierr.
1031 (when (plusp v-ierr
)
1032 (format t
"zbesi ierr = ~A~%" v-ierr
))
1034 ;; We have evaluated I[|order|](arg), now we look at
1035 ;; the the sign of the order.
1036 (cond ((minusp order
)
1038 ;; I[-a](z) = I[a](z) + (2/%pi)*sin(%pi*a)*K[a](z)
1039 (+ (complex (aref cyr n
) (aref cyi n
))
1040 (let ((dpi (coerce pi
'flonum
)))
1042 (sin (* dpi
(- order
)))
1043 (bessel-k (- order
) arg
)))))
1045 (complex (aref cyr n
) (aref cyi n
))))))))))
1047 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1049 ;;; Implementation of the Bessel K function
1051 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1053 (defmfun $bessel_k
(v z
)
1054 (simplify (list '(%bessel_k
) v z
)))
1056 (defprop $bessel_k %bessel_k alias
)
1057 (defprop $bessel_k %bessel_k verb
)
1058 (defprop %bessel_k $bessel_k reversealias
)
1059 (defprop %bessel_k $bessel_k noun
)
1061 (defprop %bessel_k simp-bessel-k operators
)
1063 ;; Bessel K distributes over lists, matrices, and equations
1065 (defprop %bessel_k
(mlist $matrix mequal
) distribute_over
)
1069 ;; Derivativer wrt order n. A&S 9.6.43.
1071 ;; %pi/2*csc(n*%pi)*['diff(bessel_i(-n,x),n)-'diff(bessel_i(n,x),n)]
1072 ;; - %pi*cot(n*%pi)*bessel_k(n,x)
1076 ((%cot
) ((mtimes) $%pi n
)))
1080 ((%csc
) ((mtimes) $%pi n
))
1082 ((%derivative
) ((%bessel_i
) ((mtimes) -
1 n
) x
) n
1)
1084 ((%derivative
) ((%bessel_i
) n x
) n
1)))))
1085 ;; Derivative wrt to x. A&S 9.6.29.
1088 ((mplus) ((%bessel_k
) ((mplus) -
1 n
) x
)
1089 ((%bessel_k
) ((mplus) 1 n
) x
))
1093 ;; Integral of the Bessel K function wrt z
1094 ;; http://functions.wolfram.com/Bessel-TypeFunctions/BesselK/21/01/01/
1095 (defun bessel-k-integral-2 (n z
)
1097 ((and ($integerp n
) (<= 0 n
))
1100 ;; integrate(bessel_k(2*N+1,z),z) , N > 0
1101 ;; = -(-1)^((n-1)/2)*bessel_k(0,z)
1102 ;; + 2*sum((-1)^(k+(n-1)/2-1)*bessel_k(2*k,z),k,1,(n-1)/2)
1105 ((mtimes) -
1 ((%bessel_k
) 0 ,z
)
1107 ((mtimes) ((rat) 1 2) ((mplus) -
1 ,n
))))
1110 ((mtimes) ((%bessel_k
) ((mtimes) 2 ,k
) ,z
)
1113 ((mtimes) ((rat) 1 2) ((mplus) -
1 ,n
)))))
1114 ,k
1 ((mtimes) ((rat) 1 2) ((mplus) -
1 ,n
)))))))
1115 ;; Expand out the sum if n < 10. Otherwise fix up the indices
1117 (meval `(($ev
) ,answer $sum
)) ; Is there a better way?
1118 (simplify ($niceindices answer
)))))
1120 ;; integrate(bessel_k(2*N,z),z) , N > 0
1121 ;; = (1/2)*(-1)^(n/2)*%pi*z*(bessel_k(0,z)*struve_l(-1,z)
1122 ;; +bessel_k(1,z)*struve_l(0,z))
1123 ;; + 2 * sum((-1)^(k+n/2)*bessel_k(2*k+1,z),k,0,n/2-1)
1130 ((%bessel_k
) ((mplus) 1 ((mtimes) 2 ,k
)) ,z
)
1132 ((mplus) ,k
((mtimes) ((rat) 1 2) ,n
))))
1133 ,k
0 ((mplus) -
1 ((mtimes) ((rat) 1 2) ,n
))))
1137 ((mexpt) -
1 ((mtimes) ((rat) 1 2) ,n
))
1142 ((%struve_l
) -
1 ,z
))
1145 ((%struve_l
) 0 ,z
)))))))
1146 ;; expand out the sum if n < 10. Otherwise fix up the indices
1148 (meval `(($ev
) ,answer $sum
)) ; Is there a better way?
1149 (simplify ($niceindices answer
)))))))
1152 (putprop '%bessel_k
`((n z
) nil
,#'bessel-k-integral-2
) 'integral
)
1154 ;; Support a simplim%bessel_k function to handle specific limits
1156 (defprop %bessel_k simplim%bessel_k simplim%function
)
1158 (defun simplim%bessel_k
(expr var val
)
1159 ;; Look for the limit of the arguments.
1160 (let ((v (limit (cadr expr
) var val
'think
))
1161 (z (limit (caddr expr
) var val
'think
)))
1163 ;; Handle an argument 0 at this place.
1171 ;; bessel_k(n,0), n an integer
1172 (cond ((evenp v
) '$inf
)
1173 (t (cond ((eq z
'$zeroa
) '$inf
)
1174 ((eq z
'$zerob
) '$minf
)
1176 ((not (zerop1 ($realpart v
)))
1177 ;; bessel_k(v,0), Re(v)#0
1179 ((and (zerop1 ($realpart v
))
1181 ;; bessel_k(v,0), Re(v)=0 and v#0
1183 ;; Call the simplifier of the function.
1184 (t (simplify (list '(%bessel_k
) v z
)))))
1192 ;; All other cases are handled by the simplifier of the function.
1193 (simplify (list '(%bessel_k
) v z
))))))
1195 (defun simp-bessel-k (expr ignored z
)
1196 (declare (ignore ignored
))
1198 (let ((order (simpcheck (cadr expr
) z
))
1199 (arg (simpcheck (caddr expr
) z
))
1203 ;; Domain error for a zero argument.
1205 (intl:gettext
"bessel_k: bessel_k(~:M,~:M) is undefined.") order arg
))
1207 ((complex-float-numerical-eval-p order arg
)
1208 (cond ((= 0 ($imagpart order
))
1209 ;; order is real, arg is real or complex
1210 (complexify (bessel-k ($float order
)
1211 (complex ($float
($realpart arg
))
1212 ($float
($imagpart arg
))))))
1214 ;; order is complex, arg is real or complex
1217 (order ($float order
))
1221 (bessel-k-hypergeometric order arg
)))))))
1224 ;; A&S 9.6.6: K[-v](x) = K[v](x)
1225 (take '(%bessel_k
) (mul -
1 order
) arg
))
1228 (setq rat-order
(max-numeric-ratio-p order
2)))
1229 ;; When order is a fraction with a denominator of 2, we
1230 ;; can express the result in terms of elementary
1231 ;; functions. From A&S 10.2.16 and 10.2.17:
1233 ;; K[1/2](z) = sqrt(%pi/2/z)*exp(-z)
1235 (bessel-k-half-order rat-order arg
))
1237 ((and $bessel_reduce
1238 (and (integerp order
)
1241 ;; Reduce a bessel function of order > 2 to order 1 and 0.
1242 ;; A&S 9.6.26: bessel_k(v,z) = 2*(v-1)/z*bessel_k(v-1,z)+bessel_k(v-2,z)
1246 (take '(%bessel_k
) (- order
1) arg
))
1247 (take '(%bessel_k
) (- order
2) arg
)))
1249 ($hypergeometric_representation
1250 (bessel-k-hypergeometric order arg
))
1253 (eqtest (list '(%bessel_k
) order arg
) expr
)))))
1255 ;; Returns the hypergeometric representation of bessel_k
1256 (defun bessel-k-hypergeometric (order arg
)
1257 ;; http://functions.wolfram.com/03.04.26.0002.01
1258 ;; hypergeometric([],[1-v],z^2/4)*2^(v-1)*gamma(v)/z^v
1259 ;; + hypergeometric([],[v+1],z^2/4)*2^(-v-1)*gamma(-v)*z^v
1260 (add (mul (power 2 (sub order
1))
1261 (take '(%gamma
) order
)
1262 (inv (power arg order
))
1263 (take '($hypergeometric
)
1265 (list '(mlist) (sub 1 order
))
1266 (div (mul arg arg
) 4)))
1267 (mul (inv (power 2 (add order
1)))
1269 (take '(%gamma
) (neg order
))
1270 (take '($hypergeometric
)
1272 (list '(mlist) (add order
1))
1273 (div (mul arg arg
) 4)))))
1275 ;; Compute value of Modified Bessel function of the second kind of order ORDER
1276 (defun bessel-k (order arg
)
1278 ((zerop (imagpart arg
))
1279 ;; We have numeric args and the first arg is purely real. Call the
1280 ;; real-valued Bessel function. Handle orders 0 and 1 specially, when
1282 (let ((arg (realpart arg
)))
1285 ;; This is the extension for negative arg.
1286 ;; We use A&S 9.6.6 and 9.6.31 for evaluation:
1287 ;; K[v](-z) = K[|v|](-z)
1288 ;; = exp(-%i*%pi*|v|)*K[|v|](z) - %i*%pi*I[|v|](z)
1289 (let* ((dpi (coerce pi
'flonum
))
1290 (s1 (cis (* dpi
(- (abs order
)))))
1291 (s2 (* (complex 0 -
1) dpi
))
1292 (result (+ (* s1
(bessel-k (abs order
) (- arg
)))
1293 (* s2
(bessel-i (abs order
) (- arg
)))))
1294 (rem (nth-value 1 (floor order
))))
1296 ;; order is an integer or a float representation of an
1297 ;; integer, the result is a general complex
1300 ;; order is half-integral-value or an float representation
1301 ;; and arg < 0, the result is pure imaginary
1302 (complex 0 (imagpart result
)))
1303 ;; in all other cases general complex result
1306 (slatec:dbesk0
(float arg
)))
1308 (slatec:dbesk1
(float arg
)))
1310 ;; From A&S 9.6.6, K[-v](z) = K[v](z), so take the
1311 ;; absolute value of the order.
1312 (multiple-value-bind (n alpha
) (floor (abs (float order
)))
1313 (let ((jvals (make-array (1+ n
) :element-type
'flonum
)))
1314 (slatec:dbesk
(float arg
) alpha
1 (1+ n
) jvals
0)
1315 (aref jvals n
)))))))
1317 ;; The arg is complex. Use the complex-valued Bessel function. From
1318 ;; A&S 9.6.6, K[-v](z) = K[v](z), so take the absolute value of the order.
1319 (multiple-value-bind (n alpha
) (floor (abs (float order
)))
1320 (let ((cyr (make-array (1+ n
) :element-type
'flonum
))
1321 (cyi (make-array (1+ n
) :element-type
'flonum
)))
1322 (multiple-value-bind (v-zr v-zi v-fnu v-kode v-n
1323 v-cyr v-cyi v-nz v-ierr
)
1324 (slatec::zbesk
(float (realpart arg
))
1325 (float (imagpart arg
))
1326 alpha
1 (1+ n
) cyr cyi
0 0)
1327 (declare (ignore v-zr v-zi v-fnu v-kode v-n v-cyr v-cyi v-nz
))
1329 ;; We should check for errors here based on the value of v-ierr.
1330 (when (plusp v-ierr
)
1331 (format t
"zbesk ierr = ~A~%" v-ierr
))
1332 (complex (aref cyr n
) (aref cyi n
))))))))
1334 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1336 ;;; Expansion of Bessel J and Y functions of half-integral order.
1338 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1340 ;; From A&S 10.1.1, we have
1342 ;; J[n+1/2](z) = sqrt(2*z/%pi)*j[n](z)
1343 ;; Y[n+1/2](z) = sqrt(2*z/%pi)*y[n](z)
1345 ;; where j[n](z) is the spherical bessel function of the first kind
1346 ;; and y[n](z) is the spherical bessel function of the second kind.
1348 ;; A&S 10.1.8 and 10.1.9 give
1350 ;; j[n](z) = 1/z*[P(n+1/2,z)*sin(z-n*%pi/2) + Q(n+1/2,z)*cos(z-n*%pi/2)]
1352 ;; y[n](z) = (-1)^(n+1)*1/z*[P(n+1/2,z)*cos(z+n*%pi/2) - Q(n+1/2,z)*sin(z+n*%pi/2)]
1357 ;; j[n](z) = f[n](z)*sin(z) + (-1)^(n+1)*f[-n-1](z)*cos(z)
1359 ;; f[0](z) = 1/z, f[1](z) = 1/z^2
1361 ;; f[n-1](z) + f[n+1](z) = (2*n+1)/z*f[n](z)
1371 ;; f[n+1](z) = (2*n+1)/z*f[n](z) - f[n-1](z) or
1372 ;; f[n](z) = (2*n-1)/z*f[n-1](z) - f[n-2](z)
1373 (sub (mul (div (+ n n -
1) z
)
1379 ;; f[n-1](z) = (2*n+1)/z*f[n](z) - f[n+1](z) or
1380 ;; f[n](z) = (2*n+3)/z*f[n+1](z) - f[n+2](z)
1381 (sub (mul (div (+ n n
3) z
)
1383 (f-fun (+ n
2) z
)))))
1385 ;; Compute sqrt(2*z/%pi)
1386 (defun root-2z/pi
(z)
1387 (power (mul 2 z
(inv '$%pi
)) '((rat simp
) 1 2)))
1389 (defun bessel-j-half-order (order arg
)
1390 "Compute J[n+1/2](z)"
1391 (let* ((n (floor order
))
1392 (sign (if (oddp n
) -
1 1))
1393 (jn (sub (mul ($expand
(f-fun n arg
))
1396 ($expand
(f-fun (- (- n
) 1) arg
))
1397 (take '(%cos
) arg
)))))
1398 (mul (root-2z/pi arg
)
1401 (defun bessel-y-half-order (order arg
)
1402 "Compute Y[n+1/2](z)"
1404 ;; Y[n+1/2](z) = sqrt(2*z/%pi)*y[n](z)
1407 ;; y[n](z) = (-1)^(n+1)*j[-n-1](z)
1410 ;; Y[n+1/2](z) = sqrt(2*z/%pi)*(-1)^(n+1)*j[-n-1](z)
1411 ;; = (-1)^(n+1)*sqrt(2*z/%pi)*j[-n-1](z)
1412 ;; = (-1)^(n+1)*J[-n-1/2](z)
1413 (let* ((n (floor order
))
1414 (jn (bessel-j-half-order (- (- order
) 1/2) arg
)))
1419 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1421 ;;; Expansion of Bessel I and K functions of half-integral order.
1423 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1427 ;; I[n+1/2](z) = sqrt(2*z/%pi)*[g[n](z)*sinh(z) + g[-n-1](z)*cosh(z)]
1429 ;; g[0](z) = 1/z, g[1](z) = -1/z^2
1431 ;; g[n-1](z) - g[n+1](z) = (2*n+1)/z*g[n](z)
1435 (declare (type integer n
))
1441 ;; g[n](z) = g[n-2](z) - (2*n-1)/z*g[n-1](z)
1442 (sub (g-fun (- n
2) z
)
1443 (mul (div (+ n n -
1) z
)
1444 (g-fun (- n
1) z
))))
1448 ;; g[n](z) = (2*n+3)/z*g[n+1](z) + g[n+2](z)
1449 (add (mul (div (+ n n
3) z
)
1451 (g-fun (+ n
2) z
)))))
1455 ;; I[n+1/2](z) = sqrt(2*z/%pi)*[g[n](z)*sinh(z) + g[-n-1](z)*cosh(z)]
1457 (defun bessel-i-half-order (order arg
)
1458 (let ((order (floor order
)))
1459 (mul (root-2z/pi arg
)
1460 (add (mul ($expand
(g-fun order arg
))
1461 (take '(%sinh
) arg
))
1462 (mul ($expand
(g-fun (- (+ order
1)) arg
))
1463 (take '(%cosh
) arg
))))))
1467 ;; sqrt(%pi/2/z)*K[n+1/2](z) = (%pi/2/z)*exp(-z)*sum((n+1/2,k)/(2*z)^k,k,0,n)
1471 ;; K[n+1/2](z) = sqrt(%pi/2)/sqrt(z)*exp(-z)*sum((n+1/2,k)/(2*z)^k,k,0,n)
1473 ;; where (A&S 10.1.9)
1475 ;; (n+1/2,k) = (n+k)!/k!/(n-k)!
1478 (declare (type unsigned-byte n
))
1479 ;; Computes the sum above
1482 (loop for k from
0 upto n do
1483 (setf term
(mul term
1484 (div (div (* (- n k
) (+ n k
1))
1487 (setf sum
(add sum term
)))
1490 (defun bessel-k-half-order (order arg
)
1491 (let ((order (truncate (abs order
))))
1492 (mul (mul (power (div '$%pi
2) '((rat simp
) 1 2))
1493 (power arg
'((rat simp
) -
1 2))
1494 (power '$%e
(neg arg
)))
1495 (k-fun (abs order
) arg
))))
1497 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1499 ;;; Realpart und imagpart of Bessel functions
1501 ;;; We handle the special cases when we know that the Bessel function
1502 ;;; is pure real or pure imaginary. In all other cases Maxima generates
1503 ;;; a general noun form as result.
1505 ;;; To get the complex sign of the order an argument of the Bessel function
1506 ;;; the function $csign is used which calls $sign in a complex mode.
1508 ;;; This is an extension of of the algorithm of the function risplit in
1509 ;;; the file rpart.lisp. risplit looks for a risplit-function on the
1510 ;;; property list and call it if available.
1512 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1514 (defvar *debug-bessel
* nil
)
1516 ;;; Put the risplit-function for Bessel J and Bessel I on the property list
1518 (defprop %bessel_j risplit-bessel-j-or-i risplit-function
)
1519 (defprop %bessel_i risplit-bessel-j-or-i risplit-function
)
1521 ;;; realpart und imagpart for Bessel J and Bessel I function
1523 (defun risplit-bessel-j-or-i (expr)
1524 (when *debug-bessel
*
1525 (format t
"~&RISPLIT-BESSEL-J with ~A~%" expr
))
1526 (let ((order (cadr expr
))
1528 (sign-order ($csign
(cadr expr
)))
1529 (sign-arg ($csign
(caddr expr
))))
1531 (when *debug-bessel
*
1532 (format t
"~& : order = ~A~%" order
)
1533 (format t
"~& : arg = ~A~%" arg
)
1534 (format t
"~& : sign-order = ~A~%" sign-order
)
1535 (format t
"~& : sign-arg = ~A~%" sign-arg
))
1538 ((or (member sign-order
'($complex $imaginary
))
1539 (eq sign-arg
'$complex
))
1540 ;; order or arg are complex, return general noun-form
1541 (risplit-noun expr
))
1542 ((eq sign-arg
'$imaginary
)
1543 ;; arg is pure imaginary
1546 ($featurep order
'$odd
))
1547 ;; order is an odd integer, pure imaginary noun-form
1548 (cons 0 (mul -
1 '$%i expr
)))
1550 ($featurep order
'$even
))
1551 ;; order is an even integer, real noun-form
1554 ;; order is not an odd or even integer, or Maxima can not
1555 ;; determine it, return general noun-form
1556 (risplit-noun expr
))))
1557 ;; At this point order and arg are real.
1558 ;; We have to look for some special cases involing a negative arg
1559 ((or (maxima-integerp order
)
1560 (member sign-arg
'($pos $pz
)))
1561 ;; arg is positive or order an integer, real noun-form
1563 ;; At this point we know that arg is negative or the sign is not known
1564 ((zerop1 (sub ($truncate
($multthru
2 order
)) ($multthru
2 order
)))
1565 ;; order is half integral
1567 ((eq sign-arg
'$neg
)
1568 ;; order is half integral and arg negative, imaginary noun-form
1569 (cons 0 (mul -
1 '$%i expr
)))
1571 ;; the sign of arg or order is not known
1572 (risplit-noun expr
))))
1574 ;; the sign of arg or order is not known
1575 (risplit-noun expr
)))))
1577 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1579 ;;; Put the risplit-function for Bessel K and Bessel Y on the property list
1581 (defprop %bessel_k risplit-bessel-k-or-y risplit-function
)
1582 (defprop %bessel_y risplit-bessel-k-or-y risplit-function
)
1584 ;;; realpart und imagpart for Bessel K and Bessel Y function
1586 (defun risplit-bessel-k-or-y (expr)
1587 (when *debug-bessel
*
1588 (format t
"~&RISPLIT-BESSEL-K with ~A~%" expr
))
1589 (let ((order (cadr expr
))
1591 (sign-order ($csign
(cadr expr
)))
1592 (sign-arg ($csign
(caddr expr
))))
1594 (when *debug-bessel
*
1595 (format t
"~& : order = ~A~%" order
)
1596 (format t
"~& : arg = ~A~%" arg
)
1597 (format t
"~& : sign-order = ~A~%" sign-order
)
1598 (format t
"~& : sign-arg = ~A~%" sign-arg
))
1601 ((or (member sign-order
'($complex $imaginary
))
1602 (member sign-arg
'($complex
'$imaginary
)))
1603 (risplit-noun expr
))
1604 ;; At this point order and arg are real valued.
1605 ;; We have to look for some special cases involing a negative arg
1606 ((member sign-arg
'($pos $pz
))
1609 ;; At this point we know that arg is negative or the sign is not known
1610 ((and (not (maxima-integerp order
))
1611 (zerop1 (sub ($truncate
($multthru
2 order
)) ($multthru
2 order
))))
1612 ;; order is half integral
1614 ((eq sign-arg
'$neg
)
1615 (cons 0 (mul -
1 '$%i expr
)))
1617 ;; the sign of arg is not known
1618 (risplit-noun expr
))))
1620 ;; the sign of arg is not known
1621 (risplit-noun expr
)))))
1623 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1625 ;;; Implementation of scaled Bessel I functions
1627 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1629 ;; FIXME: The following scaled functions need work. They should be
1630 ;; extended to match bessel_i, but still carefully compute the scaled
1633 ;; I think g0(x) = exp(-x)*I[0](x), g1(x) = exp(-x)*I[1](x), and
1634 ;; gn(x,n) = exp(-x)*I[n](x), based on some simple numerical
1637 (defmfun $scaled_bessel_i0
($x
)
1639 ;; XXX Should we return noun forms if $x is rational?
1640 (slatec:dbsi0e
($float $x
)))
1642 (mul (power '$%e
(neg (simplifya `((mabs) ,$x
) nil
)))
1643 `((%bessel_i
) 0 ,$x
)))))
1645 (defmfun $scaled_bessel_i1
($x
)
1647 ;; XXX Should we return noun forms if $x is rational?
1648 (slatec:dbsi1e
($float $x
)))
1650 (mul (power '$%e
(neg (simplifya `((mabs) ,$x
) nil
)))
1651 `((%bessel_i
) 1 ,$x
)))))
1653 (defmfun $scaled_bessel_i
($n $x
)
1654 (cond ((and (mnump $x
) (mnump $n
))
1655 ;; XXX Should we return noun forms if $n and $x are rational?
1656 (multiple-value-bind (n alpha
) (floor ($float $n
))
1657 (let ((iarray (make-array (1+ n
) :element-type
'flonum
)))
1658 (slatec:dbesi
($float $x
) alpha
2 (1+ n
) iarray
0)
1661 (mul (power '$%e
(neg (simplifya `((mabs) ,$x
) nil
)))
1662 ($bessel_i $n $x
)))))
1664 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1666 ;;; Implementation of the Hankel 1 function
1668 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1670 (defmfun $hankel_1
(v z
)
1671 (simplify (list '(%hankel_1
) v z
)))
1673 (defprop $hankel_1 %hankel_1 alias
)
1674 (defprop $hankel_1 %hankel_1 verb
)
1675 (defprop %hankel_1 $hankel_1 reversealias
)
1676 (defprop %hankel_1 $hankel_1 noun
)
1678 ;; hankel_1 distributes over lists, matrices, and equations
1680 (defprop %hankel_1
(mlist $matrix mequal
) distribute_over
)
1682 (defprop %hankel_1 simp-hankel-1 operators
)
1684 ; Derivatives of the Hankel 1 function
1689 ;; Derivative wrt arg x. A&S 9.1.27.
1692 ((%hankel_1
) ((mplus) -
1 n
) x
)
1693 ((mtimes) -
1 ((%hankel_1
) ((mplus) 1 n
) x
)))
1697 (defun simp-hankel-1 (expr ignored z
)
1698 (declare (ignore ignored
))
1700 (let ((order (simpcheck (cadr expr
) z
))
1701 (arg (simpcheck (caddr expr
) z
))
1706 (intl:gettext
"hankel_1: hankel_1(~:M,~:M) is undefined.")
1708 ((complex-float-numerical-eval-p order arg
)
1709 (cond ((= 0 ($imagpart order
))
1710 ;; order is real, arg is real or complex
1711 (complexify (hankel-1 ($float order
)
1712 (complex ($float
($realpart arg
))
1713 ($float
($imagpart arg
))))))
1715 ;; The order is complex. Use
1716 ;; hankel_1(v,z) = bessel_j(v,z) + %i*bessel_y(v,z)
1717 ;; and evaluate using the hypergeometric function
1720 (order ($float order
))
1724 (add (bessel-j-hypergeometric order arg
)
1726 (bessel-y-hypergeometric order arg
)))))))))
1728 (setq rat-order
(max-numeric-ratio-p order
2)))
1729 ;; When order is a fraction with a denominator of 2, we can express
1730 ;; the result in terms of elementary functions.
1731 ;; Use the definition hankel_1(v,z) = bessel_j(v,z)+%i*bessel_y(v,z)
1733 (add (bessel-j-half-order rat-order arg
)
1735 (bessel-y-half-order rat-order arg
)))))
1736 (t (eqtest (list '(%hankel_1
) order arg
) expr
)))))
1738 ;; Numerically compute H1[v](z).
1740 ;; A&S 9.1.3 says H1[v](z) = J[v](z) + %i * Y[v](z)
1742 (defun hankel-1 (v z
)
1744 (z (coerce z
'(complex flonum
))))
1748 ;; H1[-v](z) = exp(v*%pi*%i)*H1[v](z)
1752 ;; H1[v](z) = exp(-v*%pi*%i)*H1[-v](z)
1754 (* (cis (* (float pi
) (- v
))) (hankel-1 (- v
) z
)))
1756 (multiple-value-bind (n fnu
) (floor v
)
1757 (let ((zr (realpart z
))
1759 (cyr (make-array (1+ n
) :element-type
'flonum
))
1760 (cyi (make-array (1+ n
) :element-type
'flonum
)))
1761 (multiple-value-bind (dzr dzi df dk dm dn dcyr dcyi nz ierr
)
1762 (slatec::zbesh zr zi fnu
1 1 (1+ n
) cyr cyi
0 0)
1763 (declare (ignore dzr dzi df dk dm dn dcyr dcyi nz ierr
))
1764 (complex (aref cyr n
) (aref cyi n
)))))))))
1766 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1768 ;;; Implementation of the Hankel 2 function
1770 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1772 (defmfun $hankel_2
(v z
)
1773 (simplify (list '(%hankel_2
) v z
)))
1775 (defprop $hankel_2 %hankel_2 alias
)
1776 (defprop $hankel_2 %hankel_2 verb
)
1777 (defprop %hankel_2 $hankel_2 reversealias
)
1778 (defprop %hankel_2 $hankel_2 noun
)
1780 ;; hankel_2 distributes over lists, matrices, and equations
1782 (defprop %hankel_2
(mlist $matrix mequal
) distribute_over
)
1784 (defprop %hankel_2 simp-hankel-2 operators
)
1786 ; Derivatives of the Hankel 2 function
1791 ;; Derivative wrt arg x. A&S 9.1.27.
1794 ((%hankel_2
) ((mplus) -
1 n
) x
)
1795 ((mtimes) -
1 ((%hankel_2
) ((mplus) 1 n
) x
)))
1799 (defun simp-hankel-2 (expr ignored z
)
1800 (declare (ignore ignored
))
1802 (let ((order (simpcheck (cadr expr
) z
))
1803 (arg (simpcheck (caddr expr
) z
))
1808 (intl:gettext
"hankel_2: hankel_2(~:M,~:M) is undefined.")
1810 ((complex-float-numerical-eval-p order arg
)
1811 (cond ((= 0 ($imagpart order
))
1812 ;; order is real, arg is real or complex
1813 (complexify (hankel-2 ($float order
)
1814 (complex ($float
($realpart arg
))
1815 ($float
($imagpart arg
))))))
1817 ;; The order is complex. Use
1818 ;; hankel_2(v,z) = bessel_j(v,z) - %i*bessel_y(v,z)
1819 ;; and evaluate using the hypergeometric function
1822 (order ($float order
))
1826 (sub (bessel-j-hypergeometric order arg
)
1828 (bessel-y-hypergeometric order arg
)))))))))
1830 (setq rat-order
(max-numeric-ratio-p order
2)))
1831 ;; When order is a fraction with a denominator of 2, we can express
1832 ;; the result in terms of elementary functions.
1833 ;; Use the definition hankel_2(v,z) = bessel_j(v,z)-%i*bessel_y(v,z)
1835 (sub (bessel-j-half-order rat-order arg
)
1837 (bessel-y-half-order rat-order arg
)))))
1838 (t (eqtest (list '(%hankel_2
) order arg
) expr
)))))
1840 ;; Numerically compute H2[v](z).
1842 ;; A&S 9.1.4 says H2[v](z) = J[v](z) - %i * Y[v](z)
1844 (defun hankel-2 (v z
)
1846 (z (coerce z
'(complex flonum
))))
1850 ;; H2[-v](z) = exp(-v*%pi*%i)*H2[v](z)
1854 ;; H2[v](z) = exp(v*%pi*%i)*H2[-v](z)
1856 (* (cis (* (float pi
) v
)) (hankel-2 (- v
) z
)))
1858 (multiple-value-bind (n fnu
) (floor v
)
1859 (let ((zr (realpart z
))
1861 (cyr (make-array (1+ n
) :element-type
'flonum
))
1862 (cyi (make-array (1+ n
) :element-type
'flonum
)))
1863 (multiple-value-bind (dzr dzi df dk dm dn dcyr dcyi nz ierr
)
1864 (slatec::zbesh zr zi fnu
1 2 (1+ n
) cyr cyi
0 0)
1865 (declare (ignore dzr dzi df dk dm dn dcyr dcyi nz ierr
))
1866 (complex (aref cyr n
) (aref cyi n
)))))))))
1868 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1870 ;;; Implementation of Struve H function
1872 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1874 (defmfun $struve_h
(v z
)
1875 (simplify (list '(%struve_h
) v z
)))
1877 (defprop $struve_h %struve_h alias
)
1878 (defprop $struve_h %struve_h verb
)
1879 (defprop %struve_h $struve_h reversealias
)
1880 (defprop %struve_h $struve_h noun
)
1882 ;; struve_h distributes over lists, matrices, and equations
1884 (defprop %struve_h
(mlist $matrix mequal
) distribute_over
)
1886 (defprop %struve_h simp-struve-h operators
)
1888 ; Derivatives of the Struve H function
1893 ;; Derivative wrt arg z. A&S 12.1.10.
1897 ((%struve_h
) ((mplus) -
1 v
) z
)
1898 ((mtimes) -
1 ((%struve_h
) ((mplus) 1 v
) z
))
1900 ((mexpt) $%pi
((rat) -
1 2))
1901 ((mexpt) 2 ((mtimes) -
1 v
))
1902 ((mexpt) ((%gamma
) ((mplus) ((rat) 3 2) v
)) -
1)
1906 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1908 (defun simp-struve-h (expr ignored z
)
1909 (declare (ignore ignored
))
1911 (let ((order (simpcheck (cadr expr
) z
))
1912 (arg (simpcheck (caddr expr
) z
)))
1915 ;; Check for special values
1918 (cond ((eq ($csign
(add order
1)) '$zero
)
1919 ; http://functions.wolfram.com/03.09.03.0018.01
1920 (cond ((or ($bfloatp order
)
1922 ($bfloat
(div 2 '$%pi
)))
1925 ($float
(div 2 '$%pi
)))
1928 ((eq ($sign
(add ($realpart order
) 1)) '$pos
)
1929 ; http://functions.wolfram.com/03.09.03.0001.01
1931 ((member ($sign
(add ($realpart order
) 1)) '($zero $neg $nz
))
1933 (intl:gettext
"struve_h: struve_h(~:M,~:M) is undefined.")
1936 (eqtest (list '(%struve_h
) order arg
) expr
))))
1938 ;; Check for numerical evaluation
1940 ((complex-float-numerical-eval-p order arg
)
1942 (let (($numer t
) ($float t
))
1946 ($rectform
(power arg
(add order
1.0)))
1947 ($rectform
(inv (power 2.0 order
)))
1948 (inv (power ($float
'$%pi
) 0.5))
1949 (inv (simplify (list '(%gamma
) (add order
1.5))))
1950 (simplify (list '($hypergeometric
)
1952 (list '(mlist) '((rat simp
) 3 2)
1953 (add order
'((rat simp
) 3 2)))
1954 (div (mul arg arg
) -
4.0))))))))
1956 ((complex-bigfloat-numerical-eval-p order arg
)
1958 (let (($ratprint nil
)
1960 (order ($bfloat order
)))
1964 ($rectform
(power arg
(add order
1)))
1965 ($rectform
(inv (power 2 order
)))
1966 (inv (power ($bfloat
'$%pi
) ($bfloat
'((rat simp
) 1 2))))
1967 (inv (simplify (list '(%gamma
)
1968 (add order
($bfloat
'((rat simp
) 3 2))))))
1969 (simplify (list '($hypergeometric
)
1971 (list '(mlist) '((rat simp
) 3 2)
1972 (add order
'((rat simp
) 3 2)))
1973 (div (mul arg arg
) ($bfloat -
4)))))))))
1975 ;; Transformations and argument simplifications
1979 (integerp (mul 2 order
)))
1981 ((eq ($sign order
) '$pos
)
1982 ;; Expansion of Struve H for a positive half integral order.
1986 (inv (simplify (list '(mfactorial) (sub order
1987 '((rat simp
) 1 2)))))
1988 (inv (power '$%pi
'((rat simp
) 1 2 )))
1989 (power (div arg
2) (add order -
1))
1990 (let ((index (gensumindex)))
1993 (simplify (list '($pochhammer
) '((rat simp
) 1 2) index
))
1994 (simplify (list '($pochhammer
)
1995 (sub '((rat simp
) 1 2) order
)
1997 (power (mul -
1 arg arg
(inv 4)) (mul -
1 index
)))
1998 index
0 (sub order
'((rat simp
) 1 2)) t
)))
2000 (power (div 2 '$%pi
) '((rat simp
) 1 2))
2001 (power -
1 (add order
'((rat simp
) 1 2)))
2002 (inv (power arg
'((rat simp
) 1 2)))
2007 (add (mul '((rat simp
) 1 2)
2009 (add order
'((rat simp
) 1 2)))
2011 (let ((index (gensumindex)))
2015 (simplify (list '(mfactorial)
2018 '((rat simp
) -
1 2))))
2019 (inv (simplify (list '(mfactorial) (mul 2 index
))))
2020 (inv (simplify (list '(mfactorial)
2023 '((rat simp
) -
1 2)))))
2024 (inv (power (mul 2 arg
) (mul 2 index
))))
2026 (simplify (list '($floor
)
2027 (div (sub (mul 2 order
) 1) 4)))
2030 (simplify (list '(%cos
)
2031 (add (mul '((rat simp
) 1 2)
2033 (add order
'((rat simp
) 1 2)))
2035 (let ((index (gensumindex)))
2039 (simplify (list '(mfactorial)
2042 '((rat simp
) 1 2))))
2043 (power (mul 2 arg
) (mul -
1 (add (mul 2 index
) 1)))
2044 (inv (simplify (list '(mfactorial)
2045 (add (mul 2 index
) 1))))
2046 (inv (simplify (list '(mfactorial)
2049 '((rat simp
) -
3 2))))))
2051 (simplify (list '($floor
)
2052 (div (sub (mul 2 order
) 3) 4)))
2055 ((eq ($sign order
) '$neg
)
2056 ;; Expansion of Struve H for a negative half integral order.
2060 (power (div 2 '$%pi
) '((rat simp
) 1 2))
2061 (power -
1 (add order
'((rat simp
) 1 2)))
2062 (inv (power arg
'((rat simp
) 1 2)))
2065 (simplify (list '(%sin
)
2070 (add order
'((rat simp
) 1 2)))
2072 (let ((index (gensumindex)))
2076 (simplify (list '(mfactorial)
2079 '((rat simp
) -
1 2))))
2080 (inv (simplify (list '(mfactorial) (mul 2 index
))))
2081 (inv (simplify (list '(mfactorial)
2084 '((rat simp
) -
1 2)))))
2085 (inv (power (mul 2 arg
) (mul 2 index
))))
2087 (simplify (list '($floor
)
2088 (div (add (mul 2 order
) 1) -
4)))
2091 (simplify (list '(%cos
)
2096 (add order
'((rat simp
) 1 2)))
2098 (let ((index (gensumindex)))
2102 (simplify (list '(mfactorial)
2105 '((rat simp
) 1 2))))
2106 (power (mul 2 arg
) (mul -
1 (add (mul 2 index
) 1)))
2107 (inv (simplify (list '(mfactorial)
2108 (add (mul 2 index
) 1))))
2109 (inv (simplify (list '(mfactorial)
2112 '((rat simp
) -
3 2))))))
2114 (simplify (list '($floor
)
2115 (div (add (mul 2 order
) 3) -
4)))
2118 (eqtest (list '(%struve_h
) order arg
) expr
)))))
2120 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2122 ;;; Implementation of Struve L function
2124 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2126 (defmfun $struve_l
(v z
)
2127 (simplify (list '(%struve_l
) v z
)))
2129 (defprop $struve_l %struve_l alias
)
2130 (defprop $struve_l %struve_l verb
)
2131 (defprop %struve_l $struve_l reversealias
)
2132 (defprop %struve_l $struve_l noun
)
2134 (defprop %struve_l simp-struve-l operators
)
2136 ;; struve_l distributes over lists, matrices, and equations
2138 (defprop %struve_l
(mlist $matrix mequal
) distribute_over
)
2140 ; Derivatives of the Struve L function
2145 ;; Derivative wrt arg z. A&S 12.2.5.
2149 ((%struve_l
) ((mplus) -
1 v
) z
)
2150 ((%struve_l
) ((mplus) 1 v
) z
)
2152 ((mexpt) $%pi
((rat) -
1 2))
2153 ((mexpt) 2 ((mtimes) -
1 v
))
2154 ((mexpt) ((%gamma
) ((mplus) ((rat) 3 2) v
)) -
1)
2158 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2160 (defun simp-struve-l (expr ignored z
)
2161 (declare (ignore ignored
))
2163 (let ((order (simpcheck (cadr expr
) z
))
2164 (arg (simpcheck (caddr expr
) z
)))
2167 ;; Check for special values
2170 (cond ((eq ($csign
(add order
1)) '$zero
)
2171 ; http://functions.wolfram.com/03.10.03.0018.01
2172 (cond ((or ($bfloatp order
)
2174 ($bfloat
(div 2 '$%pi
)))
2177 ($float
(div 2 '$%pi
)))
2180 ((eq ($sign
(add ($realpart order
) 1)) '$pos
)
2181 ; http://functions.wolfram.com/03.10.03.0001.01
2183 ((member ($sign
(add ($realpart order
) 1)) '($zero $neg $nz
))
2185 (intl:gettext
"struve_l: struve_l(~:M,~:M) is undefined.")
2188 (eqtest (list '(%struve_l
) order arg
) expr
))))
2190 ;; Check for numerical evaluation
2192 ((complex-float-numerical-eval-p order arg
)
2193 ; http://functions.wolfram.com/03.10.26.0002.01
2194 (let (($numer t
) ($float t
))
2198 ($rectform
(power arg
(add order
1.0)))
2199 ($rectform
(inv (power 2.0 order
)))
2200 (inv (power ($float
'$%pi
) 0.5))
2201 (inv (simplify (list '(%gamma
) (add order
1.5))))
2202 (simplify (list '($hypergeometric
)
2204 (list '(mlist) '((rat simp
) 3 2)
2205 (add order
'((rat simp
) 3 2)))
2206 (div (mul arg arg
) 4.0))))))))
2208 ((complex-bigfloat-numerical-eval-p order arg
)
2209 ; http://functions.wolfram.com/03.10.26.0002.01
2210 (let (($ratprint nil
))
2214 ($rectform
(power arg
(add order
1)))
2215 ($rectform
(inv (power 2 order
)))
2216 (inv (power ($bfloat
'$%pi
) ($bfloat
'((rat simp
) 1 2))))
2217 (inv (simplify (list '(%gamma
) (add order
'((rat simp
) 3 2)))))
2218 (simplify (list '($hypergeometric
)
2220 (list '(mlist) '((rat simp
) 3 2)
2221 (add order
'((rat simp
) 3 2)))
2222 (div (mul arg arg
) 4))))))))
2224 ;; Transformations and argument simplifications
2228 (integerp (mul 2 order
)))
2230 ((eq ($sign order
) '$pos
)
2231 ;; Expansion of Struve L for a positive half integral order.
2235 (power 2 (sub 1 order
))
2236 (power arg
(sub order
1))
2237 (inv (power '$%pi
'((rat simp
) 1 2)))
2238 (inv (simplify (list '(mfactorial) (sub order
2239 '((rat simp
) 1 2)))))
2240 (let ((index (gensumindex)))
2243 (simplify (list '($pochhammer
) '((rat simp
) 1 2) index
))
2244 (simplify (list '($pochhammer
)
2245 (sub '((rat simp
) 1 2) order
)
2247 (power (mul arg arg
(inv 4)) (mul -
1 index
)))
2248 index
0 (sub order
'((rat simp
) 1 2)) t
)))
2250 (power (div 2 '$%pi
) '((rat simp
) 1 2))
2251 (inv (power arg
'((rat simp
) 1 2)))
2252 ($exp
(div (mul '$%pi
'$%i
(add order
'((rat simp
) 1 2))) 2))
2255 (let (($trigexpand t
))
2256 (simplify (list '(%sinh
)
2257 (sub (mul '((rat simp
) 1 2)
2260 (add order
'((rat simp
) 1 2)))
2262 (let ((index (gensumindex)))
2265 (simplify (list '(mfactorial)
2267 (simplify (list '(mabs) order
))
2268 '((rat simp
) -
1 2))))
2269 (inv (simplify (list '(mfactorial) (mul 2 index
))))
2270 (inv (simplify (list '(mfactorial)
2271 (add (simplify (list '(mabs)
2274 '((rat simp
) -
1 2)))))
2275 (inv (power (mul 2 arg
) (mul 2 index
))))
2277 (simplify (list '($floor
)
2279 (simplify (list '(mabs)
2285 (let (($trigexpand t
))
2286 (simplify (list '(%cosh
)
2287 (sub (mul '((rat simp
) 1 2)
2290 (add order
'((rat simp
) 1 2)))
2292 (let ((index (gensumindex)))
2295 (simplify (list '(mfactorial)
2297 (simplify (list '(mabs) order
))
2298 '((rat simp
) 1 2))))
2299 (power (mul 2 arg
) (neg (add (mul 2 index
) 1)))
2300 (inv (simplify (list '(mfactorial)
2301 (add (mul 2 index
) 1))))
2302 (inv (simplify (list '(mfactorial)
2303 (add (simplify (list '(mabs)
2306 '((rat simp
) -
3 2))))))
2308 (simplify (list '($floor
)
2310 (simplify (list '(mabs)
2315 ((eq ($sign order
) '$neg
)
2316 ;; Expansion of Struve L for a negative half integral order.
2320 (power (div 2 '$%pi
) '((rat simp
) 1 2))
2321 (inv (power arg
'((rat simp
) 1 2)))
2322 ($exp
(div (mul '$%pi
'$%i
(add order
'((rat simp
) 1 2))) 2))
2325 (let (($trigexpand t
))
2326 (simplify (list '(%sinh
)
2327 (sub (mul '((rat simp
) 1 2)
2330 (add order
'((rat simp
) 1 2)))
2332 (let ((index (gensumindex)))
2335 (simplify (list '(mfactorial)
2338 '((rat simp
) -
1 2))))
2339 (inv (simplify (list '(mfactorial) (mul 2 index
))))
2340 (inv (simplify (list '(mfactorial)
2343 '((rat simp
) -
1 2)))))
2344 (inv (power (mul 2 arg
) (mul 2 index
))))
2346 (simplify (list '($floor
)
2347 (div (add (mul 2 order
) 1) -
4)))
2350 (let (($trigexpand t
))
2351 (simplify (list '(%cosh
)
2352 (sub (mul '((rat simp
) 1 2)
2355 (add order
'((rat simp
) 1 2)))
2357 (let ((index (gensumindex)))
2360 (simplify (list '(mfactorial)
2363 '((rat simp
) 1 2))))
2364 (power (mul 2 arg
) (neg (add (mul 2 index
) 1)))
2365 (inv (simplify (list '(mfactorial)
2366 (add (mul 2 index
) 1))))
2367 (inv (simplify (list '(mfactorial)
2370 '((rat simp
) -
3 2))))))
2372 (simplify (list '($floor
)
2373 (div (add (mul 2 order
) 3) -
4)))
2376 (eqtest (list '(%struve_l
) order arg
) expr
)))))
2378 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2380 (defmspec $gauss
(form)
2382 "NOTE: The gauss function is superseded by random_normal in the `distrib' package.
2383 Perhaps you meant to enter `~a'.~%"
2384 (print-invert-case (implode (mstring `(($random_normal
) ,@ (cdr form
))))))