Esempio n. 1
0
    def _twofilter_smoothing_ON(self, t, ti, info, phi, lwinfo, return_ess,
                                modif_forward, modif_info):
        """O(N) version of two-filter smoothing.

        This method should not be called directly, see twofilter_smoothing.
        """
        if modif_info is not None:
            lwinfo += modif_info
        Winfo = rs.exp_and_normalise(lwinfo)
        I = rs.multinomial(Winfo)
        if modif_forward is not None:
            lw = self.wgts[t].lw + modif_forward
            W = rs.exp_and_normalise(lw)
        else:
            W = self.wgts[t].W
        J = rs.multinomial(W)
        log_omega = self.fk.logpt(t + 1, self.X[t][J], info.hist.X[ti][I])
        if modif_forward is not None:
            log_omega -= modif_forward[J]
        if modif_info is not None:
            log_omega -= modif_info[I]
        Om = rs.exp_and_normalise(log_omega)
        est = np.average(phi(self.X[t][J], info.hist.X[ti][I]),
                         axis=0,
                         weights=Om)
        if return_ess:
            return (est, 1. / np.sum(Om**2))
        else:
            return est
Esempio n. 2
0
    def backward_sampling(self, M, linear_cost=False, return_ar=False):
        """Generate smoothing trajectories using FFBS.

        FFBS (forward filtering backward smoothing) is a class of off-line
        smoothing algorithms, which generate smoothing trajectories constructed
        from the history of a particle filter.

        Arguments
        ---------
        M: int
            number of trajectories we want to generate
        linear_cost: bool
            if set to True, the O(N) version is used, see below.

        return_ar: bool (default=False)
            if set to True, change the output, see below.

        Returns
        -------
        paths: a list of ndarrays
            paths[t][n] is component t of trajectory m.
        ar: float
            the overall acceptance rate of the rejection procedure

        Notes
        -----

        1. if ``linear_cost=False``, complexity is O(TMN); i.e. O(TN^2) for M=N;
           if ``linear_cost=True``, complexity is O(T(M+N)), i.e. O(TN) for M=N.
           This requires that model has method `upper_bound_trans`, which
           provides the log of a constant C_t such that
           :math:`p_t(x_t|x_{t-1}) \leq C_t`.

        2. main output is ``paths``, a list of T arrays such that
           ``paths[t][m]`` is component t of trajectory m.

        3. if ``linear_cost=True`` and ``return_ar=True``, output is tuple
           ``(paths, ar)``, where ``paths`` is as above, and ``ar`` is the overall
           acceptance rate (of the rejection steps that choose the ancestors);
           otherwise output is simply ``paths``.
        """
        idx = np.empty((self.T, M), dtype=int)
        idx[-1, :] = rs.multinomial(self.wgts[-1].W, M=M)
        if linear_cost:
            ar = self._backward_sampling_ON(M, idx)
        else:
            self._backward_sampling_ON2(M, idx)
        # When M=1, we want a list of states, not a list of arrays containing
        # one state
        if M == 1:
            idx = idx.squeeze(axis=1)
        paths = [self.X[t][idx[t]] for t in range(self.T)]
        if linear_cost and return_ar:
            return (paths, ar)
        else:
            return paths
Esempio n. 3
0
    def backward_sampling(self, M, linear_cost=False, return_ar=False):
        """Generate trajectories using the FFBS (forward filtering backward
        sampling) algorithm. 

        Arguments
        ---------
        M: int
            number of trajectories we want to generate
        linear_cost: bool 
            if set to True, the O(N) version is used, see below. 

        return_ar: bool (default=False)
            if set to True, change the output, see below. 
        
        Returns
        -------
        paths: a list of ndarrays
            paths[t][n] is component t of trajectory m. 
        ar: float
            the overall acceptance rate of the rejection procedure

        Notes
        -----

        1. if linear_cost=False, complexity is O(TMN); i.e. O(TN^2) for M=N;
           if =True, complexity is O(T(M+N)), i.e. O(TN) for M=N.
           This requires that model has method `upper_bound_trans(self,t)`, which
           provides the log of a constant C_t such that p_t(x_t|x_{t-1})<=C_t

        2. main output is *paths*, a list of T arrays such that
           paths[t][m] is component t of trajectory m.

        3. if linear_cost=True and return_ar=True, output is tuple (paths, ar),
           where paths is as above, and ar is the overall acceptance rate 
           (of the rejection steps that choose the ancestors); otherwise 
           output is simply paths
        """
        idx = np.empty((self.T, M), dtype=int)
        idx[-1, :] = rs.multinomial(self.wgt[-1].W, M=M)
        if linear_cost:
            ar = self._backward_sampling_ON(M, idx)
        else:
            self._backward_sampling_ON2(M, idx)
        # When M=1, we want a list of states, not a list of arrays containing
        # one state
        if M == 1:
            idx = idx.squeeze(axis=1)
        paths = [self.X[t][idx[t]] for t in range(self.T)]
        if linear_cost and return_ar:
            return (paths, ar)
        else:
            return paths
Esempio n. 4
0
    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