Implementation of Gaussian processes in Python with support for AutoGrad, TensorFlow, PyTorch, and JAX
Fundamental functionality for constructing, evaluating, and conditioning Gaussian processes. This includes creating GPs with custom kernels and means, evaluating them at specific input points to create finite-dimensional distributions, and performing Bayesian conditioning on observations to obtain posterior distributions.
Create Gaussian processes with specified mean functions and kernels. The GP class supports flexible initialization with automatic measure management and optional naming.
class GP(RandomProcess):
def __init__(self, mean=None, kernel=None, *, measure=None, name=None):
"""
Initialize a Gaussian process.
Parameters:
- mean: Mean function (mlkernels.Mean), function, or numeric. Defaults to zero.
- kernel: Kernel function (mlkernels.Kernel). Required.
- measure: Measure to attach to. Optional.
- name: Name for the GP. Optional.
"""
def __init__(self, kernel, *, measure=None, name=None):
"""Initialize GP with zero mean and specified kernel."""
def __init__(self):
"""Initialize empty GP (for advanced use cases)."""Access key properties of Gaussian processes including their associated measure, kernel, mean function, and name.
class GP:
@property
def measure(self) -> Measure:
"""Measure that the GP was constructed with."""
@property
def kernel(self):
"""Kernel of the GP."""
@property
def mean(self):
"""Mean function of the GP."""
@property
def name(self) -> str:
"""Name of the GP."""
@name.setter
def name(self, name: str):
"""Set the name of the GP."""
@property
def stationary(self) -> bool:
"""Whether the GP is stationary."""Evaluate Gaussian processes at specific input points to create finite-dimensional distributions. These represent the GP's beliefs at the specified locations and can include additive noise.
class GP:
def __call__(self, x, noise=None) -> FDD:
"""
Construct a finite-dimensional distribution at specified locations.
Parameters:
- x: Input points to evaluate at
- noise: Optional additive noise (scalar, vector, or matrix)
Returns:
- FDD: Finite-dimensional distribution
"""class FDD(Normal):
def __init__(self, p, x, noise=None):
"""
Initialize finite-dimensional distribution.
Parameters:
- p: Gaussian process or process ID
- x: Input points
- noise: Optional additive noise
"""
def __init__(self, p, x):
"""Initialize FDD without noise."""
p: Union[GP, int] # Process of FDD
x: Any # Inputs that process is evaluated at
noise: Optional[Any] # Additive noise matrixCondition Gaussian processes on observations to obtain posterior distributions. Supports both direct conditioning and shorthand operator syntax.
class GP:
def condition(self, *args) -> GP:
"""
Condition on observations and obtain posterior GP.
Parameters can be:
- observations: Observations object
- fdd, y: FDD and corresponding values
- Multiple (fdd, y) pairs
Returns:
- GP: Posterior Gaussian process
"""
def __or__(self, *args) -> GP:
"""Shorthand for condition() using | operator."""Display Gaussian processes with optional custom formatting for debugging and inspection purposes.
class GP:
def display(self, formatter=None):
"""
Display GP with optional formatting.
Parameters:
- formatter: Optional custom formatter function
"""Helper functions for working with multiple Gaussian processes, including validation and intersection operations.
def assert_same_measure(*ps):
"""
Assert that processes are associated to the same measure.
Parameters:
- *ps: Gaussian processes to check
Raises:
- AssertionError: If processes have different measures
"""
def intersection_measure_group(*ps):
"""
Get the intersection of measures associated to processes.
Parameters:
- *ps: Gaussian processes
Returns:
- set: Intersection of measure groups
"""import stheno
import numpy as np
# Create GP with exponential quadratic kernel
gp = stheno.GP(kernel=stheno.EQ())
# Evaluate at specific points
x = np.linspace(0, 1, 10)
fdd = gp(x)
# Access properties
print(f"Mean: {fdd.mean}")
print(f"Variance diagonal: {fdd.var_diag}")# Generate synthetic observations
y = np.sin(x) + 0.1 * np.random.randn(len(x))
# Condition GP on observations using | operator
posterior = gp | (fdd, y)
# or using explicit condition method:
posterior = gp.condition(fdd, y)
# Make predictions
x_new = np.linspace(0, 1, 50)
pred = posterior(x_new)
mean, lower, upper = pred.marginal_credible_bounds()# Create named GP
gp = stheno.GP(kernel=stheno.EQ(), name="signal")
print(f"GP name: {gp.name}")
# Change name
gp.name = "updated_signal"# Add scalar noise
noisy_fdd = gp(x, noise=0.1)
# Add heteroscedastic noise
noise_var = np.random.uniform(0.05, 0.2, len(x))
noisy_fdd = gp(x, noise=noise_var)
# Add correlated noise (full covariance)
noise_cov = 0.1 * np.eye(len(x))
noisy_fdd = gp(x, noise=noise_cov)Install with Tessl CLI
npx tessl i tessl/pypi-stheno