Skip to content

Commit 7d09eed

Browse files
gillisstwiecki
authored andcommitted
changed default values for TruncatedNormal lower and upper from None to -np.inf… (#3250)
* changed default values for TruncatedNormal lower and upper to -np.inf and np.inf * inserted an idea for testing in test_distributions_random.py * included a standalone test test_truncated_normal_sample_random_variable_default_params * minor * minor * changed _default value cases in continuous.TruncatedNormal to avoid np.isfinite error in distribution.Distribution * minor * removed test_truncated_normal_lower from TestScalarParameterSamples since pymc3_random sets paramdomains points anyway * added TestTruncatedNormalUpper and addressed TruncatedNormal _normalization errors * changed TruncatedNormal.logp to check for infs instead of Nones * debugging * debugging * debugging * debugging * debugging * debugging * tried np.isinf and put in the requested test_truncated_normal_lower test_truncated_normal_upper tests * added extra members self.lower_np self.upper_np for checking values * changed to upper_check and lower_check members, with None checks * minor * minor * minor * minor * removed corresponding paramdomains from upper and lower tests * removed upper positional arg from test_truncated_normal_lower and vice versa * Update pymc3/tests/test_distributions_random.py minor syntax Co-Authored-By: gilliss <[email protected]> * Update pymc3/tests/test_distributions_random.py minor syntax Co-Authored-By: gilliss <[email protected]> * Update pymc3/tests/test_distributions_random.py minor syntax Co-Authored-By: gilliss <[email protected]> * Update pymc3/tests/test_distributions_random.py minor syntax Co-Authored-By: gilliss <[email protected]> * minor syntax * added line to docs/release-notes/pymc3-3.0.md * moved release notes line to RELEASE-NOTES.md
1 parent d16a537 commit 7d09eed

File tree

4 files changed

+37
-14
lines changed

4 files changed

+37
-14
lines changed

RELEASE-NOTES.md

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
- Changed initialization of `Categorical.p`. `p` is now normalized to sum to `1` inside `logp` and `random`, but not during initialization. This could hide negative values supplied to `p` as mentioned in #2082.
3030
- `Categorical` now accepts elements of `p` equal to `0`. `logp` will return `-inf` if there are `values` that index to the zero probability categories.
3131
- Add `sigma`, `tau`, and `sd` to signature of `NormalMixture`.
32+
- Resolved issue #3248. Set default lower and upper values of -inf and inf for pm.distributions.continuous.TruncatedNormal. This avoids errors caused by their previous values of None.
3233

3334
### Deprecations
3435

docs/release-notes/pymc3-3.0.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

pymc3/distributions/continuous.py

+12-10
Original file line numberDiff line numberDiff line change
@@ -571,15 +571,17 @@ def __init__(self, mu=0, sigma=None, tau=None, lower=None, upper=None,
571571
tau, sigma = get_tau_sigma(tau=tau, sigma=sigma)
572572
self.sigma = self.sd = tt.as_tensor_variable(sigma)
573573
self.tau = tt.as_tensor_variable(tau)
574-
self.lower = tt.as_tensor_variable(floatX(lower)) if lower is not None else lower
575-
self.upper = tt.as_tensor_variable(floatX(upper)) if upper is not None else upper
574+
self.lower_check = tt.as_tensor_variable(floatX(lower)) if lower is not None else lower
575+
self.upper_check = tt.as_tensor_variable(floatX(upper)) if upper is not None else upper
576+
self.lower = tt.as_tensor_variable(floatX(lower)) if lower is not None else tt.as_tensor_variable(-np.inf)
577+
self.upper = tt.as_tensor_variable(floatX(upper)) if upper is not None else tt.as_tensor_variable(np.inf)
576578
self.mu = tt.as_tensor_variable(floatX(mu))
577579

578-
if self.lower is None and self.upper is None:
580+
if self.lower_check is None and self.upper_check is None:
579581
self._defaultval = mu
580-
elif self.lower is None and self.upper is not None:
582+
elif self.lower_check is None and self.upper_check is not None:
581583
self._defaultval = self.upper - 1.
582-
elif self.lower is not None and self.upper is None:
584+
elif self.lower_check is not None and self.upper_check is None:
583585
self._defaultval = self.lower + 1.
584586
else:
585587
self._defaultval = (self.lower + self.upper) / 2
@@ -639,19 +641,19 @@ def logp(self, value):
639641
logp = Normal.dist(mu=mu, sigma=sigma).logp(value) - norm
640642

641643
bounds = [sigma > 0]
642-
if self.lower is not None:
644+
if self.lower_check is not None:
643645
bounds.append(value >= self.lower)
644-
if self.upper is not None:
646+
if self.upper_check is not None:
645647
bounds.append(value <= self.upper)
646648
return bound(logp, *bounds)
647649

648650
def _normalization(self):
649651
mu, sigma = self.mu, self.sigma
650652

651-
if self.lower is None and self.upper is None:
653+
if self.lower_check is None and self.upper_check is None:
652654
return 0.
653655

654-
if self.lower is not None and self.upper is not None:
656+
if self.lower_check is not None and self.upper_check is not None:
655657
lcdf_a = normal_lcdf(mu, sigma, self.lower)
656658
lcdf_b = normal_lcdf(mu, sigma, self.upper)
657659
lsf_a = normal_lccdf(mu, sigma, self.lower)
@@ -663,7 +665,7 @@ def _normalization(self):
663665
logdiffexp(lcdf_b, lcdf_a),
664666
)
665667

666-
if self.lower is not None:
668+
if self.lower_check is not None:
667669
return normal_lccdf(mu, sigma, self.lower)
668670
else:
669671
return normal_lcdf(mu, sigma, self.upper)

pymc3/tests/test_distributions_random.py

+23-4
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,15 @@ class TestNormal(BaseTestCases.BaseTestCase):
257257

258258
class TestTruncatedNormal(BaseTestCases.BaseTestCase):
259259
distribution = pm.TruncatedNormal
260-
params = {'mu': 0., 'tau': 1., 'lower':-0.5, 'upper':0.5}
260+
params = {'mu': 0., 'tau': 1., 'lower': -0.5, 'upper': 0.5}
261+
262+
class TestTruncatedNormalLower(BaseTestCases.BaseTestCase):
263+
distribution = pm.TruncatedNormal
264+
params = {'mu': 0., 'tau': 1., 'lower': -0.5}
265+
266+
class TestTruncatedNormalUpper(BaseTestCases.BaseTestCase):
267+
distribution = pm.TruncatedNormal
268+
params = {'mu': 0., 'tau': 1., 'upper': 0.5}
261269

262270
class TestSkewNormal(BaseTestCases.BaseTestCase):
263271
distribution = pm.SkewNormal
@@ -461,7 +469,6 @@ def ref_rand(size, tau):
461469
def test_uniform(self):
462470
def ref_rand(size, lower, upper):
463471
return st.uniform.rvs(size=size, loc=lower, scale=upper - lower)
464-
465472
pymc3_random(pm.Uniform, {'lower': -Rplus, 'upper': Rplus}, ref_rand=ref_rand)
466473

467474
def test_normal(self):
@@ -471,8 +478,20 @@ def ref_rand(size, mu, sigma):
471478

472479
def test_truncated_normal(self):
473480
def ref_rand(size, mu, sigma, lower, upper):
474-
return st.truncnorm.rvs((lower-mu)/sigma, (upper-mu)/sigma, size=size, loc=mu, scale=sigma)
475-
pymc3_random(pm.TruncatedNormal, {'mu': R, 'sigma': Rplusbig, 'lower':-Rplusbig, 'upper':Rplusbig},
481+
return st.truncnorm.rvs((lower - mu) / sigma, (upper - mu) / sigma, size=size, loc=mu, scale=sigma)
482+
pymc3_random(pm.TruncatedNormal, {'mu': R, 'sigma': Rplusbig, 'lower': -Rplusbig, 'upper': Rplusbig},
483+
ref_rand=ref_rand)
484+
485+
def test_truncated_normal_lower(self):
486+
def ref_rand(size, mu, sigma, lower):
487+
return st.truncnorm.rvs((lower - mu) / sigma, np.inf, size=size, loc=mu, scale=sigma)
488+
pymc3_random(pm.TruncatedNormal, {'mu': R, 'sigma': Rplusbig, 'lower': -Rplusbig},
489+
ref_rand=ref_rand)
490+
491+
def test_truncated_normal_upper(self):
492+
def ref_rand(size, mu, sigma, upper):
493+
return st.truncnorm.rvs(-np.inf, (upper - mu) / sigma, size=size, loc=mu, scale=sigma)
494+
pymc3_random(pm.TruncatedNormal, {'mu': R, 'sigma': Rplusbig, 'upper': Rplusbig},
476495
ref_rand=ref_rand)
477496

478497
def test_skew_normal(self):

0 commit comments

Comments
 (0)