def sample_switching_models( models: Sequence, usage_seq: Sequence, X: Union[None, Sequence, Callable] = None, initial_conditions: Optional[Tuple[Sequence, Sequence]] = None, return_input: bool = False, ) -> Union[np.ndarray, Tuple[np.ndarray, np.ndarray]]: """ Sample from a non-stationary stochastic processes that switches between different ARMA models at given times. This functions sets the models' `history_` attribute appropriately to ensure consistency across time. Parameters ---------- models Sequence of models to use. usage_seq Sequence identifying the model to use at each time steps. Models are labeled from `0` to `len(models) - 1`. X If given, this overrides the input source for the models. If it is a sequence, it should be at least as long as `len(usage_seq)`. initial_conditions A tuple, `(initial_y, initial_x)`, of recent samples of the output and input sequences used to seed the simulation. If these are not provided, they are assumed equal to zero. return_input If true, returns both output and input. If false (the default), returns only the output. Returns a sequence `Y` of generated samples. If `return_input` is true, returns a tuple `(Y, X)` of generated output samples and input samples. If the `U` parameter was used and was a sequence, the output `X` simply mirrors the input. """ # check the inputs if len(models) == 0: raise ValueError("No models given.") if np.min(usage_seq) < 0 or np.max(usage_seq) >= len(models): raise ValueError("Invalid entry in usage_seq vector.") # handle vector X if X is not None and not callable(X): if len(X) < len(usage_seq): raise ValueError("Not enough input values in X.") X_ret = X X = sources.Stream(X) have_X_ret = True else: X_ret = np.zeros(len(usage_seq)) have_X_ret = False # handle default initial conditions if initial_conditions is None: initial_conditions = ([], []) # generate the samples Y_ret = np.zeros(len(usage_seq)) usage_rle = rle_encode(usage_seq) ptr = 0 for model_id, n_samples in usage_rle: model = models[model_id] # ensure proper history if ptr >= model.p: history_y = np.copy(Y_ret[ptr - model.p : ptr]) else: n_left = model.p - ptr if len(initial_conditions[0]) >= n_left: history_y = np.hstack((initial_conditions[0][-n_left:], Y_ret[:ptr])) else: history_y = np.hstack( ( np.zeros(n_left - len(initial_conditions[0])), initial_conditions[0], Y_ret[:ptr], ) ) if ptr >= model.q: history_x = np.copy(X_ret[ptr - model.q : ptr]) else: n_left = model.q - ptr if len(initial_conditions[1]) >= n_left: history_x = np.hstack((initial_conditions[1][-n_left:], X_ret[:ptr])) else: history_x = np.hstack( ( np.zeros(n_left - len(initial_conditions[1])), initial_conditions[1], X_ret[:ptr], ) ) model.history_ = (history_y, history_x) # generate and store the samples from this model crt_y, crt_x = model.transform(n_samples, X=X, return_input=True) Y_ret[ptr : ptr + n_samples] = crt_y if not have_X_ret: X_ret[ptr : ptr + n_samples] = crt_x ptr += n_samples if return_input: return Y_ret, X_ret else: return Y_ret
def test_reading_samples_from_empty_store_raises_index_error(self): src = sources.Stream([]) with self.assertRaises(IndexError): src(size=1)
def setUp(self): rng = np.random.default_rng(2) self.n = 10 self.data = rng.normal(size=self.n) self.src = sources.Stream(self.data)
def test_empty_result_if_zero_samples_requested_from_empty_store(self): src = sources.Stream([]) y = src(size=0) self.assertEqual(len(y), 0)