Skip to content

API Reference: Types

SamplingSpec

Dataclass specifying which functions to sample and at which points.

@dataclass
class SamplingSpec:
    x_f: Optional[np.ndarray] = None  # Points for f(x)
    x_g: Optional[np.ndarray] = None  # Points for g(x) = integral(f)
    x_h: Optional[np.ndarray] = None  # Points for h(x) = f'(x)
    x_u: Optional[np.ndarray] = None  # Points for u(x) = f''(x)
    mean: Optional[MeanSpec] = None   # Mean function specification

Requirements:

  • At least one of x_f, x_g, x_h, or x_u must be provided
  • Arrays must be 1D numpy arrays
  • Points should be sorted (not strictly required, but recommended)

Example:

from gp4c import SamplingSpec
import numpy as np

spec = SamplingSpec(
    x_f=np.linspace(0, 5, 100),
    x_h=np.linspace(0.1, 4.9, 80)
)

MeanSpec

Dataclass specifying the mean function.

@dataclass
class MeanSpec:
    type: Literal['zero', 'constant']  # Mean function type
    value: float = 0.0                 # For 'constant': the constant value

Mean function types:

  • type='zero': Zero mean (equivalent to mean=None)
  • type='constant': Constant mean
    • \(m_f(x) = c\) where \(c\) is the value
    • \(m_g(x) = c \cdot x\) (integral of constant)
    • \(m_h(x) = 0\) (derivative of constant)

Example:

from gp4c import MeanSpec

# Zero mean (default)
mean_zero = MeanSpec(type='zero')

# Constant mean
mean_const = MeanSpec(type='constant', value=2.5)

Observations

Dataclass for observed data to condition the GP posterior.

@dataclass
class Observations:
    x_f: Optional[np.ndarray] = None
    y_f: Optional[np.ndarray] = None
    x_g: Optional[np.ndarray] = None
    y_g: Optional[np.ndarray] = None
    x_h: Optional[np.ndarray] = None
    y_h: Optional[np.ndarray] = None
    x_u: Optional[np.ndarray] = None
    y_u: Optional[np.ndarray] = None
    noise_f: Union[float, np.ndarray] = 1e-6
    noise_g: Union[float, np.ndarray] = 1e-6
    noise_h: Union[float, np.ndarray] = 1e-6
    noise_u: Union[float, np.ndarray] = 1e-6
    mean: Optional[MeanSpec] = None

Requirements:

  • At least one observation type must be provided
  • x and y arrays must be paired (same length)
  • Arrays must be 1D numpy arrays

Noise formats

The noise_f, noise_g, noise_h, and noise_u fields each accept three formats:

Format Shape Interpretation
float scalar Uniform variance \(\sigma^2\) applied to all observations
np.ndarray (n,) Per-observation variances (heteroscedastic noise; diagonal covariance)
np.ndarray (n, n) Full noise covariance matrix (must be symmetric positive-definite)

Note

The float format is equivalent to noise_f * np.eye(n). Use the 1D array form when each observation has a different measurement uncertainty. Use the 2D form when observations have correlated noise.

Examples:

import numpy as np
from gp4c import Observations

obs = Observations(
    x_f=np.array([0.0, 1.0, 2.0]),
    y_f=np.array([0.1, 0.8, -0.2]),
    noise_f=0.01,
)
import numpy as np
from gp4c import Observations

x_train = np.array([0.0, 1.0, 2.0, 3.0])
y_train = np.sin(x_train)
# Each point has a different variance
noise_variances = np.array([0.005, 0.02, 0.01, 0.005])

obs = Observations(x_f=x_train, y_f=y_train, noise_f=noise_variances)
import numpy as np
from gp4c import Observations

x_train = np.array([0.0, 1.0])
y_train = np.array([0.5, 0.3])
# Correlated noise between two observation points
noise_cov = np.array([[0.01, 0.002],
                      [0.002, 0.015]])

obs = Observations(x_f=x_train, y_f=y_train, noise_f=noise_cov)
import numpy as np
from gp4c import Observations

x = np.linspace(0, 5, 10)
obs = Observations(
    x_f=x, y_f=np.sin(x), noise_f=0.01,
    x_h=x, y_h=np.cos(x), noise_h=0.005,
)
import numpy as np
from gp4c import Observations

x = np.linspace(0, 5, 10)
obs = Observations(
    x_f=x, y_f=np.sin(x),  noise_f=0.01,
    x_u=x, y_u=-np.sin(x), noise_u=0.01,  # f'' = -sin(x)
)

GPSamples

Named tuple returned by sample_prior.

class GPSamples(NamedTuple):
    f: Optional[np.ndarray]  # (n_samples, n_f) or None
    g: Optional[np.ndarray]  # (n_samples, n_g) or None
    h: Optional[np.ndarray]  # (n_samples, n_h) or None
    u: Optional[np.ndarray]  # (n_samples, n_u) or None

Fields:

  • f : Function samples (None if not requested)
  • g : Integral samples (None if not requested)
  • h : First derivative samples (None if not requested)
  • u : Second derivative samples (None if not requested)

Example:

from gp4c import sample_prior, SamplingSpec
import numpy as np

x = np.linspace(0, 5, 100)
spec = SamplingSpec(x_f=x, x_h=x)
result = sample_prior(spec, ell=0.5, n_samples=5)

print(result.f.shape)  # (5, 100)
print(result.h.shape)  # (5, 100)
print(result.g)        # None
print(result.u)        # None

PosteriorSamples

Named tuple returned by sample_posterior.

class PosteriorSamples(NamedTuple):
    f: Optional[np.ndarray]       # Posterior samples, shape (n_samples, n_f)
    g: Optional[np.ndarray]       # Posterior samples, shape (n_samples, n_g)
    h: Optional[np.ndarray]       # Posterior samples, shape (n_samples, n_h)
    u: Optional[np.ndarray]       # Posterior samples, shape (n_samples, n_u)
    f_mean: Optional[np.ndarray]  # Posterior mean, shape (n_f,)
    g_mean: Optional[np.ndarray]  # Posterior mean, shape (n_g,)
    h_mean: Optional[np.ndarray]  # Posterior mean, shape (n_h,)
    u_mean: Optional[np.ndarray]  # Posterior mean, shape (n_u,)
    f_std: Optional[np.ndarray]   # Posterior std dev, shape (n_f,)
    g_std: Optional[np.ndarray]   # Posterior std dev, shape (n_g,)
    h_std: Optional[np.ndarray]   # Posterior std dev, shape (n_h,)
    u_std: Optional[np.ndarray]   # Posterior std dev, shape (n_u,)

Fields:

  • f, g, h, u : Posterior samples (shape: (n_samples, n_x))
  • f_mean, g_mean, h_mean, u_mean : Analytical posterior means (shape: (n_x,))
  • f_std, g_std, h_std, u_std : Analytical posterior standard deviations (shape: (n_x,))

Each field is None if the corresponding quantity was not requested in SamplingSpec.

The means and standard deviations are computed analytically:

\[\mu^* = K_{*,\text{obs}} K_{\text{obs}}^{-1} \mathbf{y}\]
\[\sigma^* = \sqrt{\operatorname{diag}\!\left(K_{**} - K_{*,\text{obs}} K_{\text{obs}}^{-1} K_{\text{obs},*}\right)}\]

Example:

import numpy as np
from gp4c import sample_posterior, Observations, SamplingSpec

x_train = np.array([0.0, 1.0, 2.0, 3.0])
x_test = np.linspace(0, 5, 100)

obs = Observations(x_f=x_train, y_f=np.sin(x_train), noise_f=0.01)
spec = SamplingSpec(x_f=x_test)
result = sample_posterior(obs, spec, ell=1.0, n_samples=10)

print(result.f_mean.shape)  # (100,) — posterior mean
print(result.f_std.shape)   # (100,) — posterior std dev (uncertainty band)
print(result.f.shape)       # (10, 100) — posterior samples

OptimizationResult

Dataclass returned by fit().

@dataclass
class OptimizationResult:
    sigma2: float          # Optimized kernel variance
    ell: float             # Optimized length scale
    period: Optional[float]  # Optimized period (None for non-periodic kernels)
    log_likelihood: float  # Log marginal likelihood at optimum
    success: bool          # Whether the optimizer converged
    scipy_result: Any      # Raw scipy optimization result object

Fields:

Field Type Description
sigma2 float Optimized kernel variance \(\sigma^2\)
ell float Optimized length scale \(\ell\)
period float \| None Optimized period (only set for periodic/locally-periodic kernels)
log_likelihood float \(\log p(\mathbf{y} \mid X, \hat\theta)\) at the optimum
success bool Convergence flag from the scipy optimizer
scipy_result Any Full scipy.optimize.OptimizeResult object

Example:

import numpy as np
import gp4c

x = np.linspace(0, 10, 50)
obs = gp4c.Observations(x_f=x, y_f=np.sin(x), noise_f=0.01)

result = gp4c.fit(obs, kernel='rbf')
print(f"sigma2={result.sigma2:.3f}, ell={result.ell:.3f}")
print(f"log_likelihood={result.log_likelihood:.3f}, success={result.success}")

# Use optimized parameters for sampling
spec = gp4c.SamplingSpec(x_f=np.linspace(0, 12, 200))
posterior = gp4c.sample_posterior(
    obs, spec,
    sigma2=result.sigma2,
    ell=result.ell,
    n_samples=50,
)

Next Steps