1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;; Double Factorial, Incomplete Gamma function, ...
5 ;;; This file will be extended with further functions related to the
6 ;;; Factorial and Gamma functions.
8 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
10 ;;; This file contains the following Maxima User functions:
12 ;;; double_factorial(z)
14 ;;; gamma_incomplete(a,z)
15 ;;; gamma_incomplete_generalized(a,z1,z2)
16 ;;; gamma_incomplete_regularized(a,z)
23 ;;; erf_generalized(z1,z2)
31 ;;; beta_incomplete(a,b,z)
32 ;;; beta_incomplete_generalized(a,b,z1,z2)
33 ;;; beta_incomplete_regularized(a,b,z)
35 ;;; Maxima User variable:
37 ;;; $factorial_expand - Allows argument simplificaton for expressions like
38 ;;; double_factorial(n-1) and double_factorial(2*k+n)
39 ;;; $beta_expand - Switch on further expansions for the Beta functions
41 ;;; $erf_representation - When T erfc, erfi, erf_generalized, fresnel_s
42 ;;; and fresnel_c are transformed to erf.
43 ;;; $erf_%iargs - Enable simplification of Erf and Erfi for
44 ;;; imaginary arguments
45 ;;; $hypergeometric_representation
46 ;;; - Enables transformation to a Hypergeometric
47 ;;; representation for fresnel_s and fresnel_c
49 ;;; Maxima User variable (not definied in this file):
51 ;;; $factlim - biggest integer for numerically evaluation
52 ;;; of the Double factorial
53 ;;; $gamma_expand - Expansion of the Gamma und Incomplete Gamma
54 ;;; function for some special cases
56 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
57 ;;; This library is free software; you can redistribute it and/or modify it
58 ;;; under the terms of the GNU General Public License as published by the
59 ;;; Free Software Foundation; either version 2 of the License, or (at
60 ;;; your option) any later version.
62 ;;; This library is distributed in the hope that it will be useful, but
63 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
64 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
65 ;;; Library General Public License for more details.
67 ;;; You should have received a copy of the GNU General Public License along
68 ;;; with this library; if not, write to the Free Software
69 ;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
71 ;;; Copyright (C) 2008 Dieter Kaiser
72 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
76 (declare-top (special $factlim $gamma_expand
))
78 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
80 (defmvar $factorial_expand nil
)
81 (defmvar $beta_expand nil
)
83 (defmvar $erf_representation nil
84 "When T erfc, erfi and erf_generalized are transformed to erf.")
86 (defmvar $erf_%iargs nil
87 "When T erf and erfi simplifies for an imaginary argument.")
89 (defmvar $hypergeometric_representation nil
90 "When T a transformation to a hypergeometric representation is done.")
92 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
93 ;;; The following functions test if numerical evaluation has to be done.
94 ;;; The functions should help to test for numerical evaluation more consitent
95 ;;; and without complicated conditional tests including more than one or two
98 ;;; The functions take a list of arguments. All arguments have to be a CL or
99 ;;; Maxima number. If all arguments are numbers we have two cases:
100 ;;; 1. $numer is T we return T. The function has to be evaluated numerically.
101 ;;; 2. One of the args is a float or a bigfloat. Evaluate numerically.
102 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
104 ;;; Test for numerically evaluation in float precision
106 (defun float-numerical-eval-p (&rest args
)
109 (when (not (float-or-rational-p ll
))
110 (return-from float-numerical-eval-p nil
))
111 (when (floatp ll
) (setq flag t
)))
112 (if (or $numer flag
) t nil
)))
114 ;;; Test for numerically evaluation in complex float precision
116 (defun complex-float-numerical-eval-p (&rest args
)
117 "Determine if ARGS consists of numerical values by determining if
118 the real and imaginary parts of each arg are nuemrical (but not
119 bigfloats). A non-NIL result is returned if at least one of args is
120 a floating-point value or if numer is true. If the result is
121 non-NIL, it is a list of the arguments reduced via rectform"
124 (destructuring-bind (rll . ill
)
126 (unless (and (float-or-rational-p rll
)
127 (float-or-rational-p ill
))
128 (return-from complex-float-numerical-eval-p nil
))
129 ;; Always save the result from trisplit. But for backward
130 ;; compatibility, only set the flag if any item is a float.
131 (push (add rll
(mul ill
'$%i
)) values
)
132 (setf flag
(or flag
(or (floatp rll
) (floatp ill
))))))
133 (when (or $numer flag
)
134 ;; Return the values in the same order as the args!
137 ;;; Test for numerically evaluation in bigfloat precision
139 (defun bigfloat-numerical-eval-p (&rest args
)
142 (when (not (bigfloat-or-number-p ll
))
143 (return-from bigfloat-numerical-eval-p nil
))
146 (if (or $numer flag
) t nil
)))
148 ;;; Test for numerically evaluation in complex bigfloat precision
150 (defun complex-bigfloat-numerical-eval-p (&rest args
)
151 "Determine if ARGS consists of numerical values by determining if
152 the real and imaginary parts of each arg are nuemrical (including
153 bigfloats). A non-NIL result is returned if at least one of args is
154 a floating-point value or if numer is true. If the result is
155 non-NIL, it is a list of the arguments reduced via rectform."
159 (destructuring-bind (rll . ill
)
161 (unless (and (bigfloat-or-number-p rll
)
162 (bigfloat-or-number-p ill
))
163 (return-from complex-bigfloat-numerical-eval-p nil
))
164 ;; Always save the result from trisplit. But for backward
165 ;; compatibility, only set the flag if any item is a bfloat.
166 (push (add rll
(mul ill
'$%i
)) values
)
167 (when (or ($bfloatp rll
) ($bfloatp ill
))
169 (when (or $numer flag
)
170 ;; Return the values in the same order as the args!
173 ;;; Test for numerical evaluation in any precision, real or complex.
174 (defun numerical-eval-p (&rest args
)
175 (or (apply 'float-numerical-eval-p args
)
176 (apply 'complex-float-numerical-eval-p args
)
177 (apply 'bigfloat-numerical-eval-p args
)
178 (apply 'complex-bigfloat-numerical-eval-p args
)))
180 ;;; Check for an integer or a float or bigfloat representation. When we
181 ;;; have a float or bigfloat representation return the integer value.
183 (defun integer-representation-p (x)
185 (cond ((integerp x
) x
)
186 ((and (floatp x
) (= 0 (nth-value 1 (truncate x
))))
187 (nth-value 0 (truncate x
)))
189 (eq ($sign
(sub (setq val
($truncate x
)) x
)) '$zero
))
193 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
195 ;;; The changes to the parser to connect the operator !! to double_factorial(z)
197 ;(def-mheader |$!!| (%double_factorial))
199 ;(def-led (|$!!| 160.) (op left)
202 ; (convert left '$expr)))
204 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
206 ;;; The implementation of the function Double factorial
208 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
210 (defmfun $double_factorial
(z)
211 (simplify (list '(%double_factorial
) z
)))
213 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
215 ;;; Set properties to give full support to the parser and display
217 (defprop $double_factorial %double_factorial alias
)
218 (defprop $double_factorial %double_factorial verb
)
220 (defprop %double_factorial $double_factorial reversealias
)
221 (defprop %double_factorial $double_factorial noun
)
223 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
225 ;;; Double factorial is a simplifying function
227 (defprop %double_factorial simp-double-factorial operators
)
229 ;;; Double factorial distributes over bags
231 (defprop %double_factorial
(mlist $matrix mequal
) distribute_over
)
233 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
235 ;;; Double factorial has mirror symmetry
237 (defprop %double_factorial t commutes-with-conjugate
)
239 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
241 ;;; Differentiation of Double factorial
243 (defprop %double_factorial
247 ((%double_factorial
) z
)
252 ((mplus) 1 ((mtimes) ((rat) 1 2) z
)))
255 ((%log
) ((mtimes) 2 ((mexpt) $%pi -
1)))
256 ((%sin
) ((mtimes) $%pi z
))))))
259 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
261 (defun simp-double-factorial (expr z simpflag
)
263 (setq z
(simpcheck (cadr expr
) simpflag
))
265 ((and (fixnump z
) (> z -
1) (or (minusp $factlim
) (< z $factlim
)))
266 ;; Positive Integer less then $factlim or $factlim is -1. Call gfact.
267 (gfact z
(floor (/ z
2)) 2))
271 (zerop1 (sub (simplify (list '(%truncate
) (div z
2))) (div z
2))))
272 ;; Even negative integer or real representation. Not defined.
275 "double_factorial: double_factorial(~:M) is undefined.") z
))
277 ((or (integerp z
) ; at this point odd negative integer. Evaluate.
278 (complex-float-numerical-eval-p z
))
280 ((and (integerp z
) (= z -
1)) 1) ; Special cases -1 and -3
281 ((and (integerp z
) (= z -
3)) -
1)
283 ;; Odd negative integer, float or complex float.
286 (complex ($float
($realpart z
)) ($float
($imagpart z
))))))))
288 ((and (not (ratnump z
))
289 (complex-bigfloat-numerical-eval-p z
))
290 ;; bigfloat or complex bigfloat.
291 (bfloat-double-factorial
292 (add ($bfloat
($realpart z
)) (mul '$%i
($bfloat
($imagpart z
))))))
294 ;; double_factorial(inf) -> inf
297 ((and $factorial_expand
301 (n (simplify (cons '(mplus) (cddr z
)))))
304 ;; Special case double_factorial(n-1)
305 ;; Not sure if this simplification is useful.
306 (div (simplify (list '(mfactorial) n
))
307 (simplify (list '(%double_factorial
) n
))))
308 ((= k
(* 2 (truncate (/ k
2))))
309 ;; Special case double_factorial(2*k+n), k integer
311 ($factor
; we get more simple expression when factoring
314 (simplify (list '($pochhammer
) (add (div n
2) 1) k
))
315 (simplify (list '(%double_factorial
) n
)))))
317 (eqtest (list '(%double_factorial
) z
) expr
)))))
320 (eqtest (list '(%double_factorial
) z
) expr
))))
322 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
323 ;;; Double factorial for a complex float argument. The result is a CL complex.
324 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
326 (defun double-factorial (z)
327 (let ((pival (float pi
)))
331 (/ (- 1 (cos (* pival z
))) 4))
333 (gamma-lanczos (+ 1 (/ z
2))))))
335 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
336 ;;; Double factorial for a bigfloat or complex bigfloat argument
337 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
339 (defun bfloat-double-factorial (z)
340 (let* ((pival ($bfloat
'$%pi
))
341 (bigfloat1 ($bfloat bigfloatone
))
342 (bigfloat2 (add bigfloat1 bigfloat1
))
343 (bigfloat4 (add bigfloat2 bigfloat2
))
347 (cdiv bigfloat2 pival
)
349 (simplify (list '(%cos
) (cmul pival z
)))) bigfloat4
))
351 (cpower bigfloat2
(cdiv z bigfloat2
))
352 (simplify (list '(%gamma
) (add bigfloat1
(cdiv z bigfloat2
))))))))
354 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
356 ;;; The implementation of the Incomplete Gamma function
358 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
360 (defvar *debug-gamma
* nil
)
362 (defmfun $gamma_incomplete
(a z
)
363 (simplify (list '(%gamma_incomplete
) a z
)))
365 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
367 ;;; Set properties to give full support to the parser and display
369 (defprop $gamma_incomplete %gamma_incomplete alias
)
370 (defprop $gamma_incomplete %gamma_incomplete verb
)
372 (defprop %gamma_incomplete $gamma_incomplete reversealias
)
373 (defprop %gamma_incomplete $gamma_incomplete noun
)
375 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
377 ;;; Incomplete Gamma function is a simplifying function
379 (defprop %gamma_incomplete simp-gamma-incomplete operators
)
381 ;;; Incomplete Gamma distributes over bags
383 (defprop %gamma_incomplete
(mlist $matrix mequal
) distribute_over
)
385 ;;; Incomplete Gamma function has not mirror symmetry for z on the negative
386 ;;; real axis. We support a conjugate-function which test this case.
388 (defprop %gamma_incomplete conjugate-gamma-incomplete conjugate-function
)
390 (defun conjugate-gamma-incomplete (args)
391 (let ((a (first args
)) (z (second args
)))
392 (cond ((off-negative-real-axisp z
)
393 ;; Definitely not on the negative real axis for z. Mirror symmetry.
397 (simplify (list '($conjugate
) a
))
398 (simplify (list '($conjugate
) z
)))))
400 ;; On the negative real axis or no information. Unsimplified.
403 (simplify (list '(%gamma_incomplete
) a z
)))))))
405 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
407 ;;; Derivative of the Incomplete Gamma function
409 (putprop '%gamma_incomplete
412 (cond ((member ($sign a
) '($pos $pz
))
413 ;; The derivative wrt a in terms of hypergeometric_regularized 2F2
414 ;; function and the Generalized Incomplete Gamma function
415 ;; (functions.wolfram.com), only for a>0.
418 ((mexpt) ((%gamma
) ,a
) 2)
420 (($hypergeometric_regularized
)
422 ((mlist) ((mplus) 1 ,a
) ((mplus) 1 ,a
))
425 ((%gamma_incomplete_generalized
) ,a
0 ,z
)
429 ((mqapply) (($psi array
) 0) ,a
))))
431 ;; No derivative. Maxima generates a noun form.
433 ;; The derivative wrt z
435 ((mexpt) $%e
((mtimes) -
1 z
))
436 ((mexpt) z
((mplus) -
1 a
))))
439 ;;; Integral of the Incomplete Gamma function
441 (defprop %gamma_incomplete
445 ((mtimes) -
1 ((%gamma_incomplete
) ((mplus) 1 a
) z
))
446 ((mtimes) ((%gamma_incomplete
) a z
) z
)))
449 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
451 ;;; We support a simplim%function. The function is looked up in simplimit and
452 ;;; handles specific values of the function.
454 (defprop %gamma_incomplete simplim%gamma_incomplete simplim%function
)
456 (defun simplim%gamma_incomplete
(expr var val
)
457 ;; Look for the limit of the arguments.
458 (let ((a (limit (cadr expr
) var val
'think
))
459 (z (limit (caddr expr
) var val
'think
)))
462 ((eq z
'$infinity
) ;; http://dlmf.nist.gov/8.11#i
463 (cond ((and (zerop1 ($realpart
(caddr expr
)))
464 (eq ($csign
(m+ -
1 (cadr expr
))) '$neg
))
466 (t (throw 'limit t
))))
468 ;; Handle an argument 0 at this place.
472 (let ((sgn ($sign
($realpart a
))))
473 (cond ((zerop1 a
) '$inf
)
474 ((member sgn
'($neg $nz
)) '$infinity
)
475 ;; Call the simplifier of the function.
476 (t (simplify (list '(%gamma_incomplete
) a z
))))))
478 ;; All other cases are handled by the simplifier of the function.
479 (simplify (list '(%gamma_incomplete
) a z
))))))
481 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
483 (defmfun $gamma_incomplete_lower
(a z
)
484 (simplify (list '(%gamma_incomplete_lower
) a z
)))
486 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
488 (defprop $gamma_incomplete_lower %gamma_incomplete_lower alias
)
489 (defprop $gamma_incomplete_lower %gamma_incomplete_lower verb
)
491 (defprop %gamma_incomplete_lower $gamma_incomplete_lower reversealias
)
492 (defprop %gamma_incomplete_lower $gamma_incomplete_lower noun
)
494 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
496 (defprop %gamma_incomplete_lower simp-gamma-incomplete-lower operators
)
498 ;;; distribute over bags (aggregates)
500 (defprop %gamma_incomplete_lower
(mlist $matrix mequal
) distribute_over
)
502 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
504 ;; (defprop %gamma_incomplete_lower ??? grad) WHAT TO PUT HERE ??
506 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
508 (defun simp-gamma-incomplete-lower (expr ignored simpflag
)
509 (declare (ignore ignored
))
511 (let ((a (simpcheck (cadr expr
) simpflag
))
512 (z (simpcheck (caddr expr
) simpflag
)))
515 (float-numerical-eval-p a z
)
516 (complex-float-numerical-eval-p a z
)
517 (bigfloat-numerical-eval-p a z
)
518 (complex-bigfloat-numerical-eval-p a z
))
519 (take '(%gamma_incomplete_generalized
) a
0 z
))
521 (gamma-incomplete-lower a z
)))))
523 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
525 (defun simp-gamma-incomplete (expr ignored simpflag
)
526 (declare (ignore ignored
))
528 (let ((a (simpcheck (cadr expr
) simpflag
))
529 (z (simpcheck (caddr expr
) simpflag
))
534 ;; Check for specific values
537 ;; gamma_incomplete(v,0) is gamma(v) only if the realpart(v) >
538 ;; 0. If realpart(v) <= 0, gamma_incomplete is undefined. For
539 ;; all other cases, return the noun form.
540 (let ((sgn ($sign
($realpart a
))))
541 (cond ((member sgn
'($neg $zero
))
544 "gamma_incomplete: gamma_incomplete(~:M,~:M) is undefined.")
546 ((member sgn
'($pos $pz
)) ($gamma a
))
547 (t (eqtest (list '(%gamma_incomplete
) a z
) expr
)))))
554 ;; Check for numerical evaluation in Float or Bigfloat precision
556 ((float-numerical-eval-p a z
)
558 (format t
"~&SIMP-GAMMA-INCOMPLETE in float-numerical-eval-p~%"))
559 ;; a and z are Maxima numbers, at least one has a float value
564 (and (= 0 (- a
(truncate a
)))
566 ;; a is zero or a negative float representing an integer.
567 ;; For these cases the numerical routines of gamma-incomplete
568 ;; do not work. Call the numerical routine for the Exponential
569 ;; Integral E(n,z). The routine is called with a positive integer!.
570 (setq a
(truncate a
))
571 (complexify (* (expt z a
) (expintegral-e (- 1 a
) z
))))
573 (complexify (gamma-incomplete a z
))))))
575 ((complex-float-numerical-eval-p a z
)
578 "~&SIMP-GAMMA-INCOMPLETE in complex-float-numerical-eval-p~%"))
579 ;; a and z are Maxima numbers, at least one is a complex value and
580 ;; we have at least one float part
581 (let ((ca (complex ($float
($realpart a
)) ($float
($imagpart a
))))
582 (cz (complex ($float
($realpart z
)) ($float
($imagpart z
)))))
584 ((and (= (imagpart ca
) 0.0)
585 (or (= (realpart ca
) 0.0)
586 (and (= 0 (- (realpart ca
) (truncate (realpart ca
))))
587 (< (realpart ca
) 0.0))))
588 ;; Call expintegral-e. See comment above.
589 (setq ca
(truncate (realpart ca
)))
590 (complexify (* (expt cz ca
) (expintegral-e (- 1 ca
) cz
))))
592 (complexify (gamma-incomplete ca cz
))))))
594 ((bigfloat-numerical-eval-p a z
)
596 (format t
"~&SIMP-GAMMA-INCOMPLETE in bigfloat-numerical-eval-p~%"))
597 (let ((a ($bfloat a
))
600 ((or (eq ($sign a
) '$zero
)
601 (and (eq ($sign
(sub a
($truncate a
))) '$zero
)
602 (eq ($sign a
) '$neg
)))
603 ;; Call bfloat-expintegral-e. See comment above.
604 (setq a
($truncate a
))
605 ($rectform
(mul (power z a
) (bfloat-expintegral-e (- 1 a
) z
))))
607 (bfloat-gamma-incomplete a z
)))))
609 ((complex-bigfloat-numerical-eval-p a z
)
612 "~&SIMP-GAMMA-INCOMPLETE in complex-bigfloat-numerical-eval-p~%"))
613 (let ((ca (add ($bfloat
($realpart a
))
614 (mul '$%i
($bfloat
($imagpart a
)))))
615 (cz (add ($bfloat
($realpart z
))
616 (mul '$%i
($bfloat
($imagpart z
))))))
618 ((and (eq ($sign
($imagpart ca
)) '$zero
)
619 (or (eq ($sign
($realpart ca
)) '$zero
)
620 (and (eq ($sign
(sub ($realpart ca
)
621 ($truncate
($realpart ca
))))
623 (eq ($sign
($realpart ca
)) '$neg
))))
624 ;; Call bfloat-expintegral-e. See comment above.
627 "~& bigfloat-numerical-eval-p calls bfloat-expintegral-e~%"))
628 (setq a
($truncate
($realpart a
)))
629 ($rectform
(mul (power cz a
)
630 (bfloat-expintegral-e (- 1 a
) cz
))))
632 (complex-bfloat-gamma-incomplete ca cz
)))))
634 ;; Check for transformations and argument simplification
636 ((and $gamma_expand
(integerp a
))
637 ;; Integer or a symbol declared to be an integer. Expand in a series.
638 (let ((sgn ($sign a
)))
643 (simplify (list '(%expintegral_ei
) (mul -
1 z
))))
647 (simplify (list '(%log
) (mul -
1 z
)))
648 (simplify (list '(%log
) (div -
1 z
)))))
649 (mul -
1 (simplify (list '(%log
) z
)))))
650 ((member sgn
'($pos $pz
))
652 (simplify (list '(%gamma
) a
))
653 (power '$%e
(mul -
1 z
))
654 (let ((index (gensumindex)))
658 (let (($gamma_expand nil
))
659 ;; Simplify gamma, but do not expand to avoid division
661 (simplify (list '(%gamma
) (add index
1)))))
662 index
0 (sub a
1)))))
663 ((member sgn
'($neg $nz
))
667 (power -
1 (add (mul -
1 a
) -
1))
668 (simplify (list '(%gamma
) (add (mul -
1 a
) 1))))
670 (simplify (list '(%expintegral_ei
) (mul -
1 z
)))
674 (simplify (list '(%log
) (mul -
1 z
)))
675 (simplify (list '(%log
) (div -
1 z
)))))
676 (simplify (list '(%log
) z
))))
678 (power '$%e
(mul -
1 z
))
679 (let ((index (gensumindex)))
682 (power z
(add index a -
1))
683 (simplify (list '($pochhammer
) a index
)))
684 index
1 (mul -
1 a
))))))
685 (t (eqtest (list '(%gamma_incomplete
) a z
) expr
)))))
687 ((and $gamma_expand
(setq ratorder
(max-numeric-ratio-p a
2)))
688 ;; We have a half integral order and $gamma_expand is not NIL.
689 ;; We expand in a series with the Erfc function
690 (setq ratorder
(- ratorder
(/ 1 2)))
694 (power '$%pi
'((rat simp
) 1 2))
695 (simplify (list '(%erfc
) (power z
'((rat simp
) 1 2))))))
699 (simplify (list '(%gamma
) a
))
700 (simplify (list '(%erfc
) (power z
'((rat simp
) 1 2)))))
702 (power -
1 (sub ratorder
1))
703 (power '$%e
(mul -
1 z
))
704 (power z
'((rat simp
) 1 2))
705 (let ((index (gensumindex)))
707 (mul -
1 ; we get more simple results
708 (simplify ; when multiplying with -1
711 (sub '((rat simp
) 1 2) ratorder
)
712 (sub ratorder
(add index
1))))
713 (power (mul -
1 z
) index
))
714 index
0 (sub ratorder
1))))))
716 (setq ratorder
(- ratorder
))
721 (power '$%pi
'((rat simp
) 1 2))
722 (simplify (list '(%erfc
) (power z
'((rat simp
) 1 2)))))
723 (simplify (list '($pochhammer
) '((rat simp
) 1 2) ratorder
)))
725 (power z
(sub '((rat simp
) 1 2) ratorder
))
726 (power '$%e
(mul -
1 z
))
727 (let ((index (gensumindex)))
734 (sub '((rat simp
) 1 2) ratorder
)
736 index
0 (sub ratorder
1))))))))
738 ((and $gamma_expand
(mplusp a
) (integerp (cadr a
)))
740 (a (simplify (cons '(mplus) (cddr a
)))))
745 (simplify (list '($pochhammer
) a n
))
746 (simplify (list '(%gamma_incomplete
) a z
)))
748 (power '$%e
(mul -
1 z
))
749 (power z
(add a n -
1))
750 (let ((index (gensumindex)))
755 '($pochhammer
) (add 1 (mul -
1 a
) (mul -
1 n
)) index
))
756 (power (mul -
1 z
) (mul -
1 index
)))
757 index
0 (add n -
1))))))
764 (simplify (list '(%gamma_incomplete
) a z
)))
765 (simplify (list '($pochhammer
) (sub 1 a
) n
)))
767 (power '$%e
(mul -
1 z
))
769 (let ((index (gensumindex)))
773 (simplify (list '($pochhammer
) (sub a n
) (add index
1))))
774 index
0 (sub n
1)))))))))
776 (t (eqtest (list '(%gamma_incomplete
) a z
) expr
)))))
778 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
779 ;;; Numerical evaluation of the Incomplete Gamma function
781 ;;; gamma-incomplete (a,z) - real and complex double float
782 ;;; bfloat-gamma-incomplete (a z) - bigfloat
783 ;;; complex-bfloat-gamma-incomplete (a z) - complex bigfloat
785 ;;; Expansion in a power series for abs(x) < R, where R is
786 ;;; *gamma-radius* + real(a) if real(a) > 0 or *gamma-radius*
794 ;;; gamma(a,z) = exp(-x)*z^a * > ------------ * z^n
799 ;;; This expansion does not work for an integer a<=0, because the Gamma function
800 ;;; in the denominator is not defined for a=0 and negative integers. For this
801 ;;; case we use the Exponential Integral E for numerically evaluation. The
802 ;;; Incomplete Gamma function and the Exponential integral are connected by
804 ;;; gamma(a,z) = z^a * expintegral_e(1-a,z)
806 ;;; When the series is not used, two forms of the continued fraction
807 ;;; are used. When z is not near the negative real axis use the
808 ;;; continued fractions (A&S 6.5.31):
811 ;;; gamma(a,z) = exp(-z) z^a *( -- --- --- --- --- ... )
814 ;;; The accuracy is controlled by *gamma-incomplete-eps* for double float
815 ;;; precision. For bigfloat precision epsilon is 10^(-$fpprec). The expansions
816 ;;; in a power series or continued fractions stops if *gamma-incomplete-maxit*
817 ;;; is exceeded and an Maxima error is thrown.
819 ;;; The above fraction does not converge on the negative real axis and
820 ;;; converges very slowly near the axis. In this case, use the
823 ;;; gamma(a,z) = gamma(a) - gamma_lower(a,z)
825 ;;; The continued fraction for gamma_incomplete_lower(a,z) is
826 ;;; (http://functions.wolfram.com/06.06.10.0009.01):
828 ;;; gamma_lower(a,z) = exp(-z) * z^a / cf(a,z)
832 ;;; -a*z z (a+1)*z 2*z (a+2)*z
833 ;;; cf(a,z) = a + ---- ---- ------- ---- -------
834 ;;; a+1+ a+2- a+3+ a+4- a+5+
836 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
838 (defvar *gamma-incomplete-maxit
* 10000)
839 (defvar *gamma-incomplete-eps
* (* 2 flonum-epsilon
))
840 (defvar *gamma-incomplete-min
* 1.0e-32)
842 (defvar *gamma-radius
* 1.0
843 "Controls the radius within a series expansion is done.")
844 (defvar *gamma-imag
* 1.0)
846 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
848 ;;; The numerical evaluation for CL float or complex values a and x
849 ;;; When the flag regularized is T, the result is divided by gamma(a) and
850 ;;; Maxima returns the numercial result for gamma_incomplete_regularized
852 (defun gamma-incomplete (a x
&optional
(regularized nil
))
853 (setq x
(+ x
(cond ((complexp x
) #C
(0.0
0.0)) ((realp x
) 0.0))))
856 ;; Compute the factor needed to scale the series or continued
857 ;; fraction. This is x^a*exp(-x) or x^a*exp(-x)/gamma(a)
858 ;; depending on whether we want a non-regularized or
859 ;; regularized form. We want to compute the factor carefully
860 ;; to avoid unnecessary overflow if possible.
862 (or (try-float-computation
864 ;; gammafloat is more accurate for real
867 (/ (* (expt x a
) (exp (- x
)))
870 (/ (* (expt x a
) (exp (- x
)))
872 ;; Easy way failed. Use logs to compute the
873 ;; result. This loses some precision, especially
874 ;; for large values of a and/or x because we use
875 ;; many bits to hold the exponent part.
876 (exp (- (* a
(log x
))
878 (log-gamma-lanczos (if (complexp a
)
882 (or (try-float-computation
884 (* (expt x a
) (exp (- x
)))))
885 ;; Easy way failed, so use the log form.
886 (exp (- (* a
(log x
))
888 (multiple-value-bind (result lower-incomplete-tail-p
)
889 (%gamma-incomplete a x
)
890 (cond (lower-incomplete-tail-p
891 ;; %gamma-incomplete compute the lower incomplete gamma
892 ;; function, so we need to subtract that from gamma(a),
895 (- 1 (* result factor
)))
897 (- (gamma-lanczos a
) (* result factor
)))
899 (- (gammafloat a
) (* result factor
)))))
901 ;; Continued fraction used. Just multiply by the factor
902 ;; to get the final result.
903 (* factor result
))))))
905 ;; Compute the key part of the gamma incomplete function using either
906 ;; a series expression or a continued fraction expression. Two values
907 ;; are returned: the value itself and a boolean, indicating what the
908 ;; computed value is. If the boolean non-NIL, then the computed value
909 ;; is the lower incomplete gamma function.
910 (defun %gamma-incomplete
(a x
)
911 (let ((gm-maxit *gamma-incomplete-maxit
*)
912 (gm-eps *gamma-incomplete-eps
*)
913 (gm-min *gamma-incomplete-min
*))
915 (format t
"~&GAMMA-INCOMPLETE with ~A and ~A~%" a x
))
917 ;; The series expansion is done for x within a circle of radius
918 ;; R, where R = *gamma-radius*+(realpart(a)) for realpart(a) > 0
919 ;; and R = *gamma-radisu* for realpart(a) < 0. Otherwise a
920 ;; continued fraction is used.
921 ((and (> (abs x
) (+ *gamma-radius
*
922 (if (> (realpart a
) 0.0) (realpart a
) 0.0))))
923 (cond ((and (< (realpart x
) 0)
924 (< (abs (imagpart x
))
925 (* *gamma-imag
* (abs (realpart x
)))))
926 ;; For x near the negative real axis, use the
927 ;; relationship gamma_incomplete(a,z) = gamma(a) -
928 ;; gamma_incomplete_lower(a,z), where
929 ;; gamma_incomplete_lower(a,z) is the lower poart of the
930 ;; incomplete gamma function. We can evaluate that
931 ;; using a continued fraction from
932 ;; http://functions.wolfram.com/06.06.10.0009.01. (Note
933 ;; that the alternative fraction,
934 ;; http://functions.wolfram.com/06.06.10.0007.01,
935 ;; appears to be less accurate.)
937 ;; Also note that this appears to be valid for all
938 ;; values of x (real or complex), but we don't want to
939 ;; use this everywhere for gamma_incomplete. Consider
940 ;; what happens for large real x. gamma_incomplete(a,x)
941 ;; is small, but gamma_incomplete(a,x) = gamma(x) - cf
942 ;; will have large roundoff errors.
944 (format t
"~&GAMMA-INCOMPLETE in continued fractions for lower integral~%"))
945 (let ((a (bigfloat:to a
))
947 (bigfloat::*debug-cf-eval
* *debug-gamma
*)
948 (bigfloat::*max-cf-iterations
* *gamma-incomplete-maxit
*))
949 (values (/ (bigfloat::lentz
#'(lambda (n)
954 (- (* (+ a
(ash n -
1)) x
))))))
957 ;; Expansion in continued fractions for gamma_incomplete.
959 (format t
"~&GAMMA-INCOMPLETE in continued fractions~%"))
961 (an (- a
1.0) (* i
(- a i
)))
962 (b (+ 3.0 x
(- a
)) (+ b
2.0))
964 (d (/ 1.0 (- b
2.0)))
968 (merror (intl:gettext
"gamma_incomplete: continued fractions failed for gamma_incomplete(~:M, ~:M).") a x
))
969 (setq d
(+ (* an d
) b
))
970 (when (< (abs d
) gm-min
) (setq d gm-min
))
971 (setq c
(+ b
(/ an c
)))
972 (when (< (abs c
) gm-min
) (setq c gm-min
))
976 (when (< (abs (- del
1.0)) gm-eps
)
977 ;; Return nil to indicate we used the continued fraction.
978 (return (values h nil
)))))))
980 ;; Expansion in a series
982 (format t
"~&GAMMA-INCOMPLETE in series~%"))
985 (del (/ 1.0 a
) (* del
(/ x ap
)))
986 (sum del
(+ sum del
)))
988 (merror (intl:gettext
"gamma_incomplete: series expansion failed for gamma_incomplete(~:M, ~:M).") a x
))
989 (when (< (abs del
) (* (abs sum
) gm-eps
))
990 (when *debug-gamma
* (format t
"~&Series converged.~%"))
991 ;; Return T to indicate we used the series and the series
992 ;; is for the integral from 0 to x, not x to inf.
993 (return (values sum t
))))))))
995 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
997 ;;; This function is called for a and x real
999 (defun bfloat-gamma-incomplete (a x
)
1000 (let* ((gm-maxit *gamma-incomplete-maxit
*)
1001 (gm-eps (power ($bfloat
10.0) (- $fpprec
)))
1002 (gm-min (mul gm-eps gm-eps
))
1005 ;; The series expansion is done for x within a circle of radius
1006 ;; R, where R = *gamma-radius*+(realpart(a)) for realpart(a) > 0
1007 ;; and R = *gamma-radisu* for realpart(a) < 0. Otherwise a
1008 ;; continued fraction is used.
1009 ((eq ($sign
(sub (simplify (list '(mabs) x
))
1011 (if (eq ($sign a
) '$pos
) a
0.0))))
1014 ((and (eq ($sign x
) '$pos
))
1015 ;; Expansion in continued fractions of the Incomplete Gamma function
1017 (an (sub a
1.0) (mul i
(sub a i
)))
1018 (b (add 3.0 x
(mul -
1 a
)) (add b
2.0))
1019 (c (div 1.0 gm-min
))
1020 (d (div 1.0 (sub b
2.0)))
1024 (merror (intl:gettext
"gamma_incomplete: continued fractions failed for gamma_incomplete(~:M, ~:M).") a x
))
1026 (format t
"~&in continued fractions:~%")
1027 (mformat t
"~& : i = ~M~%" i
)
1028 (mformat t
"~& : h = ~M~%" h
))
1029 (setq d
(add (mul an d
) b
))
1030 (when (eq ($sign
(sub (simplify (list '(mabs) d
)) gm-min
)) '$neg
)
1032 (setq c
(add b
(div an c
)))
1033 (when (eq ($sign
(sub (simplify (list '(mabs) c
)) gm-min
)) '$neg
)
1035 (setq d
(div 1.0 d
))
1036 (setq del
(mul d c
))
1037 (setq h
(mul h del
))
1038 (when (eq ($sign
(sub (simplify (list '(mabs) (sub del
1.0))) gm-eps
))
1043 (power ($bfloat
'$%e
) (mul -
1 x
)))))))
1045 ;; Expand to multiply everything out.
1047 ;; Expansion in continued fraction for the lower incomplete gamma.
1048 (sub (simplify (list '(%gamma
) a
))
1049 ;; NOTE: We want (power x a) instead of bigfloat:expt
1050 ;; because this preserves how maxima computes x^a when
1051 ;; x is negative and a is rational. For, example
1052 ;; (-8)^(1/2) is -2. bigfloat:expt returns the
1055 (power ($bfloat
'$%e
) (mul -
1 x
))
1056 (let ((a (bigfloat:to a
))
1057 (x (bigfloat:to x
)))
1064 (bigfloat:* (ash n -
1) x
)
1065 (bigfloat:-
(bigfloat:* (bigfloat:+ a
(ash n -
1))
1069 ;; Series expansion of the Incomplete Gamma function
1072 (del (div 1.0 a
) (mul del
(div x ap
)))
1073 (sum del
(add sum del
)))
1075 (merror (intl:gettext
"gamma_incomplete: series expansion failed for gamma_incomplete(~:M, ~:M).") a x
))
1077 (format t
"~&GAMMA-INCOMPLETE in series:~%")
1078 (mformat t
"~& : i = ~M~%" i
)
1079 (mformat t
"~& : ap = ~M~%" ap
)
1080 (mformat t
"~& : x/ap = ~M~%" (div x ap
))
1081 (mformat t
"~& : del = ~M~%" del
)
1082 (mformat t
"~& : sum = ~M~%" sum
))
1083 (when (eq ($sign
(sub (simplify (list '(mabs) del
))
1084 (mul (simplify (list '(mabs) sum
)) gm-eps
)))
1086 (when *debug-gamma
* (mformat t
"~&Series converged to ~M.~%" sum
))
1088 (sub (simplify (list '(%gamma
) a
))
1092 (power ($bfloat
'$%e
) (mul -
1 x
))))))))))))
1094 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1096 (defun complex-bfloat-gamma-incomplete (a x
)
1097 (let* ((gm-maxit *gamma-incomplete-maxit
*)
1098 (gm-eps (power ($bfloat
10.0) (- $fpprec
)))
1099 (gm-min (mul gm-eps gm-eps
))
1102 (format t
"~&COMPLEX-BFLOAT-GAMMA-INCOMPLETE~%")
1103 (format t
" : a = ~A~%" a
)
1104 (format t
" : x = ~A~%" x
))
1106 ;; The series expansion is done for x within a circle of radius
1107 ;; R, where R = *gamma-radius*+(realpart(a)) for realpart(a) > 0
1108 ;; and R = *gamma-radisu* for realpart(a) < 0. Otherwise a
1109 ;; continued fraction is used.
1110 ((and (eq ($sign
(sub (simplify (list '(mabs) x
))
1112 (if (eq ($sign
($realpart a
)) '$pos
)
1117 ((not (and (eq ($sign
($realpart x
)) '$neg
)
1118 (eq ($sign
(sub (simplify (list '(mabs) ($imagpart x
)))
1119 (simplify (list '(mabs) ($realpart x
)))))
1121 ;; Expansion in continued fractions of the Incomplete Gamma function
1123 (format t
"~&in continued fractions:~%"))
1125 (an (sub a
1.0) (mul i
(sub a i
)))
1126 (b (add 3.0 x
(mul -
1 a
)) (add b
2.0))
1127 (c (cdiv 1.0 gm-min
))
1128 (d (cdiv 1.0 (sub b
2.0)))
1132 (merror (intl:gettext
"gamma_incomplete: continued fractions failed for gamma_incomplete(~:M, ~:M).") a x
))
1133 (setq d
(add (cmul an d
) b
))
1134 (when (eq ($sign
(sub (simplify (list '(mabs) d
)) gm-min
)) '$neg
)
1136 (setq c
(add b
(cdiv an c
)))
1137 (when (eq ($sign
(sub (simplify (list '(mabs) c
)) gm-min
)) '$neg
)
1139 (setq d
(cdiv 1.0 d
))
1140 (setq del
(cmul d c
))
1141 (setq h
(cmul h del
))
1142 (when (eq ($sign
(sub (simplify (list '(mabs) (sub del
1.0)))
1146 ($bfloat
; force evaluation of expressions with sin or cos
1150 (cpower ($bfloat
'$%e
) ($bfloat
(mul -
1 x
))))))))))
1152 ;; Expand to multiply everything out.
1154 ;; Expansion in continued fraction for the lower incomplete gamma.
1155 (sub ($rectform
(simplify (list '(%gamma
) a
)))
1156 ;; NOTE: We want (power x a) instead of bigfloat:expt
1157 ;; because this preserves how maxima computes x^a when
1158 ;; x is negative and a is rational. For, example
1159 ;; (-8)^(1/2) is -2. bigfloat:expt returns the
1161 (mul ($rectform
(power x a
))
1162 ($rectform
(power ($bfloat
'$%e
) (mul -
1 x
)))
1163 (let ((a (bigfloat:to a
))
1164 (x (bigfloat:to x
)))
1171 (bigfloat:* (ash n -
1) x
)
1172 (bigfloat:-
(bigfloat:* (bigfloat:+ a
(ash n -
1))
1175 ;; Series expansion of the Incomplete Gamma function
1177 (format t
"~&GAMMA-INCOMPLETE in series:~%"))
1180 (del (cdiv 1.0 a
) (cmul del
(cdiv x ap
)))
1181 (sum del
(add sum del
)))
1183 (merror (intl:gettext
"gamma_incomplete: series expansion failed for gamma_incomplete(~:M, ~:M).") a x
))
1184 (when (eq ($sign
(sub (simplify (list '(mabs) del
))
1185 (mul (simplify (list '(mabs) sum
)) gm-eps
)))
1187 (when *debug-gamma
* (format t
"~&Series converged.~%"))
1189 ($bfloat
; force evaluation of expressions with sin or cos
1190 (sub (simplify (list '(%gamma
) a
))
1194 (cpower ($bfloat
'$%e
) (mul -
1 x
)))))))))))))
1196 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1198 ;;; Implementation of the Generalized Incomplete Gamma function
1200 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1202 (defmfun $gamma_incomplete_generalized
(a z1 z2
)
1203 (simplify (list '(%gamma_incomplete_generalized
) a z1 z2
)))
1205 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1207 ;;; Set the properties alias, reversealias, noun and verb
1209 (defprop $gamma_incomplete_generalized %gamma_incomplete_generalized alias
)
1210 (defprop $gamma_incomplete_generalized %gamma_incomplete_generalized verb
)
1212 (defprop %gamma_incomplete_generalized
1213 $gamma_incomplete_generalized reversealias
)
1214 (defprop %gamma_incomplete_generalized
1215 $gamma_incomplete_generalized noun
)
1217 ;;; Generalized Incomplete Gamma function has not mirror symmetry for z1 or z2
1218 ;;; on the negative real axis.
1219 ;;; We support a conjugate-function which test this case.
1221 (defprop %gamma_incomplete_generalized
1222 conjugate-gamma-incomplete-generalized conjugate-function
)
1224 (defun conjugate-gamma-incomplete-generalized (args)
1225 (let ((a (first args
)) (z1 (second args
)) (z2 (third args
)))
1226 (cond ((and (off-negative-real-axisp z1
) (off-negative-real-axisp z2
))
1227 ;; z1 and z2 definitely not on the negative real axis.
1231 '(%gamma_incomplete_generalized
)
1232 (simplify (list '($conjugate
) a
))
1233 (simplify (list '($conjugate
) z1
))
1234 (simplify (list '($conjugate
) z2
)))))
1236 ;; On the negative real axis or no information. Unsimplified.
1239 (simplify (list '(%gamma_incomplete_generalized
) a z1 z2
)))))))
1241 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1243 ;;; Generalized Incomplete Gamma function is a simplifying function
1245 (defprop %gamma_incomplete_generalized
1246 simp-gamma-incomplete-generalized operators
)
1248 ;;; Generalized Incomplete Gamma distributes over bags
1250 (defprop %gamma_incomplete_generalized
(mlist $matrix mequal
) distribute_over
)
1252 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1254 ;;; Differentiation of Generalized Incomplete Gamma function
1256 (defprop %gamma_incomplete_generalized
1258 ;; The derivative wrt a in terms of hypergeometric_regularized 2F2 function
1259 ;; and the Generalized Incomplete Gamma function (functions.wolfram.com)
1262 ((mexpt) ((%gamma
) a
) 2)
1264 (($hypergeometric_regularized
)
1266 ((mlist) ((mplus) 1 a
) ((mplus) 1 a
))
1269 ((mexpt) ((%gamma
) a
) 2)
1271 (($hypergeometric_regularized
)
1273 ((mlist) ((mplus) 1 a
) ((mplus) 1 a
))
1276 ((%gamma_incomplete_generalized
) a
0 z1
)
1279 ((%gamma_incomplete_generalized
) a
0 z2
)
1281 ;; The derivative wrt z1
1283 ((mexpt) $%e
((mtimes) -
1 z1
))
1284 ((mexpt) z1
((mplus) -
1 a
)))
1285 ;; The derivative wrt z2
1287 ((mexpt) $%e
((mtimes) -
1 z2
))
1288 ((mexpt) z2
((mplus) -
1 a
))))
1291 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1293 (defun simp-gamma-incomplete-generalized (expr ignored simpflag
)
1294 (declare (ignore ignored
))
1295 (arg-count-check 3 expr
)
1296 (let ((a (simpcheck (cadr expr
) simpflag
))
1297 (z1 (simpcheck (caddr expr
) simpflag
))
1298 (z2 (simpcheck (cadddr expr
) simpflag
))
1303 ;; Check for specific values
1306 (let ((sgn ($sign
($realpart a
))))
1308 ((member sgn
'($pos $pz
))
1310 (simplify (list '(%gamma_incomplete
) a z1
))
1311 (simplify (list '(%gamma
) a
))))
1313 (eqtest (list '(%gamma_incomplete_generalized
) a z1 z2
) expr
)))))
1316 (let ((sgn ($sign
($realpart a
))))
1318 ((member sgn
'($pos $pz
))
1320 (simplify (list '(%gamma
) a
))
1321 (simplify (list '(%gamma_incomplete
) a z2
))))
1323 (eqtest (list '(%gamma_incomplete_generalized
) a z1 z2
) expr
)))))
1325 ((zerop1 (sub z1 z2
)) 0)
1327 ((eq z2
'$inf
) (simplify (list '(%gamma_incomplete
) a z1
)))
1328 ((eq z1
'$inf
) (mul -
1 (simplify (list '(%gamma_incomplete
) a z2
))))
1330 ;; Check for numerical evaluation in Float or Bigfloat precision
1331 ;; Use the numerical routines of the Incomplete Gamma function
1333 ((float-numerical-eval-p a z1 z2
)
1335 (- (gamma-incomplete ($float a
) ($float z1
))
1336 (gamma-incomplete ($float a
) ($float z2
)))))
1338 ((complex-float-numerical-eval-p a z1 z2
)
1339 (let ((ca (complex ($float
($realpart a
)) ($float
($imagpart a
))))
1340 (cz1 (complex ($float
($realpart z1
)) ($float
($imagpart z1
))))
1341 (cz2 (complex ($float
($realpart z2
)) ($float
($imagpart z2
)))))
1342 (complexify (- (gamma-incomplete ca cz1
) (gamma-incomplete ca cz2
)))))
1344 ((bigfloat-numerical-eval-p a z1 z2
)
1345 (sub (bfloat-gamma-incomplete ($bfloat a
) ($bfloat z1
))
1346 (bfloat-gamma-incomplete ($bfloat a
) ($bfloat z2
))))
1348 ((complex-bigfloat-numerical-eval-p a z1 z2
)
1349 (let ((ca (add ($bfloat
($realpart a
))
1350 (mul '$%i
($bfloat
($imagpart a
)))))
1351 (cz1 (add ($bfloat
($realpart z1
))
1352 (mul '$%i
($bfloat
($imagpart z1
)))))
1353 (cz2 (add ($bfloat
($realpart z2
))
1354 (mul '$%i
($bfloat
($imagpart z2
))))))
1355 (sub (complex-bfloat-gamma-incomplete ca cz1
)
1356 (complex-bfloat-gamma-incomplete ca cz2
))))
1358 ;; Check for transformations and argument simplification
1360 ((and $gamma_expand
(mplusp a
) (integerp (cadr a
)))
1361 ;; Expand gamma_incomplete_generalized(a+n,z1,z2) with n an integer
1363 (a (simplify (cons '(mplus) (cddr a
)))))
1367 (simplify (list '($pochhammer
) a n
))
1369 (simplify (list '(%gamma_incomplete_generalized
) a z1 z2
))
1371 (power '$%e
(mul -
1 z1
))
1372 (let ((index (gensumindex)))
1375 (power z1
(add a index -
1))
1376 (simplify (list '($pochhammer
) a index
)))
1379 (power '$%e
(mul -
1 z2
))
1380 (let ((index (gensumindex)))
1383 (power z2
(add a index -
1))
1384 (simplify (list '($pochhammer
) a index
)))
1393 ($factor
(simplify (list '($pochhammer
) (sub 1 a
) n
))))
1394 (simplify (list '(%gamma_incomplete_generalized
) a z1 z2
)))
1396 (power '$%e
(mul -
1 z2
))
1397 (let ((index (gensumindex)))
1400 (power z1
(add a index
(- n
) -
1))
1401 (simplify (list '($pochhammer
) (sub a n
) index
)))
1404 (power '$%e
(mul -
1 z2
))
1405 (let ((index (gensumindex)))
1408 (power z2
(add a index
(- n
) -
1))
1409 (simplify (list '($pochhammer
) (sub a n
) index
)))
1412 (t (eqtest (list '(%gamma_incomplete_generalized
) a z1 z2
) expr
)))))
1414 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1416 ;;; Implementation of the Regularized Incomplete Gamma function
1418 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1420 (defmfun $gamma_incomplete_regularized
(a z
)
1421 (simplify (list '(%gamma_incomplete_regularized
) a z
)))
1423 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1425 (defprop $gamma_incomplete_regularized %gamma_incomplete_regularized alias
)
1426 (defprop $gamma_incomplete_regularized %gamma_incomplete_regularized verb
)
1428 (defprop %gamma_incomplete_regularized
1429 $gamma_incomplete_regularized reversealias
)
1430 (defprop %gamma_incomplete_regularized
1431 $gamma_incomplete_regularized noun
)
1433 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1435 ;;; Generalized Incomplete Gamma function has not mirror symmetry for z1 or z2
1436 ;;; on the negative real axis.
1437 ;;; We support a conjugate-function which test this case.
1439 (defprop %gamma_incomplete_regularized
1440 conjugate-gamma-incomplete-regularized conjugate-function
)
1442 (defun conjugate-gamma-incomplete-regularized (args)
1443 (let ((a (first args
)) (z (second args
)))
1444 (cond ((off-negative-real-axisp z
)
1445 ;; z definitely not on the negative real axis. Mirror symmetry.
1448 '(%gamma_incomplete_regularized
)
1449 (simplify (list '($conjugate
) a
))
1450 (simplify (list '($conjugate
) z
)))))
1452 ;; On the negative real axis or no information. Unsimplified.
1455 (simplify (list '(%gamma_incomplete_regularized
) a z
)))))))
1457 ;;; Regularized Incomplete Gamma function is a simplifying function
1459 (defprop %gamma_incomplete_regularized
1460 simp-gamma-incomplete-regularized operators
)
1462 ;;; Regularized Incomplete Gamma distributes over bags
1464 (defprop %gamma_incomplete_regularized
(mlist $matrix mequal
) distribute_over
)
1466 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1468 ;;; Differentiation of Regularized Incomplete Gamma function
1470 (defprop %gamma_incomplete_regularized
1472 ;; The derivative wrt a in terms of hypergeometric_regularized 2F2 function
1473 ;; and the Regularized Generalized Incomplete Gamma function
1474 ;; (functions.wolfram.com)
1479 (($hypergeometric_regularized
)
1481 ((mlist) ((mplus) 1 a
) ((mplus) 1 a
))
1484 ((%gamma_incomplete_generalized_regularized
) a z
0)
1487 ((mtimes) -
1 ((mqapply) (($psi array
) 0) a
)))))
1488 ;; The derivative wrt z
1491 ((mexpt) $%e
((mtimes) -
1 z
))
1492 ((mexpt) z
((mplus) -
1 a
))
1493 ((mexpt) ((%gamma
) a
) -
1)))
1496 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1498 (defun simp-gamma-incomplete-regularized (expr ignored simpflag
)
1499 (declare (ignore ignored
))
1501 (let ((a (simpcheck (cadr expr
) simpflag
))
1502 (z (simpcheck (caddr expr
) simpflag
))
1508 ;; Check for specific values
1511 (let ((sgn ($sign
($realpart a
))))
1512 (cond ((member sgn
'($neg $zero
))
1515 "gamma_incomplete_regularized: gamma_incomplete_regularized(~:M,~:M) is undefined.")
1517 ((member sgn
'($pos $pz
)) 1)
1518 (t (eqtest (list '(%gamma_incomplete_regularized
) a z
) expr
)))))
1523 ;; Check for numerical evaluation in Float or Bigfloat precision
1525 ((float-numerical-eval-p a z
)
1527 ;; gamma_incomplete returns a regularized result
1528 (gamma-incomplete ($float a
) ($float z
) t
)))
1530 ((complex-float-numerical-eval-p a z
)
1531 (let ((ca (complex ($float
($realpart a
)) ($float
($imagpart a
))))
1532 (cz (complex ($float
($realpart z
)) ($float
($imagpart z
)))))
1533 ;; gamma_incomplete returns a regularized result
1534 (complexify (gamma-incomplete ca cz t
))))
1536 ((bigfloat-numerical-eval-p a z
)
1537 (div (bfloat-gamma-incomplete ($bfloat a
) ($bfloat z
))
1538 (simplify (list '(%gamma
) ($bfloat a
)))))
1540 ((complex-bigfloat-numerical-eval-p a z
)
1541 (let ((ca (add ($bfloat
($realpart a
))
1542 (mul '$%i
($bfloat
($imagpart a
)))))
1543 (cz (add ($bfloat
($realpart z
))
1544 (mul '$%i
($bfloat
($imagpart z
))))))
1547 (complex-bfloat-gamma-incomplete ca cz
)
1548 (simplify (list '(%gamma
) ca
))))))
1550 ;; Check for transformations and argument simplification
1552 ((and $gamma_expand
(integerp a
))
1553 ;; An integer. Expand the expression.
1554 (let ((sgn ($sign a
)))
1556 ((member sgn
'($pos $pz
))
1558 (power '$%e
(mul -
1 z
))
1559 (let ((index (gensumindex)))
1563 (let (($gamma_expand nil
))
1564 (simplify (list '(%gamma
) (add index
1)))))
1565 index
0 (sub a
1)))))
1566 ((member sgn
'($neg $nz
)) 0)
1567 (t (eqtest (list '(%gamma_incomplete_regularized
) a z
) expr
)))))
1569 ((and $gamma_expand
(setq ratorder
(max-numeric-ratio-p a
2)))
1570 ;; We have a half integral order and $gamma_expand is not NIL.
1571 ;; We expand in a series with the Erfc function
1572 (setq ratorder
(- ratorder
(/ 1 2)))
1574 (format t
"~&SIMP-GAMMA-INCOMPLETE-REGULARIZED in RATORDER~%")
1575 (format t
"~& : a = ~A~%" a
)
1576 (format t
"~& : ratorder = ~A~%" ratorder
))
1579 (simplify (list '(%erfc
) (power z
'((rat simp
) 1 2)))))
1583 (simplify (list '(%erfc
) (power z
'((rat simp
) 1 2))))
1585 (power -
1 (sub ratorder
1))
1586 (power '$%e
(mul -
1 z
))
1587 (power z
'((rat simp
) 1 2))
1588 (div 1 (simplify (list '(%gamma
) a
)))
1589 (let ((index (gensumindex)))
1592 (power (mul -
1 z
) index
)
1593 (simplify (list '($pochhammer
)
1594 (sub '((rat simp
) 1 2) ratorder
)
1595 (sub ratorder
(add index
1)))))
1596 index
0 (sub ratorder
1))))))
1599 (setq ratorder
(- ratorder
))
1601 (simplify (list '(%erfc
) (power z
'((rat simp
) 1 2))))
1603 (power '$%e
(mul -
1 z
))
1604 (power z
(sub '((rat simp
) 1 2) ratorder
))
1605 (inv (simplify (list '(%gamma
) (sub '((rat simp
) 1 2) ratorder
))))
1606 (let ((index (gensumindex)))
1610 (simplify (list '($pochhammer
)
1611 (sub '((rat simp
) 1 2) ratorder
)
1613 index
0 (sub ratorder
1))))))))
1615 ((and $gamma_expand
(mplusp a
) (integerp (cadr a
)))
1617 (format t
"~&SIMP-GAMMA-INCOMPLETE-REGULARIZED in COND (mplusp)~%"))
1619 (a (simplify (cons '(mplus) (cddr a
)))))
1623 (simplify (list '(%gamma_incomplete_regularized
) a z
))
1624 ;; We factor the second summand.
1625 ;; Some factors vanish and the result is more readable.
1628 (power '$%e
(mul -
1 z
))
1629 (power z
(add a -
1))
1630 (div 1 (simplify (list '(%gamma
) a
)))
1631 (let ((index (gensumindex)))
1635 (simplify (list '($pochhammer
) a index
)))
1640 (simplify (list '(%gamma_incomplete_regularized
) a z
))
1641 ;; We factor the second summand.
1644 (power '$%e
(mul -
1 z
))
1645 (power z
(sub a
(add n
1)))
1646 (div 1 (simplify (list '(%gamma
) (add a
(- n
)))))
1647 (let ((index (gensumindex)))
1651 (simplify (list '($pochhammer
) (add a
(- n
)) index
)))
1654 (t (eqtest (list '(%gamma_incomplete_regularized
) a z
) expr
)))))
1656 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1658 ;;; Implementation of the Logarithm of the Gamma function
1660 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1662 (defmfun $log_gamma
(z)
1663 (simplify (list '(%log_gamma
) z
)))
1665 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1667 (defprop $log_gamma %log_gamma alias
)
1668 (defprop $log_gamma %log_gamma verb
)
1670 (defprop %log_gamma $log_gamma reversealias
)
1671 (defprop %log_gamma $log_gamma noun
)
1673 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1675 (defprop %log_gamma simp-log-gamma operators
)
1677 ;;; Logarithm of the Gamma function distributes over bags
1679 (defprop %log_gamma
(mlist $matrix mequal
) distribute_over
)
1681 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1685 ((mqapply) (($psi array
) 0) z
))
1688 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1690 (defun simp-log-gamma (expr z simpflag
)
1692 (setq z
(simpcheck (cadr expr
) simpflag
))
1695 ;; Check for specific values
1699 (and (eq ($sign z
) '$neg
)
1700 (zerop1 (sub z
($truncate z
))))))
1701 ;; We have zero, a negative integer or a float or bigfloat representation.
1703 (intl:gettext
"log_gamma: log_gamma(~:M) is undefined.") z
))
1705 ((eq z
'$inf
) '$inf
)
1707 ;; Check for numerical evaluation
1709 ((float-numerical-eval-p z
)
1710 (complexify (log-gamma-lanczos (complex ($float z
) 0))))
1712 ((complex-float-numerical-eval-p z
)
1715 (complex ($float
($realpart z
)) ($float
($imagpart z
))))))
1717 ((bigfloat-numerical-eval-p z
)
1718 (bfloat-log-gamma ($bfloat z
)))
1720 ((complex-bigfloat-numerical-eval-p z
)
1721 (complex-bfloat-log-gamma
1722 (add ($bfloat
($realpart z
)) (mul '$%i
($bfloat
($imagpart z
))))))
1724 ;; Transform to Logarithm of Factorial for integer values
1725 ;; At this point the integer value is positive and not zero.
1728 (simplify (list '(%log
) (simplify (list '(mfactorial) (- z
1))))))
1730 (t (eqtest (list '(%log_gamma
) z
) expr
))))
1732 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1733 ;;; The functions log-gamma-lanczos, bfloat-log-gamma and
1734 ;;; complex-bfloat-log-gamma are modified versions of the related functions
1735 ;;; gamma-lanczos, bffac and cbffac. The functions return the Logarithm of
1736 ;;; the Gamma function. If we have to calculate the quotient of Gamma functions,
1737 ;;; e. g. for the Beta function, it is much more appropriate to use the
1738 ;;; logarithmic versions to avoid overflow.
1740 ;;; Be careful log(gamma(z)) is only for realpart(z) positive equal to
1741 ;;; log_gamma(z). For a negative realpart(z) log_gamma differ by multiple of
1742 ;;; %pi from log(gamma(z)). But we always have exp(log_gamma(z))= gamma(z).
1743 ;;; The terms to get the transformation for log_gamma(-z) are taken from
1744 ;;; functions.wolfram.com.
1745 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1747 (defun log-gamma-lanczos (z)
1748 (declare (type (complex flonum
) z
)
1749 (optimize (safety 3)))
1750 (let ((c (make-array 15 :element-type
'flonum
1752 '(0.99999999999999709182
1753 57.156235665862923517
1754 -
59.597960355475491248
1755 14.136097974741747174
1756 -
0.49191381609762019978
1757 .33994649984811888699e-4
1758 .46523628927048575665e-4
1759 -
.98374475304879564677e-4
1760 .15808870322491248884e-3
1761 -
.21026444172410488319e-3
1762 .21743961811521264320e-3
1763 -
.16431810653676389022e-3
1764 .84418223983852743293e-4
1765 -
.26190838401581408670e-4
1766 .36899182659531622704e-5))))
1767 (declare (type (simple-array flonum
(15)) c
))
1768 (if (minusp (realpart z
))
1775 (abs (floor (realpart z
)))
1776 (- 1 (abs (signum (imagpart z
)))))
1779 (- (log (sin (* (float pi
) (- z
(floor (realpart z
)))))))
1783 (floor (realpart z
))
1784 (signum (imagpart z
))))
1785 (log-gamma-lanczos z
)))
1788 (zgh (+ zh
607/128))
1789 (lnzp (* (/ zh
2) (log zgh
)))
1792 (pp (1- (length c
)) (1- pp
)))
1795 (incf sum
(/ (aref c pp
) (+ z pp
))))))
1796 (+ (log (sqrt (float (* 2 pi
))))
1797 (log (+ ss
(aref c
0)))
1798 (+ (- zgh
) (* 2 lnzp
)))))))
1800 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1802 (defun bfloat-log-gamma (z)
1803 (let (($ratprint nil
)
1804 (bigfloat%pi
($bfloat
'$%pi
)))
1806 ((eq ($sign z
) '$neg
)
1807 (let ((z (mul -
1 z
)))
1810 (mul -
1 bigfloat%pi
'$%i
1811 (simplify (list '(mabs) (simplify (list '($floor
) ($realpart z
)))))
1814 (list '(mabs) (simplify (list '(%signum
) ($imagpart z
)))))))
1815 (simplify (list '(%log
) bigfloat%pi
))
1816 (mul -
1 (simplify (list '(%log
) (mul -
1 z
))))
1818 (simplify (list '(%log
)
1819 (simplify (list '(%sin
)
1822 (sub z
(simplify (list '($floor
) ($realpart z
))))))))))
1825 (simplify (list '($floor
) ($realpart z
)))
1826 (simplify (list '(%signum
) ($imagpart z
)))))
1827 (bfloat-log-gamma z
))))
1829 (let* ((k (* 2 (+ 1 ($entier
(* 0.41 $fpprec
)))))
1830 (m ($bfloat bigfloatone
))
1833 (x ($bfloat bigfloatzero
))
1835 (dotimes (i (/ k
2))
1836 (setq ii
(* 2 (+ i
1)))
1837 (setq m
(mul m
(add z ii -
2) (add z ii -
1)))
1840 (div ($bern
(+ k
(- ii
) 2))
1841 (* (+ k
(- ii
) 1) (+ k
(- ii
) 2))))
1844 (div (simplify (list '(%log
) (mul 2 bigfloat%pi z
+k
))) 2)
1845 (mul z
+k
(add (simplify (list '(%log
) z
+k
)) x -
1))
1846 (mul -
1 (simplify (list '(%log
) m
)))))))))
1848 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1850 (defun complex-bfloat-log-gamma (z)
1851 (let (($ratprint nil
)
1852 (bigfloat%pi
($bfloat
'$%pi
)))
1854 ((eq ($sign
($realpart z
)) '$neg
)
1855 (let ((z (mul -
1 z
)))
1858 (mul -
1 bigfloat%pi
'$%i
1859 (simplify (list '(mabs) (simplify (list '($floor
) ($realpart z
)))))
1862 (list '(mabs) (simplify (list '(%signum
) ($imagpart z
)))))))
1863 (simplify (list '(%log
) bigfloat%pi
))
1864 (mul -
1 (simplify (list '(%log
) (mul -
1 z
))))
1866 (simplify (list '(%log
)
1867 (simplify (list '(%sin
)
1870 (sub z
(simplify (list '($floor
) ($realpart z
))))))))))
1873 (simplify (list '($floor
) ($realpart z
)))
1874 (simplify (list '(%signum
) ($imagpart z
)))))
1875 (complex-bfloat-log-gamma z
))))
1877 (let* ((k (* 2 (+ 1 ($entier
(* 0.41 $fpprec
)))))
1878 (m ($bfloat bigfloatone
))
1880 (y ($rectform
(power z
+k
2)))
1881 (x ($bfloat bigfloatzero
))
1883 (dotimes (i (/ k
2))
1884 (setq ii
(* 2 (+ i
1)))
1885 (setq m
($rectform
(mul m
(add z ii -
2) (add z ii -
1))))
1889 (div ($bern
(+ k
(- ii
) 2))
1890 (* (+ k
(- ii
) 1) (+ k
(- ii
) 2))))
1894 (div (simplify (list '(%log
) (mul 2 bigfloat%pi z
+k
))) 2)
1895 (mul z
+k
(add (simplify (list '(%log
) z
+k
)) x -
1))
1896 (mul -
1 (simplify (list '(%log
) m
))))))))))
1898 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1900 ;;; Implementation of the Error function Erf(z)
1902 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1905 (simplify (list '(%erf
) z
)))
1907 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1909 (defprop $erf %erf alias
)
1910 (defprop $erf %erf verb
)
1912 (defprop %erf $erf reversealias
)
1913 (defprop %erf $erf noun
)
1915 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1917 ;;; erf has mirror symmetry
1919 (defprop %erf t commutes-with-conjugate
)
1921 ;;; erf is an odd function
1923 (defprop %erf odd-function-reflect reflection-rule
)
1925 ;;; erf is a simplifying function
1927 (defprop %erf simp-erf operators
)
1929 ;;; erf distributes over bags
1931 (defprop %erf
(mlist $matrix mequal
) distribute_over
)
1933 ;;; Derivative of the Error function erf
1938 ((mexpt) $%pi
((rat) -
1 2))
1939 ((mexpt) $%e
((mtimes) -
1 ((mexpt) z
2)))))
1942 ;;; Integral of the Error function erf
1948 ((mexpt) $%pi
((rat) -
1 2))
1949 ((mexpt) $%e
((mtimes) -
1 ((mexpt) z
2))))
1950 ((mtimes) z
((%erf
) z
))))
1953 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1955 (defun simp-erf (expr z simpflag
)
1957 (setq z
(simpcheck (cadr expr
) simpflag
))
1960 ;; Check for specific values
1966 ;; Check for numerical evaluation
1968 ((float-numerical-eval-p z
)
1969 (bigfloat::bf-erf
($float z
)))
1970 ((complex-float-numerical-eval-p z
)
1972 (bigfloat::bf-erf
(complex ($float
($realpart z
)) ($float
($imagpart z
))))))
1973 ((bigfloat-numerical-eval-p z
)
1974 (to (bigfloat::bf-erf
(bigfloat:to
($bfloat z
)))))
1975 ((complex-bigfloat-numerical-eval-p z
)
1976 (to (bigfloat::bf-erf
1977 (bigfloat:to
(add ($bfloat
($realpart z
)) (mul '$%i
($bfloat
($imagpart z
))))))))
1979 ;; Argument simplification
1981 ((taylorize (mop expr
) (second expr
)))
1983 (not $erf_representation
)
1985 (mul '$%i
(simplify (list '(%erfi
) (coeff z
'$%i
1)))))
1986 ((apply-reflection-simp (mop expr
) z $trigsign
))
1988 ;; Representation through equivalent functions
1990 ($hypergeometric_representation
1992 (power '$%pi
'((rat simp
) 1 2))
1993 (list '(%hypergeometric simp
)
1994 (list '(mlist simp
) '((rat simp
) 1 2))
1995 (list '(mlist simp
) '((rat simp
) 3 2))
1996 (mul -
1 (power z
2)))))
1998 ;; Transformation to Erfc or Erfi
2000 ((and $erf_representation
2001 (not (eq $erf_representation
'$erf
)))
2002 (case $erf_representation
2004 (sub 1 (take '(%erfc
) z
)))
2006 (mul -
1 '$%i
(take '(%erfi
) (mul '$%i z
))))
2008 (eqtest (list '(%erf
) z
) expr
))))
2011 (eqtest (list '(%erf
) z
) expr
))))
2013 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2016 ;; We use the slatec routine for float values.
2017 (slatec:derf
(float z
)))
2019 ;; Compute erf(z) using the relationship
2021 ;; erf(z) = sqrt(z^2)/z*(1 - gamma_incomplete(1/2,z^2)/sqrt(%pi))
2023 ;; When z is real sqrt(z^2)/z is signum(z). For complex z,
2024 ;; sqrt(z^2)/z = 1 if -%pi/2 < arg(z) <= %pi/2 and -1 otherwise.
2026 ;; This relationship has serious round-off issues when z is small
2027 ;; because gamma_incomplete(1/2,z^2)/sqrt(%pi) is near 1.
2029 ;; complex-erf is for (lisp) complex numbers; bfloat-erf is for real
2030 ;; bfloats, and complex-bfloat-erf is for complex bfloats. Care is
2031 ;; taken to return real results for real arguments and imaginary
2032 ;; results for imaginary arguments
2033 (defun complex-erf (z)
2036 (if (or (< (realpart z
) 0.0) (and (= (realpart z
) 0.0) (< (imagpart z
) 0.0)))
2040 (* (/ (sqrt (float pi
))) (gamma-incomplete 0.5 (* z z
)))))))
2042 ((= (imagpart z
) 0.0)
2043 ;; Pure real argument, the result is real
2044 (complex (realpart result
) 0.0))
2045 ((= (realpart z
) 0.0)
2046 ;; Pure imaginary argument, the result is pure imaginary
2047 (complex 0.0 (imagpart result
)))
2051 (defun bfloat-erf (z)
2052 ;; Warning! This has round-off problems when abs(z) is very small.
2053 (let ((1//2 ($bfloat
'((rat simp
) 1 2))))
2054 ;; The argument is real, the result is real too
2057 (simplify (list '(%signum
) z
))
2060 (div 1 (power ($bfloat
'$%pi
) 1//2))
2061 (bfloat-gamma-incomplete 1//2 ($bfloat
(power z
2)))))))))
2063 (defun complex-bfloat-erf (z)
2064 ;; Warning! This has round-off problems when abs(z) is very small.
2065 (let* (($ratprint nil
)
2066 (1//2 ($bfloat
'((rat simp
) 1 2)))
2069 (cdiv (cpower (cpower z
2) 1//2) z
)
2072 (div 1 (power ($bfloat
'$%pi
) 1//2))
2073 (complex-bfloat-gamma-incomplete
2075 ($bfloat
(cpower z
2))))))))
2077 ((zerop1 ($imagpart z
))
2078 ;; Pure real argument, the result is real
2080 ((zerop1 ($realpart z
))
2081 ;; Pure imaginary argument, the result is pure imaginary
2082 (mul '$%i
($imagpart result
)))
2084 ;; A general complex result
2087 (in-package :bigfloat
)
2089 ;; Erf(z) for all z. Z must be a CL real or complex number or a
2090 ;; BIGFLOAT or COMPLEX-BIGFLOAT object. The result will be of the
2093 (cond ((typep z
'cl
:real
)
2094 ;; Use Slatec derf, which should be faster than the series.
2096 ((<= (abs z
) 0.476936)
2097 ;; Use the series A&S 7.1.5 for small x:
2099 ;; erf(z) = 2*z/sqrt(%pi) * sum((-1)^n*z^(2*n)/n!/(2*n+1), n, 0, inf)
2101 ;; The threshold is approximately erf(x) = 0.5. (Doesn't
2102 ;; have to be super accurate.) This gives max accuracy when
2103 ;; using the identity erf(x) = 1 - erfc(x).
2104 (let ((z^
2 (* z z
)))
2105 (/ (* 2 z
(sum-power-series z^
2
2113 ;; The general case.
2115 (cl:real
(maxima::erf z
))
2116 (cl:complex
(maxima::complex-erf z
))
2118 (bigfloat (maxima::$bfloat
(maxima::$expand
(maxima::bfloat-erf
(maxima::to z
))))))
2120 (bigfloat (maxima::$bfloat
(maxima::$expand
(maxima::complex-bfloat-erf
(maxima::to z
))))))))))
2123 ;; Compute erfc(z) via 1 - erf(z) is not very accurate if erf(z) is
2124 ;; near 1. Wolfram says
2126 ;; erfc(z) = 1 - sqrt(z^2)/z * (1 - 1/sqrt(pi)*gamma_incomplete_tail(1/2, z^2))
2128 ;; For real(z) > 0, sqrt(z^2)/z is 1 so
2130 ;; erfc(z) = 1 - (1 - 1/sqrt(pi)*gamma_incomplete_tail(1/2,z^2))
2131 ;; = 1/sqrt(pi)*gamma_incomplete_tail(1/2,z^2)
2133 ;; For real(z) < 0, sqrt(z^2)/z is -1 so
2135 ;; erfc(z) = 1 + (1 - 1/sqrt(pi)*gamma_incomplete_tail(1/2,z^2))
2136 ;; = 2 - 1/sqrt(pi)*gamma_incomplete(1/2,z^2)
2137 (flet ((gamma-inc (z)
2140 (maxima::gamma-incomplete
0.5 z
))
2142 (bigfloat:to
(maxima::$bfloat
2143 (maxima::bfloat-gamma-incomplete
(maxima::$bfloat maxima
::1//2)
2146 (bigfloat:to
(maxima::$bfloat
2147 (maxima::complex-bfloat-gamma-incomplete
(maxima::$bfloat maxima
::1//2)
2148 (maxima::to z
))))))))
2149 (if (>= (realpart z
) 0)
2150 (/ (gamma-inc (* z z
))
2153 (/ (gamma-inc (* z z
))
2156 (in-package :maxima
)
2158 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2160 ;;; Implementation of the Generalized Error function Erf(z1,z2)
2162 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2164 (defmfun $erf_generalized
(z1 z2
)
2165 (simplify (list '(%erf_generalized
) z1 z2
)))
2167 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2169 (defprop $erf_generalized %erf_generalized alias
)
2170 (defprop $erf_generalized %erf_generalized verb
)
2172 (defprop %erf_generalized $erf_generalized reversealias
)
2173 (defprop %erf_generalized $erf_generalized noun
)
2175 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2177 ;;; Generalized Erf has mirror symmetry
2179 (defprop %erf_generalized t commutes-with-conjugate
)
2181 ;;; Generalized Erf distributes over bags
2183 (defprop %erf_generalized
(mlist $matrix mequal
) distribute_over
)
2185 ;;; Generalized Erf is antisymmetric Erf(z1,z2) = - Erf(z2,z1)
2189 #-gcl
(:load-toplevel
:execute
)
2190 (let (($context
'$global
) (context '$global
))
2191 (meval '(($declare
) %erf_generalized $antisymmetric
))
2192 ;; Let's remove built-in symbols from list for user-defined properties.
2193 (setq $props
(remove '%erf_generalized $props
))))
2195 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2197 (defprop %erf_generalized simp-erf-generalized operators
)
2199 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2201 (defprop %erf_generalized
2203 ;; derivative wrt z1
2205 ((mexpt) $%pi
((rat) -
1 2))
2206 ((mexpt) $%e
((mtimes) -
1 ((mexpt) z1
2))))
2207 ;; derviative wrt z2
2209 ((mexpt) $%pi
((rat) -
1 2))
2210 ((mexpt) $%e
((mtimes) -
1 ((mexpt) z2
2)))))
2213 ;;; ----------------------------------------------------------------------------
2215 (defprop %erf_generalized simplim%erf_generalized simplim%function
)
2217 (defun simplim%erf_generalized
(expr var val
)
2218 ;; Look for the limit of the arguments.
2219 (let ((z1 (limit (cadr expr
) var val
'think
))
2220 (z2 (limit (caddr expr
) var val
'think
)))
2222 ;; Handle infinities at this place.
2224 (alike1 z2
'((mtimes) -
1 $minf
)))
2225 (sub 1 (take '(%erf
) z1
)))
2227 (alike1 z2
'((mtimes) -
1 $inf
)))
2228 (sub (mul -
1 (take '(%erf
) z1
)) 1))
2230 (alike1 z1
'((mtimes) -
1 $minf
)))
2231 (sub (take '(%erf
) z2
) 1))
2233 (alike1 z1
'((mtimes) -
1 $inf
)))
2234 (add (take '(%erf
) z2
) 1))
2236 ;; All other cases are handled by the simplifier of the function.
2237 (simplify (list '(%erf_generalized
) z1 z2
))))))
2239 ;;; ----------------------------------------------------------------------------
2241 (defun simp-erf-generalized (expr ignored simpflag
)
2242 (declare (ignore ignored
))
2244 (let ((z1 (simpcheck (cadr expr
) simpflag
))
2245 (z2 (simpcheck (caddr expr
) simpflag
)))
2248 ;; Check for specific values
2250 ((and (zerop1 z1
) (zerop1 z2
)) 0)
2251 ((zerop1 z1
) (take '(%erf
) z2
))
2252 ((zerop1 z2
) (mul -
1 (take '(%erf
) z1
)))
2254 (alike1 z2
'((mtimes) -
1 $minf
)))
2255 (sub 1 (take '(%erf
) z1
)))
2257 (alike1 z2
'((mtimes) -
1 $inf
)))
2258 (sub (mul -
1 (take '(%erf
) z1
)) 1))
2260 (alike1 z1
'((mtimes) -
1 $minf
)))
2261 (sub (take '(%erf
) z2
) 1))
2263 (alike1 z1
'((mtimes) -
1 $inf
)))
2264 (add (take '(%erf
) z2
) 1))
2266 ;; Check for numerical evaluation. Use erf(z1,z2) = erf(z2)-erf(z1)
2268 ((float-numerical-eval-p z1 z2
)
2269 (- (bigfloat::bf-erf
($float z2
))
2270 (bigfloat::bf-erf
($float z1
))))
2271 ((complex-float-numerical-eval-p z1 z2
)
2275 (complex ($float
($realpart z2
)) ($float
($imagpart z2
))))
2277 (complex ($float
($realpart z1
)) ($float
($imagpart z1
)))))))
2278 ((bigfloat-numerical-eval-p z1 z2
)
2280 (bigfloat::bf-erf
(bigfloat:to
($bfloat z2
)))
2281 (bigfloat::bf-erf
(bigfloat:to
($bfloat z1
))))))
2282 ((complex-bigfloat-numerical-eval-p z1 z2
)
2285 (bigfloat:to
(add ($bfloat
($realpart z2
)) (mul '$%i
($bfloat
($imagpart z2
))))))
2287 (bigfloat:to
(add ($bfloat
($realpart z1
)) (mul '$%i
($bfloat
($imagpart z1
)))))))))
2289 ;; Argument simplification
2291 ((and $trigsign
(great (mul -
1 z1
) z1
) (great (mul -
1 z2
) z2
))
2292 (mul -
1 (simplify (list '(%erf_generalized
) (mul -
1 z1
) (mul -
1 z2
)))))
2294 ;; Transformation to Erf
2296 ($erf_representation
2297 (sub (simplify (list '(%erf
) z2
)) (simplify (list '(%erf
) z1
))))
2300 (eqtest (list '(%erf_generalized
) z1 z2
) expr
)))))
2302 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2304 ;;; Implementation of the Complementary Error function Erfc(z)
2306 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2309 (simplify (list '(%erfc
) z
)))
2311 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2313 (defprop $erfc %erfc alias
)
2314 (defprop $erfc %erfc verb
)
2316 (defprop %erfc $erfc reversealias
)
2317 (defprop %erfc $erfc noun
)
2319 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2321 (defprop %erfc t commutes-with-conjugate
)
2323 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2325 (defprop %erfc simp-erfc operators
)
2327 ;;; Complementary Error function distributes over bags
2329 (defprop %erfc
(mlist $matrix mequal
) distribute_over
)
2331 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2336 ((mexpt) $%pi
((rat) -
1 2))
2337 ((mexpt) $%e
((mtimes) -
1 ((mexpt) z
2)))))
2340 ;;; Integral of the Error function erfc
2346 ((mexpt) $%pi
((rat) -
1 2))
2347 ((mexpt) $%e
((mtimes) -
1 ((mexpt) z
2))))
2348 ((mtimes) z
((%erfc
) z
))))
2351 ;;; ----------------------------------------------------------------------------
2353 (defprop %erfc simplim%erfc simplim%function
)
2355 (defun simplim%erfc
(expr var val
)
2356 ;; Look for the limit of the arguments.
2357 (let ((z (limit (cadr expr
) var val
'think
)))
2359 ;; Handle infinities at this place.
2362 ((eq z
'$infinity
) ;; parallel to code in simplim%erf-%tanh
2363 (destructuring-let (((rpart . ipart
) (trisplit (cadr expr
)))
2365 (setq rlim
(limit rpart var val
'think
))
2367 (limit (m* rpart
(m^t ipart -
1)) var val
'think
))
2368 (setq ans
($asksign
(m+ `((mabs) ,ans
) -
1)))
2369 (cond ((or (eq ans
'$pos
) (eq ans
'$zero
))
2370 (cond ((eq rlim
'$inf
) 0)
2371 ((eq rlim
'$minf
) 2)
2374 ((eq z
'$ind
) '$ind
)
2376 ;; All other cases are handled by the simplifier of the function.
2377 (simplify (list '(%erfc
) z
))))))
2379 ;;; ----------------------------------------------------------------------------
2381 (defun simp-erfc (expr z simpflag
)
2383 (setq z
(simpcheck (cadr expr
) simpflag
))
2386 ;; Check for specific values
2392 ;; Check for numerical evaluation.
2394 ((numerical-eval-p z
)
2395 (to (bigfloat::bf-erfc
(bigfloat:to z
))))
2397 ;; Argument simplification
2399 ((taylorize (mop expr
) (second expr
)))
2400 ((and $trigsign
(great (mul -
1 z
) z
))
2401 (sub 2 (simplify (list '(%erfc
) (mul -
1 z
)))))
2403 ;; Representation through equivalent functions
2405 ($hypergeometric_representation
2408 (power '$%pi
'((rat simp
) 1 2))
2409 (list '(%hypergeometric simp
)
2410 (list '(mlist simp
) '((rat simp
) 1 2))
2411 (list '(mlist simp
) '((rat simp
) 3 2))
2412 (mul -
1 (power z
2))))))
2414 ;; Transformation to Erf or Erfi
2416 ((and $erf_representation
2417 (not (eq $erf_representation
'$erfc
)))
2418 (case $erf_representation
2420 (sub 1 (take '(%erf
) z
)))
2422 (add 1 (mul '$%i
(take '(%erfi
) (mul '$%i z
)))))
2424 (eqtest (list '(%erfc
) z
) expr
))))
2427 (eqtest (list '(%erfc
) z
) expr
))))
2429 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2431 ;;; Implementation of the Imaginary Error function Erfi(z)
2433 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2436 (simplify (list '(%erfi
) z
)))
2438 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2440 (defprop $erfi %erfi alias
)
2441 (defprop $erfi %erfi verb
)
2443 (defprop %erfi $erfi reversealias
)
2444 (defprop %erfi $erfi noun
)
2446 ;;; erfi has mirror symmetry
2448 (defprop %erfi t commutes-with-conjugate
)
2450 ;;; erfi is an odd function
2452 (defprop %erfi odd-function-reflect reflection-rule
)
2454 ;;; erfi is an simplifying function
2456 (defprop %erfi simp-erfi operators
)
2458 ;;; erfi distributes over bags
2460 (defprop %erfi
(mlist $matrix mequal
) distribute_over
)
2462 ;;; Derivative of the Error function erfi
2467 ((mexpt) $%pi
((rat) -
1 2))
2468 ((mexpt) $%e
((mexpt) z
2))))
2471 ;;; Integral of the Error function erfi
2477 ((mexpt) $%pi
((rat) -
1 2))
2478 ((mexpt) $%e
((mexpt) z
2)))
2479 ((mtimes) z
((%erfi
) z
))))
2482 ;;; ----------------------------------------------------------------------------
2484 (defprop %erfi simplim%erfi simplim%function
)
2486 (defun simplim%erfi
(expr var val
)
2487 ;; Look for the limit of the arguments.
2488 (let ((z (limit (cadr expr
) var val
'think
)))
2490 ;; Handle infinities at this place.
2491 ((eq z
'$inf
) '$inf
)
2492 ((eq z
'$minf
) '$minf
)
2494 ;; All other cases are handled by the simplifier of the function.
2495 (simplify (list '(%erfi
) z
))))))
2497 ;;; ----------------------------------------------------------------------------
2499 (in-package :bigfloat
)
2502 ;; Use the relationship erfi(z) = -%i*erf(%i*z)
2503 (let* ((iz (complex (- (imagpart z
)) (realpart z
))) ; %i*z
2504 (result (bf-erf iz
)))
2505 (complex (imagpart result
) (- (realpart result
))))))
2506 ;; Take care to return real results when the argument is real.
2510 (realpart (erfi z
)))
2513 (in-package :maxima
)
2515 (defun simp-erfi (expr z simpflag
)
2517 (setq z
(simpcheck (cadr expr
) simpflag
))
2520 ;; Check for specific values
2523 ((eq z
'$inf
) '$inf
)
2524 ((eq z
'$minf
) '$minf
)
2526 ;; Check for numerical evaluation. Use erfi(z) = -%i*erf(%i*z).
2528 ((numerical-eval-p z
)
2529 (to (bigfloat::bf-erfi
(bigfloat:to z
))))
2531 ;; Argument simplification
2533 ((taylorize (mop expr
) (second expr
)))
2536 (mul '$%i
(simplify (list '(%erf
) (coeff z
'$%i
1)))))
2537 ((apply-reflection-simp (mop expr
) z $trigsign
))
2539 ;; Representation through equivalent functions
2541 ($hypergeometric_representation
2543 (power '$%pi
'((rat simp
) 1 2))
2544 (list '(%hypergeometric simp
)
2545 (list '(mlist simp
) '((rat simp
) 1 2))
2546 (list '(mlist simp
) '((rat simp
) 3 2))
2549 ;; Transformation to Erf or Erfc
2551 ((and $erf_representation
2552 (not (eq $erf_representation
'$erfi
)))
2553 (case $erf_representation
2555 (mul -
1 '$%i
(take '(%erf
) (mul '$%i z
))))
2557 (sub (mul '$%i
(take '(%erfc
) (mul '$%i z
))) '$%i
))
2559 (eqtest (list '(%erfi
) z
) expr
))))
2562 (eqtest (list '(%erfi
) z
) expr
))))
2564 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2566 ;;; The implementation of the Inverse Error function
2568 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2570 (defmfun $inverse_erf
(z)
2571 (simplify (list '(%inverse_erf
) z
)))
2573 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2575 ;;; Set properties to give full support to the parser and display
2577 (defprop $inverse_erf %inverse_erf alias
)
2578 (defprop $inverse_erf %inverse_erf verb
)
2580 (defprop %inverse_erf $inverse_erf reversealias
)
2581 (defprop %inverse_erf $inverse_erf noun
)
2583 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2585 ;;; The Inverse Error function is a simplifying function
2587 (defprop %inverse_erf simp-inverse-erf operators
)
2589 ;;; The Inverse Error function distributes over bags
2591 (defprop %inverse_erf
(mlist $matrix mequal
) distribute_over
)
2593 ;;; inverse_erf is the inverse of the erf function
2595 (defprop %inverse_erf %erf $inverse
)
2596 (defprop %erf %inverse_erf $inverse
)
2598 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2600 ;;; Differentiation of the Inverse Error function
2602 (defprop %inverse_erf
2606 ((mexpt) $%pi
((rat) 1 2))
2607 ((mexpt) $%e
((mexpt) ((%inverse_erf
) z
) 2))))
2610 ;;; Integral of the Inverse Error function
2612 (defprop %inverse_erf
2615 ((mexpt) $%pi
((rat) -
1 2))
2616 ((mexpt) $%e
((mtimes) -
1 ((mexpt) ((%inverse_erf
) z
) 2)))))
2619 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2621 ;;; We support a simplim%function. The function is looked up in simplimit and
2622 ;;; handles specific values of the function.
2624 (defprop %inverse_erf simplim%inverse_erf simplim%function
)
2626 (defun simplim%inverse_erf
(expr var val
)
2627 ;; Look for the limit of the argument.
2628 (let ((z (limit (cadr expr
) var val
'think
)))
2630 ;; Handle an argument 1 at this place
2632 ((onep1 (mul -
1 z
)) '$minf
)
2634 ;; All other cases are handled by the simplifier of the function.
2635 (simplify (list '(%inverse_erf
) z
))))))
2637 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2639 (defun simp-inverse-erf (expr z simpflag
)
2641 (setq z
(simpcheck (cadr expr
) simpflag
))
2646 (intl:gettext
"inverse_erf: inverse_erf(~:M) is undefined.") z
))
2648 ((numerical-eval-p z
)
2649 (to (bigfloat::bf-inverse-erf
(bigfloat:to z
))))
2650 ((taylorize (mop expr
) (cadr expr
)))
2652 (eqtest (list '(%inverse_erf
) z
) expr
))))
2654 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2656 ;;; The implementation of the Inverse Complementary Error function
2658 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2660 (defmfun $inverse_erfc
(z)
2661 (simplify (list '(%inverse_erfc
) z
)))
2663 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2665 ;;; Set properties to give full support to the parser and display
2667 (defprop $inverse_erfc %inverse_erfc alias
)
2668 (defprop $inverse_erfc %inverse_erfc verb
)
2670 (defprop %inverse_erfc $inverse_erfc reversealias
)
2671 (defprop %inverse_erfc $inverse_erfc noun
)
2673 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2675 ;;; Inverse Complementary Error function is a simplifying function
2677 (defprop %inverse_erfc simp-inverse-erfc operators
)
2679 ;;; Inverse Complementary Error function distributes over bags
2681 (defprop %inverse_erfc
(mlist $matrix mequal
) distribute_over
)
2683 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2685 ;;; inverse_erfc is the inverse of the erfc function
2687 (defprop %inverse_erfc %erfc $inverse
)
2688 (defprop %erfc %inverse_erfc $inverse
)
2691 ;;; Differentiation of the Inverse Complementary Error function
2693 (defprop %inverse_erfc
2697 ((mexpt) $%pi
((rat) 1 2))
2698 ((mexpt) $%e
((mexpt) ((%inverse_erfc
) z
) 2))))
2701 ;;; Integral of the Inverse Complementary Error function
2703 (defprop %inverse_erfc
2706 ((mexpt) $%pi
((rat) -
1 2))
2708 ((mtimes) -
1 ((mexpt) ((%inverse_erfc
) z
) 2)))))
2711 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2713 ;;; We support a simplim%function. The function is looked up in simplimit and
2714 ;;; handles specific values of the function.
2716 (defprop %inverse_erfc simplim%inverse_erfc simplim%function
)
2718 (defun simplim%inverse_erfc
(expr var val
)
2719 ;; Look for the limit of the argument.
2720 (let ((z (limit (cadr expr
) var val
'think
)))
2722 ;; Handle an argument 0 at this place
2727 ((zerop1 (add z -
2)) '$minf
)
2729 ;; All other cases are handled by the simplifier of the function.
2730 (simplify (list '(%inverse_erfc
) z
))))))
2732 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2734 (defun simp-inverse-erfc (expr z simpflag
)
2736 (setq z
(simpcheck (cadr expr
) simpflag
))
2739 (zerop1 (add z -
2)))
2741 (intl:gettext
"inverse_erfc: inverse_erfc(~:M) is undefined.") z
))
2743 ((numerical-eval-p z
)
2744 (to (bigfloat::bf-inverse-erfc
(bigfloat:to z
))))
2745 ((taylorize (mop expr
) (cadr expr
)))
2747 (eqtest (list '(%inverse_erfc
) z
) expr
))))
2749 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2751 ;;; Implementation of the Newton algorithm to calculate numerical values
2752 ;;; of the Inverse Error functions in float or bigfloat precision.
2753 ;;; The algorithm is a modified version of the routine in newton1.mac.
2755 (defvar *debug-newton
* nil
)
2756 (defvar *newton-maxcount
* 1000)
2757 (defvar *newton-epsilon-factor
* 50)
2758 (defvar *newton-epsilon-factor-float
* 10)
2760 (defun float-newton (expr var x0 eps
)
2761 (do ((s (sdiff expr var
))
2764 (count 0 (+ count
1)))
2765 ((> count
*newton-maxcount
*)
2767 (intl:gettext
"float-newton: Newton does not converge for ~:M") expr
))
2768 (setq sn
($float
(maxima-substitute xn var expr
)))
2769 (when (< (abs sn
) eps
) (return xn
))
2770 (when *debug-newton
* (format t
"~&xn = ~A~%" xn
))
2771 (setq xn
($float
(sub xn
(div sn
(maxima-substitute xn var s
)))))))
2773 (defun bfloat-newton (expr var x0 eps
)
2774 (do ((s (sdiff expr var
))
2777 (count 0 (+ count
1)))
2778 ((> count
*newton-maxcount
*)
2780 (intl:gettext
"bfloat-newton: Newton does not converge for ~:M") expr
))
2781 (setq sn
($bfloat
(maxima-substitute xn var expr
)))
2782 (when (eq ($sign
(sub (simplify (list '(mabs) sn
)) eps
)) '$neg
)
2784 (when *debug-newton
* (format t
"~&xn = ~A~%" xn
))
2785 (setq xn
($bfloat
(sub xn
(div sn
(maxima-substitute xn var s
)))))))
2788 (in-package :bigfloat
)
2790 ;; Compute inverse_erf(z) for z a real or complex number, including
2791 ;; bigfloat objects. The value is computing using a Newton iteration
2792 ;; to solve erf(x) = z.
2793 (defun bf-inverse-erf (z)
2798 (intl:gettext
"bf-inverse-erf: inverse_erf(~M) is undefined")
2800 ((minusp (realpart z
))
2801 ;; inverse_erf is odd because erf is.
2802 (- (bf-inverse-erf (- z
))))
2806 ;; Find an approximate solution for x = inverse_erf(z).
2808 (cond ((<= (abs z
) 1)
2809 ;; For small z, inverse_erf(z) = z*sqrt(%pi)/2
2810 ;; + O(z^3). Thus, x = z*sqrt(%pi)/2 is our
2811 ;; initial starting point.
2812 (* z
(sqrt (%pi z
)) 1/2))
2814 ;; For |z| > 1 and realpart(z) >= 0, we have
2815 ;; the asymptotic series z = erf(x) = 1 -
2816 ;; exp(-x^2)/x/sqrt(%pi).
2819 ;; x = sqrt(-log(x*sqrt(%pi)*(1-z))
2821 ;; We can use this as a fixed-point iteration
2822 ;; to find x, and we can start the iteration at
2823 ;; x = 1. Just do one more iteration. I (RLT)
2824 ;; think that's close enough to get the Newton
2825 ;; algorithm to converge.
2826 (let* ((sp (sqrt (%pi z
)))
2827 (a (sqrt (- (log (* sp
(- 1 z
)))))))
2828 (setf a
(sqrt (- (log (* a sp
(- 1 z
))))))
2829 (setf a
(sqrt (- (log (* a sp
(- 1 z
)))))))))))
2830 (when maxima
::*debug-newton
*
2831 (format t
"approx = ~S~%" result
))
2833 (let ((two/sqrt-pi
(/ 2 (sqrt (%pi z
))))
2835 ;; Try to pick a reasonable epsilon value for the
2836 ;; Newton iteration.
2837 (cond ((<= (abs z
) 1)
2839 (cl:real
(* maxima
::*newton-epsilon-factor-float
*
2840 maxima
::flonum-epsilon
))
2841 (t (* maxima
::*newton-epsilon-factor
* (epsilon z
)))))
2843 (* maxima
::*newton-epsilon-factor
* (epsilon z
))))))
2844 (when maxima
::*debug-newton
*
2845 (format t
"eps = ~S~%" eps
))
2847 ;; Derivative of erf(x)
2848 (* two
/sqrt-pi
(exp (- (* x x
))))))
2855 (defun bf-inverse-erfc (z)
2858 (intl:gettext
"bf-inverse-erfc: inverse_erfc(~M) is undefined")
2865 ;; Find an approximate solution for x =
2866 ;; inverse_erfc(z). We have inverse_erfc(z) =
2867 ;; inverse_erf(1-z), so that's a good starting point.
2868 ;; We don't need full precision, so a float value is
2869 ;; good enough. But if 1-z is 1, inverse_erf is
2870 ;; undefined, so we need to do something else.
2872 (let ((1-z (float (- 1 z
) 0.0)))
2874 (if (minusp (realpart z
))
2875 (bf-inverse-erf (+ 1 (* 5 maxima
::flonum-epsilon
)))
2876 (bf-inverse-erf (- 1 (* 5 maxima
::flonum-epsilon
)))))
2878 (bf-inverse-erf 1-z
))))))
2879 (when maxima
::*debug-newton
*
2880 (format t
"approx = ~S~%" result
))
2882 (let ((-two/sqrt-pi
(/ -
2 (sqrt (%pi z
))))
2883 (eps (* maxima
::*newton-epsilon-factor
* (epsilon z
))))
2884 (when maxima
::*debug-newton
*
2885 (format t
"eps = ~S~%" eps
))
2887 ;; Derivative of erfc(x)
2888 (* -two
/sqrt-pi
(exp (- (* x x
))))))
2889 (bf-newton #'bf-erfc
2895 ;; Newton iteration for solving f(x) = z, given f and the derivative
2897 (defun bf-newton (f df z start eps
)
2899 (delta (/ (- (funcall f start
) z
)
2901 (/ (- (funcall f x
) z
)
2903 (count 0 (1+ count
)))
2904 ((or (< (abs delta
) (* (abs x
) eps
))
2905 (> count maxima
::*newton-maxcount
*))
2906 (if (> count maxima
::*newton-maxcount
*)
2908 (intl:gettext
"bf-newton: failed to converge after ~M iterations: delta = ~S, x = ~S eps = ~S")
2911 (when maxima
::*debug-newton
*
2912 (format t
"x = ~S, abs(delta) = ~S relerr = ~S~%"
2913 x
(abs delta
) (/ (abs delta
) (abs x
))))
2914 (setf x
(- x delta
))))
2916 (in-package :maxima
)
2918 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2920 ;;; Implementation of the Fresnel Integral S(z)
2922 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2924 (defmfun $fresnel_s
(z)
2925 (simplify (list '(%fresnel_s
) z
)))
2927 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2929 ;;; Set properties to give full support to the parser and display
2931 (defprop $fresnel_s %fresnel_s alias
)
2932 (defprop $fresnel_s %fresnel_s verb
)
2934 (defprop %fresnel_s $fresnel_s reversealias
)
2935 (defprop %fresnel_s $fresnel_s noun
)
2937 ;;; fresnel_s is a simplifying function
2939 (defprop %fresnel_s simp-fresnel-s operators
)
2941 ;;; fresnel_s distributes over bags
2943 (defprop %fresnel_s
(mlist $matrix mequal
) distribute_over
)
2945 ;;; fresnel_s has mirror symmetry
2947 (defprop %fresnel_s t commutes-with-conjugate
)
2949 ;;; fresnel_s is an odd function
2951 ;;; Maxima has two mechanism to define a reflection property
2952 ;;; 1. Declare the feature oddfun or evenfun
2953 ;;; 2. Put a reflection rule on the property list
2955 ;;; The second way is used for the trig functions. We use it here too.
2957 ;;; This would be the first way to give the property of an odd function.
2960 ; #-gcl (:load-toplevel :execute)
2961 ; (let (($context '$global) (context '$global))
2962 ; (meval '(($declare) %fresnel_s $oddfun))
2963 ; ;; Let's remove built-in symbols from list for user-defined properties.
2964 ; (setq $props (remove '%fresnel_s $props))))
2966 (defprop %fresnel_s odd-function-reflect reflection-rule
)
2968 ;;; Differentiation of the Fresnel Integral S
2972 ((%sin
) ((mtimes) ((rat) 1 2) $%pi
((mexpt) z
2))))
2975 ;;; Integration of the Fresnel Integral S
2980 ((mtimes) z
((%fresnel_s
) z
))
2983 ((%cos
) ((mtimes) ((rat) 1 2) $%pi
((mexpt) z
2))))))
2986 ;;; Limits of the Fresnel Integral S
2988 (defprop %fresnel_s simplim%fresnel_s simplim%function
)
2989 (defun simplim%fresnel_s
(exp var val
)
2990 (let ((arg (limit (cadr exp
) var val
'think
)))
2991 (cond ((eq arg
'$inf
)
2996 `((%fresnel_s
) ,arg
)))))
2998 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3000 (defvar *fresnel-maxit
* 1000)
3001 (defvar *fresnel-eps
* (* 2 flonum-epsilon
))
3002 (defvar *fresnel-min
* 1e-32)
3004 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3005 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3007 (in-package :bigfloat
)
3009 (defun bf-fresnel (z)
3010 (let* ((eps (epsilon z
))
3011 (maxit maxima
::*fresnel-maxit
*)
3014 ;; For very small x, we have
3015 ;; fresnel_s(x) = %pi/6*z^3
3017 (s (* (/ bf-pi
6) z z z
))
3019 (when (> (abs z
) eps
)
3022 (when maxima
::*debug-gamma
*
3023 (format t
"~& in FRESNEL series expansion.~%"))
3024 (let ((sums 0) (sumc z
))
3027 (fact (* (/ bf-pi
2) (* z z
)))
3034 (maxima::merror
(intl:gettext
"fresnel: series expansion failed for (COMPLEX-BFLOAT-FRESNEL ~:M).") z
))
3035 (setq term
(* term
(/ fact k
)))
3036 (setq sum
(+ sum
(/ (* sign term
) n
)))
3037 (setq test
(* (abs sum
) eps
))
3040 (setq sign
(- sign
))
3046 (if (< (abs term
) test
)
3051 (let* ((sqrt-pi (sqrt bf-pi
))
3052 (z+ (* (complex 1/2 1/2)
3055 (z- (* (complex 1/2 -
1/2)
3060 (setq s
(* (complex 1/4 1/4)
3061 (+ erf
+ (* (complex 0 -
1) erf-
))))
3062 (setq c
(* (complex 1/4 -
1/4)
3063 (+ erf
+ (* (complex 0 1) erf-
))))))))
3066 (defun bf-fresnel-s (z)
3067 (if (and (complexp z
) (zerop (realpart z
)))
3068 ;; A pure imaginary argument. Use fresnel_s(%i*x)=-%i*fresnel_s(x).
3070 (- (bf-fresnel-s (imagpart z
))))
3071 (let ((fs (bf-fresnel z
)))
3076 (defun bf-fresnel-c (z)
3077 (if (and (complexp z
) (zerop (realpart z
)))
3078 ;; A pure imaginary argument. Use fresnel_c(%i*x)=%i*fresnel_c(x).
3080 (bf-fresnel-c (imagpart z
)))
3081 (let ((fc (nth-value 1 (bf-fresnel z
))))
3086 (in-package :maxima
)
3087 (defun simp-fresnel-s (expr z simpflag
)
3089 (setq z
(simpcheck (cadr expr
) simpflag
))
3092 ;; Check for specific values
3095 ((eq z
'$inf
) '((rat simp
) 1 2))
3096 ((eq z
'$minf
) '((rat simp
) -
1 2))
3098 ;; Check for numerical evaluation
3099 ((numerical-eval-p z
)
3100 (to (bigfloat::bf-fresnel-s
(bigfloat::to z
))))
3102 ;; Check for argument simplification
3104 ((taylorize (mop expr
) (second expr
)))
3105 ((and $%iargs
(multiplep z
'$%i
))
3106 (mul -
1 '$%i
(simplify (list '(%fresnel_s
) (coeff z
'$%i
1)))))
3107 ((apply-reflection-simp (mop expr
) z $trigsign
))
3109 ;; Representation through equivalent functions
3111 ($erf_representation
3113 (div (add 1 '$%i
) 4)
3118 (mul (div (add 1 '$%i
) 2) (power '$%pi
'((rat simp
) 1 2)) z
)))
3123 (mul (div (sub 1 '$%i
) 2)
3124 (power '$%pi
'((rat simp
) 1 2)) z
)))))))
3126 ($hypergeometric_representation
3127 (mul (div (mul '$%pi
(power z
3)) 6)
3128 (take '($hypergeometric
)
3129 (list '(mlist) (div 3 4))
3130 (list '(mlist) (div 3 2) (div 7 4))
3131 (mul -
1 (div (mul (power '$%pi
2) (power z
4)) 16)))))
3134 (eqtest (list '(%fresnel_s
) z
) expr
))))
3136 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3138 ;;; Implementation of the Fresnel Integral C(z)
3140 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3142 (defmfun $fresnel_c
(z)
3143 (simplify (list '(%fresnel_c
) z
)))
3145 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3147 ;;; Set properties to give full support to the parser and display
3149 (defprop $fresnel_c %fresnel_c alias
)
3150 (defprop $fresnel_c %fresnel_c verb
)
3152 (defprop %fresnel_c $fresnel_c reversealias
)
3153 (defprop %fresnel_c $fresnel_c noun
)
3155 ;;; fresnel_c is a simplifying function
3157 (defprop %fresnel_c simp-fresnel-c operators
)
3159 ;;; fresnel_c distributes over bags
3161 (defprop %fresnel_c
(mlist $matrix mequal
) distribute_over
)
3163 ;;; fresnel_c has mirror symmetry
3165 (defprop %fresnel_c t commutes-with-conjugate
)
3167 ;;; fresnel_c is an odd function
3168 ;;; Maxima has two mechanism to define a reflection property
3169 ;;; 1. Declare the feature oddfun or evenfun
3170 ;;; 2. Put a reflection rule on the property list
3172 ;;; The second way is used for the trig functions. We use it here too.
3174 (defprop %fresnel_c odd-function-reflect reflection-rule
)
3176 ;;; Differentiation of the Fresnel Integral C
3180 ((%cos
) ((mtimes) ((rat) 1 2) $%pi
((mexpt) z
2))))
3183 ;;; Integration of the Fresnel Integral C
3188 ((mtimes) z
((%fresnel_c
) z
))
3191 ((%sin
) ((mtimes) ((rat) 1 2) $%pi
((mexpt) z
2))))))
3194 ;;; Limits of the Fresnel Integral C
3196 (defprop %fresnel_c simplim%fresnel_c simplim%function
)
3197 (defun simplim%fresnel_c
(exp var val
)
3198 (let ((arg (limit (cadr exp
) var val
'think
)))
3199 (cond ((eq arg
'$inf
)
3204 `((%fresnel_c
) ,arg
)))))
3206 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3208 (defun simp-fresnel-c (expr z simpflag
)
3210 (setq z
(simpcheck (cadr expr
) simpflag
))
3213 ;; Check for specific values
3216 ((eq z
'$inf
) '((rat simp
) 1 2))
3217 ((eq z
'$minf
) '((rat simp
) -
1 2))
3219 ;; Check for numerical evaluation
3220 ((numerical-eval-p z
)
3221 (to (bigfloat::bf-fresnel-c
(bigfloat::to z
))))
3224 ;; Check for argument simplification
3226 ((taylorize (mop expr
) (second expr
)))
3227 ((and $%iargs
(multiplep z
'$%i
))
3228 (mul '$%i
(simplify (list '(%fresnel_c
) (coeff z
'$%i
1)))))
3229 ((apply-reflection-simp (mop expr
) z $trigsign
))
3231 ;; Representation through equivalent functions
3233 ($erf_representation
3235 (div (sub 1 '$%i
) 4)
3240 (mul (div (add 1 '$%i
) 2) (power '$%pi
'((rat simp
) 1 2)) z
)))
3245 (mul (div (sub 1 '$%i
) 2)
3246 (power '$%pi
'((rat simp
) 1 2)) z
)))))))
3248 ($hypergeometric_representation
3250 (take '($hypergeometric
)
3251 (list '(mlist) (div 1 4))
3252 (list '(mlist) (div 1 2) (div 5 4))
3253 (mul -
1 (div (mul (power '$%pi
2) (power z
4)) 16)))))
3256 (eqtest (list '(%fresnel_c
) z
) expr
))))
3259 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3261 ;;; Implementation of the Beta function
3263 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3265 ;;; The code for the implementation of the beta function is in the files
3266 ;;; csimp2.lisp, simp.lisp and mactex.lisp.
3267 ;;; At this place we only implement the operator property SYMMETRIC.
3269 ;;; Beta is symmetric beta(a,b) = beta(b,a)
3273 #-gcl
(:load-toplevel
:execute
)
3274 (let (($context
'$global
) (context '$global
))
3275 (meval '(($declare
) $beta $symmetric
))
3276 ;; Let's remove built-in symbols from list for user-defined properties.
3277 (setq $props
(remove '$beta $props
))))
3279 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3281 ;;; Implementation of the Incomplete Beta function
3283 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3285 (defvar *beta-incomplete-maxit
* 10000)
3286 (defvar *beta-incomplete-eps
* 1.0e-15)
3288 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3290 (defmfun $beta_incomplete
(a b z
)
3291 (simplify (list '(%beta_incomplete
) a b z
)))
3293 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3295 (defprop $beta_incomplete %beta_incomplete alias
)
3296 (defprop $beta_incomplete %beta_incomplete verb
)
3298 (defprop %beta_incomplete $beta_incomplete reversealias
)
3299 (defprop %beta_incomplete $beta_incomplete noun
)
3301 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3303 (defprop %beta_incomplete simp-beta-incomplete operators
)
3305 ;;; beta_incomplete distributes over bags
3307 (defprop %beta_incomplete
(mlist $matrix mequal
) distribute_over
)
3309 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3311 (defprop %beta_incomplete
3315 ((%beta_incomplete
) a b z
)
3317 ((mexpt) ((%gamma
) a
) 2)
3318 (($hypergeometric_regularized
)
3319 ((mlist) a a
((mplus) 1 ((mtimes) -
1 b
)))
3320 ((mlist) ((mplus) 1 a
) ((mplus) 1 a
))
3330 ((mtimes) -
1 ((mqapply) (($psi array
) 0) ((mplus) a b
)))))
3332 ((%beta_incomplete
) b a
((mplus) 1 ((mtimes) -
1 z
)))
3333 ((%log
) ((mplus) 1 ((mtimes) -
1 z
))))
3335 ((mexpt) ((%gamma
) b
) 2)
3336 (($hypergeometric_regularized
)
3337 ((mlist) b b
((mplus) 1 ((mtimes) -
1 a
)))
3338 ((mlist) ((mplus) 1 b
) ((mplus) 1 b
))
3339 ((mplus) 1 ((mtimes) -
1 z
)))
3340 ((mexpt) ((mplus) 1 ((mtimes) -
1 z
)) b
))))
3341 ;; The derivative wrt z
3343 ((mexpt) ((mplus) 1 ((mtimes) -
1 z
)) ((mplus) -
1 b
))
3344 ((mexpt) z
((mplus) -
1 a
))))
3347 ;;; Integral of the Incomplete Beta function
3349 (defprop %beta_incomplete
3354 ((mtimes) -
1 ((%beta_incomplete
) ((mplus) 1 a
) b z
))
3355 ((mtimes) ((%beta_incomplete
) a b z
) z
)))
3358 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3360 (defun simp-beta-incomplete (expr ignored simpflag
)
3361 (declare (ignore ignored
))
3362 (arg-count-check 3 expr
)
3363 (let ((a (simpcheck (cadr expr
) simpflag
))
3364 (b (simpcheck (caddr expr
) simpflag
))
3365 (z (simpcheck (cadddr expr
) simpflag
))
3368 (format t
"~&SIMP-BETA-INCOMPLETE:~%")
3369 (format t
"~& : a = ~A~%" a
)
3370 (format t
"~& : b = ~A~%" b
)
3371 (format t
"~& : z = ~A~%" z
))
3374 ;; Check for specific values
3377 (let ((sgn ($sign
($realpart a
))))
3378 (cond ((member sgn
'($neg $zero
))
3381 "beta_incomplete: beta_incomplete(~:M,~:M,~:M) is undefined.")
3383 ((member sgn
'($pos $pz
))
3386 (eqtest (list '(%beta_incomplete
) a b z
) expr
)))))
3388 ((and (onep1 z
) (eq ($sign
($realpart b
)) '$pos
))
3389 ;; z=1 and realpart(b)>0. Simplify to a Beta function.
3390 ;; If we have to evaluate numerically preserve the type.
3392 ((complex-float-numerical-eval-p a b z
)
3393 (simplify (list '($beta
) ($float a
) ($float b
))))
3394 ((complex-bigfloat-numerical-eval-p a b z
)
3395 (simplify (list '($beta
) ($bfloat a
) ($bfloat b
))))
3397 (simplify (list '($beta
) a b
)))))
3400 (and (integer-representation-p a
)
3401 (eq ($sign a
) '$neg
)
3403 (not (integer-representation-p b
)))
3404 (eq ($sign
(add a b
)) '$pos
))))
3405 ;; The argument a is zero or a is negative and the argument b is
3406 ;; not in a valid range. Beta incomplete is undefined.
3407 ;; It would be more correct to return Complex infinity.
3410 "beta_incomplete: beta_incomplete(~:M,~:M,~:M) is undefined.") a b z
))
3412 ;; Check for numerical evaluation in Float or Bigfloat precision
3414 ((complex-float-numerical-eval-p a b z
)
3416 ((not (and (integer-representation-p a
) (< a
0.0)))
3417 (let ((*beta-incomplete-eps
* (bigfloat:epsilon
($float
1.0))))
3418 (beta-incomplete ($float a
) ($float b
) ($float z
))))
3420 ;; Negative integer a and b is in a valid range. Expand.
3422 (beta-incomplete-expand-negative-integer
3423 (truncate a
) ($float b
) ($float z
))))))
3425 ((complex-bigfloat-numerical-eval-p a b z
)
3427 ((not (and (integer-representation-p a
) (eq ($sign a
) '$neg
)))
3428 (let ((*beta-incomplete-eps
*
3429 (bigfloat:epsilon
(bigfloat:bigfloat
1.0))))
3430 (beta-incomplete ($bfloat a
) ($bfloat b
) ($bfloat z
))))
3432 ;; Negative integer a and b is in a valid range. Expand.
3434 (beta-incomplete-expand-negative-integer
3435 ($truncate a
) ($bfloat b
) ($bfloat z
))))))
3437 ;; Argument simplifications and transformations
3441 (or (not (integerp a
))
3443 ;; Expand for b a positive integer and a not a negative integer.
3445 (simplify (list '($beta
) a b
))
3447 (let ((index (gensumindex)))
3451 (simplify (list '($pochhammer
) a index
))
3452 (power (sub 1 z
) index
))
3453 (simplify (list '(mfactorial) index
)))
3454 index
0 (sub b
1)))))
3456 ((and (integerp a
) (plusp a
))
3457 ;; Expand for a a positive integer.
3459 (simplify (list '($beta
) a b
))
3463 (let ((index (gensumindex)))
3467 (simplify (list '($pochhammer
) b index
))
3469 (simplify (list '(mfactorial) index
)))
3470 index
0 (sub a
1)))))))
3472 ((and (integerp a
) (minusp a
) (integerp b
) (plusp b
) (<= b
(- a
)))
3473 ;; Expand for a a negative integer and b an integer with b <= -a.
3476 (let ((index (gensumindex)))
3479 (mul (simplify (list '($pochhammer
) (sub 1 b
) index
))
3482 (simplify (list '(mfactorial) index
))))
3483 index
0 (sub b
1)))))
3485 ((and $beta_expand
(mplusp a
) (integerp (cadr a
)) (plusp (cadr a
)))
3487 (a (simplify (cons '(mplus) (cddr a
)))))
3491 (simplify (list '($pochhammer
) a n
))
3492 (simplify (list '($pochhammer
) (add a b
) n
)))
3493 ($beta_incomplete a b z
))
3495 (power (add a b n -
1) -
1)
3496 (let ((index (gensumindex)))
3500 (simplify (list '($pochhammer
)
3501 (add 1 (mul -
1 a
) (mul -
1 n
))
3503 (simplify (list '($pochhammer
)
3504 (add 2 (mul -
1 a
) (mul -
1 b
) (mul -
1 n
))
3506 (mul (power (sub 1 z
) b
)
3507 (power z
(add a n
(mul -
1 index
) -
1))))
3508 index
0 (sub n
1)))))))
3510 ((and $beta_expand
(mplusp a
) (integerp (cadr a
)) (minusp (cadr a
)))
3511 (let ((n (- (cadr a
)))
3512 (a (simplify (cons '(mplus) (cddr a
)))))
3516 (simplify (list '($pochhammer
) (add 1 (mul -
1 a
) (mul -
1 b
)) n
))
3517 (simplify (list '($pochhammer
) (sub 1 a
) n
)))
3518 ($beta_incomplete a b z
))
3522 (list '($pochhammer
) (add 2 (mul -
1 a
) (mul -
1 b
)) (sub n
1)))
3523 (simplify (list '($pochhammer
) (sub 1 a
) n
)))
3524 (let ((index (gensumindex)))
3528 (simplify (list '($pochhammer
) (sub 1 a
) index
))
3529 (simplify (list '($pochhammer
)
3530 (add 2 (mul -
1 a
) (mul -
1 b
))
3532 (mul (power (sub 1 z
) b
)
3533 (power z
(add a
(mul -
1 index
) -
1))))
3534 index
0 (sub n
1)))))))
3537 (eqtest (list '(%beta_incomplete
) a b z
) expr
)))))
3539 (defun beta-incomplete-expand-negative-integer (a b z
)
3542 (let ((index (gensumindex)) ($simpsum t
))
3545 (mul (simplify (list '($pochhammer
) (sub 1 b
) index
))
3547 (mul (add index a
) (simplify (list '(mfactorial) index
))))
3548 index
0 (sub b
1)))))
3550 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3552 (defun beta-incomplete (a b z
)
3554 ((eq ($sign
(sub (mul ($realpart z
) ($realpart
(add a b
2)))
3555 ($realpart
(add a
1))))
3559 (simplify (list '($beta
) a b
))
3560 (to (numeric-beta-incomplete b a
(sub 1.0 z
))))))
3562 (to (numeric-beta-incomplete a b z
)))))
3564 (defun numeric-beta-incomplete (a b z
)
3566 (format t
"~&NUMERIC-BETA-INCOMPLETE enters continued fractions~%"))
3567 (let ((a (bigfloat:to a
))
3569 (z (bigfloat:to z
)))
3570 (do* ((beta-maxit *beta-incomplete-maxit
*)
3571 (beta-eps *beta-incomplete-eps
*)
3572 (beta-min (bigfloat:* beta-eps beta-eps
))
3573 (ab (bigfloat:+ a b
))
3574 (ap (bigfloat:+ a
1.0))
3575 (am (bigfloat:- a
1.0))
3577 (d (bigfloat:-
1.0 (bigfloat:/ (bigfloat:* z ab
) ap
)))
3578 (d (if (bigfloat:< (bigfloat:abs d
) beta-min
) beta-min d
))
3579 (d (bigfloat:/ 1.0 d
))
3586 (merror (intl:gettext
"beta_incomplete: continued fractions failed for beta_incomplete(~:M, ~:M, ~:M).") a b z
))
3588 (setq aa
(bigfloat:/ (bigfloat:* m z
(bigfloat:- b m
))
3589 (bigfloat:* (bigfloat:+ am m2
)
3590 (bigfloat:+ a m2
))))
3591 (setq d
(bigfloat:+ 1.0 (bigfloat:* aa d
)))
3592 (when (bigfloat:< (bigfloat:abs d
) beta-min
) (setq d beta-min
))
3593 (setq c
(bigfloat:+ 1.0 (bigfloat:/ aa c
)))
3594 (when (bigfloat:< (bigfloat:abs c
) beta-min
) (setq c beta-min
))
3595 (setq d
(bigfloat:/ 1.0 d
))
3596 (setq h
(bigfloat:* h d c
))
3597 (setq aa
(bigfloat:/ (bigfloat:* -
1
3599 (bigfloat:+ ab m
) z
)
3600 (bigfloat:* (bigfloat:+ a m2
)
3601 (bigfloat:+ ap m2
))))
3602 (setq d
(bigfloat:+ 1.0 (bigfloat:* aa d
)))
3603 (when (bigfloat:< (bigfloat:abs d
) beta-min
) (setq d beta-min
))
3604 (setq c
(bigfloat:+ 1.0 (bigfloat:/ aa c
)))
3605 (when (bigfloat:< (bigfloat:abs c
) beta-min
) (setq c beta-min
))
3606 (setq d
(bigfloat:/ 1.0 d
))
3607 (setq de
(bigfloat:* d c
))
3608 (setq h
(bigfloat:* h de
))
3609 (when (bigfloat:< (bigfloat:abs
(bigfloat:- de
1.0)) beta-eps
)
3611 (format t
"~&Continued fractions finished.~%")
3612 (format t
"~& z = ~A~%" z
)
3613 (format t
"~& a = ~A~%" a
)
3614 (format t
"~& b = ~A~%" b
)
3615 (format t
"~& h = ~A~%" h
))
3621 (bigfloat:expt
(bigfloat:-
1.0 z
) b
)) a
)))
3623 (format t
"~& result = ~A~%" result
))
3626 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3628 ;;; Implementation of the Generalized Incomplete Beta function
3630 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3632 (defmfun $beta_incomplete_generalized
(a b z1 z2
)
3633 (simplify (list '(%beta_incomplete_generalized
) a b z1 z2
)))
3635 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3637 (defprop $beta_incomplete_generalized %beta_incomplete_generalized alias
)
3638 (defprop $beta_incomplete_generalized %beta_incomplete_generalized verb
)
3640 (defprop %beta_incomplete_generalized $beta_incomplete_generalized reversealias
)
3641 (defprop %beta_incomplete_generalized $beta_incomplete_generalized noun
)
3643 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3645 (defprop %beta_incomplete_generalized
3646 simp-beta-incomplete-generalized operators
)
3648 ;;; beta_incomplete_generalized distributes over bags
3650 (defprop %beta_incomplete_generalized
(mlist $matrix mequal
) distribute_over
)
3652 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3654 ;;; Generalized Incomplete Gamma function has not mirror symmetry for z1 or z2
3655 ;;; but not on the negative real axis and for z1 or z2 real and > 1.
3656 ;;; We support a conjugate-function which test these cases.
3658 (defprop %beta_incomplete_generalized
3659 conjugate-beta-incomplete-generalized conjugate-function
)
3661 (defun conjugate-beta-incomplete-generalized (args)
3662 (let ((a (first args
))
3666 (cond ((and (off-negative-real-axisp z1
)
3667 (not (and (zerop1 ($imagpart z1
))
3668 (eq ($sign
(sub ($realpart z1
) 1)) '$pos
)))
3669 (off-negative-real-axisp z2
)
3670 (not (and (zerop1 ($imagpart z2
))
3671 (eq ($sign
(sub ($realpart z2
) 1)) '$pos
))))
3674 '(%beta_incomplete_generalized
)
3675 (simplify (list '($conjugate
) a
))
3676 (simplify (list '($conjugate
) b
))
3677 (simplify (list '($conjugate
) z1
))
3678 (simplify (list '($conjugate
) z2
)))))
3682 (simplify (list '(%beta_incomplete_generalized
)
3685 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3687 (defprop %beta_incomplete_generalized
3692 ((%beta_incomplete
) a b z1
)
3695 ((mexpt) ((%gamma
) a
) 2)
3698 (($hypergeometric_regularized
)
3699 ((mlist) a a
((mplus) 1 ((mtimes) -
1 b
)))
3700 ((mlist) ((mplus) 1 a
) ((mplus) 1 a
))
3704 (($hypergeometric_regularized
)
3705 ((mlist) a a
((mplus) 1 ((mtimes) -
1 b
)))
3706 ((mlist) ((mplus) 1 a
) ((mplus) 1 a
))
3709 ((mtimes) ((%beta_incomplete
) a b z2
) ((%log
) z2
)))
3713 ((%beta_incomplete
) b a
((mplus) 1 ((mtimes) -
1 z1
)))
3714 ((%log
) ((mplus) 1 ((mtimes) -
1 z1
))))
3716 ((%beta_incomplete
) b a
((mplus) 1 ((mtimes) -
1 z2
)))
3717 ((%log
) ((mplus) 1 ((mtimes) -
1 z2
))))
3719 ((mexpt) ((%gamma
) b
) 2)
3722 (($hypergeometric_regularized
)
3723 ((mlist) b b
((mplus) 1 ((mtimes) -
1 a
)))
3724 ((mlist) ((mplus) 1 b
) ((mplus) 1 b
))
3725 ((mplus) 1 ((mtimes) -
1 z1
)))
3726 ((mexpt) ((mplus) 1 ((mtimes) -
1 z1
)) b
))
3728 (($hypergeometric_regularized
)
3729 ((mlist) b b
((mplus) 1 ((mtimes) -
1 a
)))
3730 ((mlist) ((mplus) 1 b
) ((mplus) 1 b
))
3731 ((mplus) 1 ((mtimes) -
1 z2
)))
3732 ((mexpt) ((mplus) 1 ((mtimes) -
1 z2
)) b
)))))
3733 ;; The derivative wrt z1
3736 ((mplus) 1 ((mtimes) -
1 z1
))
3738 ((mexpt) z1
((mplus) -
1 a
)))
3739 ;; The derivative wrt z2
3742 ((mplus) 1 ((mtimes) -
1 z2
))
3744 ((mexpt) z2
((mplus) -
1 a
))))
3747 ;;; Integral of the Incomplete Beta function
3749 (defprop %beta_incomplete_generalized
3755 ((%beta_incomplete
) ((mplus) 1 a
) b z1
)
3756 ((mtimes) ((%beta_incomplete_generalized
) a b z1 z2
) z1
))
3760 ((%beta_incomplete
) ((mplus) 1 a
) b z2
))
3761 ((mtimes) ((%beta_incomplete_generalized
) a b z1 z2
) z2
)))
3764 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3766 (defun simp-beta-incomplete-generalized (expr ignored simpflag
)
3767 (declare (ignore ignored
))
3768 (arg-count-check 4 expr
)
3769 (let ((a (simpcheck (second expr
) simpflag
))
3770 (b (simpcheck (third expr
) simpflag
))
3771 (z1 (simpcheck (fourth expr
) simpflag
))
3772 (z2 (simpcheck (fifth expr
) simpflag
))
3776 ;; Check for specific values
3779 (let ((sgn ($sign
($realpart a
))))
3780 (cond ((eq sgn
'$neg
)
3783 "beta_incomplete_generalized: beta_incomplete_generalized(~:M,~:M,~:M,~:M) is undefined.")
3785 ((member sgn
'($pos $pz
))
3786 (mul -
1 ($beta_incomplete a b z1
)))
3789 (list '(%beta_incomplete_generalized
) a b z1 z2
) expr
)))))
3792 (let ((sgn ($sign
($realpart a
))))
3793 (cond ((eq sgn
'$neg
)
3796 "beta_incomplete_generalized: beta_incomplete_generalized(~:M,~:M,~:M,~:M) is undefined.")
3798 ((member sgn
'($pos $pz
))
3799 (mul -
1 ($beta_incomplete a b z2
)))
3802 (list '(%beta_incomplete_generalized
) a b z1 z2
) expr
)))))
3804 ((and (onep1 z2
) (or (not (mnump a
)) (not (mnump b
)) (not (mnump z1
))))
3805 (let ((sgn ($sign
($realpart b
))))
3806 (cond ((member sgn
'($pos $pz
))
3807 (sub (simplify (list '($beta
) a b
))
3808 ($beta_incomplete a b z1
)))
3811 (list '(%beta_incomplete_generalized
) a b z1 z2
) expr
)))))
3813 ((and (onep1 z1
) (or (not (mnump a
)) (not (mnump b
)) (not (mnump z2
))))
3814 (let ((sgn ($sign
($realpart b
))))
3815 (cond ((member sgn
'($pos $pz
))
3816 (sub ($beta_incomplete a b z2
)
3817 (simplify (list '($beta
) a b
))))
3820 (list '(%beta_incomplete_generalized
) a b z1 z2
) expr
)))))
3822 ;; Check for numerical evaluation in Float or Bigfloat precision
3824 ((complex-float-numerical-eval-p a b z1 z2
)
3825 (let ((*beta-incomplete-eps
* (bigfloat:epsilon
($float
1.0))))
3826 (sub (beta-incomplete ($float a
) ($float b
) ($float z2
))
3827 (beta-incomplete ($float a
) ($float b
) ($float z1
)))))
3829 ((complex-bigfloat-numerical-eval-p a b z1 z2
)
3830 (let ((*beta-incomplete-eps
*
3831 (bigfloat:epsilon
(bigfloat:bigfloat
1.0))))
3832 (sub (beta-incomplete ($bfloat a
) ($bfloat b
) ($bfloat z2
))
3833 (beta-incomplete ($bfloat a
) ($bfloat b
) ($bfloat z1
)))))
3835 ;; Check for argument simplifications and transformations
3837 ((and (integerp a
) (plusp a
))
3839 (simplify (list '($beta
) a b
))
3842 (power (sub 1 z1
) b
)
3843 (let ((index (gensumindex)))
3847 (simplify (list '($pochhammer
) b index
))
3849 (simplify (list '(mfactorial) index
)))
3850 index
0 (sub a
1))))
3852 (power (sub 1 z2
) b
)
3853 (let ((index (gensumindex)))
3857 (simplify (list '($pochhammer
) b index
))
3859 (simplify (list '(mfactorial) index
)))
3860 index
0 (sub a
1)))))))
3862 ((and (integerp b
) (plusp b
))
3864 (simplify (list '($beta
) a b
))
3868 (let ((index (gensumindex)))
3872 (simplify (list '($pochhammer
) a index
))
3873 (power (sub 1 z2
) index
))
3874 (simplify (list '(mfactorial) index
)))
3875 index
0 (sub b
1))))
3878 (let ((index (gensumindex)))
3882 (simplify (list '($pochhammer
) a index
))
3883 (power (sub 1 z1
) index
))
3884 (simplify (list '(mfactorial) index
)))
3885 index
0 (sub b
1)))))))
3887 ((and $beta_expand
(mplusp a
) (integerp (cadr a
)) (plusp (cadr a
)))
3889 (a (simplify (cons '(mplus) (cddr a
)))))
3893 (simplify (list '($pochhammer
) a n
))
3894 (simplify (list '($pochhammer
) (add a b
) n
)))
3895 ($beta_incomplete_generalized a b z1 z2
))
3897 (power (add a b n -
1) -
1)
3898 (let ((index (gensumindex)))
3902 (simplify (list '($pochhammer
)
3903 (add 1 (mul -
1 a
) (mul -
1 n
))
3905 (simplify (list '($pochhammer
)
3906 (add 2 (mul -
1 a
) (mul -
1 b
) (mul -
1 n
))
3909 (mul (power (sub 1 z1
) b
)
3910 (power z1
(add a n
(mul -
1 index
) -
1)))
3911 (mul (power (sub 1 z2
) b
)
3912 (power z2
(add a n
(mul -
1 index
) -
1)))))
3913 index
0 (sub n
1)))))))
3915 ((and $beta_expand
(mplusp a
) (integerp (cadr a
)) (minusp (cadr a
)))
3916 (let ((n (- (cadr a
)))
3917 (a (simplify (cons '(mplus) (cddr a
)))))
3921 (simplify (list '($pochhammer
) (add 1 (mul -
1 a
) (mul -
1 b
)) n
))
3922 (simplify (list '($pochhammer
) (sub 1 a
) n
)))
3923 ($beta_incomplete_generalized a b z1 z2
))
3927 (list '($pochhammer
) (add 2 (mul -
1 a
) (mul -
1 b
)) (sub n
1)))
3928 (simplify (list '($pochhammer
) (sub 1 a
) n
)))
3929 (let ((index (gensumindex)))
3933 (simplify (list '($pochhammer
) (sub 1 a
) index
))
3934 (simplify (list '($pochhammer
)
3935 (add 2 (mul -
1 a
) (mul -
1 b
))
3938 (mul (power (sub 1 z2
) b
)
3939 (power z2
(add a
(mul -
1 index
) -
1)))
3940 (mul (power (sub 1 z1
) b
)
3941 (power z1
(add a
(mul -
1 index
) -
1)))))
3942 index
0 (sub n
1)))))))
3945 (eqtest (list '(%beta_incomplete_generalized
) a b z1 z2
) expr
)))))
3947 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3949 ;;; Implementation of the Regularized Incomplete Beta function
3951 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3953 (defmfun $beta_incomplete_regularized
(a b z
)
3954 (simplify (list '(%beta_incomplete_regularized
) a b z
)))
3956 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3958 (defprop $beta_incomplete_regularized %beta_incomplete_regularized alias
)
3959 (defprop $beta_incomplete_regularized %beta_incomplete_regularized verb
)
3961 (defprop %beta_incomplete_regularized $beta_incomplete_regularized reversealias
)
3962 (defprop %beta_incomplete_regularized $beta_incomplete_regularized noun
)
3964 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3966 (defprop %beta_incomplete_regularized
3967 simp-beta-incomplete-regularized operators
)
3969 ;;; beta_incomplete_regularized distributes over bags
3971 (defprop %beta_incomplete_regularized
(mlist $matrix mequal
) distribute_over
)
3973 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3975 (defprop %beta_incomplete_regularized
3981 (($hypergeometric_regularized
)
3982 ((mlist) a a
((mplus) 1 ((mtimes) -
1 b
)))
3983 ((mlist) ((mplus) 1 a
) ((mplus) 2 a
)) z
)
3984 ((mexpt) ((%gamma
) b
) -
1)
3985 ((%gamma
) ((mplus) a b
))
3988 ((%beta_incomplete_regularized
) a b z
)
3990 ((mtimes) -
1 ((mqapply) (($psi array
) 0) a
))
3991 ((mqapply) (($psi array
) 0) ((mplus) a b
))
3996 ((%beta_incomplete_regularized
) b a
((mplus) 1 ((mtimes) -
1 z
)))
3998 ((mqapply) (($psi array
) 0) b
)
3999 ((mtimes) -
1 ((mqapply) (($psi array
) 0) ((mplus) a b
)))
4000 ((mtimes) -
1 ((%log
) ((mplus) 1 ((mtimes) -
1 z
))))))
4002 ((mexpt) ((%gamma
) a
) -
1)
4004 ((%gamma
) ((mplus) a b
))
4005 (($hypergeometric_regularized
)
4006 ((mlist) b b
((mplus) 1 ((mtimes) -
1 a
)))
4007 ((mlist) ((mplus) 1 b
) ((mplus) 1 b
))
4008 ((mplus) 1 ((mtimes) -
1 z
)))
4009 ((mexpt) ((mplus) 1 ((mtimes) -
1 z
)) b
)))
4010 ;; The derivative wrt z
4012 ((mexpt) (($beta
) a b
) -
1)
4013 ((mexpt) ((mplus) 1 ((mtimes) -
1 z
)) ((mplus) -
1 b
))
4014 ((mexpt) z
((mplus) -
1 a
))))
4017 ;;; Integral of the Generalized Incomplete Beta function
4019 (defprop %beta_incomplete_regularized
4026 ((%beta_incomplete_regularized
) ((mplus) 1 a
) b z
)
4027 ((mexpt) ((mplus) a b
) -
1))
4028 ((mtimes) ((%beta_incomplete_regularized
) a b z
) z
)))
4031 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4033 (defun simp-beta-incomplete-regularized (expr ignored simpflag
)
4034 (declare (ignore ignored
))
4035 (arg-count-check 3 expr
)
4036 (let ((a (simpcheck (second expr
) simpflag
))
4037 (b (simpcheck (third expr
) simpflag
))
4038 (z (simpcheck (fourth expr
) simpflag
))
4042 ;; Check for specific values
4045 (let ((sgn ($sign
($realpart a
))))
4046 (cond ((eq sgn
'$neg
)
4049 "beta_incomplete_regularized: beta_incomplete_regularized(~:M,~:M,~:M) is undefined.")
4051 ((member sgn
'($pos $pz
))
4055 (list '(%beta_incomplete_regularized
) a b z
) expr
)))))
4061 (let ((sgn ($sign
($realpart b
))))
4062 (cond ((member sgn
'($pos $pz
))
4066 (list '(%beta_incomplete_regularized
) a b z
) expr
)))))
4068 ((and (integer-representation-p b
)
4069 (if ($bfloatp b
) (minusp (cadr b
)) (minusp b
)) )
4070 ;; Problem: for b a negative integer the Regularized Incomplete
4071 ;; Beta function is defined to be zero. BUT: When we calculate
4072 ;; e.g. beta_incomplete(1.0,-2.0,1/2)/beta(1.0,-2.0) we get the
4073 ;; result -3.0, because beta_incomplete and beta are defined for
4074 ;; for this case. How do we get a consistent behaviour?
4077 ((and (integer-representation-p a
)
4078 (if ($bfloatp a
) (minusp (cadr a
)) (minusp a
)) )
4080 ;; TODO: The following line does not work for bigfloats.
4081 ((and (integer-representation-p b
) (<= b
(- a
)))
4082 ;; Does $beta_incomplete or simpbeta underflow in this case?
4083 (div ($beta_incomplete a b z
)
4084 (simplify (list '($beta
) a b
))))
4088 ;; Check for numerical evaluation in Float or Bigfloat precision
4090 ((complex-float-numerical-eval-p a b z
)
4091 (let ((*beta-incomplete-eps
* (bigfloat:epsilon
($float
1.0)))
4093 (setq a
($float a
) b
($float b
))
4094 (if (or (< ($abs
(setq beta
(simplify (list '($beta
) a b
)))) 1e-307)
4095 (< ($abs
(setq ibeta
(beta-incomplete a b
($float z
)))) 1e-307) )
4096 ;; In case of underflow (see bug #2999) or precision loss use bigfloats
4097 ;; and emporarily give some extra precision but avoid fpprec dependency.
4098 ;; Is this workaround correct for complex values?
4100 ($float
($beta_incomplete_regularized
($bfloat a
) ($bfloat b
) z
)) )
4101 ($rectform
(div ibeta beta
)) )))
4103 ((complex-bigfloat-numerical-eval-p a b z
)
4104 (let ((*beta-incomplete-eps
*
4105 (bigfloat:epsilon
(bigfloat:bigfloat
1.0))))
4106 (setq a
($bfloat a
) b
($bfloat b
))
4108 (div (beta-incomplete a b
($bfloat z
))
4109 (simplify (list '($beta
) a b
))))))
4111 ;; Check for argument simplifications and transformations
4113 ((and (integerp b
) (plusp b
))
4114 (div ($beta_incomplete a b z
)
4115 (simplify (list '($beta
) a b
))))
4117 ((and (integerp a
) (plusp a
))
4118 (div ($beta_incomplete a b z
)
4119 (simplify (list '($beta
) a b
))))
4121 ((and $beta_expand
(mplusp a
) (integerp (cadr a
)) (plusp (cadr a
)))
4123 (a (simplify (cons '(mplus) (cddr a
)))))
4125 ($beta_incomplete_regularized a b z
)
4127 (power (add a b n -
1) -
1)
4128 (power (simplify (list '($beta
) (add a n
) b
)) -
1)
4129 (let ((index (gensumindex)))
4133 (simplify (list '($pochhammer
)
4134 (add 1 (mul -
1 a
) (mul -
1 n
))
4136 (simplify (list '($pochhammer
)
4137 (add 2 (mul -
1 a
) (mul -
1 b
) (mul -
1 n
))
4140 (power z
(add a n
(mul -
1 index
) -
1)))
4141 index
0 (sub n
1)))))))
4143 ((and $beta_expand
(mplusp a
) (integerp (cadr a
)) (minusp (cadr a
)))
4144 (let ((n (- (cadr a
)))
4145 (a (simplify (cons '(mplus) (cddr a
)))))
4147 ($beta_incomplete_regularized a b z
)
4149 (power (add a b -
1) -
1)
4150 (power (simplify (list '($beta
) a b
)) -
1)
4151 (let ((index (gensumindex)))
4155 (simplify (list '($pochhammer
) (sub 1 a
) index
))
4156 (simplify (list '($pochhammer
)
4157 (add 2 (mul -
1 a
) (mul -
1 b
))
4160 (power z
(add a
(mul -
1 index
) -
1)))
4161 index
0 (sub n
1)))))))
4164 (eqtest (list '(%beta_incomplete_regularized
) a b z
) expr
)))))
4166 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;