quadsv.kernels.base#
Abstract bases for the spatial-kernel layer.
This module hosts the two ABCs:
Kernel: the universal interface every kernel implements (Kx/xtKx/xtKy/trace/square_trace/eigenvalues). Subclass this for a custom kernel that can be expressed through a singleself._Kbuffer.MatrixKernelBase: matrix-form kernels with dense / sparse / sparse-precision auto-switching. Subclass this for a new matrix backend;MatrixKernelis the standard concrete subclass.
Concrete classes live in sibling modules: quadsv.kernels.matrix,
quadsv.kernels.fft, and quadsv.kernels.nufft.
Classes#
Abstract base class shared by all spatial kernels in |
|
Concrete base for kernels backed by an explicit or implicit |
Module Contents#
- class quadsv.kernels.base.Kernel(*args, centering=True, **kwargs)[source]#
Bases:
abc.ABCAbstract base class shared by all spatial kernels in
quadsv.Concrete backends:
MatrixKernel— explicit n×n kernel or its sparse precision matrix.quadsv.fft.FFTKernel— grid kernel via its eigenvalue spectrum.quadsv.nufft.NUFFTKernel— irregular-point kernel evaluated through a type-1 / type-2 NUFFT round-trip.
Required interface#
Every concrete kernel exposes:
n,method,params,centering— integer / string / dict / bool attributes.xtKx(),xtKy(),Kx()— quadratic / bilinear / apply primitives.
Note
The empirical data centering (z-scoring) inside
quadsv.spatial_q_test()/spatial_r_test()breaks independence across spatial obervations. As a result, the null distribution of the test statisticQ = Zᵀ K Z = Xᵀ (H K H) X / σ²withH = I - 𝟏𝟏ᵀ/nshould inspect the spectrum of a centered kernelHKH. EveryKernelcarries acenteringflag (defaultTrue). Setcentering=Falseto recover the rawKmoments (useful for diagnostics or theoretical comparison).- abstract eigenvalues(k=None)[source]#
Eigenvalues of
K(raw) orHKH(centered).- Parameters:
k (int | None)
- Return type:
- abstract square_trace()[source]#
trace(K²)ortrace((HKH)²) = trace(K²) − 2·s₂/n + s₁²/n².Same contract as
trace()re: backend-specific kwargs.- Return type:
float
- abstract trace()[source]#
trace(K)ortrace(HKH) = trace(K) − s₁/n.Concrete backends are free to add kwargs for backend-specific options (e.g.
MatrixKernelBaseexposesn_probesfor its precision-stored Hutchinson path).- Return type:
float
- Parameters:
centering (bool)
- class quadsv.kernels.base.MatrixKernelBase(n, method='gaussian', *, centering=True, **kwargs)[source]#
Bases:
KernelConcrete base for kernels backed by an explicit or implicit
n × nmatrix.Subclass this when you want a custom way to construct
K(e.g. a bespoke function of coordinates, a learnt kernel, or an ad-hoc adjacency matrix) while inheriting every downstream primitive ready-to-use.Subclasses must implement
_build_kernel()to return either the(n, n)kernel matrix (densenp.ndarrayorscipy.sparse) or its precision matrixM = K^{-1}. If a precision matrix is returned, setself.stores_precision = Truebefore callingsuper().__init__, or flip it inside_build_kernelwhile the buffer is being built; theMatrixKernelCAR / precomputed-inverse path shows a worked example.Everything else — cached sparse LU for implicit solves, Hutchinson trace estimation when
stores_precision=True, automatic sparse-vs-dense dispatch inxtKx/Kx, standardized-quadratic-form cache (_K_column_sums/xtKx_standardized()), pickle safety for the non-picklable LU factor — is already implemented here.Handles dense, sparse, and implicit (operator-based) kernels. Switches between an explicit representation (the kernel matrix
Kis stored and used directly) and an implicit representation (the precision matrixM = K^{-1}is stored and linear systems are solved on demand) based on problem size.- Variables:
n (int) – Number of observations (
n).method (str) – Kernel method name (free-form; used only for diagnostics / provenance).
params (dict) – Resolved kernel parameters — subclasses decide what goes here.
stores_precision (bool) – If
True,_Kholds the precision matrixM = K^{-1}and linear solves (via a cached LU) are used forxtKx()and trace estimation. IfFalse,_Kis the realized kernel matrix (dense or sparse).
- Parameters:
n (int)
method (str)
centering (bool)
Notes
The internal buffer
_Kstores the kernel matrix whenstores_precision=Falseand the precision matrixK^{-1}whenstores_precision=True. Public methods (xtKx(),trace(),square_trace(),eigenvalues()) transparently handle both cases; callers should not access_Kdirectly.- Kx(x)[source]#
Apply the kernel operator to
x, returningK @ x.Single public primitive for kernel–vector products. Handles explicit (dense or sparse
K) and implicit (precision matrix + cached LU) cases uniformly.- Parameters:
x (np.ndarray or scipy.sparse matrix) –
(n,)or(n, M). Sparse inputs are densified internally becausescipy.linalg.lu_solve/splu.solverequire dense RHS andK @ xtypically returns dense anyway.- Returns:
(n,)ifxwas 1D, else(n, M).- Return type:
np.ndarray
Examples
>>> import numpy as np >>> from quadsv import MatrixKernel >>> rng = np.random.default_rng(0) >>> coords = rng.standard_normal((40, 2)) >>> kernel = MatrixKernel.from_coordinates(coords, method="matern") >>> kernel.Kx(rng.standard_normal(40)).shape (40,)
- eigenvalues(k=None)[source]#
Eigenvalues of
KorHKH(according toself.centering).Three paths:
Dense ``K`` — form
HKH = K − 𝟏 r^T − c 𝟏^T + m · 𝟏𝟏^Tin closed form (r/c= row / col means,m= grand mean) and callnumpy.linalg.eigvalsh(). Same O(n³) cost as the raw case, no extra memory.Sparse explicit ``K`` — wrap
H K H · vas ascipy.sparse.linalg.LinearOperatorand calleigsh(). PreservesK’s sparsity — we never densify.Implicit precision (sparse ``M = K⁻¹``) — wrap
H K H · v = H (M⁻¹ (H v))whereM⁻¹·is the cached sparse-LU solve. Same sparsity benefit as the raw-inverse path.
Results are cached per centering mode; switching
self.centeringinvalidates and recomputes.- Parameters:
k (int, optional) – Number of largest-magnitude eigenvalues to return. If None, returns all (dense) or
max(6, n − 2)(sparse/implicit — limited by whateigshcan extract).- Returns:
Eigenvalues sorted in descending order.
- Return type:
np.ndarray
- realization()[source]#
Return the realized
(n, n)kernel matrix.When
self.centeringis False, returnsKas stored (dense ndarray or sparse matrix). Whenself.centeringis True, returns the centered operatorHKHwithH = I − 𝟏𝟏ᵀ/n— the operator thatxtKx()/Kx()/trace()/eigenvalues()all actually apply.HKHis dense even whenKis sparse (each row gets a column-mean subtracted), so the centered path always materializes a dense result.Notes
If
stores_precisionis True, this forces expensive dense inversion of the precision matrix. PreferxtKx()andtrace()for implicit kernels.
- square_trace(n_probes=None)[source]#
trace(K²)(raw) ortrace((HKH)²)(centered).Dispatch is automatic based on
stores_precision:Explicit ``K``: Frobenius norm of the stored
K—Σᵢⱼ Kᵢⱼ²inO(nnz)for sparse,O(n²)for dense.Precision-stored:
(1/m) Σᵢ ‖K vᵢ‖²with the same cached±1probes astrace()(single LU solve shared across both moments).
-2·s₂/n + s₁²/n²is applied on top whencentering=True.- Parameters:
n_probes (int, optional) – Probe count for the Hutchinson path (default 15). Ignored on the analytic / explicit-
Kpath. Shared cache withtrace().- Return type:
float
- trace(n_probes=None)[source]#
trace(K)(raw) ortrace(HKH)(centered).Dispatch is automatic based on
stores_precision:Explicit ``K`` (dense or sparse): diagonal sum of the stored
K— exact,O(n)(sparse) orO(n)(dense).Precision-stored (CAR in the implicit regime,
Konly available through the LU solve onK⁻¹): Hutchinson estimator(1/m) Σᵢ vᵢᵀ (K vᵢ)with cached±1probes solved through the precision.
-s₁/nis applied on top whencentering=True.- Parameters:
n_probes (int, optional) – Probe count for the Hutchinson path (default 15). Ignored on the analytic / explicit-
Kpath (no probes involved). On the Hutchinson path the cache is keyed onn_probes; requesting a different count recomputes the LU-solve cache and emits aRuntimeWarning.- Return type:
float
- xtKx(x)[source]#
Quadratic form
x^T K x(paired diagonal for batched inputs).- Parameters:
x (np.ndarray or scipy.sparse matrix) –
(n,)or(n, M). Sparsexis preserved through the finalx^T (K x)contraction — only the right sideK @ xneeds a dense RHS for the solver / BLAS call.- Returns:
Scalar if 1D input,
(M,)if batched.- Return type:
float or np.ndarray
- xtKx_standardized(x, means, stds)[source]#
Compute
z^T K zwherez = (x - means) / stdswithout densifying sparsex.Sparse-aware expansion using the raw-
Kprimitives:z^T K z = (x^T K x - 2·μ·(K·𝟏)^T·x + μ²·(𝟏^T K 𝟏)) / σ²
and the cached row sums of
K. This is the fast path for standardizing large sparse feature matrices (e.g. scRNA-seq counts) before a Q-test.- Parameters:
x (np.ndarray or scipy.sparse matrix) –
(n,)or(n, M). Columns correspond to features.means (np.ndarray) –
(M,)per-feature mean and std (ddof=1to matchquadsv.statistics.spatial_q_test()).stds (np.ndarray) –
(M,)per-feature mean and std (ddof=1to matchquadsv.statistics.spatial_q_test()).
- Returns:
(M,)standardized quadratic form values. Columns withstd <= 0are returned as zero.- Return type:
np.ndarray
- xtKy(x, y)[source]#
Bilinear form
x^T K y(paired diagonal for batched inputs).For
(n, M)batches returns(M,)— the diagonal ofX^T K Yin the same column order, matchingquadsv.spatial_r_test(). Sparsexis preserved; onlyK @ yis densified.- Parameters:
x (np.ndarray or scipy.sparse matrix) –
(n,)or(n, M)(must share the M).y (np.ndarray or scipy.sparse matrix) –
(n,)or(n, M)(must share the M).
- Returns:
Scalar if 1D inputs;
(M,)if batched.- Return type:
float or np.ndarray
Examples
>>> import numpy as np >>> from quadsv import MatrixKernel >>> rng = np.random.default_rng(0) >>> coords = rng.standard_normal((40, 2)) >>> kernel = MatrixKernel.from_coordinates(coords, method="matern") >>> x = rng.standard_normal(40) >>> y = rng.standard_normal(40) >>> isinstance(kernel.xtKy(x, y), float) True