With VFF landing in #3 and spherical harmonics (Dutordoir et al. 2020) planned, we need to settle the InducingVariables abstraction.
Current interface
SVGP dispatches through the inducing variable, which implements:
K_uu(kernel) — dense Kuu (for compatibility/debugging)
K_uf(kernel, X) — cross-covariance between inducing variables and data
Kuu_solve(kernel, rhs) — Kuu^{-1} @ rhs
Kuu_sqrt_solve(kernel, rhs) — R^{-1} @ rhs where R @ R.T = Kuu
Kuu_logdet(kernel) — log determinant of Kuu
The base class provides dense defaults for the solve/sqrt_solve/logdet methods. Subclasses override with structured implementations.
Subclasses and their Kuu structure
| Subclass |
Kuu structure |
Solve strategy |
Points |
Dense (M, M) |
Dense defaults (no override needed) |
FourierFeatures1D |
diag + low-rank |
Woodbury identity |
| Spherical Harmonics (future) |
Diagonal |
Elementwise division |
None of the structured subclasses have a .Z attribute. Points does.
Initialization and validation are subclass-specific
greedy_variance_init, kmeans_init, and random_subsample_init are specific to Points. They select locations in input space, which doesn't apply to spectral methods. VFF is configured by domain bounds and frequency count, SH by truncation level. These should stay separate from the base interface.
Domain validation (_domain_check) is also subclass-specific. VFF needs to check that inputs fall within [a, b]. SH may need to check that inputs are on the sphere. Points doesn't need any check.
Open questions
- Is
.Z a Points-only attribute, or should there be a base-class method for "give me something plottable/inspectable" that other subclasses can implement differently?
- Should
_domain_check be a formal optional method on the base class, or stay informal (hasattr dispatch)?
- Where should initialization utilities live and be organized?
greedy_variance_init, kmeans_init, and random_subsample_init are currently in ptgp/inducing.py alongside the base class, but they're Points-specific. VFF and SH will have their own initialization patterns (from_data, frequency/truncation config). Should each subclass module own its init utilities, or should there be a shared ptgp/init/ namespace? These utilities also need to be accessible to Claude Code skills files for VFF and SH workflows.
- Does
Points actually need K_uu, K_uf, and the solve/sqrt_solve/logdet methods? Before VFF, Points just held .Z and SVGP called kernel(Z) directly. The new methods on Points are thin wrappers (K_uu calls kernel(self.Z), K_uf calls kernel(self.Z, X)). Is that indirection worth it for API consistency, or should Points stay simple and SVGP only dispatch through the structured methods when the inducing variable isn't Points?
With VFF landing in #3 and spherical harmonics (Dutordoir et al. 2020) planned, we need to settle the
InducingVariablesabstraction.Current interface
SVGP dispatches through the inducing variable, which implements:
K_uu(kernel)— dense Kuu (for compatibility/debugging)K_uf(kernel, X)— cross-covariance between inducing variables and dataKuu_solve(kernel, rhs)— Kuu^{-1} @ rhsKuu_sqrt_solve(kernel, rhs)— R^{-1} @ rhs where R @ R.T = KuuKuu_logdet(kernel)— log determinant of KuuThe base class provides dense defaults for the solve/sqrt_solve/logdet methods. Subclasses override with structured implementations.
Subclasses and their Kuu structure
PointsFourierFeatures1DNone of the structured subclasses have a
.Zattribute.Pointsdoes.Initialization and validation are subclass-specific
greedy_variance_init,kmeans_init, andrandom_subsample_initare specific toPoints. They select locations in input space, which doesn't apply to spectral methods. VFF is configured by domain bounds and frequency count, SH by truncation level. These should stay separate from the base interface.Domain validation (
_domain_check) is also subclass-specific. VFF needs to check that inputs fall within [a, b]. SH may need to check that inputs are on the sphere. Points doesn't need any check.Open questions
.ZaPoints-only attribute, or should there be a base-class method for "give me something plottable/inspectable" that other subclasses can implement differently?_domain_checkbe a formal optional method on the base class, or stay informal (hasattrdispatch)?greedy_variance_init,kmeans_init, andrandom_subsample_initare currently inptgp/inducing.pyalongside the base class, but they'rePoints-specific. VFF and SH will have their own initialization patterns (from_data, frequency/truncation config). Should each subclass module own its init utilities, or should there be a sharedptgp/init/namespace? These utilities also need to be accessible to Claude Code skills files for VFF and SH workflows.Pointsactually needK_uu,K_uf, and the solve/sqrt_solve/logdet methods? Before VFF,Pointsjust held.Zand SVGP calledkernel(Z)directly. The new methods onPointsare thin wrappers (K_uucallskernel(self.Z),K_ufcallskernel(self.Z, X)). Is that indirection worth it for API consistency, or shouldPointsstay simple and SVGP only dispatch through the structured methods when the inducing variable isn'tPoints?