-
Notifications
You must be signed in to change notification settings - Fork 10
/
math_util.py
55 lines (41 loc) · 1.32 KB
/
math_util.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# Copyright 2020 MIT Probabilistic Computing Project.
# See LICENSE.txt
from math import isinf
import numpy
from scipy.special import logsumexp
# Implementation of log1mexp and logdiffexp from PyMC3 math module.
# https://github.com/pymc-devs/pymc3/blob/master/pymc3/math.py
def log1mexp(x):
if x < 0.683:
return numpy.log(-numpy.expm1(-x))
else:
return numpy.log1p(-numpy.exp(-x))
def logdiffexp(a, b):
if b < a:
return a + log1mexp(a - b)
if allclose(b, a):
return -float('inf')
raise ValueError('Negative term in logdiffexp.')
def lognorm(array):
M = logsumexp(array)
return [a - M for a in array]
def logflip(logp, array, size, rng):
p = numpy.exp(lognorm(logp))
return flip(p, array, size, rng)
def flip(p, array, size, rng):
p = normalize(p)
return random(rng).choice(array, size=size, p=p)
def normalize(p):
s = float(sum(p))
return numpy.asarray(p, dtype=float) / s
def allclose(values, x):
return numpy.allclose(values, x)
def isinf_pos(x):
return isinf(x) and x > 0
def isinf_neg(x):
return isinf(x) and x < 0
def random(x):
return x or numpy.random
int_or_isinf_neg = lambda a: isinf_neg(a) or float(a) == int(a)
int_or_isinf_pos = lambda a: isinf_pos(a) or float(a) == int(a)
float_to_int = lambda a: a if isinf(a) else int(a)