def integral_abcd(a, b, c, d): """Compute the a-b-c-d integral from the paper. Args: a (tensor): First upper integration bound. b (tensor): Second upper integration bound. c (tensor): Decay for sum. d (tensor): Decay for absolute difference. Returns: tensor: Value of the integral. """ # Compute the conditional and signs. sign = B.sign(a) condition = a * b >= 0 # Compute the two parts. part1 = sign * d / c * (1 - B.exp(2 * c * sign * B.minimum(B.abs(a), B.abs(b)))) part2 = ( 1 - B.exp(c * a - d * B.abs(a)) - B.exp(c * b - d * B.abs(b)) + B.exp(c * (a + b) - d * B.abs(a - b)) ) # Combine and return. condition = B.cast(B.dtype(part1), condition) return (condition * part1 + part2) / (c**2 - d**2)
def k_h(self): """Get the kernel function of the filter. Returns: :class:`mlkernels.Kernel`: Kernel for :math:`h`. """ k_h = Exp().stretch(1 / self.lam) # Kernel of filter before window k_h *= lambda t: B.exp(-self.alpha * B.abs(t)) # Window k_h *= lambda t: B.cast(self.dtype, t >= 0) # Causality constraint return k_h
def sample(model, t, noise_f): """Sample from a model. Args: model (:class:`gpcm.model.AbstractGPCM`): Model to sample from. t (vector): Time points to sample at. noise_f (vector): Noise for the sample of the function. Should have the same size as `t`. Returns: tuple[vector, ...]: Tuple containing kernel samples, filter samples, and function samples. """ ks, us, fs = [], [], [] # In the below, we look at the third inducing point, because that is the one # determining the value of the filter at zero: the CGPCM adds two extra inducing # points to the left. # Get a smooth sample. u1 = B.ones(model.n_u) while B.abs(u1[2]) > 1e-2: u1 = B.sample(model.compute_K_u())[:, 0] u = GP(model.k_h()) u = u | (u(model.t_u), u1) u1_full = u(t).mean.flatten() # Get a rough sample. u2 = B.zeros(model.n_u) while u2[2] < 0.5: u2 = B.sample(model.compute_K_u())[:, 0] u = GP(model.k_h()) u = u | (u(model.t_u), u2) u2_full = u(t).mean.flatten() with wbml.out.Progress(name="Sampling", total=5) as progress: for c in [0, 0.1, 0.23, 0.33, 0.5]: # Sample kernel. K = model.kernel_approx(t, t, c * u2 + (1 - c) * u1) wbml.out.kv("Sampled variance", K[0, 0]) K = K / K[0, 0] ks.append(K[0, :]) # Store filter. us.append(c * u2_full + (1 - c) * u1_full) # Sample function. f = B.matmul(B.chol(closest_psd(K)), noise_f) fs.append(f) progress() return ks, us, fs
def eig(a, compute_eigvecs=True): if compute_eigvecs: vals, vecs = B.eig(a, compute_eigvecs=True) vals = B.flatten(vals) if B.rank(vecs) == 3: vecs = B.transpose(vecs, perm=(1, 0, 2)) vecs = B.reshape(vecs, 3, -1) order = compute_order(vals) return B.take(vals, order), B.abs(B.take(vecs, order, axis=1)) else: vals = B.flatten(B.eig(a, compute_eigvecs=False)) return B.take(vals, compute_order(vals))
def compute_K_u(model): """Covariance matrix of inducing variables :math:`u` associated with :math:`h`. Args: model (:class:`.gprv.GPRV`): Model. Returns: tensor: :math:`K_u`. """ return Dense( (model.gamma_t**2 / (2 * model.gamma)) * B.exp(-model.gamma * B.abs(model.t_u[:, None] - model.t_u[None, :])) )
def compute_i_hx(model, t1=None, t2=None): """Compute the :math:`I_{hx}` integral. Args: model (:class:`.gprv.GPRV`): Model. t1 (tensor, optional): First time input. Defaults to zero. t2 (tensor, optional): Second time input. Defaults to zero. Returns: tensor: Value of :math:`I_{hx}` for all `t1` and `t2`. """ if t1 is None: t1 = B.zero(model.dtype) if t2 is None: t2 = B.zero(model.dtype) return model.alpha_t**2 / 2 / model.alpha * B.exp(-model.lam * B.abs(t1 - t2))
def _est_cov(a): num = 500_000 samples = B.dense(B.sample(a, num=num)) cov_est = B.matmul(samples, samples, tr_b=True) / num err = B.max(B.abs(B.dense(a) - cov_est)) / B.max(B.abs(B.dense(a))) assert err < 1e-1
def svd(a, compute_uv=True): if compute_uv: u, s, v = B.svd(a, compute_uv=True) return B.abs(u), s, B.abs(v) else: return B.svd(a, compute_uv=False)