def __init__(self, scipy_solution: OdeSolution, rvs: list): self.scipy_solution = scipy_solution # rvs is of the type `list` of `RandomVariable` and can therefore be # directly transformed into a _RandomVariableList rv_states = randvars._RandomVariableList(rvs) super().__init__(locations=scipy_solution.ts, states=rv_states)
def test_inputs(self): """Inputs rejected or accepted according to expected types.""" numpy_array = np.ones(3) * Constant(0.1) constant_list = [Constant(0.1), Constant(0.4)] number_list = [0.5, 0.41] inputs = [numpy_array, constant_list, number_list] inputs_acceptable = [False, True, False] for inputs, is_acceptable in zip(inputs, inputs_acceptable): with self.subTest(input=inputs, is_acceptable=is_acceptable): if is_acceptable: _RandomVariableList(inputs) else: with self.assertRaises(TypeError): _RandomVariableList(inputs)
def __init__(self, kalman_posterior: filtsmooth.gaussian.KalmanPosterior): self.kalman_posterior = kalman_posterior # Pre-compute projection matrices. # The prior must be an integrator, if not, an error is thrown in 'ODEFilter'. self.proj_to_y = self.kalman_posterior.transition.proj2coord(coord=0) self.proj_to_dy = self.kalman_posterior.transition.proj2coord(coord=1) states = randvars._RandomVariableList( [_project_rv(self.proj_to_y, rv) for rv in self.kalman_posterior.states] ) derivatives = randvars._RandomVariableList( [_project_rv(self.proj_to_dy, rv) for rv in self.kalman_posterior.states] ) super().__init__( locations=kalman_posterior.locations, states=states, derivatives=derivatives )
def __init__( self, locations: np.ndarray, states: randvars._RandomVariableList, derivatives: Optional[randvars._RandomVariableList] = None, ): super().__init__(locations=locations, states=states) self.derivatives = ( randvars._RandomVariableList(derivatives) if derivatives is not None else None )
def smooth_list(self, rv_list, locations, _diffusion_list, _previous_posterior=None): """Apply smoothing to a list of random variables, according to the present transition. Parameters ---------- rv_list : randvars._RandomVariableList List of random variables to be smoothed. locations : Locations :math:`t` of the random variables in the time-domain. Used for continuous-time transitions. _diffusion_list : List of diffusions that correspond to the intervals in the locations. If `locations=(t0, ..., tN)`, then `_diffusion_list=(d1, ..., dN)`, i.e. it contains one element less. _previous_posterior : Specify a previous posterior to improve linearisation in approximate backward passes. Used in iterated smoothing based on posterior linearisation. Returns ------- randvars._RandomVariableList List of smoothed random variables. """ final_rv = rv_list[-1] curr_rv = final_rv out_rvs = [curr_rv] for idx in reversed(range(1, len(locations))): unsmoothed_rv = rv_list[idx - 1] _linearise_smooth_step_at = (None if _previous_posterior is None else _previous_posterior( locations[idx - 1])) squared_diffusion = _diffusion_list[idx - 1] # Actual smoothing step curr_rv, _ = self.backward_rv( curr_rv, unsmoothed_rv, t=locations[idx - 1], dt=locations[idx] - locations[idx - 1], _diffusion=squared_diffusion, _linearise_at=_linearise_smooth_step_at, ) out_rvs.append(curr_rv) out_rvs.reverse() return randvars._RandomVariableList(out_rvs)
def __call__(self, t: DenseOutputLocationArgType) -> DenseOutputValueType: """Evaluate the time-continuous solution at time t. Parameters ---------- t Location / time at which to evaluate the continuous ODE solution. Returns ------- randvars.RandomVariable or randvars._RandomVariableList Estimate of the states at time ``t`` based on a fourth order polynomial. """ states = self.scipy_solution(t).T if np.isscalar(t): solution_as_rv = randvars.Constant(states) else: solution_as_rv = randvars._RandomVariableList( [randvars.Constant(state) for state in states]) return solution_as_rv
def setUp(self): self.rv_list = _RandomVariableList([Constant(0.1), Constant(0.2)])
def setUp(self): self.rv_list = _RandomVariableList([])
def __call__(self, t: DenseOutputLocationArgType) -> DenseOutputValueType: """Evaluate the time-continuous posterior at location `t` Algorithm: 1. Find closest t_prev and t_next, with t_prev < t < t_next 2. Predict from t_prev to t 3. (if `self._with_smoothing=True`) Predict from t to t_next 4. (if `self._with_smoothing=True`) Smooth from t_next to t 5. Return random variable for time t Parameters ---------- t : Location, or time, at which to evaluate the posterior. Returns ------- randvars.RandomVariable or randvars._RandomVariableList Estimate of the states at time ``t``. """ # The variable "squeeze_eventually" indicates whether # the dimension of the time-array has been promoted # (which is there for a well-behaved loop). # If this has been the case, the final result needs to be # reshaped ("squeezed") accordingly. if np.isscalar(t): t = np.atleast_1d(t) t_has_been_promoted = True else: t_has_been_promoted = False if not np.all(np.diff(t) >= 0.0): raise ValueError("Time-points have to be sorted.") # Split left-extrapolation, interpolation, right_extrapolation t0, tmax = np.amin(self.locations), np.amax(self.locations) t_extra_left = t[t < t0] t_extra_right = t[t > tmax] t_inter = t[(t0 <= t) & (t <= tmax)] # Indices of t where they would be inserted # into self.locations ("left": right-closest states -- this is the default in searchsorted) indices = np.searchsorted(self.locations, t_inter, side="left") interpolated_values = [ self.interpolate( t=ti, previous_index=previdx, next_index=nextidx, ) for ti, previdx, nextidx in zip( t_inter, indices - 1, indices, ) ] extrapolated_values_left = [ self.interpolate(t=ti, previous_index=None, next_index=0) for ti in t_extra_left ] extrapolated_values_right = [ self.interpolate(t=ti, previous_index=-1, next_index=None) for ti in t_extra_right ] dense_output_values = extrapolated_values_left dense_output_values.extend(interpolated_values) dense_output_values.extend(extrapolated_values_right) if t_has_been_promoted: return dense_output_values[0] return randvars._RandomVariableList(dense_output_values)
def states(self): return randvars._RandomVariableList(self._states)
def states(self): """States of the posterior.""" return randvars._RandomVariableList(self._states)