Source code for cofi.utils._kernel

"""Kernel functions for parameterized covariance matrices."""

import numpy as np


[docs] class SquaredExponentialKernel: r"""Squared exponential (Gaussian/RBF) correlation kernel. Computes the kernel matrix and its first and second derivatives with respect to :math:`\eta = \log \ell`, where :math:`\ell` is the correlation length. .. math:: K(\eta)_{ij} = \exp\!\Big(-\frac{d_{ij}^2}{2\ell^2}\Big) + \nu\,\delta_{ij} where :math:`\ell = e^\eta`, :math:`d_{ij} = |x_i - x_j|`, and :math:`\nu` is a small nugget for numerical stability. Parameters ---------- positions : array_like 1-D array of data point positions (e.g. time samples). Shape ``(n_data,)``. nugget : float, optional Small diagonal addition for positive-definiteness. Default ``1e-10``. Attributes ---------- n_params : int Number of kernel hyperparameters (always 1 for this kernel). n_data : int Number of data points. D2 : np.ndarray Precomputed squared-distance matrix, shape ``(n_data, n_data)``. """ n_params = 1 def __init__(self, positions, nugget=1e-10): positions = np.asarray(positions, dtype=float).ravel() self.positions = positions self.n_data = positions.size self.nugget = float(nugget) # Precompute squared-distance matrix (symmetric, zero diagonal) self.D2 = (positions[:, None] - positions[None, :]) ** 2 # ------------------------------------------------------------------ # Internal helper – shared by evaluate / derivative / second_derivative # ------------------------------------------------------------------ def _U_and_K0(self, eta): """Return (U, K0) where U = D2/(2 ell^2) and K0 = exp(-U).""" ell2 = np.exp(2.0 * float(eta)) U = self.D2 / (2.0 * ell2) K0 = np.exp(-U) return U, K0 # ------------------------------------------------------------------ # Public API # ------------------------------------------------------------------
[docs] def evaluate(self, eta): r"""Kernel matrix :math:`K(\eta)`. Parameters ---------- eta : float Log-correlation-length, :math:`\eta = \log \ell`. Returns ------- K : np.ndarray, shape (n_data, n_data) """ _, K0 = self._U_and_K0(eta) K = K0.copy() np.fill_diagonal(K, K.diagonal() + self.nugget) return K
[docs] def derivative(self, eta): r"""First derivative :math:`\partial K / \partial \eta`. .. math:: \frac{\partial K_{ij}}{\partial\eta} = 2\,U_{ij}\,K^0_{ij} where :math:`U_{ij} = d_{ij}^2/(2\ell^2)` and :math:`K^0_{ij} = e^{-U_{ij}}` (without nugget). Parameters ---------- eta : float Returns ------- K_eta : np.ndarray, shape (n_data, n_data) """ U, K0 = self._U_and_K0(eta) return 2.0 * U * K0
[docs] def second_derivative(self, eta): r"""Second derivative :math:`\partial^2 K / \partial \eta^2`. .. math:: \frac{\partial^2 K_{ij}}{\partial\eta^2} = 4\,U_{ij}\,(U_{ij} - 1)\,K^0_{ij} Parameters ---------- eta : float Returns ------- K_etaeta : np.ndarray, shape (n_data, n_data) """ U, K0 = self._U_and_K0(eta) return 4.0 * U * (U - 1.0) * K0