50 from fpconst
import NaN, NegInf, PosInf
55 NegInf = float(
"-inf")
56 PosInf = float(
"+inf")
60 from scipy.special
import ive
84 with numpy.errstate(divide =
"ignore"):
85 a = numpy.log(ive(v,z))
91 with numpy.errstate(divide =
"ignore", invalid =
"ignore"):
92 b = -math.log(2. * math.pi) / 2. * numpy.log(z)
93 z = numpy.clip(z, 1., PosInf)
94 b += numpy.log1p((mu - 1.) / (8. * z) * (-1. + (mu - 9.) / (16. * z) * (1. - (mu - 25.) / (24. * z))))
96 return z + numpy.where(z < 1e8, a, b)
99 def ncx2logpdf(x, k, l):
100 return -math.log(2.) - (x+l)/2. + (k/4.-.5) * (numpy.log(x) - numpy.log(l)) + logiv(k/2.-1., numpy.sqrt(l) * numpy.sqrt(x))
102 def ncx2pdf(x, k, l):
103 return numpy.exp(ncx2logpdf(x, k, l))
115 def assert_probability(f):
116 def g(*args, **kwargs):
117 p = f(*args, **kwargs)
118 if isinstance(p, numpy.ndarray):
119 assert ((0. <= p) & (p <= 1.)).all()
126 def assert_ln_probability(f):
127 def g(*args, **kwargs):
128 p = f(*args, **kwargs)
129 if isinstance(p, numpy.ndarray):
130 assert (p <= 0.).all()
139 def poisson_p_not_0(l):
141 Return the probability that a Poisson process with a mean rate of l 142 yields a non-zero count. = 1 - exp(-l), but computed in a way that 143 avoids loss of precision and over-/underflows. 147 >>> print(poisson_p_not_0(1e+60)) 149 >>> print(poisson_p_not_0(1) 151 >>> print(poisson_p_not_0(1e-60)) 153 >>> print(poisson_p_not_0(0)) 168 if l < -0.69314718055994529:
169 return 1. - math.exp(l)
181 threshold = -1e-20 * l
182 for n
in itertools.count(2):
185 if abs(term) <= threshold:
194 return s
if s
else 0.
200 Return the probability that a Poisson process with a mean rate of l 201 yields a zero count. = exp(-l), but with a sanity check that l is 208 @assert_ln_probability
209 def poisson_ln_p_0(l):
211 Return the natural logarithm of the probability that a Poisson 212 process with a mean rate of l yields a zero count. = -l, but with 213 a sanity check that l is non-negative. 230 def fap_after_trials(p, m):
232 Given the probability, p, that an event occurs, compute the 233 probability of at least one such event occuring after m independent 236 The return value is 1 - (1 - p)^m computed avoiding round-off 237 errors and underflows. m cannot be negative but need not be an 242 >>> fap_after_trials(0.5, 1) 244 >>> fap_after_trials(0.066967008463192584, 10) 246 >>> fap_after_trials(0.0069075045629640984, 100) 248 >>> fap_after_trials(0.00069290700954747807, 1000) 250 >>> fap_after_trials(0.000069312315846428086, 10000) 252 >>> fap_after_trials(.000000006931471781576803, 100000000) 254 >>> fap_after_trials(0.000000000000000069314718055994534, 10000000000000000) 256 >>> "%.15g" % fap_after_trials(0.1, 21.854345326782834) 258 >>> "%.15g" % fap_after_trials(1e-17, 2.3025850929940458e+17) 260 >>> fap_after_trials(0.1, .2) 327 raise ValueError(
"m = %g must be positive" % m)
328 if not (0. <= p <= 1.):
329 raise ValueError(
"p = %g must be between 0 and 1 inclusively" % p)
342 return -m * math.log1p(-p)
343 except OverflowError:
356 for n
in itertools.count():
357 term *= (n - m) * p / (n + 1.)
360 if abs(term) <= 1e-18 * s[0]:
371 x = m * math.log1p(-p)
372 except OverflowError:
383 return float(poisson_p_not_0(-x))
386 def trials_from_faps(p0, p1):
388 Given the probabiity, p0, of an event occuring, and the 389 probability, p1, of at least one such event being observed after 390 some number of independent trials, solve for and return the number 391 of trials, m, that relates the two probabilities. The three 392 quantities are related by p1 = 1 - (1 - p0)^m. Generally the 393 return value is not an integer. 395 See also fap_after_trials(). Note that if p0 is 0 or 1 then p1 396 must be 0 or 1 respectively, and in both cases m is undefined. 397 Otherwise if p1 is 1 then inf is returned. 399 assert 0. <= p0 <= 1.
400 assert 0. <= p1 <= 1.
402 if p0 == 0.
or p0 == 1.:
405 raise ValueError(
"m undefined")
413 return math.log1p(-p1) / math.log1p(-p0)