Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e74f51b
Add GPU acceleration support for CUDA and Metal with NumPy 2.0 compat…
claude Nov 1, 2025
83e8e8a
Add test scripts for GPU implementation verification
claude Nov 1, 2025
f4e37fe
Fix Metal (MPS) backend to support float32 instead of float64
claude Nov 1, 2025
56952c9
Add Metal backend float32 conversion test
claude Nov 1, 2025
96bed41
Major GPU performance optimizations: vectorize operations, reduce tra…
claude Nov 1, 2025
d84be76
Add newaxis attribute to PyTorchArrayWrapper for Metal backend
claude Nov 1, 2025
81f58c6
Fix critical backend initialization timing issue
claude Nov 1, 2025
5adb9f1
Add comprehensive Metal GPU diagnostic and benchmark scripts
claude Nov 1, 2025
91d3f2b
Fix critical training bug: add neglikelihood() call after optimization
claude Nov 1, 2025
405e536
Add parallel optimal Latin hypercube with 5x speedup
claude Nov 1, 2025
e4aacdc
Make parallel optimal LHC the default everywhere - 5x speedup!
claude Nov 2, 2025
5b482e4
Fix macOS multiprocessing error in benchmark_metal.py
claude Nov 2, 2025
37fff00
Add macOS/Windows multiprocessing compatibility for all scripts
claude Nov 2, 2025
891eb98
benchmark_metal.py updated to fix multiprocessor issue
capaulson Nov 2, 2025
0384a2c
Fix Metal GPU benchmark script and PyTorch tensor compatibility
capaulson Nov 2, 2025
4e3034d
added benchmarking
capaulson Nov 6, 2025
88b9f7b
Add GPU bottleneck profiling script
claude Nov 6, 2025
1f6d560
Add smart CPU/GPU selection to fix 6x slowdown for small problems
claude Nov 6, 2025
f341f4c
Fix critical GPU bottleneck: batch transfer hyperparameters
claude Nov 6, 2025
0f294c5
Add batch transfer optimization summary
claude Nov 6, 2025
17a60ae
Revert "Add smart CPU/GPU selection to fix 6x slowdown for small prob…
claude Nov 6, 2025
7850d76
pre-prep for release
capaulson Nov 30, 2025
7b91a22
Clean up repository structure for release
capaulson Nov 30, 2025
c5d0a4f
patching a few minor things
capaulson Dec 1, 2025
46ec1ee
Streamline README for release
capaulson Jan 3, 2026
88d96f9
Add docstrings to testfunctions.py and utilities.py
capaulson Jan 3, 2026
ebf05a4
Speed up, shrink and fix pyKriging
CAPNV Oct 22, 2026
324a52c
Make the non-positive-definite test independent of the LAPACK library
CAPNV Oct 22, 2026
949376c
Optionally limit BLAS threads during batch prediction (threadpoolctl)
CAPNV Oct 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: CI

on:
push:
branches: [master, main]
pull_request:
branches: [master, main]
workflow_dispatch:

permissions:
contents: read

env:
MPLBACKEND: Agg

# Python 3.9 jobs run on ubuntu-24.04, not ubuntu-latest: setup-python has no Python 3.9 build for Ubuntu 26.04.
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-24.04, macos-latest]
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14']
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
- run: pip install -e ".[dev]"
- run: pytest tests

floors:
name: oldest dependencies (Python 3.9)
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: '3.9'
- run: pip install -e . pytest "numpy==1.20.*" "scipy==1.7.*" "matplotlib==3.5.*" "dill==0.3.0"
- run: pytest tests

lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: '3.13'
- run: pip install -e . ruff
- run: ruff check pyKriging tests --select E,F,W --ignore E501
- run: python -W error::SyntaxWarning -c "import pyKriging, pyKriging.coKriging, pyKriging.CrossValidation, pyKriging.GlobalSensitivity"

examples:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: '3.13'
- run: pip install -e .
- run: |
for f in examples/*.py; do
echo "::group::$f"
python "$f" || exit 1
echo "::endgroup::"
done

build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: '3.13'
- run: pip install build twine
- run: python -m build
- run: twine check --strict dist/*
28 changes: 28 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,31 @@ docs/_build/

# PyBuilder
target/

# Test results and outputs
baseline_results.json
*_results.json
test_output/
.pytest_cache/
pytest.xml

# Benchmark outputs
*.png
benchmarks/*.png

# IDE
.vscode/
.idea/
*.swp
*.swo

# Virtual environments
venv/
.venv/
ENV/

# macOS
.DS_Store

# Claude Code
.claude/
5 changes: 3 additions & 2 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
include pyKriging/*.py
recursive-include pyKriging/sampling_plans *
# README.md and LICENSE are included automatically (pyproject.toml: readme, license-files).
# Ship the whole test suite in the sdist: by default setuptools adds tests/test_*.py but not conftest.py.
recursive-include tests *.py
147 changes: 144 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,149 @@
# pyKriging

Prefered Citation for pyKriging: [![DOI](https://zenodo.org/badge/doi/10.5281/zenodo.21389.svg)](http://dx.doi.org/10.5281/zenodo.21389)
A Python Kriging (Gaussian-process) toolkit for surrogate modelling: fit a model to a few expensive evaluations,
predict with error estimates, and choose where to sample next.

[![CI](https://github.com/capaulson/pyKriging/actions/workflows/ci.yml/badge.svg)](https://github.com/capaulson/pyKriging/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/pyKriging.svg)](https://pypi.org/project/pyKriging/)
[![Downloads](https://pepy.tech/badge/pykriging)](https://pepy.tech/project/pykriging)

Please see [http://www.pykriging.com](http://www.pykriging.com) for more details.
## Installation

[![Downloads](https://pepy.tech/badge/pykriging)](https://pepy.tech/project/pykriging)
```bash
pip install pyKriging
```

With NumPy/SciPy built on OpenBLAS (Linux, Windows, macOS before 14), also install `threadpoolctl`
(`pip install "pyKriging[threads]"`): pyKriging then keeps OpenBLAS's threads from competing with its own during
prediction, which makes predictions 2-6x faster. NumPy and SciPy on macOS 14 and later use Accelerate and gain
nothing from it.

## Quick Start

```python
import numpy as np
from pyKriging import kriging, samplingplan, testfunctions

X = samplingplan(k=2).optimallhc(20) # 20-point optimal Latin hypercube in [0, 1]^2
y = testfunctions().branin(X) # your expensive function: one value per row of X

model = kriging(X, y, seed=0) # seed makes training and infill reproducible
model.train()

model.predict([0.5, 0.5]) # one point -> float
model.predict(np.random.rand(1000, 2)) # many points -> array
model.predicterr([0.5, 0.5]) # standard error of the prediction
```

## Core API

### Kriging Model

```python
model = kriging(X, y, seed=None) # X: (n, k) samples, y: (n,) responses, in your own units
model.train(optimizer='pso') # maximum-likelihood theta and p ('pso' or 'ga')
model.predict(x) # x: one point (k,) or points (m, k)
model.predicterr(x) # standard error, in the units of y
model.infill_ei(x) # expected improvement
model.infill(2, method='ei') # 2 new points to sample: method='error' or 'ei'
model.addPoint(x_new, y_new) # add an observation; call train() again to re-tune
```

### Regression Kriging

For noisy data: the same API, with a regression constant `model.Lambda` tuned along with theta and p.

```python
from pyKriging import regression_kriging
model = regression_kriging(X, y, seed=0)
model.train()
```

### Co-Kriging

Combines many cheap, approximate samples with a few expensive ones (Forrester, Sóbester & Keane, *Multi-fidelity
optimization via surrogate modelling*, Proc. R. Soc. A 463:3251, 2007,
[doi:10.1098/rspa.2007.1900](https://doi.org/10.1098/rspa.2007.1900)).
`examples/coKriging.py` reproduces the paper's one-variable example.

```python
from pyKriging.coKriging import coKriging
ck = coKriging(Xc, yc, Xe, ye, seed=0) # cheap (Xc, yc) and expensive (Xe, ye) data
ck.train()
ck.predict(x) # prediction of the expensive function
ck.predict_var(x) # its standard error, with y scaled to [0, 1]
ck.rho # estimated scaling between the cheap and expensive data
```

### Sampling Plans

```python
sp = samplingplan(k=2) # k = number of dimensions; random_state=... for repeatable plans
X = sp.optimallhc(n) # Morris-Mitchell optimal Latin hypercube (n points)
X = sp.rlh(n) # random Latin hypercube
X = sp.fullfactorial(ppd) # full factorial (ppd points per dim)
Xe, Xrest = sp.subset(X, ne) # space-filling subset, e.g. the expensive points of a co-kriging plan
```

### Cross-Validation, Sensitivity and Saving

```python
from pyKriging import loadModel, saveModel
from pyKriging.CrossValidation import Cross_Validation
from pyKriging.GlobalSensitivity import SobolSensitivity

Cross_Validation(model).calculate_SCVR() # leave-one-out predictions and standardised residuals
sobol = SobolSensitivity(X, y) # fits its own kriging surrogate (or pass model=...)
sobol.sensitivity_Sobol() # first-order Sobol' indices; total-order indices in sobol.ST
saveModel(model, 'model.pkl') # save with dill; loadModel('model.pkl') restores it
```

### GPU Configuration

pyKriging computes on the CPU by default: all model state is float64 NumPy, and LAPACK is fastest at the sizes
kriging is usually used for. GPU use is opt-in: with PyTorch and an NVIDIA GPU (`pip install "pyKriging[gpu]"`),
`configure_gpu('cuda')` runs the likelihood search of models trained on 300 or more samples on CUDA, in float64.

```python
import pyKriging

pyKriging.configure_gpu('cuda') # use CUDA (RuntimeError without PyTorch CUDA support)
pyKriging.configure_gpu('auto') # or: CUDA if PyTorch finds a device, else the CPU
pyKriging.configure_gpu('cpu') # back to the default
pyKriging.get_device_info() # current backend and device
```

Apple Metal is not supported: it has no float64, and the float32 path was both slower than the CPU code and less
accurate. `configure_gpu('metal')` warns and uses the CPU. CuPy is no longer used.

## What's New in 0.2

- A rewritten numerical core: training, prediction and optimal Latin hypercubes are much faster, and predictions
accept arrays of points (`benchmarks/bench.py` measures it on your machine).
- New: `seed` for reproducible models, `predicterr` and `infill_ei` in the units of y, a complete co-kriging
model, `samplingplan.subset`, closed-form leave-one-out cross-validation and true Sobol' indices.
- inspyred is no longer needed; `optimallhc` no longer caches plans on disk or starts worker processes.
- GPU use is opt-in and CUDA-only (`configure_gpu('cuda')`): the `gpu-metal` and `gpu-all` extras are gone, and
`gpu-nvidia` remains as an alias of `gpu`.

## Requirements

- Python 3.9+
- NumPy, SciPy, Matplotlib, dill
- Optional: PyTorch with CUDA, for the GPU likelihood

## Citation

```bibtex
@software{paulson2015pykriging,
author = {Paulson, Chris},
title = {pyKriging: A Python Kriging Toolkit},
year = {2015},
doi = {10.5281/zenodo.21389},
url = {https://github.com/capaulson/pyKriging}
}
```

## License

MIT
Loading
Loading