Exemplo n.º 1
0
def mdd(self,
        method='laplace',
        chain=None,
        lprobs=None,
        tune=None,
        verbose=False,
        **args):
    """Approximate the marginal data density.

    Parameters
    ----------
    method : str
        The method used for the approximation. Can be either of 'laplace', 'mhm' (modified harmonic mean) or 'hess' (LaPlace approximation with the numerical approximation of the hessian; NOT FUNCTIONAL).
    """

    if verbose:
        st = time.time()

    if chain is None:
        tune = tune or self.get_tune
        chain = self.get_chain()[-tune:]
        chain = chain.reshape(-1, chain.shape[-1])

    if lprobs is None:
        tune = tune or self.get_tune
        lprobs = self.get_log_prob()[-tune:]
        lprobs = lprobs.flatten()

    if method in ('laplace', 'lp'):
        mstr = 'LaPlace approximation'
        mdd = mdd_lp(chain, lprobs, calc_hess=False, **args)
    elif method == 'hess':
        mstr = 'LaPlace approximation with hessian approximation'
        mdd = mdd_lp(chain, lprobs, calc_hess=True, **args)
    elif method == 'mhm':
        mstr = 'modified harmonic mean'
        pool = self.pool if hasattr(self, 'pool') else None
        mdd = mdd_mhm(chain, lprobs, pool=pool, verbose=verbose > 1, **args)
    else:
        raise NotImplementedError(
            '[mdd:]'.ljust(15, ' ') +
            "`method` must be one of `laplace`, `mhm` or `hess`.")

    if verbose:
        print('[mdd:]'.ljust(15, ' ') +
              "done after %s. Marginal data density according to %s is %s." %
              (timeprint(time.time() - st), mstr, mdd.round(3)))

    return mdd
Exemplo n.º 2
0
def run_filter(self,
               smoother=True,
               get_ll=False,
               dispatch=None,
               rcond=1e-14,
               seed=None,
               verbose=False):

    if verbose:
        st = time.time()

    self.Z = np.array(self.data)

    # assign current transition & observation functions (of parameters)
    if self.filter.name == 'KalmanFilter':

        pmat = self.precalc_mat[0]
        qmat = self.precalc_mat[1]

        F = np.vstack(
            (pmat[1, 0][:, :-self.neps], qmat[1, 0][:-self.neps, :-self.neps]))
        F = np.pad(F, ((0, 0), (self.dimp, 0)))

        E = np.vstack((pmat[1, 0][:, -self.neps:], qmat[1, 0][:-self.neps,
                                                              -self.neps:]))

        self.filter.F = F
        self.filter.H = np.hstack((self.hx[0], self.hx[1])), self.hx[2]

        if self.filter.Q.shape[0] == self.neps:
            self.filter.Q = E @ self.filter.Q @ E.T

    elif dispatch or self.filter.name == 'ParticleFilter':
        from .engine import func_dispatch
        t_func_jit, o_func_jit, get_eps_jit = func_dispatch(self, full=True)
        self.filter.t_func = t_func_jit
        self.filter.o_func = o_func_jit
        self.filter.get_eps = get_eps_jit

    elif self.filter.reduced_form:
        self.filter.t_func = lambda *x: self.t_func(*x, get_obs=True)
        self.filter.o_func = None

    else:
        self.filter.t_func = self.t_func
        self.filter.o_func = self.o_func

    self.filter.get_eps = self.get_eps_lin

    if self.filter.name == 'KalmanFilter':

        means, covs, ll = self.filter.batch_filter(self.Z)

        if smoother:
            means, covs, _, _ = self.filter.rts_smoother(means,
                                                         covs,
                                                         inv=np.linalg.pinv)

        if get_ll:
            res = ll
        else:
            means = means
            res = (means, covs)

    elif self.filter.name == 'ParticleFilter':

        res = self.filter.batch_filter(self.Z)

        if smoother:

            if verbose > 0:
                print(
                    '[run_filter:]'.ljust(15, ' ') +
                    ' Filtering done after %s seconds, starting smoothing...' %
                    np.round(time.time() - st, 3))

            if isinstance(smoother, bool):
                smoother = 10
            res = self.filter.smoother(smoother)

    else:
        res = self.filter.batch_filter(self.Z,
                                       calc_ll=get_ll,
                                       store=smoother,
                                       seed=seed,
                                       verbose=verbose > 0)

        if smoother:
            res = self.filter.rts_smoother(res, rcond=rcond)

    if get_ll:
        if np.isnan(res):
            res = -np.inf
        self.ll = res
    else:
        self.X = res

    if verbose > 0:
        mess = '[run_filter:]'.ljust(
            15,
            ' ') + ' Filtering done in %s.' % timeprint(time.time() - st, 3)
        if get_ll:
            mess += 'Likelihood is %s.' % res
        print(mess)

    return res
Exemplo n.º 3
0
def npas(self,
         X=None,
         vals=None,
         covs=None,
         get_eps=None,
         nsamples=False,
         bound_sigma=4,
         frtol=1e-5,
         seed=0,
         verbose=True,
         **cmaes_args):
    """Nonlinear Path-Adjustment Smoother. 

    Assumes that either `X` (a time series of ensembles) is given (or can be taken from the filter `self` object), or that the time series vals and covs are given. From the filter object, also `eps_cov` (the diagonal matrix of the standard deviations of the shocks) and the transition function `t_func(state, shock_innovations)` must be provided.
    ...

    Parameters
    ----------
    X : array, optional
        a time series of ensembles. Either this, or vals and covs have to be provided
    vals : array, optional
        the series of ensemble values, probably you want the means. Either this together with the covs, or X has to be provided
    covs : array, optional
        the series of ensemble covariances. Either this together with `vals`, or `X` has to be provided
    get_eps : function, optional
        function that, given two states (x, xp), returns a candidate solution of exogenous innovations
    bound_sigma : int, optional
        the number of standard deviations included in the box constraint of the global optimizer

    Returns
    -------
    X : array 
        the smoothed vals
    covs : array 
        the covariances
    res : array 
        the smoothed/estimated exogenousinnovations
    flag : bool
        an error flag of the transition function
    """
    if verbose:
        st = time.time()

    ## X must be time series of ensembles of x dimensions
    if X is None:
        X = np.rollaxis(self.Ss, 2)

    if covs is None:
        covs = np.empty((X.shape[1], X.shape[2], X.shape[2]))
        for i in range(X.shape[1]):
            covs[i, :, :] = np.cov(X[:, i, :].T)

    bound = np.diag(self.eps_cov) * bound_sigma

    def target(eps, x, mean, cov):

        state, flag = self.t_func(x, 2 * bound * eps)
        if flag:
            return np.inf

        return -logpdf(state, mean=mean, cov=cov)

    wrap = tqdm if verbose else lambda x: x
    owrap = wrap if nsamples > 1 else lambda x: x
    iwrap = wrap if nsamples else lambda x: x

    # the smooth version to do this would be rejection sampling. But as max(p(x) / q(x)) is unknown and expensive to evaluate, rejection sampling would likewise be expensive

    if not nsamples:
        X[0] = np.mean(X, axis=0)
        nsamples = 1
    else:
        np.random.shuffle(X)

    # preallocate
    res = np.empty((nsamples, len(self.Z) - 1, self.dim_z))
    flag = False

    for n, s in enumerate(owrap(X[:nsamples])):

        x = X[n][0]

        for t in iwrap(range(s.shape[0] - 1)):

            func = lambda eps: target(eps, x, s[t + 1], covs[t + 1])

            eps0 = get_eps(x, s[t + 1]) / bound / 2 if get_eps else np.zeros(
                self.dim_z)

            res_cma = cmaes(func,
                            eps0,
                            0.1,
                            verbose=verbose > 1,
                            frtol=frtol,
                            **cmaes_args)
            eps = res_cma[0] * bound * 2

            x, fflag = self.t_func(x, noise=eps)

            flag |= fflag

            res[n][t] = eps
            X[n][t + 1] = x

        if flag and verbose:
            print('[npas:]'.ljust(15, ' ') +
                  'Transition function returned error.')

        if not nsamples and verbose:
            print('[npas:]'.ljust(15, ' ') + 'Extraction took ',
                  timeprint(time.time() - st, 3))

    return X[:nsamples], covs, res, flag
Exemplo n.º 4
0
def run_filter(self, smoother=True, get_ll=False, dispatch=None, rcond=1e-14, constr_data=None, verbose=False):

    if verbose:
        st = time.time()

    if constr_data is None:
        if self.filter.name == 'ParticleFilter':
            constr_data = 'elb_level'  # wild guess
        else:
            constr_data = False

    if constr_data:
        # copy the data
        data = self.data
        # constaint const_obs
        x_shift = self.get_par(constr_data)
        data[str(self.const_obs)] = np.maximum(
            data[str(self.const_obs)], x_shift)
        # send to filter
        self.Z = np.array(data)
    else:
        self.Z = np.array(self.data)

    if dispatch is None:
        dispatch = self.filter.name == 'ParticleFilter'

    if dispatch:
        from .engine import func_dispatch
        t_func_jit, o_func_jit, get_eps_jit = func_dispatch(self, full=True)
        self.filter.t_func = t_func_jit
        self.filter.o_func = o_func_jit
        self.filter.get_eps = get_eps_jit

    else:
        self.filter.t_func = self.t_func
        self.filter.o_func = self.o_func
        self.filter.get_eps = self.get_eps

    if self.filter.name == 'KalmanFilter':

        res, cov, ll = self.filter.batch_filter(self.Z)

        if get_ll:
            res = ll

        if smoother:
            res, cov, _, _ = self.filter.rts_smoother(res, cov, inv=np.linalg.pinv)

        self.cov = cov

    elif self.filter.name == 'ParticleFilter':

        res = self.filter.batch_filter(self.Z)

        if smoother:

            if verbose:
                print('[run_filter:]'.ljust(
                    15, ' ')+'Filtering done after %s seconds, starting smoothing...' % np.round(time.time()-st, 3))

            if isinstance(smoother, bool):
                smoother = 10
            res = self.filter.smoother(smoother)

    else:

        res = self.filter.batch_filter(
            self.Z, calc_ll=get_ll, store=smoother, verbose=verbose)

        if smoother:
            res = self.filter.rts_smoother(res, rcond=rcond)

    if get_ll:
        if np.isnan(res):
            res = -np.inf
        self.ll = res

        if verbose:
            print('[run_filter:]'.ljust(15, ' ')+'Filtering done in %s. Likelihood is %s.' %
                  (timeprint(time.time()-st, 3), res))
    else:
        self.X = res

        if verbose:
            print('[run_filter:]'.ljust(15, ' ')+'Filtering done in %s.' %
                  timeprint(time.time()-st, 3))

    return res
Exemplo n.º 5
0
def run_filter(self,
               smoother=True,
               get_ll=False,
               dispatch=None,
               rcond=1e-14,
               verbose=False):

    if verbose:
        st = time.time()

    self.Z = np.array(self.data)

    # assign latest transition & observation functions (of parameters)
    if self.filter.name == 'KalmanFilter':
        self.filter.F = self.lin_t_func
        self.filter.H = self.lin_o_func
    elif dispatch or self.filter.name == 'ParticleFilter':
        from .engine import func_dispatch
        t_func_jit, o_func_jit, get_eps_jit = func_dispatch(self, full=True)
        self.filter.t_func = t_func_jit
        self.filter.o_func = o_func_jit
        self.filter.get_eps = get_eps_jit
    else:
        self.filter.t_func = self.t_func
        self.filter.o_func = self.o_func
    self.filter.get_eps = self.get_eps_lin

    if self.filter.name == 'KalmanFilter':

        means, covs, ll = self.filter.batch_filter(self.Z)
        res = (means, covs)

        if get_ll:
            res = ll

        if smoother:
            means, covs, _, _ = self.filter.rts_smoother(means,
                                                         covs,
                                                         inv=np.linalg.pinv)
            res = (means, covs)

    elif self.filter.name == 'ParticleFilter':

        res = self.filter.batch_filter(self.Z)

        if smoother:

            if verbose > 0:
                print(
                    '[run_filter:]'.ljust(15, ' ') +
                    ' Filtering done after %s seconds, starting smoothing...' %
                    np.round(time.time() - st, 3))

            if isinstance(smoother, bool):
                smoother = 10
            res = self.filter.smoother(smoother)

    else:

        res = self.filter.batch_filter(self.Z,
                                       calc_ll=get_ll,
                                       store=smoother,
                                       verbose=verbose > 0)

        if smoother:
            res = self.filter.rts_smoother(res, rcond=rcond)

    if get_ll:
        if np.isnan(res):
            res = -np.inf
        self.ll = res

        if verbose > 0:
            print('[run_filter:]'.ljust(15, ' ') +
                  ' Filtering done in %s. Likelihood is %s.' %
                  (timeprint(time.time() - st, 3), res))
    else:
        self.X = res

        if verbose > 0:
            print('[run_filter:]'.ljust(15, ' ') +
                  ' Filtering done in %s.' % timeprint(time.time() - st, 3))

    return res