1 ;;; Airy functions Ai(z) and Bi(z) - A&S 10.4
3 ;;; airy_ai(z) - Airy function Ai(z)
4 ;;; airy_dai(z) - Derivative of Airy function Ai(z)
5 ;;; airy_bi(z) - Airy function Bi(z)
6 ;;; airy_dbi(z) - Derivative of Airy function Bi(z)
8 ;;;; Copyright (C) 2005 David Billinghurst
10 ;;;; airy.lisp is free software; you can redistribute it
11 ;;;; and/or modify it under the terms of the GNU General Public
12 ;;;; License as published by the Free Software Foundation; either
13 ;;;; version 2, or (at your option) any later version.
15 ;;;; airy.lisp is distributed in the hope that it will be
16 ;;;; useful, but WITHOUT ANY WARRANTY; without even the implied
17 ;;;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 ;;;; See the GNU General Public License for more details.
20 ;;;; You should have received a copy of the GNU General Public License
21 ;;;; along with command-line.lisp; see the file COPYING. If not,
22 ;;;; write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
26 (declaim (special *flonum-op
*))
31 (simplify (list '(%airy_ai
) (resimplify z
))))
33 (defprop %airy_ai simplim%airy_ai simplim%function
)
34 (defprop %airy_ai
((z) ((%airy_dai
) z
)) grad
)
36 ;; airy_ai distributes over lists, matrices, and equations
37 (defprop %airy_ai
(mlist $matrix mequal
) distribute_over
)
39 ;; airy_ai has mirror symmetry
40 (defprop %airy_ai t commutes-with-conjugate
)
43 ;; http://functions.wolfram.com/03.05.21.0002.01
44 ;; (z/(3^(2/3)*gamma(2/3)))*hypergeometric([1/3],[2/3,4/3],z^3/9)
45 ;; - (3^(1/6)/(4*%pi))*z^2*gamma(2/3)*hypergeometric([2/3],[4/3,5/3],z^3/9);
50 ((mexpt) 3 ((rat) -
2 3))
51 ((mexpt) ((%gamma
) ((rat) 2 3)) -
1)
54 ((mlist) ((rat) 2 3) ((rat) 4 3))
55 ((mtimes) ((rat) 1 9) ((mexpt) z
3)))
58 ((rat) -
1 4) ((mexpt) 3 ((rat) 1 6)) ((mexpt) $%pi -
1) ((%gamma
) ((rat) 2 3))
61 ((mlist) ((rat) 4 3) ((rat) 5 3))
62 ((mtimes) ((rat) 1 9) ((mexpt) z
3)))
67 (cond ((floatp z
) (airy-ai-real z
))
68 ((complexp z
) (airy-ai-complex z
))))
70 (setf (gethash '%airy_ai
*flonum-op
*) #'airy-ai
)
72 (defun simplim%airy_ai
(expr var val
)
73 ; Look for the limit of the argument
74 (let ((z (limit (cadr expr
) var val
'think
)))
75 (cond ((or (eq z
'$inf
) ; A&S 10.4.59
76 (eq z
'$minf
)) ; A&S 10.4.60
79 ; Handle other cases with the function simplifier
80 (simplify (list '(%airy_ai
) z
))))))
82 (defun airy-ai-hypergeometric (z)
83 "Returns the hypergeometric representation of Airy Ai"
84 ;; See http://functions.wolfram.com/03.05.26.0001.01 and
85 ;; https://fungrim.org/entry/01bbb6/:
87 ;; Ai(z) = Ai(0)*hypergeometric([],[2/3],z^3/9)
88 ;; + z*Ai'(0)*hypergeometric([],[4/3],z^3/9)
89 (add (mul (ftake '%airy_ai
0)
90 (ftake '$hypergeometric
92 (list '(mlist) (div 2 3))
97 (ftake '$hypergeometric
99 (list '(mlist) (div 4 3))
103 (def-simplifier airy_ai
(z)
104 (cond ((equal z
0) ; A&S 10.4.4: Ai(0) = 3^(-2/3)/gamma(2/3)
105 (div (power 3 (div -
2 3))
106 (take '(%gamma
) (div 2 3))))
107 ((flonum-eval (mop form
) z
))
108 ((or (bigfloat-numerical-eval-p z
)
109 (complex-bigfloat-numerical-eval-p z
))
111 ($bfloat
(airy-ai-hypergeometric z
))))
112 ($hypergeometric_representation
113 (airy-ai-hypergeometric z
))
117 ;; Derivative dAi/dz of Airy function Ai(z)
118 (defmfun $airy_dai
(z)
119 "Derivative dAi/dz of Airy function Ai(z)"
120 (simplify (list '(%airy_dai
) (resimplify z
))))
122 (defprop %airy_dai simplim%airy_dai simplim%function
)
123 (defprop %airy_dai
((z) ((mtimes) z
((%airy_ai
) z
))) grad
)
124 (defprop %airy_dai
((z) ((%airy_ai
) z
)) integral
)
126 ;; airy_dai distributes over lists, matrices, and equations
127 (defprop %airy_dai
(mlist $matrix mequal
) distribute_over
)
129 ;; airy_dai has mirror symmetry
130 (defprop %airy_dai t commutes-with-conjugate
)
133 (cond ((floatp z
) (airy-dai-real z
))
134 ((complexp z
) (airy-dai-complex z
))))
136 (setf (gethash '%airy_dai
*flonum-op
*) #'airy-dai
)
138 (defun simplim%airy_dai
(expr var val
)
139 ; Look for the limit of the argument
140 (let ((z (limit (cadr expr
) var val
'think
)))
141 (cond ((eq z
'$inf
) ; A&S 10.4.61
143 ((eq z
'$minf
) ; A&S 10.4.62
146 ; Handle other cases with the function simplifier
147 (simplify (list '(%airy_dai
) z
))))))
149 (defun airy-dai-hypergeometric (z)
150 "Returns the hypergeometric representation of Ai'(x), the derivative
151 of the Airy function Ai(x)"
152 ;; See http://functions.wolfram.com/03.07.26.0001.01 and
153 ;; https://fungrim.org/entry/20e530/.
156 ;; Ai'(z) = Ai'(0)*hypergeometric([],[1/3],z^3/9)
157 ;; + z^2/2*Ai(0)*hypergeometric([],[5/3],z^3/9)
158 (add (mul (ftake '%airy_dai
0)
159 (ftake '$hypergeometric
161 (list '(mlist) (div 1 3))
166 (ftake '$hypergeometric
168 (list '(mlist) (div 5 3))
172 (def-simplifier airy_dai
(z)
173 (cond ((equal z
0) ; A&S 10.4.5: Ai'(0) = -3^(-1/3)/gamma(1/3)
175 (mul (power 3 (div 1 3))
176 (take '(%gamma
) (div 1 3)))))
177 ((flonum-eval (mop form
) z
))
178 ((or (bigfloat-numerical-eval-p z
)
179 (complex-bigfloat-numerical-eval-p z
))
181 ($bfloat
(airy-dai-hypergeometric z
))))
182 ($hypergeometric_representation
183 (airy-dai-hypergeometric z
))
187 (defmfun $airy_bi
(z)
188 "Airy function Bi(z)"
189 (simplify (list '(%airy_bi
) (resimplify z
))))
191 (defprop %airy_bi simplim%airy_bi simplim%function
)
192 (defprop %airy_bi
((z) ((%airy_dbi
) z
)) grad
)
194 ;; airy_bi distributes over lists, matrices, and equations
195 (defprop %airy_bi
(mlist $matrix mequal
) distribute_over
)
197 ;; airy_bi has mirror symmetry
198 (defprop %airy_bi t commutes-with-conjugate
)
201 ;; http://functions.wolfram.com/03.06.21.0002.01
202 ;; (z/(3^(1/6)*gamma(2/3)))*hypergeometric([1/3],[2/3,4/3],z^3/9)
203 ;; + (3^(2/3)/(4*%pi))*z^2*gamma(2/3)*hypergeometric([2/3],[4/3,5/3],z^3/9);
208 ((mexpt) 3 ((rat) -
1 6))
209 ((mexpt) ((%gamma
) ((rat) 2 3)) -
1)
211 ((mlist) ((rat) 1 3))
212 ((mlist) ((rat) 2 3) ((rat) 4 3))
213 ((mtimes) ((rat) 1 9) ((mexpt) z
3)))
216 ((rat) 1 4) ((mexpt) 3 ((rat) 2 3)) ((mexpt) $%pi -
1) ((%gamma
) ((rat) 2 3))
218 ((mlist) ((rat) 2 3))
219 ((mlist) ((rat) 4 3) ((rat) 5 3))
220 ((mtimes) ((rat) 1 9) ((mexpt) z
3)))
225 (cond ((floatp z
) (airy-bi-real z
))
226 ((complexp z
) (airy-bi-complex z
))))
228 (setf (gethash '%airy_bi
*flonum-op
*) #'airy-bi
)
230 (defun simplim%airy_bi
(expr var val
)
231 ; Look for the limit of the argument
232 (let ((z (limit (cadr expr
) var val
'think
)))
233 (cond ((eq z
'$inf
) ; A&S 10.4.63
235 ((eq z
'$minf
) ; A&S 10.4.64
238 ; Handle other cases with the function simplifier
239 (simplify (list '(%airy_bi
) z
))))))
241 (defun airy-bi-hypergeometric (z)
242 "Returns the hypergeometric representation of Airy Bi"
243 ;; See http://functions.wolfram.com/03.06.26.0001.01 and https://fungrim.org/entry/bd319e/
245 ;; Bi(z) = Bi(0)*hypergeometric([],[2/3],z^3/9)
246 ;; + z*Bi'(0)*hypergeometric([],[4/2],z^3/9)
247 (add (mul (ftake '%airy_bi
0)
248 (ftake '$hypergeometric
250 (list '(mlist) (div 2 3))
255 (ftake '$hypergeometric
257 (list '(mlist) (div 4 3))
261 (def-simplifier airy_bi
(z)
262 (cond ((equal z
0) ; A&S 10.4.4: Bi(0) = sqrt(3) 3^(-2/3)/gamma(2/3)
263 (div (mul (power 3 1//2)
264 (power 3 (div -
2 3)))
265 (take '(%gamma
) (div 2 3))))
266 ((flonum-eval (mop form
) z
))
267 ((or (bigfloat-numerical-eval-p z
)
268 (complex-bigfloat-numerical-eval-p z
))
270 ($bfloat
(airy-bi-hypergeometric z
))))
271 ($hypergeometric_representation
272 (airy-bi-hypergeometric z
))
276 ;; Derivative dBi/dz of Airy function Bi(z)
277 (defmfun $airy_dbi
(z)
278 "Derivative dBi/dz of Airy function Bi(z)"
279 (simplify (list '(%airy_dbi
) (resimplify z
))))
281 (defprop %airy_dbi simplim%airy_dbi simplim%function
)
282 (defprop %airy_dbi
((z) ((mtimes) z
((%airy_bi
) z
))) grad
)
283 (defprop %airy_dbi
((z) ((%airy_bi
) z
)) integral
)
285 ;; airy_dbi distributes over lists, matrices, and equations
286 (defprop %airy_dbi
(mlist $matrix mequal
) distribute_over
)
288 ;; airy_dbi has mirror symmetry
289 (defprop %airy_dbi t commutes-with-conjugate
)
292 (cond ((floatp z
) (airy-dbi-real z
))
293 ((complexp z
) (airy-dbi-complex z
))))
295 (setf (gethash '%airy_dbi
*flonum-op
*) #'airy-dbi
)
297 (defun simplim%airy_dbi
(expr var val
)
298 ; Look for the limit of the argument
299 (let ((z (limit (cadr expr
) var val
'think
)))
300 (cond ((eq z
'$inf
) ; A&S 10.4.66
302 ((eq z
'$minf
) ; A&S 10.4.67
305 ; Handle other cases with the function simplifier
306 (simplify (list '(%airy_dbi
) z
))))))
308 (defun airy-dbi-hypergeometric (z)
309 "Returns the hypergeometric representation of Bi'(z), the derivative
311 ;; See http://functions.wolfram.com/03.08.26.0001.01 and
312 ;; https://fungrim.org/entry/4d65e5/.
314 ;; Bi'(z) = Bi'(0)*hypergeometric([],[1/3],z^3/9)
315 ;; + z^2/2*Bi(0)*hypergeometric([],[5/3],z^3/9)
316 (add (mul (ftake '%airy_dbi
0)
317 (ftake '$hypergeometric
319 (list '(mlist) (div 1 3))
324 (ftake '$hypergeometric
326 (list '(mlist) (div 5 3))
330 (def-simplifier airy_dbi
(z)
331 (cond ((equal z
0) ; A&S 10.4.5: Bi'(0) = sqrt(3) 3^(-1/3)/gamma(1/3)
332 (div (mul (power 3 1//2)
333 (power 3 (div -
1 3)))
334 (take '(%gamma
) (div 1 3))))
335 ((flonum-eval (mop form
) z
))
336 ((or (bigfloat-numerical-eval-p z
)
337 (complex-bigfloat-numerical-eval-p z
))
339 ($bfloat
(airy-dbi-hypergeometric z
))))
340 ($hypergeometric_representation
341 (airy-dbi-hypergeometric z
))
344 ;; Numerical routines using slatec functions
346 (defun airy-ai-real (z)
347 " Airy function Ai(z) for real z"
348 (declare (type flonum z
))
349 ;; slatec:dai issues underflow warning for z > zmax. See dai.{f,lisp}
350 ;; This value is correct for IEEE double precision
351 (let ((zmax 92.5747007268))
352 (declare (type flonum zmax
))
353 (if (< z zmax
) (slatec:dai z
) 0.0)))
355 (defun airy-ai-complex (z)
356 "Airy function Ai(z) for complex z"
357 (declare (type (complex flonum
) z
))
358 (multiple-value-bind (var-0 var-1 var-2 var-3 air aii nz ierr
)
359 (slatec:zairy
(realpart z
) (imagpart z
) 0 1 0.0 0.0 0 0)
360 (declare (type flonum air aii
)
361 (type f2cl-lib
:integer4 nz ierr
)
362 (ignore var-0 var-1 var-2 var-3
))
363 ;; Check nz and ierr for errors
364 (if (and (= nz
0) (= ierr
0)) (complex air aii
) nil
)))
366 (defun airy-dai-real (z)
367 "Derivative dAi/dz of Airy function Ai(z) for real z"
368 (declare (type flonum z
))
369 (let ((rz (sqrt (abs z
)))
370 (c (* 2/3 (expt (abs z
) 3/2))))
371 (declare (type flonum rz c
))
372 (multiple-value-bind (var-0 var-1 var-2 ai dai
)
373 (slatec:djairy z rz c
0.0 0.0)
374 (declare (ignore var-0 var-1 var-2 ai
))
377 (defun airy-dai-complex (z)
378 "Derivative dAi/dz of Airy function Ai(z) for complex z"
379 (declare (type (complex flonum
) z
))
380 (multiple-value-bind (var-0 var-1 var-2 var-3 air aii nz ierr
)
381 (slatec:zairy
(realpart z
) (imagpart z
) 1 1 0.0 0.0 0 0)
382 (declare (type flonum air aii
)
383 (type f2cl-lib
:integer4 nz ierr
)
384 (ignore var-0 var-1 var-2 var-3
))
385 ;; Check nz and ierr for errors
386 (if (and (= nz
0) (= ierr
0)) (complex air aii
) nil
)))
388 (defun airy-bi-real (z)
389 "Airy function Bi(z) for real z"
390 (declare (type flonum z
))
391 ;; slatec:dbi issues overflows for z > zmax. See dbi.{f,lisp}
392 ;; This value is correct for IEEE double precision
393 (let ((zmax 104.2179765192136))
394 (declare (type flonum zmax
))
395 (if (< z zmax
) (slatec:dbi z
) nil
)))
397 (defun airy-bi-complex (z)
398 "Airy function Bi(z) for complex z"
399 (declare (type (complex flonum
) z
))
400 (multiple-value-bind (var-0 var-1 var-2 var-3 bir bii ierr
)
401 (slatec:zbiry
(realpart z
) (imagpart z
) 0 1 0.0 0.0 0)
402 (declare (type flonum bir bii
)
403 (type f2cl-lib
:integer4 ierr
)
404 (ignore var-0 var-1 var-2 var-3
))
405 ;; Check ierr for errors
406 (if (= ierr
0) (complex bir bii
) nil
)))
408 (defun airy-dbi-real (z)
409 "Derivative dBi/dz of Airy function Bi(z) for real z"
410 (declare (type flonum z
))
411 ;; Overflows for z > zmax.
412 ;; This value is correct for IEEE double precision
413 (let ((zmax 104.1525))
414 (declare (type flonum zmax
))
416 (let ((rz (sqrt (abs z
)))
417 (c (* 2/3 (expt (abs z
) 3/2))))
418 (declare (type flonum rz c
))
419 (multiple-value-bind (var-0 var-1 var-2 bi dbi
)
420 (slatec:dyairy z rz c
0.0 0.0)
421 (declare (type flonum bi dbi
)
422 (ignore var-0 var-1 var-2 bi
))
424 ;; Will overflow. Return unevaluated.
427 (defun airy-dbi-complex (z)
428 "Derivative dBi/dz of Airy function Bi(z) for complex z"
429 (declare (type (complex flonum
) z
))
430 (multiple-value-bind (var-0 var-1 var-2 var-3 bir bii ierr
)
431 (slatec:zbiry
(realpart z
) (imagpart z
) 1 1 0.0 0.0 0)
432 (declare (type flonum bir bii
)
433 (type f2cl-lib
:integer4 ierr
)
434 (ignore var-0 var-1 var-2 var-3
))
435 ;; Check ierr for errors
436 (if (= ierr
0) (complex bir bii
) nil
)))