Ejemplo n.º 1
0
def test_as_shape_int(shape_arg, ndim):
    if ndim:
        shape = pnut.as_shape(shape_arg, ndim=1)
    else:
        shape = pnut.as_shape(shape_arg)

    assert isinstance(shape, tuple)
    assert len(shape) == 1
    assert all(isinstance(entry, int) for entry in shape)
    assert shape[0] == shape_arg
Ejemplo n.º 2
0
def test_as_shape_iterable(shape_arg, ndim):
    if ndim:
        shape = pnut.as_shape(shape_arg, ndim=len(shape_arg))
    else:
        shape = pnut.as_shape(shape_arg)

    assert isinstance(shape, tuple)
    assert len(shape) == len(shape_arg)
    assert all(isinstance(entry, int) for entry in shape)
    assert all(entry_shape == entry_shape_arg
               for entry_shape, entry_shape_arg in zip(shape_arg, shape))
Ejemplo n.º 3
0
    def __init__(
            self,
            input_shape: ShapeLike,
            output_shape: ShapeLike = (),
    ):
        self._input_shape = _pn_utils.as_shape(input_shape)
        self._input_ndim = len(self._input_shape)

        if self._input_ndim > 1:
            raise ValueError(
                "Currently, we only support kernels with at most 1 input dimension."
            )

        self._output_shape = _pn_utils.as_shape(output_shape)
        self._output_ndim = len(self._output_shape)
Ejemplo n.º 4
0
    def _get_shape_kernelmatrix(
        self,
        x0_shape: ShapeArgType,
        x1_shape: ShapeArgType,
    ) -> ShapeType:
        """Determine the shape of the kernel matrix based on the given arguments.

        Determine the correct shape of the covariance function evaluated at the given
        input arguments. If inputs are vectors the output is a numpy scalar if the
        output dimension of the kernel is 1, otherwise *shape=(output_dim,
        output_dim)*. If inputs represent multiple observations, then the resulting
        matrix has *shape=(n0, n1) or (n0, n1, output_dim, output_dim)*.

        Parameters
        ----------
        x0_shape :
            Shape of the first input to the covariance function.
        x1_shape :
            Shape of the second input to the covariance function.
        """
        if len(x0_shape) <= 1 and len(x1_shape) <= 1:
            if self.output_dim == 1:
                kern_shape = 0
            else:
                kern_shape = ()
        else:
            kern_shape = (x0_shape[0], x1_shape[0])

        if self.output_dim > 1:
            kern_shape += (
                self.output_dim,
                self.output_dim,
            )

        return _utils.as_shape(kern_shape)
Ejemplo n.º 5
0
    def sample(self, locations=None, size=()):
        # In the present setting, only works for sampling from the smoothing posterior.

        size = utils.as_shape(size)

        if locations is None:
            locations = self.locations
            random_vars = self.filtering_posterior.state_rvs
        else:
            random_vars = self.filtering_posterior(locations)

            # Inform the final point in the list about all the data by
            # conditioning on the final state rv
            if locations[-1] < self.locations[-1]:
                final_sample = self.state_rvs[-1].sample()
                random_vars[-1], _ = self.transition.backward_realization(
                    final_sample,
                    random_vars[-1],
                    t=locations[-1],
                    dt=self.locations[-1] - locations[-1],
                )

        if size == ():
            return np.array(
                self.transition.jointly_sample_list_backward(
                    locations=locations, rv_list=random_vars
                )
            )

        return np.array(
            [self.sample(locations=locations, size=size[1:]) for _ in range(size[0])]
        )
def test_sampling_shapes_1d(locs, size):
    """Make the sampling tests for a 1d posterior."""
    locations = np.linspace(0, 2 * np.pi, 100)
    data = 0.5 * np.random.randn(100) + np.sin(locations)

    prior = statespace.IBM(0, 1)
    measmod = statespace.DiscreteLTIGaussian(state_trans_mat=np.eye(1),
                                             shift_vec=np.zeros(1),
                                             proc_noise_cov_mat=np.eye(1))
    initrv = randvars.Normal(np.zeros(1), np.eye(1))

    kalman = filtsmooth.Kalman(prior, measmod, initrv)
    regression_problem = problems.RegressionProblem(observations=data,
                                                    locations=locations)
    posterior, _ = kalman.filtsmooth(regression_problem)

    size = utils.as_shape(size)
    if locs is None:
        base_measure_reals = np.random.randn(
            *(size + posterior.locations.shape + (1, )))
        samples = posterior.transform_base_measure_realizations(
            base_measure_reals, t=posterior.locations)
    else:
        locs = np.union1d(locs, posterior.locations)
        base_measure_reals = np.random.randn(*(size + (len(locs), )) + (1, ))
        samples = posterior.transform_base_measure_realizations(
            base_measure_reals, t=locs)

    assert samples.shape == base_measure_reals.shape
Ejemplo n.º 7
0
    def reshape(self, newshape: ShapeArgType) -> "RandomVariable":
        """Give a new shape to a random variable.

        Parameters
        ----------
        newshape :
            New shape for the random variable. It must be compatible with the original
            shape.
        """
        newshape = _utils.as_shape(newshape)

        return RandomVariable(
            shape=newshape,
            dtype=self.dtype,
            random_state=_utils.derive_random_seed(self.random_state),
            sample=lambda size: self.sample(size).reshape(size + newshape),
            mode=lambda: self.mode.reshape(newshape),
            median=lambda: self.median.reshape(newshape),
            mean=lambda: self.mean.reshape(newshape),
            cov=lambda: self.cov,
            var=lambda: self.var.reshape(newshape),
            std=lambda: self.std.reshape(newshape),
            entropy=lambda: self.entropy,
            as_value_type=self.__as_value_type,
        )
Ejemplo n.º 8
0
    def _sample(self, size: ShapeArgType = ()) -> _ValueType:
        size = _utils.as_shape(size)

        if size == ():
            return self._support.copy()
        else:
            return np.tile(self._support, reps=size + (1, ) * self.ndim)
Ejemplo n.º 9
0
    def _sample_at_input(
            self,
            rng: np.random.Generator,
            args: InputType,
            size: ShapeLike = (),
    ) -> OutputType:

        size = utils.as_shape(size)
        args = np.atleast_1d(args)
        if args.ndim > 1:
            raise ValueError(f"Invalid args shape {args.shape}")

        base_measure_realizations = scipy.stats.norm.rvs(
            size=(size + args.shape + self.initrv.shape), random_state=rng)

        if size == ():
            return np.array(
                self.transition.
                jointly_transform_base_measure_realization_list_forward(
                    base_measure_realizations=base_measure_realizations,
                    t=args,
                    initrv=self.initrv,
                    _diffusion_list=np.ones_like(args[:-1]),
                ))

        return np.stack([
            self.transition.
            jointly_transform_base_measure_realization_list_forward(
                base_measure_realizations=base_real,
                t=args,
                initrv=self.initrv,
                _diffusion_list=np.ones_like(args[:-1]),
            ) for base_real in base_measure_realizations
        ])
Ejemplo n.º 10
0
def test_sampling_shapes_1d(locs, size):
    """Make the sampling tests for a 1d posterior."""
    locations = np.linspace(0, 2 * np.pi, 100)
    data = 0.5 * np.random.randn(100) + np.sin(locations)

    prior = randprocs.markov.integrator.IntegratedWienerTransition(0, 1)
    measmod = randprocs.markov.discrete.LTIGaussian(
        state_trans_mat=np.eye(1),
        shift_vec=np.zeros(1),
        proc_noise_cov_mat=np.eye(1))
    initrv = randvars.Normal(np.zeros(1), np.eye(1))

    prior_process = randprocs.markov.MarkovProcess(transition=prior,
                                                   initrv=initrv,
                                                   initarg=locations[0])
    kalman = filtsmooth.gaussian.Kalman(prior_process)
    regression_problem = problems.TimeSeriesRegressionProblem(
        observations=data, measurement_models=measmod, locations=locations)
    posterior, _ = kalman.filtsmooth(regression_problem)

    size = utils.as_shape(size)
    if locs is None:
        base_measure_reals = np.random.randn(
            *(size + posterior.locations.shape + (1, )))
        samples = posterior.transform_base_measure_realizations(
            base_measure_reals, t=posterior.locations)
    else:
        locs = np.union1d(locs, posterior.locations)
        base_measure_reals = np.random.randn(*(size + (len(locs), )) + (1, ))
        samples = posterior.transform_base_measure_realizations(
            base_measure_reals, t=locs)

    assert samples.shape == base_measure_reals.shape
Ejemplo n.º 11
0
    def __init__(
        self,
        input_dim: IntArgType,
        shape: ShapeArgType = (),
    ):
        self._input_dim = int(input_dim)

        self._shape = _pn_utils.as_shape(shape)
Ejemplo n.º 12
0
    def _sample(self, rng: np.random.Generator,
                size: ShapeLike = ()) -> ValueType:
        size = _utils.as_shape(size)

        if size == ():
            return self._support.copy()

        return np.tile(self._support, reps=size + (1, ) * self.ndim)
Ejemplo n.º 13
0
    def sample(self, size: ShapeArgType = ()) -> _ValueType:
        """Draw realizations from a random variable.

        Parameters
        ----------
        size :
            Size of the drawn sample of realizations.
        """
        if self.__sample is None:
            raise NotImplementedError("No sampling method provided.")

        return self.__sample(_utils.as_shape(size))
Ejemplo n.º 14
0
    def sample(self, t=None, size=()):
        # this has its own recursion because of the tedious undoing of preconditioning....

        size = utils.as_shape(size)

        # implement only single samples, rest via recursion
        if size != ():
            return np.array(
                [self.sample(t=t, size=size[1:]) for _ in range(size[0])])

        samples = self._kalman_posterior.sample(locations=t, size=size)
        return np.array(self._project_rv_list(samples))
Ejemplo n.º 15
0
    def __init__(
        self,
        shape: ShapeArgType,
        dtype: DTypeArgType,
        random_state: RandomStateArgType = None,
        parameters: Optional[Dict[str, Any]] = None,
        sample: Optional[Callable[[ShapeType], _ValueType]] = None,
        in_support: Optional[Callable[[_ValueType], bool]] = None,
        cdf: Optional[Callable[[_ValueType], np.float_]] = None,
        logcdf: Optional[Callable[[_ValueType], np.float_]] = None,
        quantile: Optional[Callable[[FloatArgType], _ValueType]] = None,
        mode: Optional[Callable[[], _ValueType]] = None,
        median: Optional[Callable[[], _ValueType]] = None,
        mean: Optional[Callable[[], _ValueType]] = None,
        cov: Optional[Callable[[], _ValueType]] = None,
        var: Optional[Callable[[], _ValueType]] = None,
        std: Optional[Callable[[], _ValueType]] = None,
        entropy: Optional[Callable[[], np.float_]] = None,
        as_value_type: Optional[Callable[[Any], _ValueType]] = None,
    ):
        # pylint: disable=too-many-arguments,too-many-locals
        """Create a new random variable."""
        self.__shape = _utils.as_shape(shape)

        # Data Types
        self.__dtype = np.dtype(dtype)
        self.__median_dtype = RandomVariable.infer_median_dtype(self.__dtype)
        self.__moment_dtype = RandomVariable.infer_moment_dtype(self.__dtype)

        self._random_state = _utils.as_random_state(random_state)

        # Probability distribution of the random variable
        self.__parameters = parameters.copy() if parameters is not None else {}

        self.__sample = sample

        self.__in_support = in_support
        self.__cdf = cdf
        self.__logcdf = logcdf
        self.__quantile = quantile

        # Properties of the random variable
        self.__mode = mode
        self.__median = median
        self.__mean = mean
        self.__cov = cov
        self.__var = var
        self.__std = std
        self.__entropy = entropy

        # Utilities
        self.__as_value_type = as_value_type
Ejemplo n.º 16
0
    def sample(self, locations=None, size=()):

        size = utils.as_shape(size)

        if locations is None:
            locations = self.locations
            random_vars = self.state_rvs
        else:
            random_vars = self.__call__(locations)

        if size == ():
            return self._single_sample_path(
                locations=locations, random_vars=random_vars
            )

        return np.array(
            [self.sample(locations=locations, size=size[1:]) for _ in range(size[0])]
        )
Ejemplo n.º 17
0
    def sample(self, size: ShapeArgType = ()) -> _ValueType:
        """
        Draw realizations from a random variable.

        Parameters
        ----------
        size : tuple
            Size of the drawn sample of realizations.

        Returns
        -------
        sample : array-like
            Sample of realizations with the given ``size`` and the inherent ``shape``.
        """
        if self.__sample is None:
            raise NotImplementedError("No sampling method provided.")

        return self.__sample(size=_utils.as_shape(size))
Ejemplo n.º 18
0
    def sample(self, rng: np.random.Generator, size: ShapeArgType = ()) -> _ValueType:
        """Draw realizations from a random variable.

        Parameters
        ----------
        rng
            Random number generator used for sampling.
        size
            Size of the drawn sample of realizations.
        """
        if self.__sample is None:
            raise NotImplementedError("No sampling method provided.")

        if not isinstance(rng, np.random.Generator):
            msg = "Random number generators must be of type np.random.Generator."
            raise TypeError(msg)

        return self.__sample(rng=rng, size=_utils.as_shape(size))
Ejemplo n.º 19
0
    def __init__(
        self,
        input_shape: ShapeLike,
        lengthscales: Union[np.ndarray, ScalarLike],
        nus: Union[np.ndarray, ScalarLike],
    ):
        input_shape = _utils.as_shape(input_shape)
        if input_shape == () and not (np.isscalar(lengthscales)
                                      and np.isscalar(nus)):
            raise ValueError(
                f"'lengthscales' and 'nus' must be scalar if 'input_shape' is "
                f"{input_shape}.")

        input_dim = 1 if input_shape == () else input_shape[0]

        # If only single scalar lengthcsale or nu is given, use this in every dimension
        def expand_array(x, ndim):
            return np.full((ndim, ), _utils.as_numpy_scalar(x))

        if isinstance(lengthscales, np.ndarray):
            if lengthscales.shape == ():
                lengthscales = expand_array(lengthscales, input_dim)
        if isinstance(nus, np.ndarray):
            if nus.shape == ():
                nus = expand_array(nus, input_dim)

        # also expand if scalars are given
        if np.isscalar(lengthscales):
            lengthscales = expand_array(lengthscales, input_dim)
        if np.isscalar(nus):
            nus = expand_array(nus, input_dim)

        univariate_materns = []
        for dim in range(input_dim):
            univariate_materns.append(
                Matern(input_shape=(),
                       lengthscale=lengthscales[dim],
                       nu=nus[dim]))
        self.univariate_materns = univariate_materns
        self.nus = nus
        self.lengthscales = lengthscales

        super().__init__(input_shape=input_shape)
Ejemplo n.º 20
0
    def sample(self, locations=None, size=()):
        # In the present setting, only works for sampling from the smoothing posterior.

        size = utils.as_shape(size)

        if locations is None:
            locations = self.locations
            random_vars = self.filtering_posterior.state_rvs
        else:
            random_vars = self.filtering_posterior(locations)

        if size == ():
            return np.array(
                self.transition.jointly_sample_list_backward(
                    locations=locations, rv_list=random_vars))

        return np.array([
            self.sample(locations=locations, size=size[1:])
            for _ in range(size[0])
        ])
Ejemplo n.º 21
0
    def sample(
            self,
            rng: np.random.Generator,
            t: Optional[ArrayLike] = None,
            size: Optional[ShapeLike] = (),
    ) -> np.ndarray:

        size = utils.as_shape(size)
        single_rv_shape = self.states[0].shape
        single_rv_ndim = self.states[0].ndim

        # Early exit if no dense output is required
        if t is None:
            base_measure_realizations = stats.norm.rvs(
                size=(size + self.locations.shape + single_rv_shape),
                random_state=rng,
            )
            return self.transform_base_measure_realizations(
                base_measure_realizations=base_measure_realizations,
                t=self.locations)

        # Compute the union (as sets) of t and self.locations
        # This allows that samples "always pass" the grid points.
        all_locations = np.union1d(t, self.locations)
        slice_these_out = np.where(np.isin(all_locations, t))[0]
        base_measure_realizations = stats.norm.rvs(
            size=(size + all_locations.shape + single_rv_shape),
            random_state=rng,
        )

        samples = self.transform_base_measure_realizations(
            base_measure_realizations=base_measure_realizations,
            t=all_locations)
        new_samples = np.take(samples,
                              indices=slice_these_out,
                              axis=-(single_rv_ndim + 1))
        return new_samples
Ejemplo n.º 22
0
def test_finite_evaluation_is_normal(gaussian_process: randprocs.GaussianProcess):
    """A Gaussian process evaluated at a finite set of inputs is a Gaussian random
    variable."""
    x = np.random.normal(size=(5,) + utils.as_shape(gaussian_process.input_dim))
    assert isinstance(gaussian_process(x), randvars.Normal)
Ejemplo n.º 23
0
def test_sample(categ, size, rng):
    samples = categ.sample(rng=rng, size=size)
    expected_shape = utils.as_shape(size) + categ.shape
    assert samples.shape == expected_shape
Ejemplo n.º 24
0
def test_as_shape_wrong_type(shape_arg):
    with pytest.raises(TypeError):
        pnut.as_shape(shape_arg)
Ejemplo n.º 25
0
def test_as_shape_wrong_ndim(shape_arg, ndim):
    with pytest.raises(TypeError):
        pnut.as_shape(shape_arg, ndim=ndim)