def _backward_sampling_ON2(self, M, idx): """O(N^2) version of backward sampling. not meant to be called directly, see backward_sampling """ for m in range(M): for t in reversed(range(self.T - 1)): lwm = (self.wgts[t].lw + self.fk.logpt( t + 1, self.X[t], self.X[t + 1][idx[t + 1, m]])) idx[t, m] = rs.multinomial_once(rs.exp_and_normalise(lwm))
def multinomial_sampling(W: np.ndarray) -> Tuple: # tested """Multinomial sampling for multi-dimensional numpy arrays. :param W: a numpy array of weights, summing to 1 :returns: a tuple of indices indicating the chosen element """ W_raveled = np.ravel(W) #chosen_raveled_index = np.random.choice(len(W_raveled), p=W_raveled) chosen_raveled_index = rs.multinomial_once(W_raveled) return np.unravel_index(chosen_raveled_index, W.shape)
def extract_one_trajectory(self): """Extract a single trajectory from the particle history. The final state is chosen randomly, then the corresponding trajectory is constructed backwards, until time t=0. """ traj = [] for t in reversed(range(self.T)): if t == self.T - 1: n = rs.multinomial_once(self.wgts[-1].W) else: n = self.A[t + 1][n] traj.append(self.X[t][n]) return traj[::-1]
def sample(self, N=1): """Sample N trajectories from the posterior. Note ---- Performs the forward step in case it has not been performed. """ if not self.filt: self.forward() paths = np.empty((len(self.filt), N), np.int) paths[-1, :] = rs.multinomial(self.filt[-1], M=N) log_trans = np.log(self.hmm.trans_mat) for t, f in reversed(list(enumerate(self.filt[:-1]))): for n in range(N): probs = rs.exp_and_normalise(log_trans[:, paths[t + 1, n]] + np.log(f)) paths[t, n] = rs.multinomial_once(probs) return paths