Skip to content

Commit 111f9c5

Browse files
committed
Pass entire shape to MvNormal
This commit rewrites the random method to pass the entire shape into MvNormal. MvGaussianRandomWalk also now supports an integer shape that must match the dimensionality of mu. In this case it is assumed that there are no time steps, and a random sample from the multivariate normal distribution will be returned.
1 parent 3419969 commit 111f9c5

File tree

1 file changed

+27
-18
lines changed

1 file changed

+27
-18
lines changed

pymc3/distributions/timeseries.py

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ def __init__(
435435

436436
self.init = init
437437
self.innovArgs = (mu, cov, tau, chol, lower)
438-
self.innov = multivariate.MvNormal.dist(*self.innovArgs, shape=self.shape[-1])
438+
self.innov = multivariate.MvNormal.dist(*self.innovArgs, shape=self.shape)
439439
self.mean = tt.as_tensor_variable(0.0)
440440

441441
def logp(self, x):
@@ -452,6 +452,10 @@ def logp(self, x):
452452
-------
453453
TensorVariable
454454
"""
455+
456+
if x.ndim == 1:
457+
x = x[np.newaxis, :]
458+
455459
x_im1 = x[:-1]
456460
x_i = x[1:]
457461

@@ -500,27 +504,32 @@ def random(self, point=None, size=None):
500504
sample = MvGaussianRandomWalk(mu, cov, shape=(10, 2)).random(size=(2, 2))
501505
"""
502506

503-
time_steps = self.shape[0]
504-
size = to_tuple(size)
505-
506507
# for each draw specified by the size input, we need to draw time_steps many
507508
# samples from MvNormal.
508-
size_time_steps = size + to_tuple(time_steps)
509-
510-
multivariate_samples = self.innov.random(point=point, size=size_time_steps)
511-
# this has shape (size, time_steps, MvNormal_shape)
512509

513-
time_axis = len(size)
514-
515-
multivariate_samples = multivariate_samples.cumsum(axis=time_axis)
510+
size = to_tuple(size)
511+
multivariate_samples = self.innov.random(point=point, size=size)
512+
# this has shape (size, self.shape)
513+
514+
if len(self.shape) >= 2:
515+
# have time dimension in first slot of shape. Therefore the time
516+
# component can be accessed with the index equal to the length of size.
517+
time_axis = len(size)
518+
multivariate_samples = multivariate_samples.cumsum(axis=time_axis)
519+
520+
if time_axis:
521+
# this for loop covers the case where size is a tuple
522+
for idx in np.ndindex(size):
523+
multivariate_samples[idx] = (
524+
multivariate_samples[idx] - multivariate_samples[idx][0]
525+
)
526+
else:
527+
# size was passed as None
528+
multivariate_samples = multivariate_samples - multivariate_samples[0]
516529

517-
# shift the walk to start at zero
518-
if len(multivariate_samples.shape) > 2:
519-
# this for loop covers the case where size is a tuple
520-
for idx in np.ndindex(size):
521-
multivariate_samples[idx] = multivariate_samples[idx] - multivariate_samples[idx][0]
522-
else:
523-
multivariate_samples = multivariate_samples - multivariate_samples[0]
530+
# if the above if statement fails, then only a spatial dimension was passed in for self.shape.
531+
# Therefore don't subtract off the initial value since otherwise you get all zeros
532+
# as your output.
524533
return multivariate_samples
525534

526535

0 commit comments

Comments
 (0)