1 ;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;; The data in this file contains enhancements. ;;;;;
5 ;;; Copyright (c) 1984,1987 by William Schelter,University of Texas ;;;;;
6 ;;; All rights reserved ;;;;;
7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
11 ;; When non-NIL, the Bessel functions of half-integral order are
12 ;; expanded in terms of elementary functions.
14 (defmvar $besselexpand nil
)
16 ;; When T Bessel functions with an integer order are reduced to order 0 and 1
17 (defmvar $bessel_reduce nil
)
19 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
21 ;;; Helper functions for this file
23 ;; If E is a maxima ratio with a denominator of DEN, return the ratio
24 ;; as a Lisp rational. Otherwise NIL.
25 (defun max-numeric-ratio-p (e den
)
29 (integerp (second e
)))
30 (/ (second e
) (third e
))
33 (defun bessel-numerical-eval-p (order arg
)
34 ;; Return non-NIL if we should numerically evaluate a bessel
35 ;; function. Basically, both args have to be numbers. If both args
36 ;; are integers, we don't evaluate unless $numer is true.
37 (or (and (numberp order
) (complex-number-p arg
)
39 (floatp ($realpart arg
))
40 (floatp ($imagpart arg
))))
41 (and $numer
(numberp order
)
42 (complex-number-p arg
))))
44 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
46 ;;; Implementation of the Bessel J function
48 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
50 ;; Bessel J distributes over lists, matrices, and equations
52 (defprop %bessel_j
(mlist $matrix mequal
) distribute_over
)
54 ;; Derivatives of the Bessel function.
57 ;; Derivative wrt to order n. A&S 9.1.64. Do we really want to
58 ;; do this? It's quite messy.
61 ;; - (x/2)^n*sum((-1)^k*psi(n+k+1)/gamma(n+k+1)*(x^2/4)^k/k!,k,0,inf)
65 ((%log
) ((mtimes) ((rat) 1 2) x
)))
67 ((mexpt) ((mtimes) x
((rat) 1 2)) n
)
69 ((mtimes) ((mexpt) -
1 $%k
)
70 ((mexpt) ((mfactorial) $%k
) -
1)
71 ((mqapply) (($psi array
) 0) ((mplus) 1 $%k n
))
72 ((mexpt) ((%gamma
) ((mplus) 1 $%k n
)) -
1)
73 ((mexpt) ((mtimes) x x
((rat) 1 4)) $%k
))
76 ;; Derivative wrt to arg x.
77 ;; A&S 9.1.27; changed from 9.1.30 so that taylor works on Bessel functions
80 ((%bessel_j
) ((mplus) -
1 n
) x
)
81 ((mtimes) -
1 ((%bessel_j
) ((mplus) 1 n
) x
)))
85 ;; Integral of the Bessel function wrt z
86 (defun bessel-j-integral-2 (v z
)
89 ;; integrate(bessel_j(0,z),z)
90 ;; = (1/2)*z*(%pi*bessel_j(1,z)*struve_h(0,z)
91 ;; +bessel_j(0,z)*(2-%pi*struve_h(1,z)))
92 `((mtimes) ((rat) 1 2) ,z
99 ((mplus) 2 ((mtimes) -
1 $%pi
((%struve_h
) 1 ,z
)))))))
101 ;; integrate(bessel_j(1,z),z) = -bessel_j(0,z)
102 `((mtimes) -
1 ((%bessel_j
) 0 ,z
)))
104 ;; http://functions.wolfram.com/03.01.21.0002.01
105 ;; integrate(bessel_j(v,z),z)
106 ;; = 2^(-v-1)*z^(v+1)*gamma(v/2+1/2)
107 ;; * hypergeometric_regularized([v/2+1/2],[v+1,v/2+3/2],-z^2/4)
108 ;; = 2^(-v)*z^(v+1)*hypergeometric([v/2+1/2],[v+1,v/2+3/2],-z^2/4)
113 ((mplus) ((rat) 1 2) ((mtimes) ((rat) 1 2) ,v
)))
115 ((mplus) ((rat) 3 2) ((mtimes) ((rat) 1 2) ,v
))
117 ((mtimes) ((rat) -
1 4) ((mexpt) ,z
2)))
118 ((mexpt) 2 ((mtimes) -
1 ,v
))
119 ((mexpt) ((%gamma
) ((mplus) 2 ,v
)) -
1)
120 ((mexpt) z
((mplus) 1 ,v
))))))
122 (putprop '%bessel_j
`((v z
) nil
,'bessel-j-integral-2
) 'integral
)
124 ;; Support a simplim%bessel_j function to handle specific limits
126 (defprop %bessel_j simplim%bessel_j simplim%function
)
128 (defun simplim%bessel_j
(expr var val
)
129 ;; Look for the limit of the arguments.
130 (let ((v (limit (cadr expr
) var val
'think
))
131 (z (limit (caddr expr
) var val
'think
)))
133 ;; Handle an argument 0 at this place.
137 (let ((sgn ($sign
($realpart v
))))
138 (cond ((and (eq sgn
'$neg
)
139 (not (maxima-integerp v
)))
140 ;; bessel_j(v,0), Re(v)<0 and v not an integer
142 ((and (eq sgn
'$zero
)
144 ;; bessel_j(v,0), Re(v)=0 and v #0
146 ;; Call the simplifier of the function.
147 (t (simplify (list '(%bessel_j
) v z
))))))
150 ;; bessel_j(v,inf) or bessel_j(v,minf)
153 ;; All other cases are handled by the simplifier of the function.
154 (simplify (list '(%bessel_j
) v z
))))))
156 (def-simplifier bessel_j
(order arg
)
157 (let ((rat-order nil
))
160 ;; We handle the different case for zero arg carefully.
161 (let ((sgn ($sign
($realpart order
))))
162 (cond ((and (eq sgn
'$zero
)
163 (zerop1 ($imagpart order
)))
165 (cond ((or ($bfloatp order
) ($bfloatp arg
)) ($bfloat
1))
166 ((or (floatp order
) (floatp arg
)) 1.0)
169 (maxima-integerp order
))
170 ;; bessel_j(v,0) and Re(v)>0 or v an integer
171 (cond ((or ($bfloatp order
) ($bfloatp arg
)) ($bfloat
0))
172 ((or (floatp order
) (floatp arg
)) 0.0)
175 (not (maxima-integerp order
)))
176 ;; bessel_j(v,0) and Re(v)<0 and v not an integer
178 (intl:gettext
"bessel_j: bessel_j(~:M,~:M) is undefined.")
180 ((and (eq sgn
'$zero
)
181 (not (zerop1 ($imagpart order
))))
182 ;; bessel_j(v,0) and Re(v)=0 and v # 0
184 (intl:gettext
"bessel_j: bessel_j(~:M,~:M) is undefined.")
187 ;; No information about the sign of the order
190 ((complex-float-numerical-eval-p order arg
)
191 ;; We have numeric order and arg and $numer is true, or we have either
192 ;; the order or arg being floating-point, so let's evaluate it
194 ;; The numerical routine bessel-j returns a CL number, so we have
195 ;; to add the conversion to a Maxima-complex-number.
196 (cond ((= 0 ($imagpart order
))
197 ;; order is real, arg is real or complex
198 (complexify (bessel-j ($float order
)
199 (complex ($float
($realpart arg
))
200 ($float
($imagpart arg
))))))
202 ;; order is complex, arg is real or complex
205 (order ($float order
))
209 (bessel-j-hypergeometric order arg
)))))))
211 ((or (bigfloat-numerical-eval-p order arg
)
212 (complex-bigfloat-numerical-eval-p order arg
))
213 ;; We have the order or arg being a bigfloat, so evaluate it
214 ;; numerically using the hypergeometric representation
216 (destructuring-bind (re . im
)
218 (cond ((and (zerop1 im
)
219 (zerop1 (sub re
(take '($floor
) re
)))
221 ;; bessel_j(-n,z) = (-1)^n*bessel_j(n,z)
224 ($bfloat
(bessel-j-hypergeometric (mul -
1 re
) arg
)))))
227 ($bfloat
(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
))
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 ;; Bessel Y distributes over lists, matrices, and equations
381 (defprop %bessel_y
(mlist $matrix mequal
) distribute_over
)
385 ;; Derivative wrt order n. A&S 9.1.65.
387 ;; cot(n*%pi)*[diff(bessel_j(n,x),n)-%pi*bessel_y(n,x)]
388 ;; - csc(n*%pi)*diff(bessel_j(-n,x),n)-%pi*bessel_j(n,x)
390 ((mtimes) -
1 $%pi
((%bessel_j
) n x
))
393 ((%csc
) ((mtimes) $%pi n
))
394 ((%derivative
) ((%bessel_j
) ((mtimes) -
1 n
) x
) n
1))
396 ((%cot
) ((mtimes) $%pi n
))
398 ((mtimes) -
1 $%pi
((%bessel_y
) n x
))
399 ((%derivative
) ((%bessel_j
) n x
) n
1))))
401 ;; Derivative wrt to arg x. A&S 9.1.27; changed from A&S 9.1.30
402 ;; to be consistent with bessel_j.
405 ((%bessel_y
)((mplus) -
1 n
) x
)
406 ((mtimes) -
1 ((%bessel_y
) ((mplus) 1 n
) x
)))
410 ;; Integral of the Bessel Y function wrt z
411 ;; http://functions.wolfram.com/Bessel-TypeFunctions/BesselY/21/01/01/
412 (defun bessel-y-integral-2 (n z
)
414 ((and ($integerp n
) (<= 0 n
))
417 ;; integrate(bessel_y(2*N+1,z),z) , N > 0
418 ;; = -bessel_y(0,z) - 2 * sum(bessel_y(2*k,z),k,1,N)
420 (answer `((mplus) ((mtimes) -
1 ((%bessel_y
) 0 ,z
))
422 ((%sum
) ((%bessel_y
) ((mtimes) 2 ,k
) ,z
) ,k
1
423 ((mtimes) ((rat) 1 2) ((mplus) -
1 ,n
)))))))
424 ;; Expand out the sum if n < 10. Otherwise fix up the indices
426 (meval `(($ev
) ,answer $sum
)) ; Is there a better way?
427 (simplify ($niceindices answer
)))))
429 ;; integrate(bessel_y(2*N,z),z) , N > 0
430 ;; = (1/2)*%pi*z*(bessel_y(0,z)*struve_h(-1,z)
431 ;; +bessel_y(1,z)*struve_h(0,z))
432 ;; - 2 * sum(bessel_y(2*k+1,z),k,0,N-1)
438 ((%bessel_y
) ((mplus) 1 ((mtimes) 2 ,k
)) ,z
)
442 ((mtimes) ((rat) 1 2) ,n
))))
443 ((mtimes) ((rat) 1 2) $%pi
,z
450 ((%struve_h
) 0 ,z
)))))))
451 ;; Expand out the sum if n < 10. Otherwise fix up the indices
453 (meval `(($ev
) ,answer $sum
)) ; Is there a better way?
454 (simplify ($niceindices answer
)))))))
457 (putprop '%bessel_y
`((n z
) nil
,'bessel-y-integral-2
) 'integral
)
459 ;; Support a simplim%bessel_y function to handle specific limits
461 (defprop %bessel_y simplim%bessel_y simplim%function
)
463 (defun simplim%bessel_y
(expr var val
)
464 ;; Look for the limit of the arguments.
465 (let ((v (limit (cadr expr
) var val
'think
))
466 (z (limit (caddr expr
) var val
'think
)))
468 ;; Handle an argument 0 at this place.
476 ;; bessel_y(n,0), n an integer
477 (cond ((evenp v
) '$minf
)
478 (t (cond ((eq z
'$zeroa
) '$minf
)
479 ((eq z
'$zerob
) '$inf
)
481 ((not (zerop1 ($realpart v
)))
482 ;; bessel_y(v,0), Re(v)#0
484 ((and (zerop1 ($realpart v
))
486 ;; bessel_y(v,0), Re(v)=0 and v#0
488 ;; Call the simplifier of the function.
489 (t (simplify (list '(%bessel_y
) v z
)))))
492 ;; bessel_y(v,inf) or bessel_y(v,minf)
495 ;; All other cases are handled by the simplifier of the function.
496 (simplify (list '(%bessel_y
) v z
))))))
498 (def-simplifier bessel_y
(order arg
)
499 (let ((rat-order nil
))
502 ;; Domain error for a zero argument.
504 (intl:gettext
"bessel_y: bessel_y(~:M,~:M) is undefined.") order arg
))
506 ((complex-float-numerical-eval-p order arg
)
507 ;; We have numeric order and arg and $numer is true, or
508 ;; we have either the order or arg being floating-point,
509 ;; so let's evaluate it numerically.
510 (cond ((= 0 ($imagpart order
))
511 ;; order is real, arg is real or complex
512 (complexify (bessel-y ($float order
)
513 (complex ($float
($realpart arg
))
514 ($float
($imagpart arg
))))))
516 ;; order is complex, arg is real or complex
519 (order ($float order
))
523 (bessel-y-hypergeometric order arg
)))))))
525 ((or (bigfloat-numerical-eval-p order arg
)
526 (complex-bigfloat-numerical-eval-p order arg
))
527 ;; When the order is not an integer, we can use the
528 ;; hypergeometric representation to evaluate it.
529 (destructuring-bind (re . im
)
531 (cond ((and (zerop1 im
)
532 (not (zerop1 (sub re
(take '($floor
) re
)))))
534 ($bfloat
(bessel-y-hypergeometric re arg
))))
538 ((and (integerp order
) (minusp order
))
539 ;; Special case when the order is an integer.
540 ;; A&S 9.1.5: Y[-n](x) = (-1)^n*Y[n](x)
542 (take '(%bessel_y
) (- order
) arg
)
543 (mul -
1 (take '(%bessel_y
) (- order
) arg
))))
546 (setq rat-order
(max-numeric-ratio-p order
2)))
547 ;; When order is a fraction with a denominator of 2, we
548 ;; can express the result in terms of elementary functions.
549 ;; From A&S 10.1.1, 10.1.11-12 and 10.1.15:
551 ;; Y[1/2](z) = -J[-1/2](z) is a function of cos(z).
552 ;; Y[-1/2](z) = J[1/2](z) is a function of sin(z).
553 (bessel-y-half-order rat-order arg
))
556 (and (integerp order
)
559 ;; Reduce a bessel function of order > 2 to order 1 and 0.
560 ;; A&S 9.1.27: bessel_y(v,z) = 2*(v-1)/z*bessel_y(v-1,z)-bessel_y(v-2,z)
564 (take '(%bessel_y
) (- order
1) arg
))
565 (take '(%bessel_y
) (- order
2) arg
)))
567 ($hypergeometric_representation
568 (bessel-y-hypergeometric order arg
))
573 ;; Returns the hypergeometric representation of bessel_y
574 (defun bessel-y-hypergeometric (order arg
)
575 ;; http://functions.wolfram.com/03.03.26.0002.01
576 ;; -hypergeometric([],[1-v],-z^2/4)*(2/z)^v*gamma(v)/%pi
577 ;; - hypergeometric([],[v+1],-z^2/4)*gamma(-v)*cos(%pi*v)*(z/2)^v/%pi
580 (inv (power arg order
))
581 (take '(%gamma
) order
)
583 (take '(%hypergeometric
)
585 (list '(mlist) (sub 1 order
))
586 (neg (div (mul arg arg
) 4))))
588 (inv (power 2 order
))
590 (take '(%cos
) (mul order
'$%pi
))
591 (take '(%gamma
) (neg order
))
593 (take '(%hypergeometric
)
595 (list '(mlist) (add 1 order
))
596 (neg (div (mul arg arg
) 4))))))
598 ;; Bessel function of the second kind, Y[n](z), for real or complex z
599 (defun bessel-y (order arg
)
601 ((zerop (imagpart arg
))
602 ;; We have numeric args and the first arg is purely
603 ;; real. Call the real-valued Bessel function.
605 ;; For negative values, use the analytic continuation formula
608 ;; Y[v](z*exp(m*%pi*%i)) = exp(-v*m*%pi*%i) * Y[v](z)
609 ;; + 2*%i*sin(m*v*%pi)*cot(v*%pi)*J[v](z)
611 ;; In particular for m = 1:
612 ;; Y[v](-z) = exp(-v*%pi*%i) * Y[v](z) + 2*%i*cos(v*%pi)*J[v](z)
613 (let ((arg (realpart arg
)))
617 (slatec:dbesy0
(float arg
)))
619 ;; For v = 0, this simplifies to
620 ;; Y[0](-z) = Y[0](z) + 2*%i*J[0](z)
621 ;; the return value has to be a CL number
622 (+ (slatec:dbesy0
(float (- arg
)))
623 (complex 0 (* 2 (slatec:dbesj0
(float (- arg
)))))))))
626 (slatec:dbesy1
(float arg
)))
628 ;; For v = 1, this simplifies to
629 ;; Y[1](-z) = -Y[1](z) - 2*%i*J[1](v)
630 ;; the return value has to be a CL number
631 (+ (- (slatec:dbesy1
(float (- arg
))))
632 (complex 0 (* -
2 (slatec:dbesj1
(float (- arg
)))))))))
634 (cond ((zerop (nth-value 1 (truncate order
)))
635 ;; Order is a negative integer or float representation.
636 ;; Use A&S 9.1.5: Y[-n](z) = (-1)^n*Y[n](z).
637 (if (evenp (floor order
))
638 (bessel-y (- order
) arg
)
639 (- (bessel-y (- order
) arg
))))
641 ;; Bessel function of negative order. We use the Hankel
642 ;; functions to compute this:
643 ;; Y[v](z) = (H1[v](z) - H2[v](z)) / 2 / %i
644 (let ((result (/ (- (hankel-1 order arg
)
645 (hankel-2 order arg
))
647 (cond ((= (nth-value 1 (floor order
)) 1/2)
648 ;; ORDER is half-integral-value or a float
649 ;; representation thereof.
651 ;; arg is negative, the result is purely imaginary
652 (complex 0 (imagpart result
))
653 ;; arg is positive, the result is purely real
655 ;; in all other cases general complex result
658 (multiple-value-bind (n alpha
) (floor (float order
))
659 (let ((jvals (make-array (1+ n
) :element-type
'flonum
)))
660 ;; First we do the calculation for an positive argument.
661 (slatec:dbesy
(abs (float arg
)) alpha
(1+ n
) jvals
)
663 ;; Now we look at the sign of the argument
667 (let* ((dpi (coerce pi
'flonum
))
668 (s1 (cis (- (* order dpi
))))
669 (s2 (* #c
(0 2) (cos (* order dpi
)))))
670 (let ((result (+ (* s1
(aref jvals n
))
671 (* s2
(bessel-j order
(- arg
))))))
672 (cond ((zerop (nth-value 1 (truncate order
)))
673 ;; ORDER is an integer or a float representation
674 ;; of an integer, and the arg is positive the
675 ;; result is general complex.
677 ((= (nth-value 1 (floor order
)) 1/2)
678 ;; ORDER is a half-integral-value or an float
679 ;; representation and we have arg < 0. The
680 ;; result is purely imaginary.
681 (complex 0 (imagpart result
)))
682 ;; in all other cases general complex result
683 (t result
))))))))))))
685 (cond ((minusp order
)
686 ;; Bessel function of negative order. We use the Hankel function to
687 ;; compute this, because A&S 9.1.3 and 9.1.4 say
688 ;; H1[v](z) = J[v](z) + %i * Y[v](z)
690 ;; H2[v](z) = J[v](z) - %i * Y[v](z).
692 ;; Y[v](z) = (H1[v](z) - H2[v](z)) / 2 / %i
693 (/ (- (hankel-1 order arg
) (hankel-2 order arg
))
696 (multiple-value-bind (n alpha
) (floor (float order
))
697 (let ((cyr (make-array (1+ n
) :element-type
'flonum
))
698 (cyi (make-array (1+ n
) :element-type
'flonum
))
699 (cwrkr (make-array (1+ n
) :element-type
'flonum
))
700 (cwrki (make-array (1+ n
) :element-type
'flonum
)))
701 (multiple-value-bind (v-zr v-zi v-fnu v-kode v-n v-cyr v-cyi
702 v-nz v-cwrkr v-cwrki v-ierr
)
703 (slatec::zbesy
(float (realpart arg
))
704 (float (imagpart arg
))
705 alpha
1 (1+ n
) cyr cyi
0 cwrkr cwrki
0)
706 (declare (ignore v-zr v-zi v-fnu v-kode v-n
707 v-cyr v-cyi v-cwrkr v-cwrki v-nz
))
709 ;; We should check for errors based on the value of v-ierr.
711 (format t
"zbesy ierr = ~A~%" v-ierr
))
713 (complex (aref cyr n
) (aref cyi n
))))))))))
715 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
717 ;;; Implementation of the Bessel I function
719 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
721 ;; Bessel I distributes over lists, matrices, and equations
723 (defprop %bessel_i
(mlist $matrix mequal
) distribute_over
)
727 ;; Derivative wrt order n. A&S 9.6.42.
730 ;; - (x/2)^n*sum(psi(n+k+1)/gamma(n+k+1)*(x^2/4)^k/k!,k,0,inf)
734 ((%log
) ((mtimes) ((rat) 1 2) x
)))
736 ((mexpt) ((mtimes) x
((rat) 1 2)) n
)
739 ((mexpt) ((mfactorial) $%k
) -
1)
740 ((mqapply) (($psi array
) 0) ((mplus) 1 $%k n
))
741 ((mexpt) ((%gamma
) ((mplus) 1 $%k n
)) -
1)
742 ((mexpt) ((mtimes) x x
((rat) 1 4)) $%k
))
744 ;; Derivative wrt to x. A&S 9.6.29.
746 ((mplus) ((%bessel_i
) ((mplus) -
1 n
) x
)
747 ((%bessel_i
) ((mplus) 1 n
) x
))
751 ;; Integral of the Bessel I function wrt z
752 ;; http://functions.wolfram.com/Bessel-TypeFunctions/BesselI/21/01/01/
753 (defun bessel-i-integral-2 (v z
)
756 ;; integrate(bessel_i(0,z),z)
757 ;; = (1/2)*z*(bessel_i(0,z)*(%pi*struve_l(1,z)+2)
758 ;; -%pi*bessel_i(1,z)*struve_l(0,z))
759 `((mtimes) ((rat) 1 2) ,z
767 ((mtimes) $%pi
((%struve_l
) 1 ,z
)))))))
769 ;; integrate(bessel_i(1,z),z) = bessel_i(0,z)
772 ;; http://functions.wolfram.com/03.02.21.0002.01
773 ;; integrate(bessel_i(v,z),z)
774 ;; = 2^(-v-1)*z^(v+1)*gamma(v/2+1/2)
775 ;; * hypergeometric_regularized([v/2+1/2],[v+1,v/2+3/2],z^2/4)
776 ;; = 2^(-v)*z^(v+1)*hypergeometric([v/2+1/2],[v+1,v/2+3/2],z^2/4)
781 ((mplus) ((rat) 1 2) ((mtimes) ((rat) 1 2) ,v
)))
783 ((mplus) ((rat) 3 2) ((mtimes) ((rat) 1 2) ,v
))
785 ((mtimes) ((rat) 1 4) ((mexpt) ,z
2)))
786 ((mexpt) 2 ((mtimes) -
1 ,v
))
787 ((mexpt) ((%gamma
) ((mplus) 2 ,v
)) -
1)
788 ((mexpt) z
((mplus) 1 ,v
))))))
790 (putprop '%bessel_i
`((v z
) nil
,'bessel-i-integral-2
) 'integral
)
792 ;; Support a simplim%bessel_i function to handle specific limits
794 (defprop %bessel_i simplim%bessel_i simplim%function
)
796 (defun simplim%bessel_i
(expr var val
)
797 ;; Look for the limit of the arguments.
798 (let ((v (limit (cadr expr
) var val
'think
))
799 (z (limit (caddr expr
) var val
'think
)))
801 ;; Handle an argument 0 at this place.
805 (let ((sgn ($sign
($realpart v
))))
806 (cond ((and (eq sgn
'$neg
)
807 (not (maxima-integerp v
)))
808 ;; bessel_i(v,0), Re(v)<0 and v not an integer
810 ((and (eq sgn
'$zero
)
812 ;; bessel_i(v,0), Re(v)=0 and v #0
814 ;; Call the simplifier of the function.
815 (t (simplify (list '(%bessel_i
) v z
))))))
823 ;; All other cases are handled by the simplifier of the function.
824 (simplify (list '(%bessel_i
) v z
))))))
826 (def-simplifier bessel_i
(order arg
)
827 (let ((rat-order nil
))
830 ;; We handle the different case for zero arg carefully.
831 (let ((sgn ($sign
($realpart order
))))
832 (cond ((and (eq sgn
'$zero
)
833 (zerop1 ($imagpart order
)))
835 (cond ((or ($bfloatp order
) ($bfloatp arg
)) ($bfloat
1))
836 ((or (floatp order
) (floatp arg
)) 1.0)
839 (maxima-integerp order
))
840 ;; bessel_i(v,0) and Re(v)>0 or v an integer
841 (cond ((or ($bfloatp order
) ($bfloatp arg
)) ($bfloat
0))
842 ((or (floatp order
) (floatp arg
)) 0.0)
845 (not (maxima-integerp order
)))
846 ;; bessel_i(v,0) and Re(v)<0 and v not an integer
848 (intl:gettext
"bessel_i: bessel_i(~:M,~:M) is undefined.")
850 ((and (eq sgn
'$zero
)
851 (not (zerop1 ($imagpart order
))))
852 ;; bessel_i(v,0) and Re(v)=0 and v # 0
854 (intl:gettext
"bessel_i: bessel_i(~:M,~:M) is undefined.")
857 ;; No information about the sign of the order
860 ((complex-float-numerical-eval-p order arg
)
861 (cond ((= 0 ($imagpart order
))
862 ;; order is real, arg is real or complex
863 (complexify (bessel-i ($float order
)
864 (complex ($float
($realpart arg
))
865 ($float
($imagpart arg
))))))
867 ;; order is complex, arg is real or complex
870 (order ($float order
))
874 (bessel-i-hypergeometric order arg
)))))))
876 ((or (bigfloat-numerical-eval-p order arg
)
877 (complex-bigfloat-numerical-eval-p order arg
))
878 ;; We have the order or arg being a bigfloat, so evaluate it
879 ;; numerically using the hypergeometric representation
882 ;; When the order is a negative integer, the hypergeometric
883 ;; representation is invalid. However,
884 ;; https://dlmf.nist.gov/10.27.E1 says bessel_i(-n,z) =
886 (destructuring-bind (re . im
)
888 (cond ((and (zerop im
)
889 (zerop1 (sub re
(take '($floor
) re
)))
892 ($bfloat
(bessel-i-hypergeometric (mul -
1 order
) arg
))))
895 ($bfloat
(bessel-i-hypergeometric order arg
)))))))
897 ((and (integerp order
) (minusp order
))
898 ;; Some special cases when the order is an integer
899 ;; A&S 9.6.6: I[-n](x) = I[n](x)
900 (take '(%bessel_i
) (- order
) arg
))
902 ((and $besselexpand
(setq rat-order
(max-numeric-ratio-p order
2)))
903 ;; When order is a fraction with a denominator of 2, we
904 ;; can express the result in terms of elementary functions.
905 ;; From A&S 10.2.13 and 10.2.14:
907 ;; I[1/2](z) = sqrt(2/%pi/z)*sinh(z)
908 ;; I[-1/2](z) = sqrt(2/%pi/z)*cosh(z)
909 (bessel-i-half-order rat-order arg
))
912 (and (integerp order
)
915 ;; Reduce a bessel function of order > 2 to order 1 and 0.
916 ;; A&S 9.6.26: bessel_i(v,z) = -2*(v-1)/z*bessel_i(v-1,z)+bessel_i(v-2,z)
920 (take '(%bessel_i
) (- order
1) arg
))
921 (take '(%bessel_i
) (- order
2) arg
)))
923 ((and $%iargs
(multiplep arg
'$%i
))
924 ;; bessel_i(v, %i*x) = (%i*x)^v/(x^v) * bessel_j(v, x)
925 ;; (From http://functions.wolfram.com/03.02.27.0002.01)
926 (let ((x (coeff arg
'$%i
1)))
927 (mul (power (mul '$%i x
) order
)
928 (inv (power x order
))
929 (take '(%bessel_j
) order x
))))
931 ($hypergeometric_representation
932 (bessel-i-hypergeometric order arg
))
937 ;; Returns the hypergeometric representation of bessel_i
938 (defun bessel-i-hypergeometric (order arg
)
939 ;; A&S 9.6.47 / http://functions.wolfram.com/03.02.26.0002.01
940 ;; hypergeometric([],[v+1],z^2/4)*(z/2)^v/gamma(v+1)
941 (mul (inv (take '(%gamma
) (add order
1)))
942 (power (div arg
2) order
)
943 (take '(%hypergeometric
)
945 (list '(mlist) (add order
1))
946 (div (mul arg arg
) 4))))
948 ;; Compute value of Modified Bessel function of the first kind of order ORDER
949 (defun bessel-i (order arg
)
951 ((zerop (imagpart arg
))
952 ;; We have numeric args and the first arg is purely
953 ;; real. Call the real-valued Bessel function. Use special
954 ;; routines for order 0 and 1, when possible
955 (let ((arg (realpart arg
)))
958 (slatec:dbesi0
(float arg
)))
960 (slatec:dbesi1
(float arg
)))
961 ((or (minusp order
) (< arg
0))
962 (multiple-value-bind (order-int order-frac
) (floor order
)
963 (cond ((zerop order-frac
)
964 ;; Order is an integer. From A&S 9.6.6 and 9.6.30 we have
965 ;; I[-n](z) = I[n](z)
967 ;; I[n](-z) = (-1)^n*I[n](z)
969 (if (evenp order-int
)
970 (bessel-i (abs order
) (abs arg
))
971 (- (bessel-i (abs order
) (abs arg
))))
972 (bessel-i (abs order
) arg
)))
974 ;; Order or arg is negative and order is not an integer, use
975 ;; the bessel-j function for calculation. We know from
976 ;; the definition I[v](x) = x^v/(%i*x)^v * J[v](%i*x).
977 (let* ((arg (float arg
))
978 (result (* (expt arg order
)
979 (expt (complex 0 arg
) (- order
))
980 (bessel-j order
(complex 0 arg
)))))
981 ;; Try to clean up result if we know the result is
982 ;; purely real or purely imaginary.
984 ;; Result is purely real for arg >= 0
987 ;; Order is an integer or a float representation of
988 ;; an integer, the result is purely real.
991 ;; Order is half-integral-value or a float
992 ;; representation and arg < 0, the result
993 ;; is purely imaginary.
994 (complex 0 (imagpart result
)))
997 ;; Now the case order > 0 and arg >= 0
998 (multiple-value-bind (n alpha
) (floor (float order
))
999 (let ((jvals (make-array (1+ n
) :element-type
'flonum
)))
1000 (slatec:dbesi
(float (realpart arg
)) alpha
1 (1+ n
) jvals
0)
1001 (aref jvals n
)))))))
1003 ((and (zerop (realpart arg
))
1004 (zerop (rem order
1)))
1005 ;; Handle the case for a pure imaginary arg and integer order.
1006 ;; In this case, the result is purely real or purely imaginary,
1007 ;; so we want to make sure that happens.
1009 ;; bessel_i(n, %i*x) = (%i*x)^n/x^n * bessel_j(n,x)
1010 ;; = %i^n * bessel_j(n,x)
1011 (let* ((n (floor order
))
1012 (result (bessel-j (float n
) (imagpart arg
))))
1014 ;; %i^(2*m) = (-1)^m, where n=2*m
1019 ;; %i^(2*m+1) = %i*(-1)^m, where n = 2*m+1
1020 (if (evenp (floor n
2))
1022 (complex 0 (- result
)))))))
1025 ;; The arg is complex. Use the complex-valued Bessel function.
1026 (multiple-value-bind (n alpha
) (floor (abs (float order
)))
1027 ;; Evaluate the function for positive order and fixup the result later.
1028 (let ((cyr (make-array (1+ n
) :element-type
'flonum
))
1029 (cyi (make-array (1+ n
) :element-type
'flonum
)))
1030 (multiple-value-bind (v-zr v-zi v-fnu v-kode v-n
1031 v-cyr v-cyi v-nz v-ierr
)
1032 (slatec::zbesi
(float (realpart arg
))
1033 (float (imagpart arg
))
1034 alpha
1 (1+ n
) cyr cyi
0 0)
1035 (declare (ignore v-zr v-zi v-fnu v-kode v-n v-cyr v-cyi v-nz
))
1036 ;; We should check for errors here based on the value of v-ierr.
1037 (when (plusp v-ierr
)
1038 (format t
"zbesi ierr = ~A~%" v-ierr
))
1040 ;; We have evaluated I[|order|](arg), now we look at
1041 ;; the the sign of the order.
1042 (cond ((minusp order
)
1044 ;; I[-a](z) = I[a](z) + (2/%pi)*sin(%pi*a)*K[a](z)
1045 (+ (complex (aref cyr n
) (aref cyi n
))
1046 (let ((dpi (coerce pi
'flonum
)))
1048 (sin (* dpi
(- order
)))
1049 (bessel-k (- order
) arg
)))))
1051 (complex (aref cyr n
) (aref cyi n
))))))))))
1053 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1055 ;;; Implementation of the Bessel K function
1057 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1059 ;; Bessel K distributes over lists, matrices, and equations
1061 (defprop %bessel_k
(mlist $matrix mequal
) distribute_over
)
1065 ;; Derivativer wrt order n. A&S 9.6.43.
1067 ;; %pi/2*csc(n*%pi)*['diff(bessel_i(-n,x),n)-'diff(bessel_i(n,x),n)]
1068 ;; - %pi*cot(n*%pi)*bessel_k(n,x)
1072 ((%cot
) ((mtimes) $%pi n
)))
1076 ((%csc
) ((mtimes) $%pi n
))
1078 ((%derivative
) ((%bessel_i
) ((mtimes) -
1 n
) x
) n
1)
1080 ((%derivative
) ((%bessel_i
) n x
) n
1)))))
1081 ;; Derivative wrt to x. A&S 9.6.29.
1084 ((mplus) ((%bessel_k
) ((mplus) -
1 n
) x
)
1085 ((%bessel_k
) ((mplus) 1 n
) x
))
1089 ;; Integral of the Bessel K function wrt z
1090 ;; http://functions.wolfram.com/Bessel-TypeFunctions/BesselK/21/01/01/
1091 (defun bessel-k-integral-2 (n z
)
1093 ((and ($integerp n
) (<= 0 n
))
1096 ;; integrate(bessel_k(2*N+1,z),z) , N > 0
1097 ;; = -(-1)^((n-1)/2)*bessel_k(0,z)
1098 ;; + 2*sum((-1)^(k+(n-1)/2-1)*bessel_k(2*k,z),k,1,(n-1)/2)
1101 ((mtimes) -
1 ((%bessel_k
) 0 ,z
)
1103 ((mtimes) ((rat) 1 2) ((mplus) -
1 ,n
))))
1106 ((mtimes) ((%bessel_k
) ((mtimes) 2 ,k
) ,z
)
1109 ((mtimes) ((rat) 1 2) ((mplus) -
1 ,n
)))))
1110 ,k
1 ((mtimes) ((rat) 1 2) ((mplus) -
1 ,n
)))))))
1111 ;; Expand out the sum if n < 10. Otherwise fix up the indices
1113 (meval `(($ev
) ,answer $sum
)) ; Is there a better way?
1114 (simplify ($niceindices answer
)))))
1116 ;; integrate(bessel_k(2*N,z),z) , N > 0
1117 ;; = (1/2)*(-1)^(n/2)*%pi*z*(bessel_k(0,z)*struve_l(-1,z)
1118 ;; +bessel_k(1,z)*struve_l(0,z))
1119 ;; + 2 * sum((-1)^(k+n/2)*bessel_k(2*k+1,z),k,0,n/2-1)
1126 ((%bessel_k
) ((mplus) 1 ((mtimes) 2 ,k
)) ,z
)
1128 ((mplus) ,k
((mtimes) ((rat) 1 2) ,n
))))
1129 ,k
0 ((mplus) -
1 ((mtimes) ((rat) 1 2) ,n
))))
1133 ((mexpt) -
1 ((mtimes) ((rat) 1 2) ,n
))
1138 ((%struve_l
) -
1 ,z
))
1141 ((%struve_l
) 0 ,z
)))))))
1142 ;; expand out the sum if n < 10. Otherwise fix up the indices
1144 (meval `(($ev
) ,answer $sum
)) ; Is there a better way?
1145 (simplify ($niceindices answer
)))))))
1148 (putprop '%bessel_k
`((n z
) nil
,'bessel-k-integral-2
) 'integral
)
1150 ;; Support a simplim%bessel_k function to handle specific limits
1152 (defprop %bessel_k simplim%bessel_k simplim%function
)
1154 (defun simplim%bessel_k
(expr var val
)
1155 ;; Look for the limit of the arguments.
1156 (let ((v (limit (cadr expr
) var val
'think
))
1157 (z (limit (caddr expr
) var val
'think
)))
1159 ;; Handle an argument 0 at this place.
1167 ;; bessel_k(n,0), n an integer
1168 (cond ((evenp v
) '$inf
)
1169 (t (cond ((eq z
'$zeroa
) '$inf
)
1170 ((eq z
'$zerob
) '$minf
)
1172 ((not (zerop1 ($realpart v
)))
1173 ;; bessel_k(v,0), Re(v)#0
1175 ((and (zerop1 ($realpart v
))
1177 ;; bessel_k(v,0), Re(v)=0 and v#0
1179 ;; Call the simplifier of the function.
1180 (t (simplify (list '(%bessel_k
) v z
)))))
1188 ;; All other cases are handled by the simplifier of the function.
1189 (simplify (list '(%bessel_k
) v z
))))))
1191 (def-simplifier bessel_k
(order arg
)
1192 (let ((rat-order nil
))
1195 ;; Domain error for a zero argument.
1197 (intl:gettext
"bessel_k: bessel_k(~:M,~:M) is undefined.") order arg
))
1199 ((complex-float-numerical-eval-p order arg
)
1200 (cond ((= 0 ($imagpart order
))
1201 ;; order is real, arg is real or complex
1202 (complexify (bessel-k ($float order
)
1203 (complex ($float
($realpart arg
))
1204 ($float
($imagpart arg
))))))
1206 ;; order is complex, arg is real or complex
1209 (order ($float order
))
1213 (bessel-k-hypergeometric order arg
)))))))
1215 ((or (bigfloat-numerical-eval-p order arg
)
1216 (complex-bigfloat-numerical-eval-p order arg
))
1217 ;; When the order is not an integer, we can use the
1218 ;; hypergeometric representation to evaluate it.
1219 (destructuring-bind (re . im
)
1221 (cond ((and (zerop1 im
)
1222 (not (zerop1 (sub re
(take '($floor
) re
)))))
1224 ($bfloat
(bessel-k-hypergeometric re arg
))))
1229 ;; A&S 9.6.6: K[-v](x) = K[v](x)
1230 (take '(%bessel_k
) (mul -
1 order
) arg
))
1233 (setq rat-order
(max-numeric-ratio-p order
2)))
1234 ;; When order is a fraction with a denominator of 2, we
1235 ;; can express the result in terms of elementary
1236 ;; functions. From A&S 10.2.16 and 10.2.17:
1238 ;; K[1/2](z) = sqrt(%pi/2/z)*exp(-z)
1240 (bessel-k-half-order rat-order arg
))
1242 ((and $bessel_reduce
1243 (and (integerp order
)
1246 ;; Reduce a bessel function of order > 2 to order 1 and 0.
1247 ;; A&S 9.6.26: bessel_k(v,z) = 2*(v-1)/z*bessel_k(v-1,z)+bessel_k(v-2,z)
1251 (take '(%bessel_k
) (- order
1) arg
))
1252 (take '(%bessel_k
) (- order
2) arg
)))
1254 ($hypergeometric_representation
1255 (bessel-k-hypergeometric order arg
))
1260 ;; Returns the hypergeometric representation of bessel_k
1261 (defun bessel-k-hypergeometric (order arg
)
1262 ;; http://functions.wolfram.com/03.04.26.0002.01
1263 ;; hypergeometric([],[1-v],z^2/4)*2^(v-1)*gamma(v)/z^v
1264 ;; + hypergeometric([],[v+1],z^2/4)*2^(-v-1)*gamma(-v)*z^v
1265 (add (mul (power 2 (sub order
1))
1266 (take '(%gamma
) order
)
1267 (inv (power arg order
))
1268 (take '(%hypergeometric
)
1270 (list '(mlist) (sub 1 order
))
1271 (div (mul arg arg
) 4)))
1272 (mul (inv (power 2 (add order
1)))
1274 (take '(%gamma
) (neg order
))
1275 (take '(%hypergeometric
)
1277 (list '(mlist) (add order
1))
1278 (div (mul arg arg
) 4)))))
1280 ;; Compute value of Modified Bessel function of the second kind of order ORDER
1281 (defun bessel-k (order arg
)
1283 ((zerop (imagpart arg
))
1284 ;; We have numeric args and the first arg is purely real. Call the
1285 ;; real-valued Bessel function. Handle orders 0 and 1 specially, when
1287 (let ((arg (realpart arg
)))
1290 ;; This is the extension for negative arg.
1291 ;; We use A&S 9.6.6 and 9.6.31 for evaluation:
1292 ;; K[v](-z) = K[|v|](-z)
1293 ;; = exp(-%i*%pi*|v|)*K[|v|](z) - %i*%pi*I[|v|](z)
1294 (let* ((dpi (coerce pi
'flonum
))
1295 (s1 (cis (* dpi
(- (abs order
)))))
1296 (s2 (* (complex 0 -
1) dpi
))
1297 (result (+ (* s1
(bessel-k (abs order
) (- arg
)))
1298 (* s2
(bessel-i (abs order
) (- arg
)))))
1299 (rem (nth-value 1 (floor order
))))
1301 ;; order is an integer or a float representation of an
1302 ;; integer, the result is a general complex
1305 ;; order is half-integral-value or an float representation
1306 ;; and arg < 0, the result is pure imaginary
1307 (complex 0 (imagpart result
)))
1308 ;; in all other cases general complex result
1311 (slatec:dbesk0
(float arg
)))
1313 (slatec:dbesk1
(float arg
)))
1315 ;; From A&S 9.6.6, K[-v](z) = K[v](z), so take the
1316 ;; absolute value of the order.
1317 (multiple-value-bind (n alpha
) (floor (abs (float order
)))
1318 (let ((jvals (make-array (1+ n
) :element-type
'flonum
)))
1319 (slatec:dbesk
(float arg
) alpha
1 (1+ n
) jvals
0)
1320 (aref jvals n
)))))))
1322 ;; The arg is complex. Use the complex-valued Bessel function. From
1323 ;; A&S 9.6.6, K[-v](z) = K[v](z), so take the absolute value of the order.
1324 (multiple-value-bind (n alpha
) (floor (abs (float order
)))
1325 (let ((cyr (make-array (1+ n
) :element-type
'flonum
))
1326 (cyi (make-array (1+ n
) :element-type
'flonum
)))
1327 (multiple-value-bind (v-zr v-zi v-fnu v-kode v-n
1328 v-cyr v-cyi v-nz v-ierr
)
1329 (slatec::zbesk
(float (realpart arg
))
1330 (float (imagpart arg
))
1331 alpha
1 (1+ n
) cyr cyi
0 0)
1332 (declare (ignore v-zr v-zi v-fnu v-kode v-n v-cyr v-cyi v-nz
))
1334 ;; We should check for errors here based on the value of v-ierr.
1335 (when (plusp v-ierr
)
1336 (format t
"zbesk ierr = ~A~%" v-ierr
))
1337 (complex (aref cyr n
) (aref cyi n
))))))))
1339 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1341 ;;; Expansion of Bessel J and Y functions of half-integral order.
1343 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1345 ;; From A&S 10.1.1, we have
1347 ;; J[n+1/2](z) = sqrt(2*z/%pi)*j[n](z)
1348 ;; Y[n+1/2](z) = sqrt(2*z/%pi)*y[n](z)
1350 ;; where j[n](z) is the spherical bessel function of the first kind
1351 ;; and y[n](z) is the spherical bessel function of the second kind.
1353 ;; A&S 10.1.8 and 10.1.9 give
1355 ;; 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)]
1357 ;; 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)]
1362 ;; j[n](z) = f[n](z)*sin(z) + (-1)^(n+1)*f[-n-1](z)*cos(z)
1364 ;; f[0](z) = 1/z, f[1](z) = 1/z^2
1366 ;; f[n-1](z) + f[n+1](z) = (2*n+1)/z*f[n](z)
1376 ;; f[n+1](z) = (2*n+1)/z*f[n](z) - f[n-1](z) or
1377 ;; f[n](z) = (2*n-1)/z*f[n-1](z) - f[n-2](z)
1378 (sub (mul (div (+ n n -
1) z
)
1384 ;; f[n-1](z) = (2*n+1)/z*f[n](z) - f[n+1](z) or
1385 ;; f[n](z) = (2*n+3)/z*f[n+1](z) - f[n+2](z)
1386 (sub (mul (div (+ n n
3) z
)
1388 (f-fun (+ n
2) z
)))))
1390 ;; Compute sqrt(2*z/%pi)
1391 (defun root-2z/pi
(z)
1392 (power (mul 2 z
(inv '$%pi
)) '((rat simp
) 1 2)))
1394 (defun bessel-j-half-order (order arg
)
1395 "Compute J[n+1/2](z)"
1396 (let* ((n (floor order
))
1397 (sign (if (oddp n
) -
1 1))
1398 (jn (sub (mul ($expand
(f-fun n arg
))
1401 ($expand
(f-fun (- (- n
) 1) arg
))
1402 (take '(%cos
) arg
)))))
1403 (mul (root-2z/pi arg
)
1406 (defun bessel-y-half-order (order arg
)
1407 "Compute Y[n+1/2](z)"
1409 ;; Y[n+1/2](z) = sqrt(2*z/%pi)*y[n](z)
1412 ;; y[n](z) = (-1)^(n+1)*j[-n-1](z)
1415 ;; Y[n+1/2](z) = sqrt(2*z/%pi)*(-1)^(n+1)*j[-n-1](z)
1416 ;; = (-1)^(n+1)*sqrt(2*z/%pi)*j[-n-1](z)
1417 ;; = (-1)^(n+1)*J[-n-1/2](z)
1418 (let* ((n (floor order
))
1419 (jn (bessel-j-half-order (- (- order
) 1/2) arg
)))
1424 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1426 ;;; Expansion of Bessel I and K functions of half-integral order.
1428 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1432 ;; I[n+1/2](z) = sqrt(2*z/%pi)*[g[n](z)*sinh(z) + g[-n-1](z)*cosh(z)]
1434 ;; g[0](z) = 1/z, g[1](z) = -1/z^2
1436 ;; g[n-1](z) - g[n+1](z) = (2*n+1)/z*g[n](z)
1440 (declare (type integer n
))
1446 ;; g[n](z) = g[n-2](z) - (2*n-1)/z*g[n-1](z)
1447 (sub (g-fun (- n
2) z
)
1448 (mul (div (+ n n -
1) z
)
1449 (g-fun (- n
1) z
))))
1453 ;; g[n](z) = (2*n+3)/z*g[n+1](z) + g[n+2](z)
1454 (add (mul (div (+ n n
3) z
)
1456 (g-fun (+ n
2) z
)))))
1460 ;; I[n+1/2](z) = sqrt(2*z/%pi)*[g[n](z)*sinh(z) + g[-n-1](z)*cosh(z)]
1462 (defun bessel-i-half-order (order arg
)
1463 (let ((order (floor order
)))
1464 (mul (root-2z/pi arg
)
1465 (add (mul ($expand
(g-fun order arg
))
1466 (take '(%sinh
) arg
))
1467 (mul ($expand
(g-fun (- (+ order
1)) arg
))
1468 (take '(%cosh
) arg
))))))
1472 ;; 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)
1476 ;; K[n+1/2](z) = sqrt(%pi/2)/sqrt(z)*exp(-z)*sum((n+1/2,k)/(2*z)^k,k,0,n)
1478 ;; where (A&S 10.1.9)
1480 ;; (n+1/2,k) = (n+k)!/k!/(n-k)!
1483 (declare (type unsigned-byte n
))
1484 ;; Computes the sum above
1487 (loop for k from
0 upto n do
1488 (setf term
(mul term
1489 (div (div (* (- n k
) (+ n k
1))
1492 (setf sum
(add sum term
)))
1495 (defun bessel-k-half-order (order arg
)
1496 (let ((order (truncate (abs order
))))
1497 (mul (mul (power (div '$%pi
2) '((rat simp
) 1 2))
1498 (power arg
'((rat simp
) -
1 2))
1499 (power '$%e
(neg arg
)))
1500 (k-fun (abs order
) arg
))))
1502 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1504 ;;; Realpart und imagpart of Bessel functions
1506 ;;; We handle the special cases when we know that the Bessel function
1507 ;;; is pure real or pure imaginary. In all other cases Maxima generates
1508 ;;; a general noun form as result.
1510 ;;; To get the complex sign of the order an argument of the Bessel function
1511 ;;; the function $csign is used which calls $sign in a complex mode.
1513 ;;; This is an extension of of the algorithm of the function risplit in
1514 ;;; the file rpart.lisp. risplit looks for a risplit-function on the
1515 ;;; property list and call it if available.
1517 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1519 (defvar *debug-bessel
* nil
)
1521 ;;; Put the risplit-function for Bessel J and Bessel I on the property list
1523 (defprop %bessel_j risplit-bessel-j-or-i risplit-function
)
1524 (defprop %bessel_i risplit-bessel-j-or-i risplit-function
)
1526 ;;; realpart und imagpart for Bessel J and Bessel I function
1528 (defun risplit-bessel-j-or-i (expr)
1529 (when *debug-bessel
*
1530 (format t
"~&RISPLIT-BESSEL-J with ~A~%" expr
))
1531 (let ((order (cadr expr
))
1533 (sign-order ($csign
(cadr expr
)))
1534 (sign-arg ($csign
(caddr expr
))))
1536 (when *debug-bessel
*
1537 (format t
"~& : order = ~A~%" order
)
1538 (format t
"~& : arg = ~A~%" arg
)
1539 (format t
"~& : sign-order = ~A~%" sign-order
)
1540 (format t
"~& : sign-arg = ~A~%" sign-arg
))
1543 ((or (member sign-order
'($complex $imaginary
))
1544 (eq sign-arg
'$complex
))
1545 ;; order or arg are complex, return general noun-form
1546 (risplit-noun expr
))
1547 ((eq sign-arg
'$imaginary
)
1548 ;; arg is pure imaginary
1551 ($featurep order
'$odd
))
1552 ;; order is an odd integer, pure imaginary noun-form
1553 (cons 0 (mul -
1 '$%i expr
)))
1555 ($featurep order
'$even
))
1556 ;; order is an even integer, real noun-form
1559 ;; order is not an odd or even integer, or Maxima can not
1560 ;; determine it, return general noun-form
1561 (risplit-noun expr
))))
1562 ;; At this point order and arg are real.
1563 ;; We have to look for some special cases involing a negative arg
1564 ((or (maxima-integerp order
)
1565 (member sign-arg
'($pos $pz
)))
1566 ;; arg is positive or order an integer, real noun-form
1568 ;; At this point we know that arg is negative or the sign is not known
1569 ((zerop1 (sub ($truncate
($multthru
2 order
)) ($multthru
2 order
)))
1570 ;; order is half integral
1572 ((eq sign-arg
'$neg
)
1573 ;; order is half integral and arg negative, imaginary noun-form
1574 (cons 0 (mul -
1 '$%i expr
)))
1576 ;; the sign of arg or order is not known
1577 (risplit-noun expr
))))
1579 ;; the sign of arg or order is not known
1580 (risplit-noun expr
)))))
1582 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1584 ;;; Put the risplit-function for Bessel K and Bessel Y on the property list
1586 (defprop %bessel_k risplit-bessel-k-or-y risplit-function
)
1587 (defprop %bessel_y risplit-bessel-k-or-y risplit-function
)
1589 ;;; realpart und imagpart for Bessel K and Bessel Y function
1591 (defun risplit-bessel-k-or-y (expr)
1592 (when *debug-bessel
*
1593 (format t
"~&RISPLIT-BESSEL-K with ~A~%" expr
))
1594 (let ((order (cadr expr
))
1596 (sign-order ($csign
(cadr expr
)))
1597 (sign-arg ($csign
(caddr expr
))))
1599 (when *debug-bessel
*
1600 (format t
"~& : order = ~A~%" order
)
1601 (format t
"~& : arg = ~A~%" arg
)
1602 (format t
"~& : sign-order = ~A~%" sign-order
)
1603 (format t
"~& : sign-arg = ~A~%" sign-arg
))
1606 ((or (member sign-order
'($complex $imaginary
))
1607 (member sign-arg
'($complex
'$imaginary
)))
1608 (risplit-noun expr
))
1609 ;; At this point order and arg are real valued.
1610 ;; We have to look for some special cases involing a negative arg
1611 ((member sign-arg
'($pos $pz
))
1614 ;; At this point we know that arg is negative or the sign is not known
1615 ((and (not (maxima-integerp order
))
1616 (zerop1 (sub ($truncate
($multthru
2 order
)) ($multthru
2 order
))))
1617 ;; order is half integral
1619 ((eq sign-arg
'$neg
)
1620 (cons 0 (mul -
1 '$%i expr
)))
1622 ;; the sign of arg is not known
1623 (risplit-noun expr
))))
1625 ;; the sign of arg is not known
1626 (risplit-noun expr
)))))
1628 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1630 ;;; Implementation of scaled Bessel I functions
1632 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1634 ;; FIXME: The following scaled functions need work. They should be
1635 ;; extended to match bessel_i, but still carefully compute the scaled
1638 ;; I think g0(x) = exp(-x)*I[0](x), g1(x) = exp(-x)*I[1](x), and
1639 ;; gn(x,n) = exp(-x)*I[n](x), based on some simple numerical
1642 (defmfun $scaled_bessel_i0
($x
)
1644 ;; XXX Should we return noun forms if $x is rational?
1645 (slatec:dbsi0e
($float $x
)))
1647 (mul (power '$%e
(neg (simplifya `((mabs) ,$x
) nil
)))
1648 `((%bessel_i
) 0 ,$x
)))))
1650 (defmfun $scaled_bessel_i1
($x
)
1652 ;; XXX Should we return noun forms if $x is rational?
1653 (slatec:dbsi1e
($float $x
)))
1655 (mul (power '$%e
(neg (simplifya `((mabs) ,$x
) nil
)))
1656 `((%bessel_i
) 1 ,$x
)))))
1658 (defmfun $scaled_bessel_i
($n $x
)
1659 (cond ((and (mnump $x
) (mnump $n
))
1660 ;; XXX Should we return noun forms if $n and $x are rational?
1661 (multiple-value-bind (n alpha
) (floor ($float $n
))
1662 (let ((iarray (make-array (1+ n
) :element-type
'flonum
)))
1663 (slatec:dbesi
($float $x
) alpha
2 (1+ n
) iarray
0)
1666 (mul (power '$%e
(neg (simplifya `((mabs) ,$x
) nil
)))
1667 ($bessel_i $n $x
)))))
1669 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1671 ;;; Implementation of the Hankel 1 function
1673 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1675 ;; hankel_1 distributes over lists, matrices, and equations
1677 (defprop %hankel_1
(mlist $matrix mequal
) distribute_over
)
1680 (defprop %hankel_1 simp-hankel-1 operators
)
1682 ; Derivatives of the Hankel 1 function
1687 ;; Derivative wrt arg x. A&S 9.1.27.
1690 ((%hankel_1
) ((mplus) -
1 n
) x
)
1691 ((mtimes) -
1 ((%hankel_1
) ((mplus) 1 n
) x
)))
1695 (def-simplifier hankel_1
(order arg
)
1700 (intl:gettext
"hankel_1: hankel_1(~:M,~:M) is undefined.")
1702 ((complex-float-numerical-eval-p order arg
)
1703 (cond ((= 0 ($imagpart order
))
1704 ;; order is real, arg is real or complex
1705 (complexify (hankel-1 ($float order
)
1706 (complex ($float
($realpart arg
))
1707 ($float
($imagpart arg
))))))
1709 ;; The order is complex. Use
1710 ;; hankel_1(v,z) = bessel_j(v,z) + %i*bessel_y(v,z)
1711 ;; and evaluate using the hypergeometric function
1714 (order ($float order
))
1718 (add (bessel-j-hypergeometric order arg
)
1720 (bessel-y-hypergeometric order arg
)))))))))
1722 (setq rat-order
(max-numeric-ratio-p order
2)))
1723 ;; When order is a fraction with a denominator of 2, we can express
1724 ;; the result in terms of elementary functions.
1725 ;; Use the definition hankel_1(v,z) = bessel_j(v,z)+%i*bessel_y(v,z)
1727 (add (bessel-j-half-order rat-order arg
)
1729 (bessel-y-half-order rat-order arg
)))))
1732 ;; Numerically compute H1[v](z).
1734 ;; A&S 9.1.3 says H1[v](z) = J[v](z) + %i * Y[v](z)
1736 (defun hankel-1 (v z
)
1738 (z (coerce z
'(complex flonum
))))
1742 ;; H1[-v](z) = exp(v*%pi*%i)*H1[v](z)
1746 ;; H1[v](z) = exp(-v*%pi*%i)*H1[-v](z)
1748 (* (cis (* (float pi
) (- v
))) (hankel-1 (- v
) z
)))
1750 (multiple-value-bind (n fnu
) (floor v
)
1751 (let ((zr (realpart z
))
1753 (cyr (make-array (1+ n
) :element-type
'flonum
))
1754 (cyi (make-array (1+ n
) :element-type
'flonum
)))
1755 (multiple-value-bind (dzr dzi df dk dm dn dcyr dcyi nz ierr
)
1756 (slatec::zbesh zr zi fnu
1 1 (1+ n
) cyr cyi
0 0)
1757 (declare (ignore dzr dzi df dk dm dn dcyr dcyi nz ierr
))
1758 (complex (aref cyr n
) (aref cyi n
)))))))))
1760 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1762 ;;; Implementation of the Hankel 2 function
1764 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1766 ;; hankel_2 distributes over lists, matrices, and equations
1768 (defprop %hankel_2
(mlist $matrix mequal
) distribute_over
)
1771 (defprop %hankel_2 simp-hankel-2 operators
)
1773 ; Derivatives of the Hankel 2 function
1778 ;; Derivative wrt arg x. A&S 9.1.27.
1781 ((%hankel_2
) ((mplus) -
1 n
) x
)
1782 ((mtimes) -
1 ((%hankel_2
) ((mplus) 1 n
) x
)))
1786 (def-simplifier hankel_2
(order arg
)
1791 (intl:gettext
"hankel_2: hankel_2(~:M,~:M) is undefined.")
1793 ((complex-float-numerical-eval-p order arg
)
1794 (cond ((= 0 ($imagpart order
))
1795 ;; order is real, arg is real or complex
1796 (complexify (hankel-2 ($float order
)
1797 (complex ($float
($realpart arg
))
1798 ($float
($imagpart arg
))))))
1800 ;; The order is complex. Use
1801 ;; hankel_2(v,z) = bessel_j(v,z) - %i*bessel_y(v,z)
1802 ;; and evaluate using the hypergeometric function
1805 (order ($float order
))
1809 (sub (bessel-j-hypergeometric order arg
)
1811 (bessel-y-hypergeometric order arg
)))))))))
1813 (setq rat-order
(max-numeric-ratio-p order
2)))
1814 ;; When order is a fraction with a denominator of 2, we can express
1815 ;; the result in terms of elementary functions.
1816 ;; Use the definition hankel_2(v,z) = bessel_j(v,z)-%i*bessel_y(v,z)
1818 (sub (bessel-j-half-order rat-order arg
)
1820 (bessel-y-half-order rat-order arg
)))))
1823 ;; Numerically compute H2[v](z).
1825 ;; A&S 9.1.4 says H2[v](z) = J[v](z) - %i * Y[v](z)
1827 (defun hankel-2 (v z
)
1829 (z (coerce z
'(complex flonum
))))
1833 ;; H2[-v](z) = exp(-v*%pi*%i)*H2[v](z)
1837 ;; H2[v](z) = exp(v*%pi*%i)*H2[-v](z)
1839 (* (cis (* (float pi
) v
)) (hankel-2 (- v
) z
)))
1841 (multiple-value-bind (n fnu
) (floor v
)
1842 (let ((zr (realpart z
))
1844 (cyr (make-array (1+ n
) :element-type
'flonum
))
1845 (cyi (make-array (1+ n
) :element-type
'flonum
)))
1846 (multiple-value-bind (dzr dzi df dk dm dn dcyr dcyi nz ierr
)
1847 (slatec::zbesh zr zi fnu
1 2 (1+ n
) cyr cyi
0 0)
1848 (declare (ignore dzr dzi df dk dm dn dcyr dcyi nz ierr
))
1849 (complex (aref cyr n
) (aref cyi n
)))))))))
1851 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1853 ;;; Implementation of Struve H function
1855 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1857 ;; struve_h distributes over lists, matrices, and equations
1859 (defprop %struve_h
(mlist $matrix mequal
) distribute_over
)
1862 (defprop %struve_h simp-struve-h operators
)
1864 ; Derivatives of the Struve H function
1869 ;; Derivative wrt arg z. A&S 12.1.10.
1873 ((%struve_h
) ((mplus) -
1 v
) z
)
1874 ((mtimes) -
1 ((%struve_h
) ((mplus) 1 v
) z
))
1876 ((mexpt) $%pi
((rat) -
1 2))
1877 ((mexpt) 2 ((mtimes) -
1 v
))
1878 ((mexpt) ((%gamma
) ((mplus) ((rat) 3 2) v
)) -
1)
1882 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1884 (def-simplifier struve_h
(order arg
)
1887 ;; Check for special values
1890 (cond ((eq ($csign
(add order
1)) '$zero
)
1891 ; http://functions.wolfram.com/03.09.03.0018.01
1892 (cond ((or ($bfloatp order
)
1894 ($bfloat
(div 2 '$%pi
)))
1897 ($float
(div 2 '$%pi
)))
1900 ((eq ($sign
(add ($realpart order
) 1)) '$pos
)
1901 ; http://functions.wolfram.com/03.09.03.0001.01
1903 ((member ($sign
(add ($realpart order
) 1)) '($zero $neg $nz
))
1905 (intl:gettext
"struve_h: struve_h(~:M,~:M) is undefined.")
1910 ;; Check for numerical evaluation
1912 ((complex-float-numerical-eval-p order arg
)
1914 (let (($numer t
) ($float t
))
1918 ($rectform
(power arg
(add order
1.0)))
1919 ($rectform
(inv (power 2.0 order
)))
1920 (inv (power ($float
'$%pi
) 0.5))
1921 (inv (simplify (list '(%gamma
) (add order
1.5))))
1922 (simplify (list '(%hypergeometric
)
1924 (list '(mlist) '((rat simp
) 3 2)
1925 (add order
'((rat simp
) 3 2)))
1926 (div (mul arg arg
) -
4.0))))))))
1928 ((complex-bigfloat-numerical-eval-p order arg
)
1930 (let (($ratprint nil
)
1932 (order ($bfloat order
)))
1936 ($rectform
(power arg
(add order
1)))
1937 ($rectform
(inv (power 2 order
)))
1938 (inv (power ($bfloat
'$%pi
) ($bfloat
'((rat simp
) 1 2))))
1939 (inv (simplify (list '(%gamma
)
1940 (add order
($bfloat
'((rat simp
) 3 2))))))
1941 (simplify (list '(%hypergeometric
)
1943 (list '(mlist) '((rat simp
) 3 2)
1944 (add order
'((rat simp
) 3 2)))
1945 (div (mul arg arg
) ($bfloat -
4)))))))))
1947 ;; Transformations and argument simplifications
1951 (integerp (mul 2 order
)))
1953 ((eq ($sign order
) '$pos
)
1954 ;; Expansion of Struve H for a positive half integral order.
1958 (inv (simplify (list '(mfactorial) (sub order
1959 '((rat simp
) 1 2)))))
1960 (inv (power '$%pi
'((rat simp
) 1 2 )))
1961 (power (div arg
2) (add order -
1))
1962 (let ((index (gensumindex)))
1965 (simplify (list '($pochhammer
) '((rat simp
) 1 2) index
))
1966 (simplify (list '($pochhammer
)
1967 (sub '((rat simp
) 1 2) order
)
1969 (power (mul -
1 arg arg
(inv 4)) (mul -
1 index
)))
1970 index
0 (sub order
'((rat simp
) 1 2)) t
)))
1972 (power (div 2 '$%pi
) '((rat simp
) 1 2))
1973 (power -
1 (add order
'((rat simp
) 1 2)))
1974 (inv (power arg
'((rat simp
) 1 2)))
1979 (add (mul '((rat simp
) 1 2)
1981 (add order
'((rat simp
) 1 2)))
1983 (let ((index (gensumindex)))
1987 (simplify (list '(mfactorial)
1990 '((rat simp
) -
1 2))))
1991 (inv (simplify (list '(mfactorial) (mul 2 index
))))
1992 (inv (simplify (list '(mfactorial)
1995 '((rat simp
) -
1 2)))))
1996 (inv (power (mul 2 arg
) (mul 2 index
))))
1998 (simplify (list '($floor
)
1999 (div (sub (mul 2 order
) 1) 4)))
2002 (simplify (list '(%cos
)
2003 (add (mul '((rat simp
) 1 2)
2005 (add order
'((rat simp
) 1 2)))
2007 (let ((index (gensumindex)))
2011 (simplify (list '(mfactorial)
2014 '((rat simp
) 1 2))))
2015 (power (mul 2 arg
) (mul -
1 (add (mul 2 index
) 1)))
2016 (inv (simplify (list '(mfactorial)
2017 (add (mul 2 index
) 1))))
2018 (inv (simplify (list '(mfactorial)
2021 '((rat simp
) -
3 2))))))
2023 (simplify (list '($floor
)
2024 (div (sub (mul 2 order
) 3) 4)))
2027 ((eq ($sign order
) '$neg
)
2028 ;; Expansion of Struve H for a negative half integral order.
2032 (power (div 2 '$%pi
) '((rat simp
) 1 2))
2033 (power -
1 (add order
'((rat simp
) 1 2)))
2034 (inv (power arg
'((rat simp
) 1 2)))
2037 (simplify (list '(%sin
)
2042 (add order
'((rat simp
) 1 2)))
2044 (let ((index (gensumindex)))
2048 (simplify (list '(mfactorial)
2051 '((rat simp
) -
1 2))))
2052 (inv (simplify (list '(mfactorial) (mul 2 index
))))
2053 (inv (simplify (list '(mfactorial)
2056 '((rat simp
) -
1 2)))))
2057 (inv (power (mul 2 arg
) (mul 2 index
))))
2059 (simplify (list '($floor
)
2060 (div (add (mul 2 order
) 1) -
4)))
2063 (simplify (list '(%cos
)
2068 (add order
'((rat simp
) 1 2)))
2070 (let ((index (gensumindex)))
2074 (simplify (list '(mfactorial)
2077 '((rat simp
) 1 2))))
2078 (power (mul 2 arg
) (mul -
1 (add (mul 2 index
) 1)))
2079 (inv (simplify (list '(mfactorial)
2080 (add (mul 2 index
) 1))))
2081 (inv (simplify (list '(mfactorial)
2084 '((rat simp
) -
3 2))))))
2086 (simplify (list '($floor
)
2087 (div (add (mul 2 order
) 3) -
4)))
2092 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2094 ;;; Implementation of Struve L function
2096 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2098 ;; struve_l distributes over lists, matrices, and equations
2100 (defprop %struve_l
(mlist $matrix mequal
) distribute_over
)
2102 ; Derivatives of the Struve L function
2107 ;; Derivative wrt arg z. A&S 12.2.5.
2111 ((%struve_l
) ((mplus) -
1 v
) z
)
2112 ((%struve_l
) ((mplus) 1 v
) z
)
2114 ((mexpt) $%pi
((rat) -
1 2))
2115 ((mexpt) 2 ((mtimes) -
1 v
))
2116 ((mexpt) ((%gamma
) ((mplus) ((rat) 3 2) v
)) -
1)
2120 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2122 (def-simplifier struve_l
(order arg
)
2125 ;; Check for special values
2128 (cond ((eq ($csign
(add order
1)) '$zero
)
2129 ; http://functions.wolfram.com/03.10.03.0018.01
2130 (cond ((or ($bfloatp order
)
2132 ($bfloat
(div 2 '$%pi
)))
2135 ($float
(div 2 '$%pi
)))
2138 ((eq ($sign
(add ($realpart order
) 1)) '$pos
)
2139 ; http://functions.wolfram.com/03.10.03.0001.01
2141 ((member ($sign
(add ($realpart order
) 1)) '($zero $neg $nz
))
2143 (intl:gettext
"struve_l: struve_l(~:M,~:M) is undefined.")
2148 ;; Check for numerical evaluation
2150 ((complex-float-numerical-eval-p order arg
)
2151 ; http://functions.wolfram.com/03.10.26.0002.01
2152 (let (($numer t
) ($float t
))
2156 ($rectform
(power arg
(add order
1.0)))
2157 ($rectform
(inv (power 2.0 order
)))
2158 (inv (power ($float
'$%pi
) 0.5))
2159 (inv (simplify (list '(%gamma
) (add order
1.5))))
2160 (simplify (list '(%hypergeometric
)
2162 (list '(mlist) '((rat simp
) 3 2)
2163 (add order
'((rat simp
) 3 2)))
2164 (div (mul arg arg
) 4.0))))))))
2166 ((complex-bigfloat-numerical-eval-p order arg
)
2167 ; http://functions.wolfram.com/03.10.26.0002.01
2168 (let (($ratprint nil
))
2172 ($rectform
(power arg
(add order
1)))
2173 ($rectform
(inv (power 2 order
)))
2174 (inv (power ($bfloat
'$%pi
) ($bfloat
'((rat simp
) 1 2))))
2175 (inv (simplify (list '(%gamma
) (add order
'((rat simp
) 3 2)))))
2176 (simplify (list '(%hypergeometric
)
2178 (list '(mlist) '((rat simp
) 3 2)
2179 (add order
'((rat simp
) 3 2)))
2180 (div (mul arg arg
) 4))))))))
2182 ;; Transformations and argument simplifications
2186 (integerp (mul 2 order
)))
2188 ((eq ($sign order
) '$pos
)
2189 ;; Expansion of Struve L for a positive half integral order.
2193 (power 2 (sub 1 order
))
2194 (power arg
(sub order
1))
2195 (inv (power '$%pi
'((rat simp
) 1 2)))
2196 (inv (simplify (list '(mfactorial) (sub order
2197 '((rat simp
) 1 2)))))
2198 (let ((index (gensumindex)))
2201 (simplify (list '($pochhammer
) '((rat simp
) 1 2) index
))
2202 (simplify (list '($pochhammer
)
2203 (sub '((rat simp
) 1 2) order
)
2205 (power (mul arg arg
(inv 4)) (mul -
1 index
)))
2206 index
0 (sub order
'((rat simp
) 1 2)) t
)))
2208 (power (div 2 '$%pi
) '((rat simp
) 1 2))
2209 (inv (power arg
'((rat simp
) 1 2)))
2210 ($exp
(div (mul '$%pi
'$%i
(add order
'((rat simp
) 1 2))) 2))
2213 (let (($trigexpand t
))
2214 (simplify (list '(%sinh
)
2215 (sub (mul '((rat simp
) 1 2)
2218 (add order
'((rat simp
) 1 2)))
2220 (let ((index (gensumindex)))
2223 (simplify (list '(mfactorial)
2225 (simplify (list '(mabs) order
))
2226 '((rat simp
) -
1 2))))
2227 (inv (simplify (list '(mfactorial) (mul 2 index
))))
2228 (inv (simplify (list '(mfactorial)
2229 (add (simplify (list '(mabs)
2232 '((rat simp
) -
1 2)))))
2233 (inv (power (mul 2 arg
) (mul 2 index
))))
2235 (simplify (list '($floor
)
2237 (simplify (list '(mabs)
2243 (let (($trigexpand t
))
2244 (simplify (list '(%cosh
)
2245 (sub (mul '((rat simp
) 1 2)
2248 (add order
'((rat simp
) 1 2)))
2250 (let ((index (gensumindex)))
2253 (simplify (list '(mfactorial)
2255 (simplify (list '(mabs) order
))
2256 '((rat simp
) 1 2))))
2257 (power (mul 2 arg
) (neg (add (mul 2 index
) 1)))
2258 (inv (simplify (list '(mfactorial)
2259 (add (mul 2 index
) 1))))
2260 (inv (simplify (list '(mfactorial)
2261 (add (simplify (list '(mabs)
2264 '((rat simp
) -
3 2))))))
2266 (simplify (list '($floor
)
2268 (simplify (list '(mabs)
2273 ((eq ($sign order
) '$neg
)
2274 ;; Expansion of Struve L for a negative half integral order.
2278 (power (div 2 '$%pi
) '((rat simp
) 1 2))
2279 (inv (power arg
'((rat simp
) 1 2)))
2280 ($exp
(div (mul '$%pi
'$%i
(add order
'((rat simp
) 1 2))) 2))
2283 (let (($trigexpand t
))
2284 (simplify (list '(%sinh
)
2285 (sub (mul '((rat simp
) 1 2)
2288 (add order
'((rat simp
) 1 2)))
2290 (let ((index (gensumindex)))
2293 (simplify (list '(mfactorial)
2296 '((rat simp
) -
1 2))))
2297 (inv (simplify (list '(mfactorial) (mul 2 index
))))
2298 (inv (simplify (list '(mfactorial)
2301 '((rat simp
) -
1 2)))))
2302 (inv (power (mul 2 arg
) (mul 2 index
))))
2304 (simplify (list '($floor
)
2305 (div (add (mul 2 order
) 1) -
4)))
2308 (let (($trigexpand t
))
2309 (simplify (list '(%cosh
)
2310 (sub (mul '((rat simp
) 1 2)
2313 (add order
'((rat simp
) 1 2)))
2315 (let ((index (gensumindex)))
2318 (simplify (list '(mfactorial)
2321 '((rat simp
) 1 2))))
2322 (power (mul 2 arg
) (neg (add (mul 2 index
) 1)))
2323 (inv (simplify (list '(mfactorial)
2324 (add (mul 2 index
) 1))))
2325 (inv (simplify (list '(mfactorial)
2328 '((rat simp
) -
3 2))))))
2330 (simplify (list '($floor
)
2331 (div (add (mul 2 order
) 3) -
4)))
2336 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2338 (defmspec $gauss
(form)
2340 "NOTE: The gauss function is superseded by random_normal in the `distrib' package.
2341 Perhaps you meant to enter `~a'.~%"
2342 (print-invert-case (implode (mstring `(($random_normal
) ,@ (cdr form
))))))