Skip to content

Commit 3d2ad33

Browse files
committed
Merge remote-tracking branch 'upstream/master' into fixup-ci
2 parents 04ed835 + 02095c2 commit 3d2ad33

21 files changed

+141
-92
lines changed

.gitmodules

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
[submodule "docs/source/pymc-examples"]
22
path = docs/source/pymc-examples
3-
url = [email protected]:pymc-devs/pymc-examples.git
3+
url = https://github.com/pymc-devs/pymc-examples.git
4+
branch = main

README.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ Features
3939
- **Variational inference**: `ADVI <http://www.jmlr.org/papers/v18/16-107.html>`__
4040
for fast approximate posterior estimation as well as mini-batch ADVI
4141
for large data sets.
42-
- Relies on `Theano <https://theano-pymc.readthedocs.io/en/latest/>`__ which provides:
43-
* Computation optimization and dynamic C compilation
42+
- Relies on `Theano-PyMC <https://theano-pymc.readthedocs.io/en/latest/>`__ which provides:
43+
* Computation optimization and dynamic C or JAX compilation
4444
* Numpy broadcasting and advanced indexing
4545
* Linear algebra operators
4646
* Simple extensibility
@@ -72,6 +72,7 @@ PyMC3 talks
7272
-----------
7373

7474
There are also several talks on PyMC3 which are gathered in this `YouTube playlist <https://www.youtube.com/playlist?list=PL1Ma_1DBbE82OVW8Fz_6Ts1oOeyOAiovy>`__
75+
and as part of `PyMCon 2020 <https://discourse.pymc.io/c/pymcon/2020talks/15>`__
7576

7677
Installation
7778
============

RELEASE-NOTES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ It also brings some dreadfully awaited fixes, so be sure to go through the chang
1616
- Removed `theanof.set_theano_config` because it illegally changed Theano's internal state (see [#4329](https://github.com/pymc-devs/pymc3/pull/4329)).
1717

1818
### New Features
19+
- Option to set `check_bounds=False` when instantiating `pymc3.Model()`. This turns off bounds checks that ensure that input parameters of distributions are valid. For correctly specified models, this is unneccessary as all parameters get automatically transformed so that all values are valid. Turning this off should lead to faster sampling (see [#4377](https://github.com/pymc-devs/pymc3/pull/4377)).
1920
- `OrderedProbit` distribution added (see [#4232](https://github.com/pymc-devs/pymc3/pull/4232)).
2021
- `plot_posterior_predictive_glm` now works with `arviz.InferenceData` as well (see [#4234](https://github.com/pymc-devs/pymc3/pull/4234))
2122

@@ -26,6 +27,7 @@ It also brings some dreadfully awaited fixes, so be sure to go through the chang
2627
- `math.logsumexp` now matches `scipy.special.logsumexp` when arrays contain infinite values (see [#4360](https://github.com/pymc-devs/pymc3/pull/4360)).
2728
- Fixed mathematical formulation in `MvStudentT` random method. (see [#4359](https://github.com/pymc-devs/pymc3/pull/4359))
2829
- Fix issue in `logp` method of `HyperGeometric`. It now returns `-inf` for invalid parameters (see [4367](https://github.com/pymc-devs/pymc3/pull/4367))
30+
- Fixed `MatrixNormal` random method to work with parameters as random variables. (see [#4368](https://github.com/pymc-devs/pymc3/pull/4368))
2931

3032
## PyMC3 3.10.0 (7 December 2020)
3133

build_and_deploy_docs.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
latesttag=$(git describe --tags `git rev-list --tags --max-count=1`)
44
echo checking out ${latesttag}
55
git checkout ${latesttag}
6-
git submodule update --init --recursive
6+
git submodule update --remote
77
pushd docs/source
88
make html
99
ghp-import -c docs.pymc.io -n -p _build/html/

pymc3/distributions/continuous.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,6 @@ class Normal(Continuous):
478478
def __init__(self, mu=0, sigma=None, tau=None, sd=None, **kwargs):
479479
if sd is not None:
480480
sigma = sd
481-
warnings.warn("sd is deprecated, use sigma instead", DeprecationWarning)
482481
tau, sigma = get_tau_sigma(tau=tau, sigma=sigma)
483482
self.sigma = self.sd = tt.as_tensor_variable(sigma)
484483
self.tau = tt.as_tensor_variable(tau)
@@ -640,7 +639,6 @@ def __init__(
640639
):
641640
if sd is not None:
642641
sigma = sd
643-
warnings.warn("sd is deprecated, use sigma instead", DeprecationWarning)
644642
tau, sigma = get_tau_sigma(tau=tau, sigma=sigma)
645643
self.sigma = self.sd = tt.as_tensor_variable(sigma)
646644
self.tau = tt.as_tensor_variable(tau)
@@ -835,7 +833,6 @@ class HalfNormal(PositiveContinuous):
835833
def __init__(self, sigma=None, tau=None, sd=None, *args, **kwargs):
836834
if sd is not None:
837835
sigma = sd
838-
warnings.warn("sd is deprecated, use sigma instead", DeprecationWarning)
839836
super().__init__(*args, **kwargs)
840837
tau, sigma = get_tau_sigma(tau=tau, sigma=sigma)
841838

@@ -1218,7 +1215,6 @@ def __init__(self, alpha=None, beta=None, mu=None, sigma=None, sd=None, *args, *
12181215
super().__init__(*args, **kwargs)
12191216
if sd is not None:
12201217
sigma = sd
1221-
warnings.warn("sd is deprecated, use sigma instead", DeprecationWarning)
12221218
alpha, beta = self.get_alpha_beta(alpha, beta, mu, sigma)
12231219
self.alpha = alpha = tt.as_tensor_variable(floatX(alpha))
12241220
self.beta = beta = tt.as_tensor_variable(floatX(beta))
@@ -1724,7 +1720,6 @@ def __init__(self, mu=0, sigma=None, tau=None, sd=None, *args, **kwargs):
17241720
super().__init__(*args, **kwargs)
17251721
if sd is not None:
17261722
sigma = sd
1727-
warnings.warn("sd is deprecated, use sigma instead", DeprecationWarning)
17281723

17291724
tau, sigma = get_tau_sigma(tau=tau, sigma=sigma)
17301725

@@ -1884,11 +1879,9 @@ class StudentT(Continuous):
18841879
"""
18851880

18861881
def __init__(self, nu, mu=0, lam=None, sigma=None, sd=None, *args, **kwargs):
1887-
super().__init__(*args, **kwargs)
18881882
super().__init__(*args, **kwargs)
18891883
if sd is not None:
18901884
sigma = sd
1891-
warnings.warn("sd is deprecated, use sigma instead", DeprecationWarning)
18921885
self.nu = nu = tt.as_tensor_variable(floatX(nu))
18931886
lam, sigma = get_tau_sigma(tau=lam, sigma=sigma)
18941887
self.lam = lam = tt.as_tensor_variable(lam)
@@ -2397,7 +2390,6 @@ def __init__(self, alpha=None, beta=None, mu=None, sigma=None, sd=None, *args, *
23972390
super().__init__(*args, **kwargs)
23982391
if sd is not None:
23992392
sigma = sd
2400-
warnings.warn("sd is deprecated, use sigma instead", DeprecationWarning)
24012393

24022394
alpha, beta = self.get_alpha_beta(alpha, beta, mu, sigma)
24032395
self.alpha = alpha = tt.as_tensor_variable(floatX(alpha))
@@ -2545,7 +2537,6 @@ def __init__(self, alpha=None, beta=None, mu=None, sigma=None, sd=None, *args, *
25452537

25462538
if sd is not None:
25472539
sigma = sd
2548-
warnings.warn("sd is deprecated, use sigma instead", DeprecationWarning)
25492540

25502541
alpha, beta = InverseGamma._get_alpha_beta(alpha, beta, mu, sigma)
25512542
self.alpha = alpha = tt.as_tensor_variable(floatX(alpha))
@@ -2902,7 +2893,6 @@ def __init__(self, nu=1, sigma=None, lam=None, sd=None, *args, **kwargs):
29022893
super().__init__(*args, **kwargs)
29032894
if sd is not None:
29042895
sigma = sd
2905-
warnings.warn("sd is deprecated, use sigma instead", DeprecationWarning)
29062896

29072897
self.mode = tt.as_tensor_variable(0)
29082898
lam, sigma = get_tau_sigma(lam, sigma)
@@ -3041,7 +3031,6 @@ def __init__(self, mu=0.0, sigma=None, nu=None, sd=None, *args, **kwargs):
30413031

30423032
if sd is not None:
30433033
sigma = sd
3044-
warnings.warn("sd is deprecated, use sigma instead", DeprecationWarning)
30453034

30463035
self.mu = mu = tt.as_tensor_variable(floatX(mu))
30473036
self.sigma = self.sd = sigma = tt.as_tensor_variable(floatX(sigma))
@@ -3317,7 +3306,6 @@ def __init__(self, mu=0.0, sigma=None, tau=None, alpha=1, sd=None, *args, **kwar
33173306

33183307
if sd is not None:
33193308
sigma = sd
3320-
warnings.warn("sd is deprecated, use sigma instead", DeprecationWarning)
33213309

33223310
tau, sigma = get_tau_sigma(tau=tau, sigma=sigma)
33233311
self.mu = mu = tt.as_tensor_variable(floatX(mu))
@@ -3721,7 +3709,6 @@ def __init__(self, nu=None, sigma=None, b=None, sd=None, *args, **kwargs):
37213709
super().__init__(*args, **kwargs)
37223710
if sd is not None:
37233711
sigma = sd
3724-
warnings.warn("sd is deprecated, use sigma instead", DeprecationWarning)
37253712

37263713
nu, b, sigma = self.get_nu_b(nu, b, sigma)
37273714
self.nu = nu = tt.as_tensor_variable(floatX(nu))
@@ -3994,7 +3981,6 @@ class LogitNormal(UnitContinuous):
39943981
def __init__(self, mu=0, sigma=None, tau=None, sd=None, **kwargs):
39953982
if sd is not None:
39963983
sigma = sd
3997-
warnings.warn("sd is deprecated, use sigma instead", DeprecationWarning)
39983984
self.mu = mu = tt.as_tensor_variable(floatX(mu))
39993985
tau, sigma = get_tau_sigma(tau=tau, sigma=sigma)
40003986
self.sigma = self.sd = tt.as_tensor_variable(sigma)

pymc3/distributions/dist_math.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
from pymc3.distributions.shape_utils import to_tuple
3535
from pymc3.distributions.special import gammaln
36+
from pymc3.model import modelcontext
3637
from pymc3.theanof import floatX
3738

3839
f = floatX
@@ -67,6 +68,15 @@ def bound(logp, *conditions, **kwargs):
6768
-------
6869
logp with elements set to -inf where any condition is False
6970
"""
71+
72+
# If called inside a model context, see if bounds check is disabled
73+
try:
74+
model = modelcontext(kwargs.get("model"))
75+
if not model.check_bounds:
76+
return logp
77+
except TypeError: # No model found
78+
pass
79+
7080
broadcast_conditions = kwargs.get("broadcast_conditions", True)
7181

7282
if broadcast_conditions:

pymc3/distributions/mixture.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
import warnings
16-
1715
from collections.abc import Iterable
1816

1917
import numpy as np
@@ -632,7 +630,6 @@ class NormalMixture(Mixture):
632630
def __init__(self, w, mu, sigma=None, tau=None, sd=None, comp_shape=(), *args, **kwargs):
633631
if sd is not None:
634632
sigma = sd
635-
warnings.warn("sd is deprecated, use sigma instead", DeprecationWarning)
636633
_, sigma = get_tau_sigma(tau=tau, sigma=sigma)
637634

638635
self.mu = mu = tt.as_tensor_variable(mu)

pymc3/distributions/multivariate.py

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1445,7 +1445,7 @@ class MatrixNormal(Continuous):
14451445
14461446
.. math::
14471447
f(x \mid \mu, U, V) =
1448-
\frac{1}{(2\pi |U|^n |V|^m)^{1/2}}
1448+
\frac{1}{(2\pi^{m n} |U|^n |V|^m)^{1/2}}
14491449
\exp\left\{
14501450
-\frac{1}{2} \mathrm{Tr}[ V^{-1} (x-\mu)^{\prime} U^{-1} (x-\mu)]
14511451
\right\}
@@ -1637,27 +1637,19 @@ def random(self, point=None, size=None):
16371637
mu, colchol, rowchol = draw_values(
16381638
[self.mu, self.colchol_cov, self.rowchol_cov], point=point, size=size
16391639
)
1640-
if size is None:
1641-
size = ()
1642-
if size in (None, ()):
1643-
standard_normal = np.random.standard_normal((self.shape[0], colchol.shape[-1]))
1644-
samples = mu + np.matmul(rowchol, np.matmul(standard_normal, colchol.T))
1645-
else:
1646-
samples = []
1647-
size = tuple(np.atleast_1d(size))
1648-
if mu.shape == tuple(self.shape):
1649-
for _ in range(np.prod(size)):
1650-
standard_normal = np.random.standard_normal((self.shape[0], colchol.shape[-1]))
1651-
samples.append(mu + np.matmul(rowchol, np.matmul(standard_normal, colchol.T)))
1652-
else:
1653-
for j in range(np.prod(size)):
1654-
standard_normal = np.random.standard_normal(
1655-
(self.shape[0], colchol[j].shape[-1])
1656-
)
1657-
samples.append(
1658-
mu[j] + np.matmul(rowchol[j], np.matmul(standard_normal, colchol[j].T))
1659-
)
1660-
samples = np.array(samples).reshape(size + tuple(self.shape))
1640+
size = to_tuple(size)
1641+
dist_shape = to_tuple(self.shape)
1642+
output_shape = size + dist_shape
1643+
1644+
# Broadcasting all parameters
1645+
(mu,) = broadcast_dist_samples_to(to_shape=output_shape, samples=[mu], size=size)
1646+
rowchol = np.broadcast_to(rowchol, shape=size + rowchol.shape[-2:])
1647+
1648+
colchol = np.broadcast_to(colchol, shape=size + colchol.shape[-2:])
1649+
colchol = np.swapaxes(colchol, -1, -2) # Take transpose
1650+
1651+
standard_normal = np.random.standard_normal(output_shape)
1652+
samples = mu + np.matmul(rowchol, np.matmul(standard_normal, colchol))
16611653
return samples
16621654

16631655
def _trquaddist(self, value):

pymc3/distributions/timeseries.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
import warnings
16-
1715
import numpy as np
1816
import theano.tensor as tt
1917

@@ -116,7 +114,6 @@ def __init__(
116114
super().__init__(*args, **kwargs)
117115
if sd is not None:
118116
sigma = sd
119-
warnings.warn("sd is deprecated, use sigma instead", DeprecationWarning)
120117

121118
tau, sigma = get_tau_sigma(tau=tau, sigma=sigma)
122119
self.sigma = self.sd = tt.as_tensor_variable(sigma)
@@ -211,7 +208,6 @@ def __init__(self, tau=None, init=Flat.dist(), sigma=None, mu=0.0, sd=None, *arg
211208
raise TypeError("GaussianRandomWalk must be supplied a non-zero shape argument!")
212209
if sd is not None:
213210
sigma = sd
214-
warnings.warn("sd is deprecated, use sigma instead", DeprecationWarning)
215211
tau, sigma = get_tau_sigma(tau=tau, sigma=sigma)
216212
self.tau = tt.as_tensor_variable(tau)
217213
sigma = tt.as_tensor_variable(sigma)

pymc3/model.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,11 @@ class Model(Factor, WithMemoization, metaclass=ContextMeta):
809809
temporarily in the model context. See the documentation
810810
of theano for a complete list. Set config key
811811
``compute_test_value`` to `raise` if it is None.
812+
check_bounds: bool
813+
Ensure that input parameters to distributions are in a valid
814+
range. If your model is built in a way where you know your
815+
parameters can only take on valid values you can set this to
816+
False for increased speed.
812817
813818
Examples
814819
--------
@@ -895,11 +900,12 @@ def __new__(cls, *args, **kwargs):
895900
instance._theano_config = theano_config
896901
return instance
897902

898-
def __init__(self, name="", model=None, theano_config=None, coords=None):
903+
def __init__(self, name="", model=None, theano_config=None, coords=None, check_bounds=True):
899904
self.name = name
900905
self.coords = {}
901906
self.RV_dims = {}
902907
self.add_coords(coords)
908+
self.check_bounds = check_bounds
903909

904910
if self.parent is not None:
905911
self.named_vars = treedict(parent=self.parent.named_vars)

pymc3/sampling_jax.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
import numpy as np
1313
import pandas as pd
1414
import theano
15-
import theano.sandbox.jax_linker
16-
import theano.sandbox.jaxify
15+
16+
from theano.link.jax.jax_dispatch import jax_funcify
1717

1818
import pymc3 as pm
1919

@@ -46,7 +46,7 @@ def sample_tfp_nuts(
4646
seed = jax.random.PRNGKey(random_seed)
4747

4848
fgraph = theano.gof.FunctionGraph(model.free_RVs, [model.logpt])
49-
fns = theano.sandbox.jaxify.jax_funcify(fgraph)
49+
fns = jax_funcify(fgraph)
5050
logp_fn_jax = fns[0]
5151

5252
rv_names = [rv.name for rv in model.free_RVs]
@@ -131,7 +131,7 @@ def sample_numpyro_nuts(
131131
seed = jax.random.PRNGKey(random_seed)
132132

133133
fgraph = theano.gof.FunctionGraph(model.free_RVs, [model.logpt])
134-
fns = theano.sandbox.jaxify.jax_funcify(fgraph)
134+
fns = jax_funcify(fgraph)
135135
logp_fn_jax = fns[0]
136136

137137
rv_names = [rv.name for rv in model.free_RVs]

pymc3/tests/helpers.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import theano
2121

2222
from theano.gradient import verify_grad as tt_verify_grad
23-
from theano.sandbox.rng_mrg import MRG_RandomStreams
23+
from theano.sandbox.rng_mrg import MRG_RandomStream as RandomStream
2424

2525
from pymc3.theanof import set_tt_rng, tt_rng
2626

@@ -35,7 +35,7 @@ def setup_class(cls):
3535
def setup_method(self):
3636
nr.seed(self.random_seed)
3737
self.old_tt_rng = tt_rng()
38-
set_tt_rng(MRG_RandomStreams(self.random_seed))
38+
set_tt_rng(RandomStream(self.random_seed))
3939

4040
def teardown_method(self):
4141
set_tt_rng(self.old_tt_rng)

pymc3/tests/test_dist_math.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,13 @@ def test_bound():
6060
assert np.prod(bound(logp, cond).eval()) == -np.inf
6161

6262

63+
def test_check_bounds_false():
64+
with pm.Model(check_bounds=False):
65+
logp = tt.ones(3)
66+
cond = np.array([1, 0, 1])
67+
assert np.all(bound(logp, cond).eval() == logp.eval())
68+
69+
6370
def test_alltrue_scalar():
6471
assert alltrue_scalar([]).eval()
6572
assert alltrue_scalar([True]).eval()

0 commit comments

Comments
 (0)