@@ -1,7 +1,7 @@
Loading
1 1
"""Abstract Base Class for posteriors over states after applying filtering/smoothing."""
2 2
3 3
import abc
4 -
from typing import Optional, Union
4 +
from typing import Iterable, Optional, Union
5 5
6 6
import numpy as np
7 7
@@ -34,9 +34,48 @@
Loading
34 34
        Posterior random variables.
35 35
    """
36 36
37 -
    def __init__(self, locations: np.ndarray, states: np.ndarray) -> None:
38 -
        self.locations = np.asarray(locations)
39 -
        self.states = _randomvariablelist._RandomVariableList(states)
37 +
    def __init__(
38 +
        self,
39 +
        locations: Optional[Iterable[FloatArgType]] = None,
40 +
        states: Optional[Iterable[randvars.RandomVariable]] = None,
41 +
    ) -> None:
42 +
        self._locations = list(locations) if locations is not None else []
43 +
        self._states = list(states) if states is not None else []
44 +
        self._frozen = False
45 +
46 +
    def _check_location(self, location: FloatArgType) -> FloatArgType:
47 +
        if len(self._locations) > 0 and location <= self._locations[-1]:
48 +
            _err_msg = "Locations have to be strictly ascending. "
49 +
            _err_msg += f"Received {location} <= {self._locations[-1]}."
50 +
            raise ValueError(_err_msg)
51 +
        return location
52 +
53 +
    def append(
54 +
        self,
55 +
        location: FloatArgType,
56 +
        state: randvars.RandomVariable,
57 +
    ) -> None:
58 +
59 +
        if self.frozen:
60 +
            raise ValueError("Cannot append to frozen TimeSeriesPosterior object.")
61 +
62 +
        self._locations.append(self._check_location(location))
63 +
        self._states.append(state)
64 +
65 +
    def freeze(self) -> None:
66 +
        self._frozen = True
67 +
68 +
    @property
69 +
    def frozen(self):
70 +
        return self._frozen
71 +
72 +
    @property
73 +
    def locations(self):
74 +
        return np.asarray(self._locations)
75 +
76 +
    @property
77 +
    def states(self):
78 +
        return _randomvariablelist._RandomVariableList(self._states)
40 79
41 80
    def __len__(self) -> int:
42 81
        """Length of the discrete-time solution.

@@ -198,21 +198,15 @@
Loading
198 198
        TimeSeriesRegressionProblem: a regression problem data class
199 199
        """
200 200
201 -
        filtered_rvs = []
201 +
        posterior = FilteringPosterior(transition=self.prior_process.transition)
202 202
        info_dicts = []
203 203
204 -
        for rv, info in self.filtered_states_generator(
204 +
        for t, rv, info in self.filtered_states_generator(
205 205
            regression_problem, _previous_posterior
206 206
        ):
207 -
            filtered_rvs.append(rv)
207 +
            posterior.append(location=t, state=rv)
208 208
            info_dicts.append(info)
209 209
210 -
        posterior = FilteringPosterior(
211 -
            locations=regression_problem.locations,
212 -
            states=filtered_rvs,
213 -
            transition=self.prior_process.transition,
214 -
        )
215 -
216 210
        return posterior, info_dicts
217 211
218 212
    def filtered_states_generator(
@@ -276,7 +270,7 @@
Loading
276 270
                realization_obtained=data, rv=curr_rv, _linearise_at=linearise_update_at
277 271
            )
278 272
279 -
            yield curr_rv, info_dict
273 +
            yield t, curr_rv, info_dict
280 274
            t_old = t
281 275
282 276
    def smooth(self, filter_posterior, _previous_posterior=None):
@@ -300,9 +294,8 @@
Loading
300 294
        )
301 295
302 296
        return SmoothingPosterior(
303 -
            filter_posterior.locations,
304 -
            rv_list,
305 -
            self.prior_process.transition,
306 297
            filtering_posterior=filter_posterior,
307 -
            diffusion_model=filter_posterior.diffusion_model,
298 +
            transition=self.prior_process.transition,
299 +
            locations=filter_posterior.locations,
300 +
            states=rv_list,
308 301
        )

@@ -347,9 +347,9 @@
Loading
347 347
        """Create an ODESolution object."""
348 348
349 349
        kalman_posterior = filtsmooth.FilteringPosterior(
350 -
            times,
351 -
            rvs,
352 -
            self.prior_process.transition,
350 +
            transition=self.prior_process.transition,
351 +
            locations=times,
352 +
            states=rvs,
353 353
            diffusion_model=self.diffusion_model,
354 354
        )
355 355
@@ -360,23 +360,27 @@
Loading
360 360
        locations = odesol.kalman_posterior.locations
361 361
        rv_list = odesol.kalman_posterior.states
362 362
363 -
        if self._calibrate_all_states_post_hoc:
364 -
            # Constant diffusion model is the only way to go here.
365 -
            s = self.diffusion_model.diffusion
363 +
        kalman_posterior = filtsmooth.FilteringPosterior(
364 +
            transition=self.prior_process.transition,
365 +
            diffusion_model=self.diffusion_model,
366 +
        )
367 +
368 +
        # Constant diffusion model is the only way to go here.
369 +
        s = (
370 +
            self.diffusion_model.diffusion
371 +
            if self._calibrate_all_states_post_hoc
372 +
            else 1.0
373 +
        )
366 374
367 -
            for idx, (t, rv) in enumerate(zip(locations, rv_list)):
368 -
                rv_list[idx] = randvars.Normal(
375 +
        for idx, (t, rv) in enumerate(zip(locations, rv_list)):
376 +
            kalman_posterior.append(
377 +
                location=t,
378 +
                state=randvars.Normal(
369 379
                    mean=rv.mean,
370 380
                    cov=s * rv.cov,
371 381
                    cov_cholesky=np.sqrt(s) * rv.cov_cholesky,
372 -
                )
373 -
374 -
        kalman_posterior = filtsmooth.FilteringPosterior(
375 -
            locations,
376 -
            rv_list,
377 -
            self.prior_process.transition,
378 -
            diffusion_model=self.diffusion_model,
379 -
        )
382 +
                ),
383 +
            )
380 384
381 385
        if self.with_smoothing is True:
382 386
@@ -385,10 +389,10 @@
Loading
385 389
                rv_list, locations, _diffusion_list=squared_diffusion_list
386 390
            )
387 391
            kalman_posterior = filtsmooth.SmoothingPosterior(
388 -
                locations,
389 -
                rv_list,
390 -
                self.prior_process.transition,
391 392
                filtering_posterior=kalman_posterior,
393 +
                transition=self.prior_process.transition,
394 +
                locations=locations,
395 +
                states=rv_list,
392 396
                diffusion_model=self.diffusion_model,
393 397
            )
394 398

@@ -4,12 +4,12 @@
Loading
4 4
by being callable. Can function values can also be accessed by indexing.
5 5
"""
6 6
import abc
7 -
from typing import Optional, Union
7 +
from typing import Iterable, Optional, Union
8 8
9 9
import numpy as np
10 10
from scipy import stats
11 11
12 -
from probnum import _randomvariablelist, randvars, statespace, utils
12 +
from probnum import randvars, statespace, utils
13 13
from probnum.typing import (
14 14
    DenseOutputLocationArgType,
15 15
    FloatArgType,
@@ -48,9 +48,9 @@
Loading
48 48
49 49
    def __init__(
50 50
        self,
51 -
        locations: np.ndarray,
52 -
        states: _randomvariablelist._RandomVariableList,
53 51
        transition: GaussMarkovPriorTransitionArgType,
52 +
        locations: Optional[Iterable[FloatArgType]] = None,
53 +
        states: Optional[Iterable[randvars.RandomVariable]] = None,
54 54
        diffusion_model=None,
55 55
    ) -> None:
56 56
@@ -158,14 +158,19 @@
Loading
158 158
159 159
    def __init__(
160 160
        self,
161 -
        locations: np.ndarray,
162 -
        states: _randomvariablelist._RandomVariableList,
163 -
        transition: GaussMarkovPriorTransitionArgType,
164 161
        filtering_posterior: TimeSeriesPosterior,
162 +
        transition: GaussMarkovPriorTransitionArgType,
163 +
        locations: Iterable[FloatArgType],
164 +
        states: Iterable[randvars.RandomVariable],
165 165
        diffusion_model=None,
166 166
    ):
167 167
        self.filtering_posterior = filtering_posterior
168 -
        super().__init__(locations, states, transition, diffusion_model=diffusion_model)
168 +
        super().__init__(
169 +
            transition=transition,
170 +
            locations=locations,
171 +
            states=states,
172 +
            diffusion_model=diffusion_model,
173 +
        )
169 174
170 175
    def interpolate(
171 176
        self,
Files Coverage
src/probnum 84.46%
Project Totals (107 files) 84.46%
1
coverage:
2
  precision: 2
3
  status:
4
    project:
5
      default:
6
        target: auto
7
        threshold: 1%
8
    patch:
9
      default:
10
        target: 90%
11
        threshold: 1%
12

13
comment:
14
  layout: "reach, diff, files"
15
  behavior: default
16
  require_changes: true
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading