# Incomplete gamma functions. (2.00)
# (and chi-squared cumulative distribution)
# @see Numerical Recipes in Fortran77 (Ch. 6.2 Special Functions).
from math import lgamma, exp, log
# P(a, x)
# γ(a, x) / Γ(a)
# Regularized lower incomplete gamma function.
def lowergamma(a, x):
return 1 - uppergamma(a, x)
# Q(a, x)
# Γ(a, x) / Γ(a)
# Regularized upper incomplete gamma function.
def uppergamma(a, x):
if x < 0 or a <= 0:
raise ValueError('bad arguments')
if x < a+1:
return 1 - p_series(a, x)
else:
return q_continued_fraction(a, x)
def p_series(a, x, itmax=1000, eps=3.0E-7):
if x == 0: # !
return 0.0
ap=a
sum_=1/a
del_=sum_
for _ in range(1, 1+itmax):
ap=ap+1
del_=del_*x/ap
sum_=sum_+del_
if abs(del_) < abs(sum_)*eps:
return sum_*exp(-x+a*log(x)-lgamma(a))
raise ValueError('a too large, itmax too small')
def q_continued_fraction(a, x, itmax=1000, eps=3.0E-7, fpmin=1.0E-30):
b=x+1-a
c=1/fpmin
d=1/b
h=d
for i in range(1, 1+itmax):
an=-i*(i-a)
b=b+2
d=an*d+b
if abs(d) < fpmin: d=fpmin
c=b+an/c
if abs(c) < fpmin: c=fpmin
d=1/d
del_=d*c
h=h*del_
if abs(del_-1) < eps:
return h*exp(-x+a*log(x)-lgamma(a))
raise ValueError('a too large, itmax too small')
# Chi-squared cumulative distribution function.
def cdf(x, k):
return lowergamma(k/2, x/2)
# Chi-squared p-value.
def pvalue(x, k):
return 1 - cdf(x, k)
# Example.
# @see Engineering Tables/Chi-squared Distribution - Wikibooks
k=1
v=[0.000157, 0.00393, 0.455, 3.841, 6.635]
print([round(pvalue(x, k), 2) for x in v])
k=2
v=[0.0201, 0.103, 1.386, 5.991, 9.210]
print([round(pvalue(x, k), 2) for x in v])
k=4
v=[0.297, 0.711, 3.357, 9.488, 13.277]
print([round(pvalue(x, k), 2) for x in v])
k=10
v=[2.558, 3.940, 9.342, 18.307, 23.209]
print([round(pvalue(x, k), 2) for x in v])
k=100
v=[70.065, 77.929, 99.334, 124.342, 135.807]
print([round(pvalue(x, k), 2) for x in v])
k=1000
v=[898.912, 927.594, 999.333, 1074.679, 1106.969]
print([round(pvalue(x, k), 2) for x in v])
IyBJbmNvbXBsZXRlIGdhbW1hIGZ1bmN0aW9ucy4gKDIuMDApCiMgKGFuZCBjaGktc3F1YXJlZCBjdW11bGF0aXZlIGRpc3RyaWJ1dGlvbikKIyBAc2VlIE51bWVyaWNhbCBSZWNpcGVzIGluIEZvcnRyYW43NyAoQ2guIDYuMiBTcGVjaWFsIEZ1bmN0aW9ucykuCgpmcm9tIG1hdGggaW1wb3J0IGxnYW1tYSwgZXhwLCBsb2cKCiMgUChhLCB4KQojIM6zKGEsIHgpIC8gzpMoYSkKIyBSZWd1bGFyaXplZCBsb3dlciBpbmNvbXBsZXRlIGdhbW1hIGZ1bmN0aW9uLgpkZWYgbG93ZXJnYW1tYShhLCB4KToKICAgIHJldHVybiAxIC0gdXBwZXJnYW1tYShhLCB4KQoKIyBRKGEsIHgpCiMgzpMoYSwgeCkgLyDOkyhhKQojIFJlZ3VsYXJpemVkIHVwcGVyIGluY29tcGxldGUgZ2FtbWEgZnVuY3Rpb24uCmRlZiB1cHBlcmdhbW1hKGEsIHgpOgogICAgaWYgeCA8IDAgb3IgYSA8PSAwOgogICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ2JhZCBhcmd1bWVudHMnKQogICAgaWYgeCA8IGErMToKICAgICAgICByZXR1cm4gMSAtIHBfc2VyaWVzKGEsIHgpCiAgICBlbHNlOgogICAgICAgIHJldHVybiBxX2NvbnRpbnVlZF9mcmFjdGlvbihhLCB4KQoKZGVmIHBfc2VyaWVzKGEsIHgsIGl0bWF4PTEwMDAsIGVwcz0zLjBFLTcpOgogICAgaWYgeCA9PSAwOiAjICEKICAgICAgICByZXR1cm4gMC4wCiAgICBhcD1hCiAgICBzdW1fPTEvYQogICAgZGVsXz1zdW1fCiAgICBmb3IgXyBpbiByYW5nZSgxLCAxK2l0bWF4KToKICAgICAgICBhcD1hcCsxCiAgICAgICAgZGVsXz1kZWxfKngvYXAKICAgICAgICBzdW1fPXN1bV8rZGVsXwogICAgICAgIGlmIGFicyhkZWxfKSA8IGFicyhzdW1fKSplcHM6CiAgICAgICAgICAgIHJldHVybiBzdW1fKmV4cCgteCthKmxvZyh4KS1sZ2FtbWEoYSkpCiAgICByYWlzZSBWYWx1ZUVycm9yKCdhIHRvbyBsYXJnZSwgaXRtYXggdG9vIHNtYWxsJykKCmRlZiBxX2NvbnRpbnVlZF9mcmFjdGlvbihhLCB4LCBpdG1heD0xMDAwLCBlcHM9My4wRS03LCBmcG1pbj0xLjBFLTMwKToKICAgIGI9eCsxLWEKICAgIGM9MS9mcG1pbgogICAgZD0xL2IKICAgIGg9ZAogICAgZm9yIGkgaW4gcmFuZ2UoMSwgMStpdG1heCk6CiAgICAgICAgYW49LWkqKGktYSkKICAgICAgICBiPWIrMgogICAgICAgIGQ9YW4qZCtiCiAgICAgICAgaWYgYWJzKGQpIDwgZnBtaW46IGQ9ZnBtaW4KICAgICAgICBjPWIrYW4vYwogICAgICAgIGlmIGFicyhjKSA8IGZwbWluOiBjPWZwbWluCiAgICAgICAgZD0xL2QKICAgICAgICBkZWxfPWQqYwogICAgICAgIGg9aCpkZWxfCiAgICAgICAgaWYgYWJzKGRlbF8tMSkgPCBlcHM6CiAgICAgICAgICAgIHJldHVybiBoKmV4cCgteCthKmxvZyh4KS1sZ2FtbWEoYSkpCiAgICByYWlzZSBWYWx1ZUVycm9yKCdhIHRvbyBsYXJnZSwgaXRtYXggdG9vIHNtYWxsJykKCiMgQ2hpLXNxdWFyZWQgY3VtdWxhdGl2ZSBkaXN0cmlidXRpb24gZnVuY3Rpb24uCmRlZiBjZGYoeCwgayk6CiAgICByZXR1cm4gbG93ZXJnYW1tYShrLzIsIHgvMikKCiMgQ2hpLXNxdWFyZWQgcC12YWx1ZS4KZGVmIHB2YWx1ZSh4LCBrKToKICAgIHJldHVybiAxIC0gY2RmKHgsIGspCgojIEV4YW1wbGUuCiMgQHNlZSBFbmdpbmVlcmluZyBUYWJsZXMvQ2hpLXNxdWFyZWQgRGlzdHJpYnV0aW9uIC0gV2lraWJvb2tzCms9MQp2PVswLjAwMDE1NywgMC4wMDM5MywgMC40NTUsIDMuODQxLCA2LjYzNV0KcHJpbnQoW3JvdW5kKHB2YWx1ZSh4LCBrKSwgMikgZm9yIHggaW4gdl0pCms9Mgp2PVswLjAyMDEsIDAuMTAzLCAxLjM4NiwgNS45OTEsIDkuMjEwXQpwcmludChbcm91bmQocHZhbHVlKHgsIGspLCAyKSBmb3IgeCBpbiB2XSkKaz00CnY9WzAuMjk3LCAwLjcxMSwgMy4zNTcsIDkuNDg4LCAxMy4yNzddCnByaW50KFtyb3VuZChwdmFsdWUoeCwgayksIDIpIGZvciB4IGluIHZdKQprPTEwCnY9WzIuNTU4LCAzLjk0MCwgOS4zNDIsIDE4LjMwNywgMjMuMjA5XQpwcmludChbcm91bmQocHZhbHVlKHgsIGspLCAyKSBmb3IgeCBpbiB2XSkKaz0xMDAKdj1bNzAuMDY1LCA3Ny45MjksIDk5LjMzNCwgMTI0LjM0MiwgMTM1LjgwN10KcHJpbnQoW3JvdW5kKHB2YWx1ZSh4LCBrKSwgMikgZm9yIHggaW4gdl0pCms9MTAwMAp2PVs4OTguOTEyLCA5MjcuNTk0LCA5OTkuMzMzLCAxMDc0LjY3OSwgMTEwNi45NjldCnByaW50KFtyb3VuZChwdmFsdWUoeCwgayksIDIpIGZvciB4IGluIHZdKQ==