1 ;; Copyright 2009 by Barton Willis
3 ;; This is free software; you can redistribute it and/or
4 ;; modify it under the terms of the GNU General Public License,
5 ;; http://www.gnu.org/copyleft/gpl.html.
7 ;; This software has NO WARRANTY, not even the implied warranty of
8 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 (if (not (mget '$hypergeometric_simp
'mexpr
)) ($load
"hypergeometric_mac.mac"))
13 (if (not (mget '$abramowitz_id
'mexpr
)) ($load
"abramowitz_id.mac"))
14 (if (not (functionp 'simp-nfloat
)) ($load
"nfloat"))
16 ;; mea culpa---for numerical evaluation of the hypergeometric functions, the
17 ;; method uses a running error. When the error is too large, the value of fpprec
18 ;; is increased and the evaluation is redone with the larger value of fpprec.
19 ;; The option variable max_fpprec is the largest value for fpprec Maxima will try.
21 (defmvar $max_fpprec
1000)
23 (setf (get '$max_fpprec
'assign
)
26 (if (not (and (atom b
) (integerp b
)))
28 (mtell "The value of `max_fpprec' must be an integer.~%")
31 (defmvar $expand_hypergeometric nil
)
33 (setf (get '$expand_hypergeometric
'assign
)
36 (if (not (or (eq b nil
) (eq b t
)))
38 (mtell "The value of `expand_hypergeometric' must be either true or false.~%")
41 ;; If the length of l is n, return true; otherwise signal wna-err = (wrong number of arguments, by the way).
43 (defun argument-length-check (l n
)
44 (if (and (consp l
) (consp (first l
)) (equal n
(length (margs l
)))) t
(wna-err (caar l
))))
46 ;; When multiple_value_return is nil, multiple_values(e1,e2,...) --> e1; otherwise
47 ;; multiple_values(e1,e2,...) --> multiple_values(e1,e2,...).
49 (setf (get '$multiple_values
'operators
) 'simp-multiple-values
)
51 (defmvar $multiple_value_return nil
)
53 (defun simp-multiple-values (e yy z
)
55 (if $multiple_value_return
56 `(($multiple_values simp
) ,@(mapcar #'(lambda (s) (simpcheck s z
)) (cdr e
)))
57 (simpcheck (cadr e
) z
)))
59 ;; Detect undefined and polynomial cases.
61 (defun classify-hypergeometric (a b x
)
62 (let ((ah nil
) (bh nil
))
64 ;; Let bh = the least member of b that is a negative integer. If there is
65 ;; no such member, set bh = nil.
68 (if (and (integerp bk
) (<= bk
0) (or (eq bh nil
) (< bk bh
))) (setq bh bk
)))
70 ;; Let ah = the greatest member of a that is a negative integer. If there is
71 ;; no such member, set ah = nil.
74 (if (and (integerp ak
) (<= ak
0) (or (eq ah nil
) (> ak ah
))) (setq ah ak
)))
76 ;; Undefined when either (1) ah is nil and bh is non-nil or (2) ah and bh are
77 ;; non-nil and ah >= bh, and each member of a and b are numbers. (We don't
78 ;; want hypergeometric([a],[-3],x) to be undefined, do we?). I suppose this
79 ;; function could look for declared integers...
81 (cond ((and (every '$numberp a
)
83 (or (and (not ah
) bh
) (and ah bh
(>= bh ah
)))) 'undefined
)
85 ((or ah
(zerop1 ($ratdisrep x
))
86 (and ($taylorp x
) (eql 0 ($second
($first
($taylorinfo x
))))
87 (integerp ($third
($first
($taylorinfo x
))))))
92 ;; The function simpcheck changes taylor polynomials to general form--that messes
93 ;; it harder to taylorize hypergeometrics (things like hypergeometric([5],[], taylor(x,x,0,3)) -->
94 ;; a taylor polynomial. So use tsimpcheck: if e is a taylor polynomial, simplify; otherwise, simpcheck.
96 (defun tsimpcheck (e z
)
97 (if (or ($taylorp e
) ($ratp e
)) (simplifya e z
) (simpcheck e z
)))
99 ;; We don't want realpart and imagpart to think that hypergeometric functions are
100 ;; real valued. So declare hypergeometric to be complex.
104 #-gcl
(:load-toplevel
:execute
)
105 (let (($context
'$global
) (context '$global
))
106 (meval '(($declare
) $hypergeometric $complex
))))
108 (setf (get '$hypergeometric
'conjugate-function
) 'conjugate-hypergeometric
)
110 ;; hypergeometric(a,b,x) is entire (commutes with conjugate) when length(a) < length(b) + 1. Also
111 ;; hypergeometric(a,b,x) is analytic inside the unit disk. Outside the unit disk, we need to be careful;
112 ;; for now, conjugate gives a nounform in this case. I suppose we could check for declared negative integer
113 ;; parameter in the list a...I'll wait for a user to request this feature :)
115 (defun conjugate-hypergeometric (l)
116 (let ((a (first l
)) (b (second l
)) (x (third l
)))
117 (cond ((or (< ($length a
) (+ 1 ($length b
))) (eq t
(mgrp 1 (take '(mabs) x
))))
118 (take '($hypergeometric
) (take '($conjugate
) a
) (take '($conjugate
) b
) (take '($conjugate
) x
)))
119 (t `(($conjugate simp
) (($hypergeometric
) ,a
,b
,x
))))))
121 (defun lenient-complex-p (e)
122 (and ($freeof
'$infinity
'$und
'$ind
'$inf
'$minf
'$false
'$true t nil e
) ;; what else?
124 (not ($featurep e
'$nonscalarp
))
126 (not ($member e $arrays
))))
128 (defprop $hypergeometric simp-hypergeometric operators
)
130 ;; Do noncontroversial simplifications on the hypergeometric function. A user that
131 ;; wants additional simplifications can use $hypergeometric_simp. The simplifications are
133 ;; (a) hypergeometric([], [], x) --> exp(x),
135 ;; (b) hypergeometric([a], [], x) --> 1 / (1 - x)^a,
137 ;; (c) hypergeometric([a1,...], [b1, ...], 0) --> 1,
139 ;; (d) hypergeometric([-n,...], [b1, ...], x) --> polynomial.
141 ;; (d) sort and delete common parameters; for example
142 ;; hypergeometric([p,b,a],[c,b],x) --> hypergeometric([a,p],[c],x).
144 ;; (e) hypergeometric([0,a1, ... ], [b1, ...], x) --> 1.
146 ;; Why does this code do (take '(mlist) a) instead of (cons '(mlist) a)? Because
147 ;; (cons '(mlist) a) messes up tellsimp rules. Say tellsimp([a], a]). Then
148 ;; (take (mlist) a) --> a, but (cons '(mlist) a) --> ((mlist) a). And that's not correct.
150 (defun simp-hypergeometric (e yy z
)
151 (declare (ignore yy
))
152 (argument-length-check e
3)
153 (let ((a (second e
)) (b (third e
)) (x (fourth e
)) (l nil
) (a-len) (b-len)
154 (hg-type nil
) (dig) (return-type) ($domain
'$complex
))
156 (cond ((or (not ($listp a
)) (not ($listp b
)))
157 (mtell "warning: The first two arguments to 'hypergeometric' must be lists.~%")
158 `(($hypergeometric simp
) ,(tsimpcheck a z
) ,(tsimpcheck b z
) ,(tsimpcheck x z
)))
161 (setq a
(mapcar #'(lambda (s) (tsimpcheck s z
)) (margs a
))
162 b
(mapcar #'(lambda (s) (tsimpcheck s z
)) (margs b
))
165 ;; Delete common members of a and b. This code is taken from hyp.lisp.
167 (setq l
(zl-intersection a b
))
171 ;; Check for undefined cases
172 (setq hg-type
(classify-hypergeometric a b x
))
174 (setq a-len
(length a
))
175 (setq b-len
(length b
))
177 ;; Sort a and b and reconvert to Maxima lists.
179 (setq a
(sort a
'$orderlessp
))
180 (setq b
(sort b
'$orderlessp
))
181 (setq a
(simplify (cons '(mlist) a
)))
182 (setq b
(simplify (cons '(mlist) b
)))
184 ;; If constantp(x), apply rectform to x. For now, multiplication and division
185 ;; of complex numbers doesn't always return a number in rectangular form. Let's
186 ;; apply rectform to constants.
188 (if ($constantp x
) (setq x
($rectform x
)))
191 ;; Catch undefined cases and return a nounform.
192 ((or (eq hg-type
'undefined
)
193 (member-if #'(lambda(s) (not (lenient-complex-p s
))) (cdr a
))
194 (member-if #'(lambda(s) (not (lenient-complex-p s
))) (cdr b
))
195 (not (lenient-complex-p x
)))
196 `(($hypergeometric simp
) ,a
,b
,x
))
198 ;; pFq([a1,...,ap], [b1,...,bq], 0) --> 1 + 0
199 ((zerop1 x
) (add 1 x
))
201 ;; pFq([0,a1,...,ap], [b1,...,bq], x) --> 1
202 ((member-if 'zerop1
(margs a
)) 1)
204 ;; Do hypergeometric([],[],x) --> exp(x). All numerical evaluation is funneled through
205 ;; the same entry point; the function hypergeometric-0f0 doesn't do numerical evaluation.
206 ((and (= 0 a-len
) (= 0 b-len
) (hypergeometric-0f0 x
)))
208 ;; Do hypergeometric([a],[],x) --> 1 / (1-x)^a.
209 ((and (= a-len
1) (= 0 b-len
) (hypergeometric-1f0 (second a
) x
)))
211 ;; Try reflection identity for 1F1.
212 ((and (= a-len
1) (= b-len
1) (hypergeometric-1f1 (second a
) (second b
) x hg-type
)))
214 ;; For 2F1, value at 1--nothing else.
215 ((and (= a-len
2) (= b-len
1) (hypergeometric-2f1 (second a
) (third a
) (second b
) x
)))
217 ;; Try numerical evaluation; return nil on failure. This should handle IEEE float,
218 ;; IEEE complex float, bigfloat, and complex big float cases.
219 ((and (setq return-type
(use-float-hypergeometric-numerical-eval (margs a
) (margs b
) x
))
220 (setq dig
(ceiling (* (if (eq return-type
'float
) (float-digits 1.0) fpprec
)
221 #.
(/ (log 2) (log 10)))))
222 (hypergeometric-float-eval (margs a
) (margs b
) x dig return-type
)))
224 ;; Try rational number numerical evaluation; return nil on failure. This should handle
225 ;; rational and complex rational numerical evaluation.
226 ((use-rational-hypergeometric-numerical-eval (margs a
) (margs b
) x
)
227 (rational-hypergeometric-numerical-eval (margs a
) (margs b
) x
))
229 ;; Handle all other polynomial cases; this includes the case that
230 ;; x is a Taylor polynomial centered at zero.
231 ((hypergeometric-poly-case (margs a
) (margs b
) x
))
233 ;; Return a nounform.
234 (t `(($hypergeometric simp
) ,a
,b
,x
)))))))
236 ;; When x isn't a float, do 0F0([],[],x) --> exp(x).
237 (defun hypergeometric-0f0 (x)
238 (if (use-float-hypergeometric-numerical-eval nil nil x
) nil
(take '(mexpt) '$%e x
)))
240 ;; When a or x aren't floats, do 1F0([a],[],x) --> 1/(1-x)^a.
241 (defun hypergeometric-1f0 (a x
)
242 (cond ((use-float-hypergeometric-numerical-eval (list a
) nil x
) nil
)
244 (if (eq t
(mgrp 0 a
)) 0 nil
))
245 (t (div 1 (take '(mexpt) (sub 1 x
) a
)))))
247 ;; Apply the Kummer reflection identity when b-a is a negative integer and we know that
248 ;; the hypergeometric function is not already known to be a polynomial (that is a is not a
249 ;; negative integer) or when (great (neg x) x); otherwise, return nil. This function
250 ;; doesn't do floating point evaluation.
252 (defun hypergeometric-1f1 (a b x hg-type
)
253 (cond ((use-float-hypergeometric-numerical-eval (list a
) (list b
) x
) nil
)
254 ((or (and (not (eq hg-type
'polynomial
)) (great (neg x
) x
))
255 (and (not (eq hg-type
'polynomial
)) (integerp (sub b a
)) (< (sub b a
) 0)))
256 (mul (take '(mexpt) '$%e x
)
257 (take '($hypergeometric
) (take '(mlist) (sub b a
)) (take '(mlist) b
) (neg x
))))
260 ;; Coerce x to the number type of z. The Maxima function safe_float returns a bigfloat when
261 ;; conversion to a float fails (overflow, for example).
262 (defun number-coerce (x z
)
263 (cond ((complex-number-p z
'$bfloatp
)
265 ((complex-number-p z
'floatp
)
266 (mfuncall '$safe_float x
))
269 ;; 2F1(a,b;c, x) --> gamma(c) gamma(c - a - b) / (gamma(c-a) gamma (c-b))
270 ;; (Chu-Vandermonde identity, A & S 15.1.20) provided real_part(c-a-b) > 0 and c # 0,-1,-2, ...
271 ;; The c = 0, -1, -2, ... case should be caught previously. If we wanted to be super careful, we'd
272 ;; demand explicitly that c isn't a negative integer.
274 (defun hypergeometric-2f1 (a b c x
)
276 (setq z
(sub c
(add a b
)))
277 (cond ((and (onep1 x
) (complex-number-p z
'$numberp
) (eq t
(mgrp ($realpart z
) 0)))
280 (mul (take '(%gamma
) c
) (take '(%gamma
) z
))
281 (mul (take '(%gamma
) (sub c a
)) (take '(%gamma
) (sub c b
))))
287 ;; For numerical evaluation of a general hypergeometric function, there aren't many
288 ;; alternatives to power series summation.
290 ;; Pursuant to well-established Maxima coding practices :), bigfloat
291 ;; functions receive bigfloat arguments and return bigfloat values.
293 (in-package #-gcl
#:bigfloat
#+gcl
"BIGFLOAT")
295 ;(import 'maxima::while) ;; <--- broken Why?
297 (defmacro while
(cond &rest body
)
302 (defun 0f0-numeric (x)
305 (defun 1f0-numeric (a x
)
306 (/ 1 (expt (- 1 x
) a
)))
309 (bigfloat (maxima::$bfloat
(maxima::take
'(maxima::%gamma
) (maxima::to x
)))))
311 ;; This is DLMF: http://dlmf.nist.gov/15.15#E1 with zo = 1/2. Also here is Maxima code that
312 ;; sums the first n+1 terms of the sum. The CL function 2f1-numeric-alt uses a running
313 ;; error and it sums until three consecutive partial sums have a modified relative difference
314 ;; that is bounded by the machine epsilon.
317 ff
(a,b
,c
,x
,n
) := block
([f
, f0
: 1, f1
: 1-
2 * b
/ c
,s
: 1,k
: 1, cf
: a
/ (1-2/x
), z
],
322 cf
: cf
* (a + k
) / ((k + 1) * z
),
323 f
: (k * f0
+ b
* f1
)/(k+c
),
330 (defun 2f1-numeric-alt (a b c x
)
331 (let ((f) (f0 1) (f1 (- 1 (/ (* 2 b
) c
))) (s 1) (ds 1) (k 1) (cf (/ a
(- 1 (/ 2 x
)))) (z) (se 0)
332 (eps (epsilon x
)) (done 0))
333 (setq b
(- c
(* 2 b
)))
334 (setq z
(- 1 (/ 2 x
)))
338 (setq done
(if (< (abs ds
) (* eps
(max 1 (abs s
)))) (+ done
1) 0))
339 (setq se
(+ se
(abs s
) (abs ds
)))
340 (setq cf
(/ (* cf
(+ a k
)) (* (+ 1 k
) z
)))
341 (setq f
(/ (+ (* k f0
) (* b f1
)) (+ k c
)))
345 (values (/ s
(expt (- 1 (/ x
2)) a
)) (* se
(epsilon x
)))))
347 ;; hypergeometric([ma,mb],[mc],mx); prefix m means Maxima expression.
349 (defun 2f1-numeric (ma mb mc mx digits
)
350 (let* ((region) (f) (ff) (er) (local-fpprec digits
) (eps) (mma) (mmb) (mmc) (mmx)
351 (x (bigfloat::to mx
))
352 (d (list (list "none" (abs x
)) ;; region I, inside unit disk
353 (list "15.3.4" (if (= x
1) nil
(abs (/ x
(- x
1)))))
354 (list "15.3.6" (abs (- 1 x
)))
355 (list "15.3.7" (if (zerop x
) nil
(abs (/ 1 x
))))
356 (list "15.3.8" (if (= x
1) nil
(abs (/ 1 (- 1 x
)))))
357 (list "15.3.9" (if (zerop x
) nil
(abs (- 1 (/ 1 x
))))))))
359 (setq d
(delete-if #'(lambda(s) (null (second s
))) d
))
360 ;; Sort d from least to greatest magnitude.
362 (setq d
(sort d
#'(lambda (a b
) (< (second a
) (second b
)))))
363 (setq region
(first (first d
)))
364 ;;(print `(region = ,region))
365 ;;(print `(d = ,(second (first d))))
368 ;; When x = 0, return 1.
371 ;; Use the alternative numerical method when |x| > 0.9; this happens when x is near exp(+/- %i %pi / 3).
373 ((> (second (first d
)) 0.9)
374 (setq eps
(epsilon (bigfloat::to mx
)))
378 (while (> (abs er
) (* eps
(max (abs f
) 1)))
379 (maxima::bind-fpprec local-fpprec
380 (setq mma
(maxima::nfloat ma
`((maxima::mlist
)) local-fpprec maxima
::$max_fpprec
))
381 (setq mmb
(maxima::nfloat mb
`((maxima::mlist
)) local-fpprec maxima
::$max_fpprec
))
382 (setq mmc
(maxima::nfloat mc
`((maxima::mlist
)) local-fpprec maxima
::$max_fpprec
))
383 (setq mmx
(maxima::nfloat mx
`((maxima::mlist
)) local-fpprec maxima
::$max_fpprec
))
384 (multiple-value-setq (f er
)
386 (bigfloat::to mma
) (bigfloat::to mmb
) (bigfloat:to mmc
) (bigfloat::to mmx
)))
387 (setq local-fpprec
(* 2 local-fpprec
))))
390 ;; ma or mb negative integers--that causes trouble for most of the A&S 15.3.4--15.3.9
391 ;; transformations--let's quickly dispatch hypergeometric-float-eval; also dispatch
392 ;; hypergeometric-float-eval when the tranformation is "none" (with adjust-parameters
395 ((or (equal region
"none") (and (integerp ma
) (<= ma
0)) (and (integerp mb
) (<= mb
0))
397 (hypergeometric-float-eval (list ma mb
) (list mc
) mx digits nil
))
399 ;; The case of a,b, and c integers causes trouble; let's dispatch hgfred on it.
400 ((and (integerp ma
) (integerp mb
) (integerp mc
))
401 (setq f
(maxima::$hgfred
(maxima::take
'(maxima::mlist
) ma mb
)
402 (maxima::take
'(maxima::mlist
) mc
) 'maxima
::z
))
403 (setq f
(maxima::$horner f
'maxima
::z
))
405 (multiple-value-setq (f d
)
406 (maxima::nfloat f
`((maxima::mlist
) ((maxima::mequal
) maxima
::z
,mx
)) digits maxima
::$max_fpprec
))
407 (values (bigfloat f
) (bigfloat d
))))
410 (let ((maxima::$multiple_value_return t
))
411 (setq ff
`((maxima::$hypergeometric maxima
::simp
)
412 ((maxima::mlist maxima
::simp
) ,ma
,mb
)
413 ((maxima::mlist maxima
::simp
) ,mc
) maxima
::z
))
416 (setq f
(if (equal region
"none")
417 `((maxima::multiple_values
) ,ff t
)
418 (maxima::mfuncall
'maxima
::$abramowitz_id ff region
)))
419 (if (maxima::$second f
)
420 (setq d nil f
(maxima::$first f
)) (setq region
(first (pop d
)))))
423 ;;(maxima::displa `((maxima::mequal) maxima::z ,mx))
424 (setq f
(multiple-value-list
425 (maxima::nfloat f
`((maxima::mlist
) ((maxima::mequal
) maxima
::z
,mx
))
426 digits maxima
::$max_fpprec
)))
427 (values (bigfloat::to
(first f
)) (bigfloat::to
(second f
))))))))
429 ;; Let a = (a1, a2, ..., am) and b = (b1, b2, ..., bn). Approximate sum(c(k) x^k / k!,k,1,inf),
430 ;; where c(k + 1) / c(k) = (a1 + k) (a2 + k) ... (am + k) / (b1 + k) (b2 + k) ... (bn + k).
432 (defun hypergeometric-by-series (a b x
)
433 ;; es = running error for e and ez running error for z.
435 (let ((s 0) (s0 1) (k 0) (z 1) (es 0) (ez 1) (n) (p) (q) (stop 20000) (dig))
436 (setq n
(* 2 (+ (length a
) (length b
) 1)))
437 (while (and (< k stop
) (/= s s0
)) ;; (not (= s s0)))
439 (setq p
(reduce #'* (mapcar #'(lambda (s) (+ s k
)) a
))) ;; p adds and p-1 multiplications
440 (setq q
(reduce #'* (mapcar #'(lambda (s) (+ s k
)) b
))) ;; q adds and q-1 multiplications
442 (setq z
(* z
(/ (* p x
) (* q k
))))
443 ;;(setq ez (+ (* n (abs z)) ez))
444 (setq ez
(+ (* (abs (/ (* x p
) (* q k
))) ez
) (* (abs z
) n
)))
446 (setq es
(+ es ez
(abs s0
))))
449 (if (>= k stop
) (values nil nil
)
451 ;; estimate number of correct digits:
455 (- (log (max (abs s
) (epsilon x
))) (log (* es
(epsilon x
))))
456 #.
(/ (log 2) (log 10)))))
458 ;;(print "-----------")
459 ;;(maxima::displa `((maxima::mequal) k ,k))
460 ;;(maxima::displa `((maxima::mequal) xxx ,(maxima::to (epsilon x))))
461 ;;(maxima::displa `((maxima::mequal) es ,(maxima::$float (maxima::to es))))
462 ;;(maxima::displa `((maxima::mequal) s ,(maxima::$float (maxima::to s))))
463 ;;(maxima::displa `((maxima::mequal) dig ,(maxima::$float (maxima::to dig))))
466 (defun hypergeometric-poly-case (a b x
)
467 (let ((z 1) (s 1) (k 0) (p) (q))
468 (while (not (zerop z
))
469 (setq p
(reduce #'* (mapcar #'(lambda (s) (+ s k
)) a
)))
470 (setq q
(reduce #'* (mapcar #'(lambda (s) (+ s k
)) b
)))
472 (setq z
(/ (* p x z
) (* q k
)))
476 ;; This function numerically evaluates pFq([a1,...,ap], [b1,....bq], x), where all the arguments
477 ;; are Maxima expressions, not bigfloat objects.
479 (defun hypergeometric-float-eval (ma mb mx digits
&optional
(adjust-params t
))
480 (let ((a-len (length ma
)) (b-len (length mb
)) (f nil
) (local-fpprec maxima
::$fpprec
) (d) (a) (b) (x))
482 ;(maxima::displa `((maxima::mlist) ,@ma))
483 ;(maxima::displa `((maxima::mlist) ,@mb))
484 ;(maxima::displa `((maxima::mlist) ,mx))
485 (setq a
(mapcar #'bigfloat
::to ma
))
486 (setq b
(mapcar #'bigfloat
::to mb
))
487 (setq x
(bigfloat::to mx
))
489 ;; Special case 0f0, 1f0, 2f1 for |x| > 1, and pfq for |x| > 1 and p >= q + 1.
490 ;; For a general hypergeometric, I don't know how to analytically continue, so in the last case,
493 ;; In the general case, sum the hypergeometric series using a running error, recursing
494 ;; on local-fpprec; bailout when local-fpprec exceeds 1000.
496 (cond ((and (eql a-len
0) (eql b-len
0)) ;; special case 0f0
497 (values (0f0-numeric x
) digits
))
499 ((and (eql a-len
1) (eql b-len
0)) ;; special case 1f0
500 (values (1f0-numeric (first a
) x
) digits
))
502 ((and (eql a-len
1) (integerp (first a
)) (< (first a
) 0) (eql b-len
1)) ;; special case 1f1
503 (maxima::bind-fpprec local-fpprec
504 (multiple-value-setq (f d
) (1f1-downward-recursion (first a
) (first b
) x
)))
507 ;; Optionally do Kummer transformation--when is the Kummer transformation advantageous?
508 ;; I think the sum is ill-conditioned when realpart(x) < 0. Since x is a float, realpart
511 ;; The adjust-params argument should prevent an infinite loop (transform --> untransform ...)
512 ;; In this case, an infinite loop shouldn't happen even without the adjust-param scheme.
520 (multiple-value-setq (f d
) (hypergeometric-float-eval
521 (list (maxima::sub
(car mb
) (car ma
)))
522 mb
(maxima::neg mx
) digits nil
))
523 (values (* (exp x
) f
) d
)))
525 ;; analytic continuation for 2f1;
526 ((and (eql a-len
2) (eql b-len
1) adjust-params
)
527 (2f1-numeric (car ma
) (cadr ma
) (car mb
) mx digits
))
529 ((or (< a-len
(+ b-len
1)) (in-unit-circle-p x
) (eq 'maxima
::polynomial
530 (maxima::classify-hypergeometric ma mb mx
)))
532 ;; recurse on local-fpprec; bailout when local-fpprec exceeds $max_fpprec.
534 (while (and (or (null f
) (< d digits
)) (< local-fpprec maxima
::$max_fpprec
))
535 (maxima::bind-fpprec local-fpprec
536 (multiple-value-setq (f d
) (hypergeometric-by-series a b x
))
537 (setq a
(mapcar #'(lambda (s) (bigfloat::to
(maxima::$bfloat s
))) ma
))
538 (setq b
(mapcar #'(lambda (s) (bigfloat::to
(maxima::$bfloat s
))) mb
))
539 (setq x
(bigfloat::to
(maxima::$bfloat mx
)))
540 ;(print "----------")
541 ;(print `(fpprec = ,local-fpprec))
543 ;(print `(digits = ,digits))
544 ;(incf local-fpprec (+ (- digits d) 10))))
545 (setq local-fpprec
(* 2 local-fpprec
))))
547 (if (>= local-fpprec maxima
::$max_fpprec
)
549 (maxima::mtell
"Exceeded maximum allowed fpprec.~%")
553 (defun in-unit-circle-p (x)
556 ;; Compute f11(a,b,x) using downward recursion (A&S 13.4.1). The first argument must be a negative integer:
558 ;; f <-- (k * fo + (2 * k + x) * fm1)/(b-k)
561 ;; I think this is faster than the power series summation--it might be useful for orthogonal polynomials.
562 (defun 1f1-downward-recursion (a b x
)
563 (let ((fo 1) (fm1 (- 1 (/ x b
))) (f) (k -
1) (efo 0) (efm1 0) (ef 0))
564 (declare (type fixnum k
))
566 (cond ((eql a
0) (values fo
0))
567 ((eql a -
1) (values fm1
0))
571 (setq f
(/ (- (* k fo
) (* (+ (* 2 k
) x
) fm1
)) (- b k
)))
575 (* (abs (+ (* 2 k
) x
))) (+ efm1
(* 2 fm1
))
589 (defun float-or-bigfloat-p (x)
590 (or (floatp x
) ($bfloatp x
)))
592 (defun float-or-rational-p (x)
593 (or (floatp x
) ($ratnump x
)))
595 ;; Return true iff it is possible to evaluate hypergeometric(a,b,x) using (exact)
596 ;; rational arithmetic. Thus (1) x and every member of a and b (Common Lisp lists) must be
597 ;; a $ratnump and (2) some member of a must be an explicit negative integer. When $numer
598 ;; is true, never do exact rational evaluation? (Likely when $numer is true, we'll never
601 (defun use-rational-hypergeometric-numerical-eval (a b x
)
603 (complex-number-p x
'$ratnump
)
604 (every #'(lambda (s) (complex-number-p s
'$ratnump
)) a
)
605 (every #'(lambda (s) (complex-number-p s
'$ratnump
)) b
)
606 (some #'(lambda (s) (and (integerp s
) (< s
0))) a
)))
608 ;; Evaluate hypergeometric(a,b,x) using (exact) rational arithmetic. Here a
609 ;; and b are Common Lisp lists. Don't call this function without first
610 ;; checking that use-rational-hypergeometric-numerical-eval returns true.
611 ;; These are all polynomial cases, so we don't need any analytic continuations.
613 (defun rational-hypergeometric-numerical-eval (a b x
)
614 (setq a
(mapcar #'(lambda (s) (bigfloat::to s
)) a
))
615 (setq b
(mapcar #'(lambda (s) (bigfloat::to s
)) b
))
616 (setq x
(bigfloat::to x
))
617 (maxima::to
(bigfloat::hypergeometric-poly-case a b x
)))
619 ;; Return float if hypergeometric(a,b,x) should evaluate to a double float (real or
620 ;; complex; return bigfloat if it should evaluate to a bigfloat (real or complex); otherwise
623 (defun use-float-hypergeometric-numerical-eval (a b x
)
625 ;; float, complex float, bigfloat, and complex bigfloat; this is a great deal of
626 ;; stuff to check. When $numer is true, everybody must be a $numberp for numerical
627 ;; evaluation; when numer is false, everybody must be a $numberp and somebody must
630 (if (and (every #'(lambda (s) (complex-number-p s
'$numberp
)) a
)
631 (every #'(lambda (s) (complex-number-p s
'$numberp
)) b
)
632 (complex-number-p x
'$numberp
)
635 (not (every #'(lambda (s) (complex-number-p s
'$ratnump
)) a
))
636 (not (every #'(lambda (s) (complex-number-p s
'$ratnump
)) b
))
637 (not (complex-number-p x
'$ratnump
))))
639 ;; When everybody is a float or rational, the return type is float; otherwise bigfloat.
641 (every #'(lambda (s) (complex-number-p s
'float-or-rational-p
)) a
)
642 (every #'(lambda (s) (complex-number-p s
'float-or-rational-p
)) b
)
643 (complex-number-p x
'float-or-rational-p
))
644 'float
'bigfloat
) nil
))
646 ;; Evaluate pFq(a,b,x) using floating point arithmetic. Coerce the returned value
647 ;; to the type described by return-type.
649 ;; When there is a double float overflow, ignore-errors should return nil. After that, we'll
650 ;; try again with a bigfloat.
652 (defun hypergeometric-float-eval (a b z digits return-type
)
654 (multiple-value-setq (x d
) (ignore-errors (bigfloat::hypergeometric-float-eval a b z digits
)))
656 (cond ((and (null x
) (eq return-type
'float
))
658 (hypergeometric-float-eval (mapcar '$bfloat a
)
664 ((or (null x
) (null d
)) nil
)
666 ((eq return-type
'float
)
667 ($float
(maxima::to x
)))
669 ((eq return-type
'bigfloat
)
670 ($bfloat
(maxima::to x
)))
672 ;; Unused hypergeometric-float-eval doesn't return rational
673 ;; ((eq return-type 'rational)
674 ;; ($rationalize (maxima::to x)))
676 ;; This should not happen.
677 (t (maxima::to x
)))))
679 (defun hypergeometric-poly-case (a b x
)
680 (let ((n nil
) (z 1) (s 1) (p) (q) (cf 1))
682 ;; Determine how many terms to sum
683 (cond ((and ($taylorp x
) (eql 0 ($second
($first
($taylorinfo x
))))
684 (integerp ($third
($first
($taylorinfo x
)))))
685 (setq n
($third
($first
($taylorinfo x
)))))
687 ((some #'(lambda (s) (and (integerp s
) (<= s
0))) a
)
689 (if (and (integerp ak
) (< ak
0)) (setq n
(if (null n
) ak
(max n ak
)))))
693 (if ($ratp x
) (setq s
($rat
1) z
($rat
1)))
695 ;; Expand to a polynomial when n is an integer and either
696 ;; (1) x and each member of a and b are complex numbers,
697 ;; (2) n < $expop or $expand_hypergeometric
698 ;; (3) x is a CRE expression.
700 (if (and (integerp n
) (or (and (complex-number-p x
'$numberp
)
701 (every #'(lambda (s) (complex-number-p s
'$numberp
)) a
)
702 (every #'(lambda (s) (complex-number-p s
'$numberp
)) b
))
703 (or $expand_hypergeometric
(< n $expop
))
706 (setq p
(reduce #'mul
(mapcar #'(lambda (s) (add s k
)) a
)))
707 (setq q
(reduce #'mul
(mapcar #'(lambda (s) (add s k
)) b
)))
709 ;; sigh..Maxima should (I think) return a rectangular form for
710 ;; complex number multiplication and division. But it doesn't. If
711 ;; that changes, delete the next two lines.
713 (setq cf
(mul cf
(div p
(mul q
(+ k
1)))))
714 (if ($constantp cf
) (setq cf
($rectform cf
)))
716 (setq s
(add s
(mul cf z
))))
720 (defun diff-hypergeometric (a b z x
)
721 (cond ((and ($freeof x a
) ($freeof x b
))
724 (let ((p (reduce #'mul a
))
725 (q (reduce #'mul b
)))
726 (setq a
(simplify (cons '(mlist) (mapcar #'(lambda (s) (add 1 s
)) a
))))
727 (setq b
(simplify (cons '(mlist) (mapcar #'(lambda (s) (add 1 s
)) b
))))
728 (mul ($diff z x
) p
(div 1 q
) (take '($hypergeometric
) a b z
))))
729 (t (merror "Maxima does not know the derivatives of the hypergeometric functions with respect to the parameters"))))
732 ;; TeX hypergeometric([a],[b,c],x) as $$F\left( \begin{bmatrix}a\\b\;\,c\end{bmatrix} ,x\right)$$
733 ;; For no good reason, I'm not so fond of pFq notation. Some newer references don't use
736 (defprop $hypergeometric tex-hypergeometric tex
)
738 (defun tex-hypergeometric (x l r
)
739 (let ((p) (q) (wide-space ",\\;"))
740 (setq p
(tex-list (margs (cadr x
)) nil nil wide-space
))
741 (setq q
(tex-list (margs (caddr x
)) nil nil wide-space
))
742 (setq p
`(,@l
"F\\left( \\left. \\begin{array}{c}" ,@p
"\\\\" ,@q
"\\end{array} \\right |,"))
743 (tex (fourth x
) p
`("\\right)" ,@r
) 'mparen
'mparen
)))
745 ;; Integral of hypergeometric(a,b,z)
747 ;; Integrals and Series: Volume 3, More Special Functions
748 ;; Prudnikov, A. P., Brychkov, Yu A., Gould, G. G., Marichev, O.I.
752 ;; I pFq((a_p);(b_q);c z) dz
756 ;; = z (p+1)F(q+1)((a_p),1;(b_q),2;c z) 1.16.1.2
758 ;; product((b_q - 1))
759 ;; = ------------------ pFq((a_p)-1; (b_q)-1; c z) 1.16.1.3
760 ;; product((a_p - 1))
762 (defun hyp-integral-3 (a b z
)
763 "Integral of hypergeometric(a,b,z) wrt z"
764 (let* (($listarith t
)
767 (prod_b-1 (reduce #'mul
(margs b-1
)))
768 (prod_a-1 (reduce #'mul
(margs a-1
))))
770 (mul z
(take '($hypergeometric
) (append a
'(1)) (append b
'(2)) z
))
771 (mul prod_b-1
(inv prod_a-1
) (take '($hypergeometric
) a-1 b-1 z
)))))
773 (putprop '$hypergeometric
`((a b z
) nil nil
,#'hyp-integral-3
) 'integral
)