Skip to content

Commit 9a6fc64

Browse files
mikemoss3cgobat
andauthored
Fix problems with CDF method (#15)
CDF evaluation was previously problematic in a number of ways. This should both correct it and make things cleaner. --------- Co-authored-by: Caden Gobat <[email protected]>
1 parent b9a31ae commit 9a6fc64

File tree

2 files changed

+23
-19
lines changed

2 files changed

+23
-19
lines changed

asymmetric_uncertainty/core.py

+22-18
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
import numpy as np
1515
import matplotlib.pyplot as plt
1616
import warnings
17+
from math import erf
18+
19+
np_erf = np.vectorize(erf, doc="Vectorized error function at x.") # prevents need for SciPy dependency
1720

1821
class a_u:
1922
"""
@@ -74,29 +77,33 @@ def _repr_latex_(self):
7477
else:
7578
return "$%f_{-%f}^{+%f}$" %(self.value,self.minus,self.plus)
7679

77-
def pdf(self,x):
80+
def pdf(self, x):
7881
"""
7982
Computes and returns the values of the probability distribution function for the specified input.
8083
"""
81-
return np.piecewise(x, [x<self.value, x>=self.value],
82-
[lambda x : np.sqrt(2)/np.sqrt(np.pi)/(self.plus+self.minus) * np.exp(-1*(x-self.value)**2 / (2*self.minus**2)),
83-
lambda x : np.sqrt(2)/np.sqrt(np.pi)/(self.plus+self.minus) * np.exp(-1*(x-self.value)**2 / (2*self.plus**2))])
84+
x_arr = np.asanyarray(x).astype(float)
85+
pdf_arr = np.piecewise(x_arr, [x_arr<self.value, x_arr>=self.value],
86+
[lambda x: np.sqrt(2)/np.sqrt(np.pi)/(self.plus+self.minus) * np.exp(-1*(x-self.value)**2 / (2*self.minus**2)),
87+
lambda x: np.sqrt(2)/np.sqrt(np.pi)/(self.plus+self.minus) * np.exp(-1*(x-self.value)**2 / (2*self.plus**2))])
88+
return pdf_arr.item() if np.isscalar(x) else pdf_arr
8489

85-
def cdf(self,x):
90+
def cdf(self, x):
8691
"""
8792
Computes and returns the values of the cumulative distribution function for the specified input.
8893
"""
89-
return np.cumsum(self.pdf(x))/np.sum(self.pdf(x))
90-
94+
x_arr = np.asanyarray(x).astype(float)
95+
cdf_arr = np.piecewise(x_arr, [x_arr<self.value, x_arr>=self.value],
96+
[lambda x: 0.5*(1 + np_erf((x-self.value)/(self.minus*np.sqrt(2)))),
97+
lambda x: 0.5*(1 + np_erf((x-self.value)/(self.plus*np.sqrt(2))))])
98+
return cdf_arr.item() if np.isscalar(x) else cdf_arr
99+
91100
def pdfplot(self,num_sigma=5,discretization=100,**kwargs):
92101
"""
93102
Plots the associated PDF over the specified number of sigma, using 2*`discretization` points.
94103
`**kwargs` are passed on to `matplotlib` for configuration of the resulting plot.
95104
"""
96-
neg_x = np.linspace(self.value-(num_sigma*self.minus),self.value,discretization)
97-
pos_x = np.linspace(self.value,self.value+(num_sigma*self.minus),discretization)
98-
p_neg = np.sqrt(2)/np.sqrt(np.pi)/(self.plus+self.minus) * np.exp(-1*(neg_x-self.value)**2 / (2*self.minus**2))
99-
p_pos = np.sqrt(2)/np.sqrt(np.pi)/(self.plus+self.minus) * np.exp(-1*(pos_x-self.value)**2 / (2*self.plus**2))
105+
neg_x = np.linspace(self.value-(num_sigma*self.minus), self.value, discretization)
106+
pos_x = np.linspace(self.value, self.value+(num_sigma*self.plus), discretization)
100107
x = np.array(list(neg_x)+list(pos_x))
101108
pdf = self.pdf(x)
102109
plt.plot(x,pdf,**kwargs)
@@ -107,13 +114,10 @@ def cdfplot(self,num_sigma=5,discretization=100,**kwargs):
107114
Plots the associated CDF over the specified number of sigma, using 2*`discretization` points.
108115
`**kwargs` are passed on to `matplotlib` for configuration of the resulting plot.
109116
"""
110-
neg_x = np.linspace(self.value-(num_sigma*self.minus),self.value,discretization)
111-
pos_x = np.linspace(self.value,self.value+(num_sigma*self.minus),discretization)
112-
p_neg = np.sqrt(2)/np.sqrt(np.pi)/(self.plus+self.minus) * np.exp(-1*(neg_x-self.value)**2 / (2*self.minus**2))
113-
p_pos = np.sqrt(2)/np.sqrt(np.pi)/(self.plus+self.minus) * np.exp(-1*(pos_x-self.value)**2 / (2*self.plus**2))
117+
neg_x = np.linspace(self.value-(num_sigma*self.minus), self.value, discretization)
118+
pos_x = np.linspace(self.value, self.value+(num_sigma*self.plus), discretization)
114119
x = np.array(list(neg_x)+list(pos_x))
115-
pdf = self.pdf(x)
116-
cdf = np.cumsum(pdf)/np.sum(pdf)
120+
cdf = self.cdf(x)
117121
plt.plot(x,cdf,**kwargs)
118122
plt.show()
119123

@@ -426,4 +430,4 @@ def neg_errors(array):
426430
Stand-alone function to return an array of the negative errors of an array of `a_u` objects.
427431
Functional equivalent to `UncertaintyArray(array).minus`.
428432
"""
429-
return [v.minus for v in array]
433+
return [v.minus for v in array]

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
if __name__ == '__main__':
77
setup(name="asymmetric_uncertainty",
8-
version="0.2.2",
8+
version="0.2.3",
99
author="Caden Gobat",
1010
author_email="[email protected]",
1111
packages=find_packages(),

0 commit comments

Comments
 (0)