def logeta(self, t, x, xp, data): "Log of auxiliary function at time t. The auxiliary function is $\frac{p(y_{t+1}|X_{t}^{i})}{p(y_{t}|x_{t-1}^{i})}$" scale = np.sqrt(self.sigma**2 + self.tau**2) try: return dists.Normal(self.rho * x, scale).logpdf(data[t + 1]) - dists.Normal( self.rho * xp, scale).logpdf(data[t]) except TypeError: return np.ones(x.shape)
def filter_step(G, covY, pred, yt): """Filtering step of Kalman filter. Parameters ---------- G: (dy, dx) numpy array mean of Y_t | X_t is G * X_t covX: (dx, dx) numpy array covariance of Y_t | X_t pred: MeanAndCov object predictive distribution at time t Returns ------- pred: MeanAndCov object filtering distribution at time t logpyt: float log density of Y_t | Y_{0:t-1} """ # data prediction data_pred_mean = np.matmul(pred.mean, G.T) data_pred_cov = dotdot(G, pred.cov, G.T) + covY if covY.shape[0] == 1: logpyt = dists.Normal(loc=data_pred_mean, scale=np.sqrt(data_pred_cov)).logpdf(yt) else: logpyt = dists.MvNormal(loc=data_pred_mean, cov=data_pred_cov).logpdf(yt) # filter residual = yt - data_pred_mean gain = dotdotinv(pred.cov, G.T, data_pred_cov) filt_mean = pred.mean + np.matmul(residual, gain.T) filt_cov = pred.cov - dotdot(gain, G, pred.cov) return MeanAndCov(mean=filt_mean, cov=filt_cov), logpyt
def get_prior(): prior_dict = { 'lam': dists.Normal(loc=0., scale=1.),#W 'log_alpha': dists.LogD(dists.Gamma(a=.1, b=.1)),#W 'log_delta': dists.LogD(dists.Gamma(a=.1, b=.1)), } return dists.StructDist(prior_dict)
def PY(self, t, xp, x): # u is realisation of noise U_t, conditional on X_t, X_{t-1} if t==0: u = (x - self.mu) / self.sig0() else: u = (x - self.EXt(xp)) / self.sigma std_x = np.exp(0.5 * x) return dists.Normal(loc=std_x * self.phi * u, scale=std_x * np.sqrt(1. - self.phi**2))
def PY(self, t, xp, x): # print(f"PY is called, shape of x {x}, {x.shape}") if self.num_yields == 1: mu = -self.Atau + self.Btau * x scale = np.sqrt(self.H) return dists.Normal(mu, scale) else: # In particles\core.py\SMC reweight_particles call the fk model's logG and therefore PY here is called by # the Bootstrap filter. In this process, x is inputed as a list, containing all particles in one time step. # So the normal broadcast mechanism doen not work as desire. mu = [-self.Atau + self.Btau * xi for xi in x] cov = np.eye(self.num_yields) * self.H # cov = np.diag(np.asanyarray(self.H)) # cov = np.zeros((self.num_yields, self.num_yields)) # cov[:self.num_yields].flat[0::self.num_yields+1] = self.H return dists.MvNormal(loc=mu, cov=cov)
def filter_step(G, covY, pred_mean, pred_cov, yt): """Filtering step. Note ---- filt_mean may either be of shape (dx,) or (N, dx); in the latter case N predictive steps are performed in parallel. """ # data prediction data_pred_mean = np.matmul(pred_mean, G.T) data_pred_cov = dotdot(G, pred_cov, G.T) + covY if covY.shape[0] == 1: logpyt = dists.Normal(loc=data_pred_mean, scale=np.sqrt(data_pred_cov)).logpdf(yt) else: logpyt = dists.MvNormal(loc=data_pred_mean, cov=data_pred_cov).logpdf(yt) # filter residual = yt - data_pred_mean gain = dotdot(pred_cov, G.T, inv(data_pred_cov)) filt_mean = pred_mean + np.matmul(residual, gain.T) filt_cov = pred_cov - dotdot(gain, G, pred_cov) return filt_mean, filt_cov, logpyt
def PX0(self): return dists.Normal(scale=2.)
def logeta(self, t, x, data): law = dists.Normal(loc=self.rho * x, scale=np.sqrt(self.sigmaX**2 + self.sigmaY**2)) return law.logpdf(data[t + 1])
def proposal(self, t, xp, data): sig2post = 1. / (1. / self.sigmaX**2 + 1. / self.sigmaY**2) mupost = sig2post * (self.rho * xp / self.sigmaX**2 + data[t] / self.sigmaY**2) return dists.Normal(loc=mupost, scale=np.sqrt(sig2post))
def proposal0(self, data): sig2post = 1. / (1. / self.sigma0**2 + 1. / self.sigmaY**2) mupost = sig2post * (data[0] / self.sigmaY**2) return dists.Normal(loc=mupost, scale=np.sqrt(sig2post))
def PY(self, t, xp, x): # Distribution of Y_t given X_t=x (and possibly X_{t-1}=xp) return dists.Normal(loc=0., scale=np.exp(x))
def PY(self, t, xp, x): angle = np.arctan(x[:, 3] / x[:, 2]) angle[x[:, 2] < 0.] += np.pi return dists.Normal(loc=angle, scale=self.sigmaY)
def PX0(self): return dists.IndepProd(dists.Normal(loc=self.x0[0], scale=self.sigmaX), dists.Normal(loc=self.x0[1], scale=self.sigmaX), dists.Dirac(loc=self.x0[2]), dists.Dirac(loc=self.x0[3]) )
def proposal(self, t, xp, data): # Pitt & Shephard return dists.Normal(loc=self._xhat(self.EXt(xp), self.sigma, data[t]), scale=self.sigma)
def proposal0(self, data): # Pitt & Shephard return dists.Normal(loc=self._xhat(0., self.sig0(), data[0]), scale=self.sig0())
def PY(self, t, xp, x): return dists.Normal(loc=0., scale=np.exp(0.5 * x))
def PX(self, t, xp): return dists.Normal(loc=self.EXt(xp), scale=self.sigma)
def PX0(self): return dists.Normal(loc=self.mu, scale=self.sig0())
from numpy import random import particles from particles import datasets as dts from particles import distributions as dists from particles import resampling as rs from particles import smc_samplers as ssp from particles import state_space_models from particles.collectors import Moments # data data = dts.GBP_vs_USD_9798().data # prior dictprior = { 'mu': dists.Normal(scale=2.), 'sigma': dists.Gamma(a=2., b=2.), 'rho': dists.Beta(a=9., b=1.), 'phi': dists.Uniform(a=-1., b=1.) } prior = dists.StructDist(dictprior) # moment function def qtiles(W, x): alphas = np.linspace(0.05, 0.95, 19) return rs.wquantiles_str_array(W, x.theta, alphas=alphas) # algorithms N = 10**3 # re-run with N= 10^4 for the second CDF plots
def PX(self, t, xp): return dists.Normal(loc=self.b * xp + self.c * xp / (1. + xp**2) + self.d * np.cos(self.e * (t - 1)), scale=self.sigmaX)
def PY(self, t, xp, x): return dists.Normal(loc=self.a * x**2)
def PX(self, t, xp): return dists.Normal(loc=self.mu + self.phi * (xp - self.mu), scale=self.sigma)
def PX(self, t, xp): return dists.IndepProd(dists.Normal(loc=xp[:, 0], scale=self.sigmaX), dists.Normal(loc=xp[:, 1], scale=self.sigmaX), dists.Dirac(loc=xp[:, 0] + xp[:, 2]), dists.Dirac(loc=xp[:, 1] + xp[:, 3]) )
def PX(self, t, xp): return dists.Normal(loc=xp + self.tau0 - self.tau1 * np.exp(self.tau2 * xp), scale=self.sigmaX)
def PX0(self): return dists.Normal(loc=self.mu, scale=self.sigma / np.sqrt(1. - self.phi**2))
def PX(self, t, xp): # Distribution of X_t given X_{t-1}=xp (p=past) return dists.Normal(loc=self.mu + self.rho * (xp - self.mu), scale=self.sigma)
def PX0(self): return dists.Normal(loc=0., scale=1.)
def PX0(self): return dists.Normal(scale=self.sigma0)
def PY(self, t, xp, x): return dists.Normal(loc=x, scale=self.sigmaY)
def PX(self, t, xp): return dists.Normal(loc=self.rho * xp, scale=self.sigmaX)