class gpr::laplace::TCovSecondOrder

Overview

Analytical closed-form 2nd-order TCOV-INLA correction cache (partial). More…

#include <TCovSecondOrder.h>
 
class TCovSecondOrder {
public:
    // fields
 
    static double kTrustTau = 0.5;
 
    // construction
 
    TCovSecondOrder();
 
    // methods
 
    bool compute(const GaussianProcessRegression& gpr, const Eigen::MatrixXd& H_inv);
    void applyCorrection(const GaussianProcessRegression& gpr, Observation& image1);
    bool valid() const;
    std::size_t nLs() const;
    void invalidate();
};

Detailed Documentation

Analytical closed-form 2nd-order TCOV-INLA correction cache (partial).

At the MAP hyperparameter theta_star, precomputes the vectors needed to evaluate the quadratic-in-Delta theta correction to the predictive mean at any query x*: m(x*) = mu_MAP(x*)
  • 0.5 * sum_{ij} (H^{-1})_{ij} * d^2 mu / d theta_i d theta_j (x*)

with d^2 mu / d theta_i d theta_j (x*) =

k_{ij}(x*)^T * alpha_star

  • k_i(x*)^T * z_j - k_j(x*)^T * z_i

  • k_star(x*)^T * beta_{ij}

SymPy proof: python/tests/test_sympy_laplace_tcov_analytical.py (identities A1-A8; A8 is the partial-scope acceptance gate).

SCOPE: only (log_magn, log_magn) and (log_magn, log_ls_d) pairs are kept. Both (log_ls_d, log_ls_e) and (log_sn, *) are set to zero. The A8 gate shows this captures >= 50% of the full 2nd-order shift when H diagonal on log_ls is >= 10x the entry on log_magn, with sign agreement in the tight-posterior regime. The missed (ls, ls) terms are suppressed by 1/H_ls^2 and dominate only in the broad- posterior regime, which is opposite the post-SCG regime we target.

Required cached quantities, evaluated ONCE at theta_star:

K_d = dK / d theta_d |_* for d in {0 (magn), 1..nls (ls)} z_d = K_star^{-1} * K_d * alpha_star (m_tr vectors, size m_tr) beta_{0,d} = K_star^{-1} * (K_0 z_d + K_d z_0 - K_d alpha_star) for d in {0..nls} (beta_{00} = K_star^{-1} * (2 K_0 z_0 - K_0 alpha_star)) using A2: K_{0,0} = K_0 and K_{0,d} = K_d

m_tr = rows of gpr.R_matrix (= N_tr * (D+1) with gradient observations).

Non-copyable, value-semantic.

Fields

static double kTrustTau = 0.5

Trust-region cap on the per-component Taylor correction: applyCorrection writes image1.{E,G} += sign(corr) * min(|corr|, kTrustTau * |MAP|). With kTrustTau < 1 the corrected gradient stays in the same hemisphere as MAP proven by sympy TR2 in python/tests/test_sympy_laplace_trust_region.py. Exposed as a class constant so tests can reference the same value.

Methods

bool compute(const GaussianProcessRegression& gpr, const Eigen::MatrixXd& H_inv)

Populate the cache at the current GPR state (after decomposeCovarianceMatrix at theta_star and alpha = K_star^-1 y).

Parameters:

gpr

Configured GPR (must have valid L and a at theta*).

H_inv

Inverse Hessian (p x p) from the Laplace cache.

Returns:

true on success; false if K_star is singular or hypers are invalid (fall back to MAP or to the 1st-order TCOV-INLA path).

void applyCorrection(const GaussianProcessRegression& gpr, Observation& image1)

Apply the partial 2nd-order correction to image1.E and image1.G per query point. Adds the quadratic shift in-place.

bool valid() const

Is the cache populated and usable?

std::size_t nLs() const

Number of cached lengthscale dimensions (0..n_ls).

void invalidate()

Invalidate (drops all cached vectors).