Skip to content

Commit 54aa08a

Browse files
committed
Initial
0 parents  commit 54aa08a

File tree

8 files changed

+1798
-0
lines changed

8 files changed

+1798
-0
lines changed

.gitignore

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
*
2+
!*/
3+
*.Rcheck/
4+
**/__pycache__/
5+
*venv*/
6+
7+
########################
8+
# Archivos que NO ignora
9+
10+
!LICENSE
11+
!license
12+
13+
## Latex
14+
!*.tex
15+
*-concordance.tex
16+
!*.bib
17+
!*.bst
18+
!*.sty
19+
!*.cls
20+
21+
## Codigo
22+
!*.jl
23+
!*.py
24+
!*.R
25+
!*.c
26+
!*.sql
27+
28+
## Texto
29+
!*.md
30+
!*.txt
31+
!*.sh
32+
33+
## Dataset
34+
data/*
35+
36+
## Otros
37+
!makefile
38+
!Makefile
39+
!.keep
40+
!.gitignore

Gaussian.py

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
from scipy.stats import norm
2+
import math
3+
from scipy.stats import truncnorm
4+
5+
class Gaussian:
6+
def __init__(self, mu: float, sigma: float):
7+
self.mu = mu
8+
self.sigma = sigma
9+
self.sigma2 = sigma**2
10+
# Non-centered second moment
11+
self.ncsm = self.mu**2+self.sigma2
12+
13+
def eval(self, x: [float | list[float]]) -> [float | list[float]]:
14+
return norm.pdf(x, self.mu, self.sigma)
15+
16+
def sample(self, size=1):
17+
return norm.rvs(self.mu, self.sigma, size=size)
18+
19+
def trunc(self, a: float, b: float):
20+
mean = self.mu # Mean of the original Gaussian distribution
21+
std_dev = self.sigma # Standard deviation of the original Gaussian distribution
22+
# Create a truncated normal distribution object
23+
trunc_norm = truncnorm((a - mean) / std_dev, (b - mean) / std_dev, loc=mean, scale=std_dev)
24+
return( Gaussian(trunc_norm.mean(),trunc_norm.std()) )
25+
26+
def __mul__(self, other):
27+
if isinstance(other, (int, float)):
28+
if other == math.inf:
29+
return Uniform()
30+
else:
31+
return Gaussian(other*self.mu, abs(other)*self.sigma)
32+
else:
33+
if self.sigma == 0.0 or other.sigma == 0.0:
34+
mu = self.mu/((self.sigma**2/other.sigma**2) + 1) if self.sigma == 0.0 else other.mu/((other.sigma**2/self.sigma**2) + 1)
35+
sigma = 0.0
36+
else:
37+
_tau, _pi = self.tau + other.tau, self.pi + other.pi
38+
mu, sigma = Gaussian.mu_sigma(_tau, _pi)
39+
40+
if sigma == math.inf:
41+
return Uniform()
42+
elif sigma == 0:
43+
return PointMass(mu)
44+
return Gaussian(mu, sigma)
45+
# OLD
46+
if (other == 0):
47+
return PointMass(0)
48+
if (other == 1):
49+
return self
50+
elif (isinstance(other, (int, float))):
51+
# source: https://math.stackexchange.com/questions/275648/multiplication-of-a-random-variable-with-constant
52+
return Gaussian(self.mu*other, self.sigma*other)
53+
elif (isinstance(other, PointMass)):
54+
return PointMass(self.mu*other.mu)
55+
elif (isinstance(other, Uniform)):
56+
return self
57+
elif (isinstance(other, Gaussian)):
58+
return Gaussian.mul(self, other)
59+
else:
60+
raise NotImplementedError(f"Multiplying Gaussian by element of type {type(other)} is unsupported. Value of other: {other}")
61+
def __rmul__(self, other):
62+
return self.__mul__(other)
63+
def __matmul__(self, other):
64+
return self.__mul__(other)
65+
def __rmatmul__(self, other):
66+
return self.__rmul__(other)
67+
def __truediv__(self, other):
68+
if (other == 0):
69+
raise ZeroDivisionError(f"Tried to divide a Gaussian by zero")
70+
if (other == 1):
71+
return self
72+
elif (isinstance(other, (int, float))):
73+
return Gaussian(self.mu/other, self.sigma/other)
74+
elif (isinstance(other, PointMass)):
75+
assert self.sigma2 != 0, f"This might be a pointmass: {self}"
76+
raise ZeroDivisionError()
77+
#raise NotImplementedError(f"Dividing Gaussian by element of type {type(other)} is unsupported. Value of other: {other}")
78+
# De donde salio esto: ???
79+
#return PointMass(other.mu/((other.sigma**2/self.sigma**2) + 1))
80+
elif (isinstance(other, Uniform)):
81+
return self
82+
elif (isinstance(other, Gaussian)):
83+
return Gaussian.div(self, other)
84+
else:
85+
raise NotImplementedError(f"Dividing Gaussian by element of type {type(other)} is unsupported. Value of other: {other}")
86+
def __add__(self, other):
87+
if (other == 0):
88+
return self
89+
elif (isinstance(other, Gaussian)):
90+
return Gaussian(self.mu+other.mu, math.sqrt(self.sigma2+other.sigma2))
91+
else:
92+
raise NotImplementedError(f"Adding Gaussian with element of type {type(other)} is unsupported. Value of other: {other}")
93+
def __radd__(self, other):
94+
if (other == 0):
95+
return self
96+
elif (isinstance(other, Gaussian)):
97+
return Gaussian(self.mu+other.mu, math.sqrt(self.sigma2+other.sigma2))
98+
else:
99+
raise NotImplementedError(f"Adding Gaussian with element of type {type(other)} is unsupported. Value of other: {other}")
100+
def __sub__(self, other):
101+
if (other == 0):
102+
return self
103+
elif (isinstance(other, Gaussian)):
104+
return Gaussian(self.mu-other.mu, math.sqrt(self.sigma2+other.sigma2))
105+
else:
106+
raise NotImplementedError(f"Substracting element of type {type(other)} from Gaussian is unsupported. Value of other: {other}")
107+
def __repr__(self):
108+
return f"N(mu={self.mu:.4f}, var={self.sigma2:.4f})"
109+
def __format__(self, format_spec):
110+
return self.__repr__().__format__(format_spec)
111+
112+
@staticmethod
113+
def mul(norm1, norm2):
114+
sigma2Star = (1/norm1.sigma2 + 1/norm2.sigma2)**(-1) #c*N(mu, sigma) = N(c*mu, c*sigma) #TODO: agregar al pdf
115+
muStar = norm1.mu/norm1.sigma2 + norm2.mu/norm2.sigma2
116+
muStar *= sigma2Star
117+
sigma = math.sqrt(sigma2Star)
118+
if sigma==math.inf:
119+
return Uniform()
120+
elif sigma==0:
121+
return PointMass(muStar)
122+
else:
123+
return Gaussian(muStar, sigma)
124+
#c = Gaussian(norm2.mu, math.sqrt(norm1.sigma2+norm2.sigma2)).eval(norm1.mu) #result should be multiplied by c, but is proportional to not multiplying by it
125+
return Gaussian(muStar, math.sqrt(sigma2Star))
126+
127+
@staticmethod
128+
def div(norm1, norm2):
129+
_tau = norm1.tau - norm2.tau; _pi = norm1.pi - norm2.pi
130+
mu, sigma = Gaussian.mu_sigma(_tau, _pi)
131+
if sigma==math.inf:
132+
return Uniform()
133+
elif sigma==0:
134+
return PointMass(mu)
135+
else:
136+
return Gaussian(mu, sigma)
137+
# OLD
138+
sigma2Star = (1/norm1.sigma2 - 1/norm2.sigma2)**(-1) #c*N(mu, sigma) = N(c*mu, c*sigma) #TODO: agregar al pdf
139+
muStar = norm1.mu/norm1.sigma2 - norm2.mu/norm2.sigma2
140+
muStar *= sigma2Star
141+
#c = Gaussian(norm2.mu, math.sqrt(norm1.sigma2+norm2.sigma2)).eval(norm1.mu) #result should be multiplied by c, but is proportional to not multiplying by it
142+
return Gaussian(muStar, math.sqrt(sigma2Star))
143+
144+
@staticmethod
145+
def mu_sigma(tau_,pi_):
146+
if pi_ > 0.0:
147+
sigma = math.sqrt(1/pi_)
148+
mu = tau_ / pi_
149+
elif pi_ + 1e-5 < 0.0:
150+
raise ValueError(" sigma should be greater than 0 ")
151+
else:
152+
sigma = math.inf
153+
mu = 0.0
154+
return mu, sigma
155+
156+
@property
157+
def tau(self):
158+
if self.sigma > 0.0:
159+
return self.mu * (self.sigma**-2)
160+
else:
161+
return math.inf
162+
163+
@property
164+
def pi(self):
165+
if self.sigma > 0.0:
166+
return self.sigma**-2
167+
else:
168+
return math.inf
169+
170+
class Uniform(Gaussian):
171+
def __init__(self):
172+
super(Uniform, self).__init__(0, math.inf)
173+
def __truediv__(self, other):
174+
raise NotImplementedError("Can't divide a Uniform (inf uncertainty) by anything bc denominator must have bigger uncertainty") #TODO: ahcer esto bien
175+
def __repr__(self):
176+
return f"Uniform()"
177+
178+
class PointMass(Gaussian):
179+
def __init__(self, mu):
180+
super(PointMass, self).__init__(mu, 0)
181+
def __mul__(self, other):
182+
if (other == 0):
183+
return PointMass(0)
184+
elif (other == 1):
185+
return self
186+
elif (isinstance(other, (int, float))):
187+
# source: https://math.stackexchange.com/questions/275648/multiplication-of-a-random-variable-with-constant
188+
return PointMass(self.mu*other)
189+
elif (isinstance(other, PointMass)):
190+
return PointMass(self.mu*other.mu)
191+
elif (isinstance(other, Uniform)):
192+
return self
193+
elif (isinstance(other, Gaussian)):
194+
return PointMass(self.mu/((self.sigma**2/other.sigma**2) + 1))
195+
else:
196+
raise NotImplementedError(f"Adding PointMass with element of type {type(other)} is unsupported. Value of other: {other}")
197+
def __truediv__(self, other):
198+
if (other == 0):
199+
raise ZeroDivisionError(f"Tried to divide a PointMass by zero")
200+
if (other == 1):
201+
return self
202+
elif (isinstance(other, (int, float))):
203+
return PointMass(self.mu/other)
204+
if (isinstance(other, PointMass)):
205+
if self.mu != other.mu:
206+
raise ZeroDivisionError()
207+
return Uniform()
208+
elif (isinstance(other, Gaussian)):
209+
return self
210+
else:
211+
raise NotImplementedError(f"Dividing PointMass by element of type {type(other)} is unsupported. Value of other: {other}")
212+
def __repr__(self):
213+
return f"PointMass({self.mu:.4f})"

0 commit comments

Comments
 (0)