Python Examples¶
Code examples from the examples/ directory.
Basic Usage¶
File: examples/basic_usage.py
Sample f and its integral g:
import numpy as np
import matplotlib.pyplot as plt
from gp4c import sample_prior, SamplingSpec
# Define grid
x = np.linspace(0, 5, 100)
# Sample joint GP
spec = SamplingSpec(x_f=x, x_g=x)
result = sample_prior(
spec,
sigma2=1.0,
ell=0.5,
n_samples=5,
seed=42
)
# Plot results
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))
ax1.plot(x, result.f.T, alpha=0.7)
ax1.set_title('f(x) samples')
ax1.grid(True)
ax2.plot(x, result.g.T, alpha=0.7)
ax2.set_title('g(x) = integral of f')
ax2.grid(True)
plt.tight_layout()
plt.show()
Run:
Verification¶
File: examples/verification.py
Verify that g matches numerical integration of f:
import numpy as np
from gp4c import sample_prior, SamplingSpec
from scipy.integrate import cumulative_trapezoid
x = np.linspace(0, 5, 200)
spec = SamplingSpec(x_f=x, x_g=x)
result = sample_prior(spec, ell=0.5, n_samples=1)
# Numerically integrate f
f = result.f[0]
g_numerical = cumulative_trapezoid(f, x, initial=0)
g_analytical = result.g[0]
# Compare
error = np.abs(g_analytical - g_numerical)
print(f"Max absolute error: {error.max():.6f}")
print(f"Mean absolute error: {error.mean():.6f}")
# Plot comparison
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 6))
plt.subplot(2, 1, 1)
plt.plot(x, f, label='f(x)')
plt.legend()
plt.grid(True)
plt.subplot(2, 1, 2)
plt.plot(x, g_analytical, label='g(x) analytical')
plt.plot(x, g_numerical, '--', label='g(x) numerical')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()
Run:
Parameter Study¶
File: examples/parameter_study.py
Explore different length scale parameters:
import numpy as np
import matplotlib.pyplot as plt
from gp4c import sample_prior, SamplingSpec
x = np.linspace(0, 5, 100)
length_scales = [0.2, 0.5, 1.0, 2.0]
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
axes = axes.flatten()
for i, ell in enumerate(length_scales):
spec = SamplingSpec(x_f=x)
result = sample_prior(spec, ell=ell, n_samples=5)
axes[i].plot(x, result.f.T, alpha=0.7)
axes[i].set_title(f'Length scale ell = {ell}')
axes[i].grid(True)
plt.tight_layout()
plt.show()
Run:
Derivative Sampling¶
Sample f and its derivative h:
import numpy as np
import matplotlib.pyplot as plt
from gp4c import sample_prior, SamplingSpec
x = np.linspace(0, 5, 100)
spec = SamplingSpec(x_f=x, x_h=x)
result = sample_prior(spec, ell=0.5, n_samples=3)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))
ax1.plot(x, result.f.T, alpha=0.7)
ax1.set_title('f(x)')
ax1.grid(True)
ax2.plot(x, result.h.T, alpha=0.7)
ax2.set_title("h(x) = f'(x)")
ax2.grid(True)
plt.tight_layout()
plt.show()
Posterior Regression¶
Condition on sparse observations:
import numpy as np
import matplotlib.pyplot as plt
from gp4c import sample_posterior, Observations, SamplingSpec
# Training data
x_train = np.array([0.0, 1.0, 2.0, 3.0, 4.0])
y_train = np.sin(x_train)
# Test points
x_test = np.linspace(0, 5, 100)
# Posterior sampling
obs = Observations(x_f=x_train, y_f=y_train, noise_f=0.01)
spec = SamplingSpec(x_f=x_test)
result = sample_posterior(obs, spec, ell=1.0, n_samples=20)
# Plot
plt.figure(figsize=(10, 6))
plt.plot(x_test, result.f.T, color='lightblue', alpha=0.3)
plt.plot(x_test, result.f_mean, 'b-', linewidth=2, label='Posterior mean')
plt.plot(x_train, y_train, 'ro', markersize=8, label='Observations')
plt.legend()
plt.grid(True)
plt.show()
Hyperparameter Optimization¶
Use fit() to automatically find the kernel parameters that best explain the data, then
feed the result into sample_posterior for a fully data-driven model.
import numpy as np
import gp4c
rng = np.random.default_rng(42)
# Noisy observations of a sine wave
x_train = np.linspace(0, 10, 30)
y_train = np.sin(x_train) + rng.normal(0, 0.1, len(x_train))
obs = gp4c.Observations(x_f=x_train, y_f=y_train, noise_f=0.01)
# Find optimal hyperparameters
result = gp4c.fit(obs, kernel='rbf')
print(f"sigma2 = {result.sigma2:.3f}")
print(f"ell = {result.ell:.3f}")
print(f"log p(y|X,θ) = {result.log_likelihood:.3f}")
# Posterior at fine grid using optimized parameters
x_test = np.linspace(0, 12, 300)
spec = gp4c.SamplingSpec(x_f=x_test)
posterior = gp4c.sample_posterior(
obs, spec,
sigma2=result.sigma2,
ell=result.ell,
kernel='rbf',
n_samples=50,
)
# Plot
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 5))
plt.fill_between(
x_test,
posterior.f_mean - 2 * posterior.f_std,
posterior.f_mean + 2 * posterior.f_std,
alpha=0.3, label='95% credible band',
)
plt.plot(x_test, posterior.f_mean, label='Posterior mean')
plt.scatter(x_train, y_train, color='red', zorder=5, label='Observations')
plt.legend()
plt.grid(True)
plt.title(f'RBF GP (sigma2={result.sigma2:.2f}, ell={result.ell:.2f})')
plt.show()
For periodic data, constrain the period search range:
# True period is 2.0
x_p = np.linspace(0, 20, 80)
y_p = np.sin(np.pi * x_p) + rng.normal(0, 0.1, len(x_p)) # period = 2.0
obs_p = gp4c.Observations(x_f=x_p, y_f=y_p, noise_f=0.01)
result_p = gp4c.fit(
obs_p,
kernel='periodic',
bounds={'period': (1.0, 4.0)},
method='differential_evolution',
seed=42,
)
print(f"Recovered period = {result_p.period:.3f}") # Should be close to 2.0
Interactive Notebooks¶
See notebooks/demo_derivative_sampling.ipynb for interactive demonstrations.
Run:
Next Steps¶
- C Integration - Using gp4c from C/C++
- Tutorials - Detailed explanations