예제 #1
0
    def sample(self, prior: MarkovStateModel, n_samples: int, n_steps: Optional[int] = None, callback=None):
        r""" Performs sampling based on a prior.

        Parameters
        ----------
        prior : MarkovStateModel
            The MSM that is used as initial sampling point.
        n_samples : int
            The number of samples to draw.
        n_steps : int, optional, default=None
            The number of sampling steps for each transition matrix. If None, determined
            by :math:`\sqrt{\mathrm{n\_states}}`.
        callback : callable, optional, default=None
            Callback function that indicates progress of sampling.

        Returns
        -------
        samples : list of :obj:`MarkovStateModel`
            The generated samples

        Examples
        --------
        This method can in particular be used to append samples to an already estimated posterior:

        >>> import numpy as np
        >>> import deeptime as dt
        >>> dtrajs = [np.array([0,1,2,2,2,2,1,2,2,2,1,0,0,0,0,0,0,0]),
        ...           np.array([0,0,0,0,1,1,2,2,2,2,2,2,2,1,0,0])]
        >>> prior = dt.markov.msm.MaximumLikelihoodMSM().fit(dtrajs, lagtime=1)
        >>> estimator = dt.markov.msm.BayesianMSM()
        >>> posterior = estimator.fit(prior).fetch_model()
        >>> n_samples = len(posterior.samples)
        >>> posterior.samples.extend(estimator.sample(posterior.prior, n_samples=23))
        >>> assert len(posterior.samples) == n_samples + 23
        """
        if n_steps is None:
            # heuristic for number of steps to decorrelate
            n_steps = int(sqrt(prior.count_model.n_states_full))
        # transition matrix sampler
        from deeptime.markov.tools.estimation import tmatrix_sampler
        if self.stationary_distribution_constraint is None:
            tsampler = tmatrix_sampler(prior.count_model.count_matrix, reversible=self.reversible,
                                       T0=prior.transition_matrix, nsteps=n_steps)
        else:
            # Use the stationary distribution on the active set of states
            statdist_active = prior.stationary_distribution
            # We can not use the MLE as T0. Use the initialization in the reversible pi sampler
            tsampler = tmatrix_sampler(prior.count_model.count_matrix, reversible=self.reversible,
                                       mu=statdist_active, nsteps=n_steps)
        sample_Ps, sample_mus = tsampler.sample(nsamples=n_samples, return_statdist=True, callback=callback)
        # construct sampled MSMs
        samples = [
            MarkovStateModel(P, stationary_distribution=pi, reversible=self.reversible,
                             count_model=prior.count_model,
                             transition_matrix_tolerance=prior.transition_matrix_tolerance)
            for P, pi in zip(sample_Ps, sample_mus)
        ]
        return samples
예제 #2
0
    def fit_from_msm(self, msm: MarkovStateModel, callback=None):
        r""" Fits a bayesian posterior from a given Markov state model. The MSM must contain a count model to be able
        to produce confidences. Note that the count model should be produced using effective counting, otherwise
        counts are correlated and computed confidences are wrong.

        Parameters
        ----------
        msm : MarkovStateModel
            The Markov state model to use as sampling start point.
        callback : callable, optional, default=None
            Function to be called to indicate progress of sampling.

        Returns
        -------
        self : BayesianMSM
            Reference to self.
        """
        if not msm.has_count_model:
            raise ValueError(
                "Can only sample confidences with a count model. The counting mode should be 'effective'"
                " to avoid correlations between counts and therefore wrong confidences."
            )
        # transition matrix sampler
        from deeptime.markov.tools.estimation import tmatrix_sampler
        from math import sqrt
        if self.n_steps is None:
            # heuristic for number of steps to decorrelate
            self.n_steps = int(sqrt(msm.count_model.n_states_full))
        # use the same count matrix as the MLE. This is why we have effective as a default
        if self.stationary_distribution_constraint is None:
            tsampler = tmatrix_sampler(msm.count_model.count_matrix,
                                       reversible=self.reversible,
                                       T0=msm.transition_matrix,
                                       nsteps=self.n_steps)
        else:
            # Use the stationary distribution on the active set of states
            statdist_active = msm.stationary_distribution
            # We can not use the MLE as T0. Use the initialization in the reversible pi sampler
            tsampler = tmatrix_sampler(msm.count_model.count_matrix,
                                       reversible=self.reversible,
                                       mu=statdist_active,
                                       nsteps=self.n_steps)
        sample_Ps, sample_mus = tsampler.sample(nsamples=self.n_samples,
                                                return_statdist=True,
                                                call_back=callback)
        # construct sampled MSMs
        samples = [
            MarkovStateModel(
                P,
                stationary_distribution=pi,
                reversible=self.reversible,
                count_model=msm.count_model,
                transition_matrix_tolerance=msm.transition_matrix_tolerance)
            for P, pi in zip(sample_Ps, sample_mus)
        ]
        self._model = BayesianPosterior(prior=msm, samples=samples)
        return self
예제 #3
0
    def _estimate(self, dtrajs):

        if self.core_set is not None and self.count_mode == 'effective':
            raise RuntimeError(
                'Cannot estimate core set MSM with effective counting.')

        # conduct MLE estimation (superclass) first
        _MLMSM._estimate(self, dtrajs)

        # transition matrix sampler
        from math import sqrt
        if self.nsteps is None:
            self.nsteps = int(sqrt(
                self.nstates))  # heuristic for number of steps to decorrelate
        # use the same count matrix as the MLE. This is why we have effective as a default
        if self.statdist_constraint is None:
            tsampler = tmatrix_sampler(self.count_matrix_active,
                                       reversible=self.reversible,
                                       T0=self.transition_matrix,
                                       nsteps=self.nsteps)
        else:
            # Use the stationary distribution on the active set of states
            statdist_active = self.pi
            # We can not use the MLE as T0. Use the initialization in the reversible pi sampler
            tsampler = tmatrix_sampler(self.count_matrix_active,
                                       reversible=self.reversible,
                                       mu=statdist_active,
                                       nsteps=self.nsteps)

        if self.show_progress:  #and self.nstates >= 1000:
            self._progress_register(self.nsamples,
                                    '{}: Sampling MSMs'.format(self.name),
                                    stage=0)
            call_back = lambda: self._progress_update(1)
        else:
            call_back = None

        with self._progress_context(stage='all'):
            sample_Ps, sample_mus = tsampler.sample(nsamples=self.nsamples,
                                                    return_statdist=True,
                                                    callback=call_back)
        # construct sampled MSMs
        samples = []
        for P, pi in zip(sample_Ps, sample_mus):
            samples.append(
                _MSM(P,
                     pi=pi,
                     reversible=self.reversible,
                     dt_model=self.dt_model))

        # update self model
        self.update_model_params(samples=samples)

        # done
        return self
 def test_sample_nonrev_10(self):
     sampler = tmatrix_sampler(self.C, reversible=False)
     Ps = sampler.sample(nsamples=10)
     assert len(Ps) == 10
     for i in range(10):
         assert np.all(Ps[i].shape == self.C.shape)
         assert is_transition_matrix(Ps[i])
    def test_sample_nonrev_1(self):
        P = sample_tmatrix(self.C, reversible=False)
        assert np.all(P.shape == self.C.shape)
        assert is_transition_matrix(P)

        # same with boject
        sampler = tmatrix_sampler(self.C, reversible=False)
        P = sampler.sample()
        assert np.all(P.shape == self.C.shape)
        assert is_transition_matrix(P)
 def test_revpi(self):
     N = self.N
     sampler = tmatrix_sampler(self.C, reversible=True, mu=self.pi)
     M = self.C.shape[0]
     T_sample = np.zeros((N, M, M))
     for i in range(N):
         T_sample[i, :, :] = sampler.sample()
     H, xed = np.histogram(T_sample[:, 0, 1], self.xedges)
     P_sampled = 1.0 * H / self.N
     P_analytical = self.probabilities_revpi(self.xedges)
     self.assertTrue(np.all(np.abs(P_sampled - P_analytical) < 0.02))
    def test_rev(self):
        N = self.N
        sampler = tmatrix_sampler(self.C, reversible=True)
        M = self.C.shape[0]
        T_sample = np.zeros((N, M, M))
        for i in range(N):
            T_sample[i, :, :] = sampler.sample()
        p_12 = T_sample[:, 0, 1]
        p_21 = T_sample[:, 1, 0]
        H, xed, yed = np.histogram2d(p_12,
                                     p_21,
                                     bins=(self.xedges, self.yedges))
        P_sampled = H / self.N
        P_analytical = self.probabilities_rev(self.xedges, self.yedges)

        self.assertTrue(np.all(np.abs(P_sampled - P_analytical) < 0.01))