Skip to content

Commit b5f4c7f

Browse files
committed
cleanup and ggmp added
1 parent 74e524f commit b5f4c7f

14 files changed

Lines changed: 1134 additions & 545 deletions

File tree

AUTHORS.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ Contributors
1111
------------
1212

1313
* Ronald Pandolfi
14+
* Vardaan Tekriwal

CLAUDE.md

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ pip install -e ".[tests]"
1111
# Run the full test suite
1212
pytest tests/
1313

14-
# Run a single test
15-
pytest tests/test_fvgp.py::TestClassName::test_method_name
14+
# Run a single test (tests are top-level functions, not class methods)
15+
pytest tests/test_fvgp.py::test_single_task_init_basic
1616

1717
# Run tests with coverage
1818
pytest tests --cov=./ --cov-report=xml
@@ -38,28 +38,36 @@ Both classes are composed of internal specialist objects created at `__init__` t
3838
| `GPdata` | [gp_data.py](fvgp/gp_data.py) | Data validation, shape tracking, Euclidean vs. non-Euclidean |
3939
| `GPprior` | [gp_prior.py](fvgp/gp_prior.py) | Kernel and mean function; default is anisotropic Matérn with ARD |
4040
| `GPlikelihood` | [gp_likelihood.py](fvgp/gp_likelihood.py) | Noise model (variances or callable) |
41-
| `GPMarginalLikelihood` | [gp_marginal_likelihood.py](fvgp/gp_marginal_likelihood.py) | Log marginal likelihood; owns Cholesky/LU factorizations of K+V |
41+
| `GPkv` | [gp_kv.py](fvgp/gp_kv.py) | Owns K+V matrix state and all factorizations; dispatches solves/logdets across linalg modes |
42+
| `GPMarginalLikelihood` | [gp_marginal_likelihood.py](fvgp/gp_marginal_likelihood.py) | Log marginal likelihood and its gradient; delegates factorization to `GPkv` |
4243
| `GPposterior` | [gp_posterior.py](fvgp/gp_posterior.py) | Posterior mean/covariance; information-theoretic quantities |
43-
| `GPtraining` | [gp_training.py](fvgp/gp_training.py) | Hyperparameter optimization (scipy, hgdl async, MCMC) |
44+
| `GPtraining` | [gp_training.py](fvgp/gp_training.py) | Hyperparameter optimization (scipy, hgdl async, MCMC, Adam) |
4445

4546
### Key supporting modules
4647

47-
- **[gp_lin_alg.py](fvgp/gp_lin_alg.py)** — CPU/GPU linear algebra backend; Cholesky, LU, sparse solvers; defines `NonPositiveDefiniteError`
48+
- **[gp_lin_alg.py](fvgp/gp_lin_alg.py)** — CPU/GPU linear algebra primitives; Cholesky, LU, sparse solvers; defines `NonPositiveDefiniteError`
49+
- **[gp_kv.py](fvgp/gp_kv.py)**`GPkv` manages all K+V state across linalg modes: `"Chol"`, `"CholInv"`, `"Inv"`, `"sparseLU"`, `"sparseCG"`, `"sparseMINRES"`, and preconditioned variants. The mode is set at init and determines which factorization is updated when data or hyperparameters change. Custom solvers can be injected as a 3-tuple of callables.
4850
- **[kernels.py](fvgp/kernels.py)** — 15+ built-in kernels including Matérn, squared exponential, Wendland (compactly supported)
4951
- **[gp_mcmc.py](fvgp/gp_mcmc.py)** — Adaptive Metropolis–Hastings sampler used for Bayesian hyperparameter inference
52+
- **[gp_actor.py](fvgp/gp_actor.py)**`AsyncOptimizer` wraps `_MCMCActor` and `_AdamActor` for non-blocking background training; used by `GPtraining` for async MCMC and Adam modes
5053

5154
### Scaling to large datasets (`gp2Scale`)
5255

5356
When `gp2Scale=True`, `GP` switches to a Wendland (compactly supported) kernel producing sparse covariance matrices and uses Dask for distributed computation. This path requires a Dask client to be passed in and uses sparse linear solvers instead of dense Cholesky.
5457

5558
### Customization API
5659

57-
Kernels, mean functions, and noise models are all plain Python callables with standardized signatures. Users pass them as arguments to `GP`/`fvGP` constructors. Kernel gradients can be user-supplied or computed via finite differences.
60+
Kernels, mean functions, and noise models are all plain Python callables with standardized signatures. Users pass them as arguments to `GP`/`fvGP` constructors. The full hyperparameter vector is shared across kernel, mean, and noise callables, but each callable must only read its reserved index range. Kernel gradients can be user-supplied or computed via finite differences.
5861

5962
### Information-theoretic methods
6063

6164
`GP` exposes `gp_entropy()`, `gp_mutual_information()`, `gp_kl_div()`, and predictive metrics (`rmse`, `nlpd`, `crps`, `r2`, `picp`), all computed via `GPposterior`.
6265

66+
### Extension modules
67+
68+
- **[ggmp.py](fvgp/ggmp.py)**`GGMP` (Gaussian GP for Gaussian Mixture data): fits K GMM components per station, each backed by its own `GP`; intended for distributional regression. Written by Vardaan Tekriwal. Excluded from the test suite (`# pragma: no cover`).
69+
- **[deep_kernel_network.py](fvgp/deep_kernel_network.py)**`Network` (PyTorch `nn.Module`): a 3-layer ReLU network used as a feature extractor for deep kernel learning. Excluded from the test suite (`# pragma: no cover`).
70+
6371
## Dependencies
6472

6573
Core: `numpy`, `scipy`, `dask`, `distributed`, `hgdl`, `loguru`

docs/source/api/ggmp.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# GGMP
2+
3+
`GGMP` (Gaussian GP for Gaussian Mixture data) models distributional observations
4+
as Gaussian mixture models, fitting one GP per mixture component.
5+
6+
```{eval-rst}
7+
.. autoclass:: fvgp.ggmp.GGMP
8+
:members:
9+
```
10+
11+
## hyperparameters
12+
13+
```{eval-rst}
14+
.. autoclass:: fvgp.ggmp.hyperparameters
15+
:members:
16+
```
17+
18+
## NormalLikelihood
19+
20+
```{eval-rst}
21+
.. autoclass:: fvgp.ggmp.NormalLikelihood
22+
:members:
23+
```

docs/source/api/overview.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
77
GP.md
88
fvGP.md
9+
ggmp.md
910
kernels.md
1011
gpMCMC.md
1112
logging.md

fvgp/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
from .gp import GP
1515
from .fvgp import fvGP
1616
from .gp_mcmc import gpMCMC, ProposalDistribution
17+
from . import ggmp
1718

1819

19-
20-
__all__ = ['GP', 'fvGP', 'gpMCMC', 'ProposalDistribution']
20+
__all__ = ['GP', 'fvGP', 'gpMCMC', 'ProposalDistribution', 'ggmp']
2121

2222
logger.disable('fvgp')

fvgp/fvgp.py

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -160,24 +160,37 @@ class fvGP(GP):
160160
A local client is used as the default.
161161
gp2Scale_batch_size : int, optional
162162
Matrix batch size for distributed computing in gp2Scale. The default is 10000.
163-
gp2Scale_linalg_mode : str, optional
164-
One of ``Chol``, ``sparseLU``, ``sparseCG``, ``sparseMINRES``, ``sparseSolve``, ``sparseCGpre``
165-
(incomplete LU preconditioner), or ``sparseMINRESpre``. The default is None which amounts to
166-
an automatic determination of the mode. For advanced customization options
167-
this can also be an iterable with three callables: the first f(K), where K is the covariance matrix
168-
to compute a factorization object
169-
which is available in the second and third callable. The second being the linear solve f(obj, vec),
170-
and the third being the logdet=f(obj). If a factorization object is not required, the first callable
171-
should return the matrix itself (K).
172-
calc_inv : bool, optional
173-
If True, the algorithm calculates and stores the inverse of the covariance
174-
matrix after each training or update of the dataset or hyperparameters,
175-
which makes computing the posterior covariance faster (3-10 times).
176-
For larger problems (>5000 data points), the use of inversion should be avoided due
177-
to computational instability and costs. The default is
178-
False. Note, the training will not use the
179-
inverse for stability reasons. Storing the inverse is
180-
a good option when the dataset is not too large and the posterior covariance is heavily used.
163+
linalg_mode : str, optional
164+
Controls the linear-algebra backend used to solve (K+V)x=b and compute log|K+V|.
165+
The default is ``None``, which selects ``"Chol"`` for standard GPs and automatically
166+
picks the best sparse mode for gp2Scale GPs.
167+
168+
**Recommended for standard (non-gp2Scale) GPs:**
169+
170+
* ``"Chol"`` *(default)* — Cholesky factorization; numerically stable and memory-efficient.
171+
* ``"CholInv"`` — Cholesky factorization, then explicitly stores the inverse; speeds up posterior
172+
covariance evaluation 3–10×. Avoid for datasets larger than ~5 000 points due to memory
173+
and numerical cost. Training always uses the Cholesky factor for stability.
174+
* ``"Inv"`` — computes and stores the explicit inverse directly (no Cholesky). Only suitable for
175+
very small datasets where posterior covariance is computed many times.
176+
177+
**Specialized for gp2Scale (sparse covariance matrices):**
178+
179+
* ``"sparseLU"`` — sparse LU factorization; good default for sparse systems up to ~50 000 points.
180+
* ``"sparseCG"`` — sparse conjugate-gradient iterative solver.
181+
* ``"sparseMINRES"`` — sparse MINRES iterative solver.
182+
* ``"sparseSolve"`` — direct sparse solve via scipy.
183+
* ``"sparseCGpre"`` — conjugate-gradient with an incomplete-LU preconditioner.
184+
* ``"sparseMINRESpre"`` — MINRES with an incomplete-LU preconditioner.
185+
186+
**Custom solver (any GP):**
187+
188+
Pass an iterable of three callables ``[f_factor, f_solve, f_logdet]``:
189+
190+
* ``f_factor(K)`` — receives the covariance matrix and returns a factorization object
191+
(or the matrix itself if no factorization is needed).
192+
* ``f_solve(obj, b)`` — solves the linear system and returns the solution vector.
193+
* ``f_logdet(obj)`` — returns the log-determinant as a scalar.
181194
ram_economy : bool, optional
182195
Only of interest if the gradient and/or Hessian of the log marginal likelihood is/are used for the training.
183196
If True, components of the derivative of the log marginal likelihood are
@@ -306,8 +319,7 @@ def __init__(
306319
gp2Scale=False,
307320
gp2Scale_dask_client=None,
308321
gp2Scale_batch_size=10000,
309-
gp2Scale_linalg_mode=None,
310-
calc_inv=False,
322+
linalg_mode=None,
311323
ram_economy=False,
312324
args=None
313325
):
@@ -339,8 +351,7 @@ def __init__(
339351
gp2Scale=gp2Scale,
340352
gp2Scale_dask_client=gp2Scale_dask_client,
341353
gp2Scale_batch_size=gp2Scale_batch_size,
342-
gp2Scale_linalg_mode=gp2Scale_linalg_mode,
343-
calc_inv=calc_inv,
354+
linalg_mode=linalg_mode,
344355
ram_economy=ram_economy,
345356
args=args)
346357

0 commit comments

Comments
 (0)