Skip to main content
The KernelCache class stores and manages evaluations of the kernel-induced Gram matrix for efficient repeated access during SVM training and inference.

Overview

For a fixed dataset and kernel function k, the Gram matrix is defined as:
K_{ij} = k(x_i, x_j)
The cache supports:
  • Lazy evaluation (computes entries on-demand)
  • Symmetric storage (exploits K_ = K_)
  • Full precomputation for batch operations
  • Efficient numerical access via Eigen dense matrices

KernelCache

Constructor

Constructs a kernel cache for a dataset and kernel function.
data
const std::vector<Vector>&
Input samples (dataset)
kernel
KernelFunction
Kernel function to use for computing Gram matrix entries

Methods

size()

Returns the number of samples in the cached dataset.
return
std::size_t
Number of samples

operator()

Accesses a single Gram matrix entry with lazy evaluation.
i
std::size_t
Row index
j
std::size_t
Column index
return
double
Gram matrix entry K_ = k(x_i, x_j)
If the entry has not been computed yet, it is evaluated and stored. Exploits kernel symmetry to store K_ when computing K_.

gram_matrix()

Accesses the full Gram matrix, ensuring all entries are computed.
return
const Matrix&
Reference to the complete Gram matrix (Eigen::MatrixXd)
This method ensures that all entries are computed before returning. Use this when you need the complete kernel matrix for batch operations.

precompute()

Forces computation of all kernel evaluations upfront.
void precompute() const;
Useful when you know you’ll need the entire Gram matrix and want to compute it once rather than lazily.

kernel()

Accesses the underlying kernel function.
return
const KernelFunction&
Reference to the kernel function used by this cache

Type aliases

  • Matrix = Eigen::MatrixXd - Dense matrix type for storing the Gram matrix

Example usage

#include <mlpp/classifiers/kernel/kernel_cache.hpp>
#include <mlpp/classifiers/kernel/rkhs_kernels.hpp>

using namespace mlpp::classifiers::kernel;

// Prepare dataset
std::vector<Vector> data = {
    {1.0, 2.0, 3.0},
    {4.0, 5.0, 6.0},
    {7.0, 8.0, 9.0}
};

// Create RBF kernel
KernelFunction kernel(std::make_unique<RBFKernel>(0.5));

// Create cache
KernelCache cache(data, kernel);

// Access individual entries (lazy evaluation)
double k_01 = cache(0, 1);  // Computes k(x_0, x_1)
double k_12 = cache(1, 2);  // Computes k(x_1, x_2)

// Get the full Gram matrix
const auto& K = cache.gram_matrix();
std::cout << "Gram matrix:\n" << K << std::endl;

// Or precompute everything upfront
KernelCache cache2(data, kernel);
cache2.precompute();  // Computes all entries immediately

Performance considerations

Lazy evaluation

By default, entries are computed on first access. This is efficient when:
  • You only need a subset of the Gram matrix
  • Memory is limited
  • The dataset is large

Precomputation

Use precompute() or gram_matrix() when:
  • You need the entire Gram matrix
  • You’ll access entries multiple times
  • Training time is critical and you want to avoid repeated lazy checks

Symmetry exploitation

The cache automatically exploits kernel symmetry: when computing K_, it also stores K_. This reduces the number of kernel evaluations by approximately 50%.

Integration with SVM

The KernelCache is typically used internally by SVM implementations to avoid recomputing kernel values during iterative optimization algorithms like Sequential Minimal Optimization (SMO).
// Typical usage in SVM training
KernelCache cache(training_data, kernel);

// During SMO iterations
for (size_t iteration = 0; iteration < max_iter; ++iteration) {
    // Access cached kernel values efficiently
    double k_ij = cache(i, j);
    // ... update SVM parameters ...
}

Build docs developers (and LLMs) love