Full Code of ziatdinovmax/gpax for AI

main b493ba26c061 cached
101 files
23.8 MB
6.2M tokens
447 symbols
1 requests
Copy disabled (too large) Download .txt
Showing preview only (24,964K chars total). Download the full file to get everything.
Repository: ziatdinovmax/gpax
Branch: main
Commit: b493ba26c061
Files: 101
Total size: 23.8 MB

Directory structure:
gitextract_po1u8joa/

├── .flake8
├── .github/
│   └── workflows/
│       ├── ci-deploy.yml
│       ├── ci.yml
│       ├── notebook_smoke.yml
│       └── unit.yml
├── .gitignore
├── .readthedocs.yml
├── LICENSE
├── README.md
├── docs/
│   ├── Makefile
│   ├── make.bat
│   ├── requirements_rtd.txt
│   └── source/
│       ├── LICENSE.rst
│       ├── README.rst
│       ├── USAGE.rst
│       ├── acquisition.rst
│       ├── conf.py
│       ├── examples.rst
│       ├── hypo.rst
│       ├── index.rst
│       ├── kernels.rst
│       ├── models.rst
│       ├── priors.rst
│       └── utils.rst
├── examples/
│   ├── GP_sGP.ipynb
│   ├── GPax_MultiTaskGP_BO.ipynb
│   ├── MeasuredNoiseGP.ipynb
│   ├── compare_GPs.ipynb
│   ├── contrib/
│   │   ├── cBO_1D_GPax_tutorial.ipynb
│   │   └── gpax_dkl_notebookIII_molecules.ipynb
│   ├── gpax_GPBO.ipynb
│   ├── gpax_UIGP.ipynb
│   ├── gpax_hypo.ipynb
│   ├── gpax_simpleGP.ipynb
│   ├── gpax_simpleGP_tutorial.ipynb
│   ├── gpax_viDKL_plasmons.ipynb
│   ├── gpax_viGP.ipynb
│   ├── heteroskedasticGP.ipynb
│   └── simpleGP.ipynb
├── gpax/
│   ├── __init__.py
│   ├── _version.py
│   ├── acquisition/
│   │   ├── __init__.py
│   │   ├── acquisition.py
│   │   ├── base_acq.py
│   │   ├── batch_acquisition.py
│   │   ├── optimize.py
│   │   └── penalties.py
│   ├── hypo.py
│   ├── kernels/
│   │   ├── __init__.py
│   │   ├── kernels.py
│   │   └── mtkernels.py
│   ├── models/
│   │   ├── __init__.py
│   │   ├── bnn.py
│   │   ├── corgp.py
│   │   ├── dkl.py
│   │   ├── gp.py
│   │   ├── hskgp.py
│   │   ├── ibnn.py
│   │   ├── linreg.py
│   │   ├── mngp.py
│   │   ├── mtgp.py
│   │   ├── sparse_gp.py
│   │   ├── spm.py
│   │   ├── uigp.py
│   │   ├── vgp.py
│   │   ├── vi_ibnn.py
│   │   ├── vi_mtdkl.py
│   │   ├── vidkl.py
│   │   └── vigp.py
│   ├── priors/
│   │   ├── __init__.py
│   │   └── priors.py
│   └── utils/
│       ├── __init__.py
│       ├── fn.py
│       └── utils.py
├── pyproject.toml
├── scripts/
│   ├── build.sh
│   ├── install.sh
│   └── test_notebooks.sh
└── tests/
    ├── __init__.py
    ├── test_acq.py
    ├── test_bnn.py
    ├── test_corgp.py
    ├── test_dkl.py
    ├── test_func_setter.py
    ├── test_gp.py
    ├── test_hskgp.py
    ├── test_hypo.py
    ├── test_ibnn.py
    ├── test_kernels.py
    ├── test_mngp.py
    ├── test_mtgp.py
    ├── test_optimize_acq.py
    ├── test_priors.py
    ├── test_sparsegp.py
    ├── test_spm.py
    ├── test_uigp.py
    ├── test_utils.py
    ├── test_vgp.py
    ├── test_vidkl.py
    ├── test_vigp.py
    └── test_vimtdkl.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .flake8
================================================
[flake8]
exclude =
    .git,
    __pycache__,
    build,
    dist,
    docs/source/conf.py
max-line-length = 80
show-source = True
statistics = True
count = True
verbose = 1
ignore = E203, W503


================================================
FILE: .github/workflows/ci-deploy.yml
================================================
name: CI/Deploy

on:
  push:
    tags: ["v*"]

jobs:

  unit:
    uses: ./.github/workflows/unit.yml

  notebooks:
    uses: ./.github/workflows/notebook_smoke.yml

  build_and_publish:
    name: Upload release to PyPI
    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
    runs-on: ubuntu-latest
    environment:
      name: pypi
      url: https://pypi.org/p/gpax
    permissions:
      id-token: write

    needs:
      - unit
      - notebooks

    steps:

    - name: Checkout
      uses: actions/checkout@v3
      with:
        fetch-depth: 0

    - name: Set up Python 3.9
      uses: actions/setup-python@v2
      with:
        python-version: 3.12

    - name: Build and apply version
      run: bash scripts/build.sh

    - name: Publish package distributions to PyPI
      uses: pypa/gh-action-pypi-publish@release/v1
      with:
        # CURRENTLY USING TEST SERVER FOR NOW!!!!
        repository-url: https://test.pypi.org/legacy/


================================================
FILE: .github/workflows/ci.yml
================================================
name: CI

on:

  pull_request:
    branches: ["main", "dev/*"]

  push:
    branches: ["main", "dev/*"]

jobs: 

  unit:
    uses: ./.github/workflows/unit.yml

  notebooks:
    uses: ./.github/workflows/notebook_smoke.yml


================================================
FILE: .github/workflows/notebook_smoke.yml
================================================
name: notebooks

env:
  CI_SMOKE: True

on:
  workflow_call:

jobs:
  build-linux:
    
    strategy:
      matrix:
        python-version: ['3.11', '3.12']
        os: [ubuntu-latest]

    runs-on: ${{ matrix.os }}

    steps:
    - uses: actions/checkout@v2
      
    - name: Set up Python ${{ matrix.python-version }}
      
      uses: actions/setup-python@v2
      with:
        python-version: ${{ matrix.python-version }}

    - name: Install dependencies
      run: |
        bash scripts/install.sh

    - name: Notebook smoke tests
      run: |
        bash scripts/test_notebooks.sh



================================================
FILE: .github/workflows/unit.yml
================================================
name: Unit
env:
  PYTHON_MAIN_VERSION: 3.12
on:
  workflow_call:
jobs:
  build:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest]
        python-version: ["3.11", "3.12"]
    steps:
      - uses: actions/checkout@v4
      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}
      - name: Install dependencies
        run: |
          bash scripts/install.sh
          bash scripts/install.sh test
      - name: Lint with flake8
        run: |
          # stop the build if there are Python syntax errors or undefined names
          flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
          # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
          flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
      - name: Run tests
        run: |
          pytest -v --cov --cov-report=xml --cov-report=term tests
      - name: Upload coverage to Codecov
        if: ${{ matrix.python-version == env.PYTHON_MAIN_VERSION }}
        uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          file: ./coverage.xml
          flags: unittests
          name: codecov-umbrella
          fail_ci_if_error: false
          verbose: true


================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# pipenv
#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
#   However, in case of collaboration, if having platform-specific dependencies or dependencies
#   having no cross-platform support, pipenv may install dependencies that don't work, or not
#   install all needed dependencies.
#Pipfile.lock

# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# Pyright
pyrightconfig.json


================================================
FILE: .readthedocs.yml
================================================
# .readthedocs.yml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

# Required
version: 2

build:
  os: "ubuntu-22.04"
  tools:
    python: "3.11"

# Build documentation in the docs/ directory with Sphinx
sphinx:
  configuration: docs/source/conf.py

# Build documentation with MkDocs
#mkdocs:
#  configuration: mkdocs.yml

# Optionally build your docs in additional formats such as PDF and ePub
formats: []

# Optionally set the version of Python and requirements required to build your docs
python:
  install:
    - requirements: docs/requirements_rtd.txt


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2024 GPax authors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# GPax
[![build](https://github.com/ziatdinovmax/gpax/actions/workflows/ci.yml/badge.svg)](https://github.com/ziatdinovmax/gpax/actions/workflows/ci.yml)
[![notebooks](https://github.com/ziatdinovmax/gpax/actions/workflows/notebook_smoke.yml/badge.svg)](https://github.com/ziatdinovmax/gpax/actions/workflows/notebook_smoke.yml)
[![codecov](https://codecov.io/gh/ziatdinovmax/gpax/branch/main/graph/badge.svg?token=FFA8XB0FED)](https://codecov.io/gh/ziatdinovmax/gpax)
[![Documentation Status](https://readthedocs.org/projects/gpax/badge/?version=latest)](https://gpax.readthedocs.io/en/latest/?badge=latest)
[![PyPI version](https://badge.fury.io/py/gpax.svg)](https://badge.fury.io/py/gpax)

GPax is a small Python package for physics-based Gaussian processes (GPs) built on top of NumPyro and JAX. Its purpose is to take advantage of prior physical knowledge and different data modalities when using GPs for data reconstruction and active learning. It is a work in progress, and more models will be added in the near future.

![GPax_logo](https://github.com/ziatdinovmax/gpax/assets/34245227/f2117b9d-d64b-4e48-9b91-e5c7f220b866)

## How to use
### Simple GP
#### *1D Example*
[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/gpax_simpleGP.ipynb)

The code snippet below shows how to use vanilla GP in a fully Bayesian mode. First, we infer GP model parameters from the available training data
```python3
import gpax

# Get random number generator keys for training and prediction
rng_key, rng_key_predict = gpax.utils.get_keys()
# Initialize model
gp_model = gpax.ExactGP(1, kernel='RBF')
# Run Hamiltonian Monte Carlo to obtain posterior samples for the GP model parameters
gp_model.fit(rng_key, X, y)  # X and y are numpy arrays with dimensions (n, d) and (n,)
```
In the fully Bayesian mode, we get a pair of predictive mean and covariance for each Hamiltonian Monte Carlo sample containing the GP parameters (in this case, the RBF kernel hyperparameters and model noise). Hence, a prediction on new inputs with a trained GP model returns the center of the mass of all the predictive means (```posterior_mean```) and samples from multivariate normal distributions for all the pairs of predictive means and covariances (```f_samples```).
```python3
posterior_mean, f_samples = gp_model.predict(rng_key_predict, X_test)
```

<img src = "https://user-images.githubusercontent.com/34245227/167945293-8cb5b88a-1f64-4f7d-95ab-26863b90d1e5.jpg" height="60%" width="60%">

For 1-dimensional data, we can plot the GP prediction using the standard approach where the uncertainty in predictions - represented by a standard deviation in ```y_sampled``` - is depicted as a shaded area around the mean value.

<img src = "https://user-images.githubusercontent.com/34245227/167945487-05068084-86cb-4104-a792-d39d2f834151.jpg" height="60%" width="60%">

See the full example, including specification of custom GP kernel priors, [here](https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/gpax_simpleGP.ipynb).

#### *Sparse Image Reconstruction*
[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/gpax_viGP.ipynb)

One can also use GP for sparse image reconstruction. The fully Bayesian GP is typically too slow for this purpose and it makes sense to use a stochastic variational inference approximation (viGP) instead. Code-wise, the usage of viGP in GPax is almost the same as that of the fully Bayesian GP. One difference is that instead of ```num_samples``` we have ```num_steps```. We can also control the learning rate by specifying a ```step_size```. 
```python3
# Get training inputs/targets and full image indices from sparse image data
X_train, y_train, X_full = gpax.utils.preprocess_sparse_image(sparse_img) # sparse_img is a 2D numpy array

# Initialize and train a variational inference GP model
gp_model = gpax.viGP(2, kernel='Matern', guide='delta')
gp_model.fit(rng_key, X_train, y_train, num_steps=250, step_size=0.05)
```

When we run the ```.predict()``` method, the output is predictive mean and variance computed from a learned single estimate of the GP model parameters:
```python3
y_pred, y_var = gp_model.predict(rng_key_predict, X_full)
```
![viGP](https://github.com/ziatdinovmax/gpax/assets/34245227/ac9043be-dc91-46ea-88f4-42471308d149)

Finally, for larger images or hyperspecteral data, one can use the [inducing inputs](https://www.jmlr.org/papers/volume6/quinonero-candela05a/quinonero-candela05a.pdf) approximation to GP, which is also available in GPax. See the full example [here](https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/gpax_viGP.ipynb).

### Structured GP
[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/GP_sGP.ipynb)

The limitation of the standard GP is that it does not usually allow for the incorporation of prior domain knowledge and can be biased toward a trivial interpolative solution. Recently, we [introduced](https://arxiv.org/abs/2108.10280) a structured Gaussian Process (sGP), where a classical GP is augmented by a structured probabilistic model of the expected system’s behavior. This approach allows us to [balance](https://towardsdatascience.com/unknown-knowns-bayesian-inference-and-structured-gaussian-processes-why-domain-scientists-know-4659b7e924a4) the flexibility of the non-parametric GP approach with a rigid structure of prior (physical) knowledge encoded into the parametric model.
Implementation-wise, we substitute a constant/zero prior mean function in GP with a probabilistic model of the expected system's behavior.

For example, if we have prior knowledge that our objective function has a discontinuous 'phase transition', and a power law-like behavior before and after this transition, we may express it using a simple piecewise function
```python3
import jax.numpy as jnp

def piecewise(x: jnp.ndarray, params: Dict[str, float]) -> jnp.ndarray:
    """Power-law behavior before and after the transition"""
    return jnp.piecewise(
        x, [x < params["t"], x >= params["t"]],
        [lambda x: x**params["beta1"], lambda x: x**params["beta2"]])
```
where ```jnp``` corresponds to jax.numpy module. This function is deterministic. To make it probabilistic, we put priors over its parameters with the help of [NumPyro](https://github.com/pyro-ppl/numpyro)
```python3
import numpyro
from numpyro import distributions

def piecewise_priors():
    # Sample model parameters
    t = numpyro.sample("t", distributions.Uniform(0.5, 2.5))
    beta1 = numpyro.sample("beta1", distributions.Normal(3, 1))
    beta2 = numpyro.sample("beta2", distributions.Normal(3, 1))
    # Return sampled parameters as a dictionary
    return {"t": t, "beta1": beta1, "beta2": beta2}
```
Finally, we train the sGP model and make predictions on new data in the almost exact same way we did for vanilla GP. The only difference is that we pass our structured probabilistic model as two new arguments (the piecewise function and the corresponding priors over its parameters) when initializing GP.
```python3
# Get random number generator keys
rng_key, rng_key_predict = gpax.utils.get_keys()
# initialize structured GP model
sgp_model = gpax.ExactGP(1, kernel='Matern', mean_fn=piecewise, mean_fn_prior=piecewise_priors)
# Run MCMC to obtain posterior samples
sgp_model.fit(rng_key, X, y)
# Get GP prediction on new/test data
posterior_mean, f_samples = sgp_model.predict(rng_key_predict, X_test)
```

![GP_vs_sGP2](https://github.com/ziatdinovmax/gpax/assets/34245227/89de341c-f00c-468c-afe6-c0b1c1140725)


Structured GP is usually better at extrapolation and provides more reasonable uncertainty estimates. The probabilistic model in structured GP reflects our prior knowledge about the system, but it does not have to be precise, that is, the model can have a different functional form, as long as it captures general or partial trends in the data. The full example including the active learning part is available [here](https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/GP_sGP.ipynb).


### Active learning and Bayesian optimization
[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/gpax_GPBO.ipynb)

Both GP and sGP can be used for active learning to reconstruct the entire data distribution from sparse observations or to localize regions of the parameter space where a particular physical behavior is maximized or minimized with as few measurements as possible (the latter is usually referred to as [Bayesian optimization](https://ieeexplore.ieee.org/abstract/document/7352306)).

```python3
# Train a GP model (it can be sGP or vanilla GP)
gp_model.fit(rng_key, X_measured, y_measured)  # A

# Compute the upper confidence bound (UCB) acquisition function to derive the next measurement point
acq = gpax.acquisition.UCB(rng_key_predict, gp_model, X_unmeasured, beta=4, maximize=False, noiseless=True)  # B
next_point_idx = acq.argmax()  # C
next_point = X_unmeasured[next_point_idx]  # D

# Perform measurement in next_point, update measured & unmeasured data arrays, and re-run steps A-D.
```

In the figure below we illustrate the connection between the (s)GP posterior predictive distribution and the acquisition function used to derive the next measurement points. Here, the posterior mean values indicate that the minimum of a "black box" function describing a behavior of interest is around $x=0.7$. At the same time, there is a large dispersion in the samples from the posterior predictive distribution between $x=-0.5$ and $x=0.5$, resulting in high uncertainty in that region. The acquisition function is computed as a function of both predictive mean and uncertainty and its maximum corresponds to the next measurement point in the active learning and Bayesian optimization. Here, after taking into account the uncertainty in the prediction, the UCB acquisition function suggests exploring a point at x≈0 where potentially a true minimum is located. See full example [here](https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/gpax_GPBO.ipynb).

<img src="https://github.com/ziatdinovmax/gpax/assets/34245227/24f641fb-5959-4780-8d0e-edf62bd0a32b">


### Theory-informed data reconstruction and Bayesian optimization
[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/GPax_MultiTaskGP_BO.ipynb)

Sometimes when theoretical simulations are available before the experiment, they can be used to guide the measurements or simply reconstruct sparse data via a multi-task/fidelity Gaussian process. This can be used as an alternative solution to a structured Gaussian process in situations where a mean function is too costly to compute at each step or it is expressed through some complex program that is not fully differentiable. The overall scheme is the same, but now our GP model is a MultitaskGP:

```python3
key1, key2 = gpax.utils.get_keys(1)

gp_model = gpax.MultiTaskGP(
    input_dim=1, data_kernel='Matern',  # standard GP parameters
    shared_input_space=False,  # different tasks/fidelities have different numbers of observations
    num_latents=2, rank=2,  # parameters of multi-task GP
)

model.fit(key1, X, y, num_warmup=500, num_samples=500)
```

Note that X has (N, D+1) dimensions where the last column contains task/fidelity indices for each observation. We can then use the trained model to make a prediction for partially observed data:
```python3
# Create a set of inputs for the task/fidelity 2
X_unmeasured2 = np.column_stack((X_full_range, np.ones_like(X_full_range)))

# Make a prediction with the trained model
posterior_mean2, f_samples2  = model.predict(key2, X_unmeasured2, noiseless=True)
```

![GP_vs_MTGP](https://github.com/ziatdinovmax/gpax/assets/34245227/5a36d3cd-c904-4345-abc3-b1bea5025cc8)
The full example including Bayesian optimization is available [here](https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/GPax_MultiTaskGP_BO.ipynb)



### Hypothesis learning
[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/gpax_hypo.ipynb)

The structured GP can also be used for hypothesis learning in automated experiments. The [hypothesis learning](https://arxiv.org/abs/2112.06649) is based on the idea that in active learning, the correct model of the system’s behavior leads to a faster decrease in the overall Bayesian uncertainty about the system under study. In the hypothesis learning setup, probabilistic models of the possible system’s behaviors (hypotheses) are wrapped into structured GPs, and a basic reinforcement learning policy is used to select a correct model from several competing hypotheses. The example of hypothesis learning on toy data is available [here](https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/gpax_hypo.ipynb).

<img src="https://user-images.githubusercontent.com/34245227/167936394-52f5ffd5-a47c-425d-b8a7-0727938dfab2.gif">


### Deep kernel learning
[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/gpax_viDKL_plasmons.ipynb)

[Deep kernel learning (DKL)](https://arxiv.org/abs/1511.02222) can be understood as a hybrid of deep neural network (DNN) and GP. The DNN serves as a feature extractor that allows reducing the complex high-dimensional features to low-dimensional descriptors on which a standard GP kernel operates. The parameters of DNN and of GP kernel are inferred jointly in an end-to-end fashion. Practically, the DKL training inputs are usually patches from an (easy-to-acquire) structural image, and training targets represent a physical property of interest derived from the (hard-to-acquire) spectra measured in those patches. The DKL output on the new inputs (image patches for which there are no measured spectra) is the expected property value and associated uncertainty, which can be used to derive the next measurement point in the automated experiment. 

GPax package has the fully Bayesian DKL (weights of neural network and GP hyperparameters are inferred using Hamiltonian Monte Carlo) and the Variational Inference approximation of DKL, viDKL. The fully Bayesian DKL can provide an asymptotically exact solution but is too slow for most automated experiments. Hence, for the latter, one may use the viDKL
```python3
import gpax

# Get random number generator keys for training and prediction
rng_key, rng_key_predict = gpax.utils.get_keys()

# Obtain/update DKL posterior; input data dimensions are (n, h*w*c)
dkl = gpax.viDKL(input_dim=X.shape[-1], z_dim=2, kernel='RBF')  # A
dkl.fit(rng_key, X_train, y_train, num_steps=100, step_size=0.05)  # B

# Compute UCB acquisition function
obj = gpax.acquisition.UCB(rng_key_predict, dkl, X_unmeasured, maximize=True)  # C
# Select next point to measure (assuming grid data)
next_point_idx = obj.argmax()  # D

# Perform measurement in next_point_idx, update measured & unmeasured data arrays, and re-run steps A-D.
```
Below we show a result of a simple DKL-based search for regions of the nano-plasmonic array that [host edge plasmons](https://arxiv.org/abs/2108.03290). The full example is available [here](https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/gpax_viDKL_plasmons.ipynb). 

<img src="https://user-images.githubusercontent.com/34245227/160270568-147fa21b-91f3-48b8-8dd2-c33eb4b497b4.png">

Note that in viDKL, we use a simple MLP as a default feature extractor. However, you can easily write a custom DNN using [haiku](https://github.com/deepmind/dm-haiku) and pass it to the viDKL initializer
```python3
import haiku as hk

class ConvNet(hk.Module):
    def __init__(self, embedim=2):
        super().__init__()
        self._embedim = embedim   

    def __call__(self, x):
        x = hk.Conv2D(32, 3)(x)
        x = jax.nn.relu(x)
        x = hk.MaxPool(2, 2, 'SAME')(x)
        x = hk.Conv2D(64, 3)(x)
        x = jax.nn.relu(x)
        x = hk.Flatten()(x)
        x = hk.Linear(self._embedim)(x)
        return x

dkl = gpax.viDKL(X.shape[1:], 2, kernel='RBF', nn=ConvNet)  # input data dimensions are (n,h,w,c)
dkl.fit(rng_key, X_train, y_train, num_steps=100, step_size=0.05)
obj = gpax.acquisition.UCB(rng_key_predict, dkl, X_unmeasured, maximize=True)
next_point_idx = obj.argmax()
```
## Installation
If you would like to utilize a GPU acceleration, follow these [instructions](https://github.com/google/jax#installation) to install JAX with a GPU support.

Then, install GPax using pip. We recommend installing the latest stable deployment from PyPI using

```bash
pip install gpax
```

Otherwise, if you are confident in what's on the `main` branch of GPax, you can also install directly from the GitHub repository:

```bash
pip install git+https://github.com/ziatdinovmax/gpax
```

If you are a Windows user, we recommend to use the Windows Subsystem for Linux (WSL2), which comes free on Windows 10 and 11.

## Cite us

If you use GPax in your work, please consider citing our papers:
```
@article{ziatdinov2021physics,
  title={Physics makes the difference: Bayesian optimization and active learning via augmented Gaussian process},
  author={Ziatdinov, Maxim and Ghosh, Ayana and Kalinin, Sergei V},
  journal={arXiv preprint arXiv:2108.10280},
  year={2021}
}

@article{ziatdinov2021hypothesis,
  title={Hypothesis learning in an automated experiment: application to combinatorial materials libraries},
  author={Ziatdinov, Maxim and Liu, Yongtao and Morozovska, Anna N and Eliseev, Eugene A and Zhang, Xiaohang and Takeuchi, Ichiro and Kalinin, Sergei V},
  journal={arXiv preprint arXiv:2112.06649},
  year={2021}
}
```

## Funding acknowledgment
This work was supported by the U.S. Department of Energy, Office of Science, Basic Energy Sciences Program.


================================================
FILE: docs/Makefile
================================================
# Minimal makefile for Sphinx documentation
#

# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS    ?=
SPHINXBUILD   ?= sphinx-build
SOURCEDIR     = source
BUILDDIR      = build

# Put it first so that "make" without argument is like "make help".
help:
	@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help Makefile

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

================================================
FILE: docs/make.bat
================================================
@ECHO OFF

pushd %~dp0

REM Command file for Sphinx documentation

if "%SPHINXBUILD%" == "" (
	set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=source
set BUILDDIR=build

if "%1" == "" goto help

%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
	echo.
	echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
	echo.installed, then set the SPHINXBUILD environment variable to point
	echo.to the full path of the 'sphinx-build' executable. Alternatively you
	echo.may add the Sphinx directory to PATH.
	echo.
	echo.If you don't have Sphinx installed, grab it from
	echo.http://sphinx-doc.org/
	exit /b 1
)

%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end

:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%

:end
popd

================================================
FILE: docs/requirements_rtd.txt
================================================
setuptools>=41.0.1
matplotlib>=3.2
sphinx>=3,<7
sphinx_autodoc_typehints>=1.11.0
recommonmark>=0.6.0
sphinx_rtd_theme>=0.5.0
typing-extensions>=4.4.0
jax>=0.4.8
numpyro>=0.11.0
dm-haiku>=0.0.5
dunamai==1.19.2

================================================
FILE: docs/source/LICENSE.rst
================================================
MIT License

Copyright (c) 2024 GPax authors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================================================
FILE: docs/source/README.rst
================================================
Installation
============

If you would like to use GPax with a GPU acceleration, follow these `instructions <https://github.com/google/jax#installation>`_ to install JAX with a GPU support.

Then, install GPax using pip as

.. code:: bash

    pip install gpax

for the stable version or

.. code:: bash
    
    pip install git+https://github.com/ziatdinovmax/gpax

to get the most recent updates.

If you are a Windows user, we recommend to use the Windows Subsystem for Linux (WSL2).

================================================
FILE: docs/source/USAGE.rst
================================================
How To Use
==========

Simple GP
---------

1D Example
^^^^^^^^^^

|Open in Colab|

.. |Open in Colab| image:: https://colab.research.google.com/assets/colab-badge.svg
   :target: https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/gpax_simpleGP.ipynb

The code snippet below shows how to use vanilla GP in a fully Bayesian mode. First, we infer GP model parameters from the available training data

.. code:: python

    import gpax
    # Get random number generator keys for training and prediction
    rng_key_train, rng_key_predict = gpax.utils.get_keys()
    # Initialize model
    gp_model = gpax.ExactGP(1, kernel='RBF')
    # Run Hamiltonian Monte Carlo to obtain posterior samples for the GP model parameters
    gp_model.fit(rng_key_train, X, y)  # X and y are numpy arrays with dimensions (n, d) and (n,)

In the fully Bayesian mode, we get a pair of predictive mean and covariance for each Hamiltonian Monte Carlo sample containing the GP parameters (in this case, the RBF kernel hyperparameters and model noise). Hence, a prediction on new inputs with a trained GP model returns the center of the mass of all the predictive means (``y_pred``) and samples from multivariate normal distributions for all the pairs of predictive means and covariances (``y_sampled``).

.. code:: python

    y_pred, y_sampled = gp_model.predict(rng_key_predict, X_test)

.. image:: imgs/GPax_Fig1.jpg
  :alt: GPax_GP1

For 1-dimensional data, we can plot the GP prediction using the standard approach where the uncertainty in predictions - represented by a standard deviation in ``y_sampled`` - is depicted as a shaded area around the mean value.

.. image:: imgs/GPax_Fig2.jpg
  :alt: GPax_GP2

Sparse 2D Image Reconstruction
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

|viGP|

.. |viGP| image:: https://colab.research.google.com/assets/colab-badge.svg
   :target: https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/gpax_viGP.ipynb


One can also use GP for sparse image reconstruction. The fully Bayesian GP is typically too slow for this purpose and it makes sense to use a stochastic variational inference approximation (viGP) instead. Code-wise, the usage of viGP in GPax is almost the same as that of the fully Bayesian GP. One difference is that instead of ``num_samples`` we have ``num_steps``. We can also control the learning rate by specifying a ``step_size``. 

.. code:: python

  # Get training inputs/targets and full image indices from sparse image data
  X_train, y_train, X_full = gpax.utils.preprocess_sparse_image(sparse_img) # sparse_img is a 2D numpy array

  # Initialize and train a variational inference GP model
  gp_model = gpax.viGP(2, kernel='Matern', guide='delta')
  gp_model.fit(rng_key, X_train, y_train, num_steps=250, step_size=0.05)


When we run the ``.predict()`` method, the output is predictive mean and variance computed from a learned single estimate of the GP model parameters:

.. code:: python

  y_pred, y_var = gp_model.predict(rng_key_predict, X_full)

Note that it returns flattened numpy arrays that you will need to reshape back to the original image shape.

.. image:: imgs/viGP.jpg
  :alt: viGP

Finally, for larger images or hyperspecteral data, one can use the `inducing inputs <https://www.jmlr.org/papers/volume6/quinonero-candela05a/quinonero-candela05a.pdf>`_ approximation of viGP, which is also available in GPax.


Structured GP
-------------

|sGP|

.. |sGP| image:: https://colab.research.google.com/assets/colab-badge.svg
   :target: https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/GP_sGP.ipynb

The limitation of the standard GP is that it does not usually allow for the incorporation of prior domain knowledge and can be biased toward a trivial interpolative solution. Recently, we `introduced <https://arxiv.org/abs/2108.10280>`_ a structured Gaussian Process (sGP), where a classical GP is augmented by a structured probabilistic model of the expected system’s behavior. This approach allows us to `balance <https://towardsdatascience.com/unknown-knowns-bayesian-inference-and-structured-gaussian-processes-why-domain-scientists-know-4659b7e924a4>`_ the flexibility of the non-parametric GP approach with a rigid structure of prior (physical) knowledge encoded into the parametric model.
Implementation-wise, we substitute a constant/zero prior mean function in GP with a probabilistic model of the expected system's behavior.

For example, if we have prior knowledge that our objective function has a discontinuous 'phase transition', and a power law-like behavior before and after this transition, we may express it using a simple piecewise function

.. code:: python

    import jax.numpy as jnp

    def piecewise(x: jnp.ndarray, params: Dict[str, float]) -> jnp.ndarray:
        """Power-law behavior before and after the transition"""
        return jnp.piecewise(
            x, [x < params["t"], x >= params["t"]],
            [lambda x: x**params["beta1"], lambda x: x**params["beta2"]])

This function is deterministic. To make it probabilistic, we put priors over its parameters with the help of NumPyro

.. code:: python

    import numpyro
    from numpyro import distributions

    def piecewise_priors():
        # Sample model parameters
        t = numpyro.sample("t", distributions.Uniform(0.5, 2.5))
        beta1 = numpyro.sample("beta1", distributions.Normal(3, 1))
        beta2 = numpyro.sample("beta2", distributions.Normal(3, 1))
        # Return sampled parameters as a dictionary
        return {"t": t, "beta1": beta1, "beta2": beta2}

Finally, we train the sGP model and make predictions on new data in the almost exact same way we did for vanilla GP. The only difference is that we pass our structured probabilistic model as two new arguments (the piecewise function and the corresponding priors over its parameters) when initializing GP.

.. code:: python

    # Get random number generator keys
    rng_key_train, rng_key_predict = gpax.utils.get_keys()
    # Initialize structured GP model
    sgp_model = gpax.ExactGP(1, kernel='Matern', mean_fn=piecewise, mean_fn_prior=piecewise_priors)
    # Run MCMC to obtain posterior samples
    sgp_model.fit(rng_key_train, X, y)
    # Get GP prediction on new/test data
    y_pred, y_sampled = sgp_model.predict(rng_key_predict, X_test)

.. image:: imgs/GP_vs_sGP2.jpg
  :alt: GPax_sGP

Structured GP is usually better at extrapolation and provides more reasonable uncertainty estimates. The probabilistic model in structured GP reflects our prior knowledge about the system, but it does not have to be precise, that is, the model can have a different functional form, as long as it captures general or partial trends in the data. 

Active learning & Bayesian optimization
---------------------------------------

|BO|

.. |BO| image:: https://colab.research.google.com/assets/colab-badge.svg
   :target: https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/gpax_GPBO.ipynb


Both GP and sGP can be used for active learning to reconstruct the entire data distribution from sparse observations or to localize regions of the parameter space where a particular physical behavior is maximized or minimized with as few measurements as possible.

.. code:: python

  # Train a GP model (it can be sGP or vanilla GP)
  gp_model.fit(rng_key, X_measured, y_measured)  # A

  # Compute the upper confidence bound (UCB) acquisition function to derive the next measurement point
  acq = gpax.acquisition.UCB(rng_key_predict, gp_model, X_unmeasured, beta=4, maximize=False, noiseless=True)  # B
  next_point_idx = acq.argmax()  # C
  next_point = X_unmeasured[next_point_idx]  # D

  # Perform measurement in next_point, update measured & unmeasured data arrays, and re-run steps A-D.

In the figure below we illustrate the connection between the (s)GP posterior predictive distribution and the acquisition function used to derive the next measurement points. Here, the posterior mean values indicate that the minimum of a "black box" function describing a behavior of interest is around $x=0.7$. At the same time, there is a large dispersion in the samples from the posterior predictive distribution between $x=-0.5$ and $x=0.5$, resulting in high uncertainty in that region. The acquisition function is computed as a function of both predictive mean and uncertainty and its maximum corresponds to the next measurement point in the active learning and Bayesian optimization. Here, after taking into account the uncertainty in the prediction, the UCB acquisition function suggests exploring a point at x≈0 where potentially a true minimum is located.

.. image:: imgs/GP_BO2.png
  :alt: GPax_BO


Theory-informed data reconstruction and Bayesian optimization
-------------------------------------------------------------

|MTGP|

.. |MTGP| image:: https://colab.research.google.com/assets/colab-badge.svg
   :target: https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/GPax_MultiTaskGP_BO.ipynb

Sometimes when theoretical simulations are available before the experiment, they can be used to guide the measurements or simply reconstruct sparse data via a multi-task/fidelity Gaussian process. This can be an alternative to a structured Gaussian process in situations where a mean function is too costly to compute at each step or it is expressed through some complex program that is not fully differentiable. The overall scheme is the same, but now our GP model is a MultitaskGP:

.. code:: python

  key1, key2 = gpax.utils.get_keys(1)

  gp_model = gpax.MultiTaskGP(
      input_dim=1, data_kernel='Matern',  # standard GP parameters
      shared_input_space=False,  # different tasks/fidelities have different numbers of observations
      num_latents=2, rank=2,  # parameters of multi-task GP
  )

  model.fit(key1, X, y, num_warmup=500, num_samples=500)

Note that X has (N, D+1) dimensions where the last column contains task/fidelity indices for each observation. We can then use the trained model to reconstruct data from partial (expensive) observations:

.. code:: python

  # Create a set of inputs for the task/fidelity 2
  X_unmeasured2 = np.column_stack((X_full_range, np.ones_like(X_full_range)))

  # Make a prediction with the trained model
  y_mean2, y_sampled2 = model.predict(key2, X_unmeasured2, noiseless=True)

.. image:: imgs/GP_vs_MTGP.jpg
  :alt: GP_vs_MTGP

Hypothesis learning
-------------------

|hypoAL|

.. |hypoAL| image:: https://colab.research.google.com/assets/colab-badge.svg
   :target: https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/gpax_hypo.ipynb

The structured GP can be also used for hypothesis learning in automated experiments. The `hypothesis learning <https://arxiv.org/abs/2112.06649>`_ is based on the idea that in active learning, the correct model of the system’s behavior leads to a faster decrease in the overall Bayesian uncertainty about the system under study. In the hypothesis learning setup, probabilistic models of the possible system’s behaviors (hypotheses) are wrapped into structured GPs, and a basic reinforcement learning policy is used to select a correct model from several competing hypotheses. A full example is available `here <https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/hypoAL.ipynb>`_.

.. image:: imgs/HypoAL.gif
  :alt: GPax_HypoAL

Deep Kernel Learning
--------------------

|DKL|

.. |DKL| image:: https://colab.research.google.com/assets/colab-badge.svg
   :target: https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/gpax_viDKL_plasmons.ipynb

`Deep Kernel Learning <https://arxiv.org/abs/1511.02222>`_ can be understood as a hybrid of deep neural network (DNN) and GP. The DNN serves as a feature extractor that allows reducing the complex high-dimensional features to low-dimensional descriptors on which a standard GP kernel operates. The parameters of DNN and of GP kernel are inferred jointly in an end-to-end fashion. Practically, the DKL training inputs are usually patches from an (easy-to-acquire) structural image, and training targets represent a physical property of interest derived from the (hard-to-acquire) spectra measured in those patches. The DKL output on the new inputs (image patches for which there are no measured spectra) is the expected property value and associated uncertainty, which can be used to derive the next measurement point in the automated experiment.

.. code:: python
  
  import gpax

  # Get random number generator keys for training and prediction
  rng_key, rng_key_predict = gpax.utils.get_keys()

  # Obtain/update DKL posterior; input data dimensions are (n, h*w*c)
  dkl = gpax.viDKL(input_dim=X.shape[-1], z_dim=2, kernel='RBF')  # A
  dkl.fit(rng_key, X_train, y_train, num_steps=100, step_size=0.05)  # B

  # Compute UCB acquisition function
  obj = gpax.acquisition.UCB(rng_key_predict, dkl, X_unmeasured, maximize=True)  # C
  # Select next point to measure (assuming grid data)
  next_point_idx = obj.argmax()  # D

  # Perform measurement in next_point_idx, update measured & unmeasured data arrays, and re-run steps A-D.

Below we show a result of a simple DKL-based search for regions of the nano-plasmonic array that host a specific plasmon mode

.. image:: imgs/DKL_STEM.png
  :alt: GPax_DKL

Note that in viDKL, we use a simple MLP as a default feature extractor. However, you can easily write a custom DNN using `haiku <https://github.com/deepmind/dm-haiku>`_ and pass it to the viDKL initializer

.. code:: python

  import haiku as hk

  class ConvNet(hk.Module):
      def __init__(self, embedim=2):
          super().__init__()
          self._embedim = embedim   

      def __call__(self, x):
          x = hk.Conv2D(32, 3)(x)
          x = jax.nn.relu(x)
          x = hk.MaxPool(2, 2, 'SAME')(x)
          x = hk.Conv2D(64, 3)(x)
          x = jax.nn.relu(x)
          x = hk.Flatten()(x)
          x = hk.Linear(self._embedim)(x)
          return x

  dkl = gpax.viDKL(X.shape[1:], 2, kernel='RBF', nn=ConvNet)  # input data dimensions are (n,h,w,c)
  dkl.fit(rng_key, X_train, y_train, num_steps=100, step_size=0.05)
  obj = gpax.acquisition.UCB(rng_key_predict, dkl, X_unmeasured, maximize=True)
  next_point_idx = obj.argmax()


================================================
FILE: docs/source/acquisition.rst
================================================
Acquisition functions
=====================

.. autofunction:: gpax.acquisition.UCB

.. autofunction:: gpax.acquisition.EI

.. autofunction:: gpax.acquisition.POI
  
.. autofunction:: gpax.acquisition.UE

.. autofunction:: gpax.acquisition.Thompson

.. autofunction:: gpax.acquisition.KG
  
.. autofunction:: gpax.acquisition.qUCB

.. autofunction:: gpax.acquisition.qEI

.. autofunction:: gpax.acquisition.qPOI

.. autofunction:: gpax.acquisition.qKG

.. autofunction:: gpax.acquisition.optimize_acq

================================================
FILE: docs/source/conf.py
================================================
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

# -- Path setup --------------------------------------------------------------

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import sys
sys.path.insert(0, os.path.abspath('../../'))
from gpax._version import __version__

#autodoc_mock_imports = ['jax', 'jax.numpy', 'jax.random', 'numpyro', 'jaxlib',
#                        'numpyro.distributions', 'numpyro.infer', 'haiku', 'numpy']

# -- Project information -----------------------------------------------------

project = 'GPax'
copyright = '2024, GPax authors'
author = 'GPax authors'

# The full version, including alpha/beta/rc tags
release = __version__

# -- General configuration ---------------------------------------------------

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
    'sphinx.ext.autodoc',
    'sphinx.ext.doctest',
    'sphinx.ext.coverage',
    'sphinx.ext.githubpages',
    'sphinx.ext.napoleon',
    'sphinx_autodoc_typehints',
    'recommonmark',
    'sphinx.ext.viewcode',
    'sphinx.ext.mathjax'
]

napoleon_use_ivar = True

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'

# The master toctree document.
master_doc = 'index'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path .
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'

autodoc_default_options = {
    'exclude-members': 'forward'
}
# -- Options for HTML output -------------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
#
# html_theme = 'alabaster'
html_theme = 'sphinx_rtd_theme'


# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# The default sidebars (for documents that don't match any pattern) are
# defined by theme itself.  Builtin themes are using these templates by
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
# 'searchbox.html']``.
#
# html_sidebars = {}


# -- Options for HTMLHelp output ---------------------------------------------

# Output file base name for HTML help builder.
htmlhelp_basename = 'indexedconvdoc'


# -- Options for LaTeX output ------------------------------------------------

latex_elements = {
    # The paper size ('letterpaper' or 'a4paper').
    #
    # 'papersize': 'letterpaper',

    # The font size ('10pt', '11pt' or '12pt').
    #
    # 'pointsize': '10pt',

    # Additional stuff for the LaTeX preamble.
    #
    # 'preamble': '',

    # Latex figure (float) alignment
    #
    # 'figure_align': 'htbp',
}

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
#  author, documentclass [howto, manual, or own class]).
latex_documents = [
    (master_doc, 'indexedconv.tex', 'indexedconv Documentation',
     'Mikael Jacquemont, Thomas Vuillaume, Luca Antiga', 'manual'),
]


# -- Options for manual page output ------------------------------------------

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
    (master_doc, 'indexedconv', 'indexedconv Documentation',
     [author], 1)
]


# -- Options for Texinfo output ----------------------------------------------

# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
#  dir menu entry, description, category)
texinfo_documents = [
    (master_doc, 'indexedconv', 'indexedconv Documentation',
     author, 'indexedconv', 'One line description of project.',
     'Miscellaneous'),
]


# -- Extension configuration -------------------------------------------------

================================================
FILE: docs/source/examples.rst
================================================
Colab notebooks
===============

The easiest way to start using GPax is via Google Colab, which is a free research tool from Google for machine learning education and research built on top of Jupyter Notebook. The following notebooks can be executed in Google Colab by simply clicking on the "Open in Colab" icon:

*   | Gaussian process in the fully Bayesian mode |simpleGP|

*   | Structured Gaussian processes |sGP|

*   | Bayesian optimization |GPBO|

*   | Theory-informed Gaussian process & Bayesian optimization |MTGPBO|

*   | Hypothesis learning |hypoAL|

*   | Deep Kernel Learning |DKL|

*   | Heteroskedastic Gaussian processes |VarNoiseGP|

.. |simpleGP| image:: https://colab.research.google.com/assets/colab-badge.svg
   :target: https://colab.research.google.com/github/ziatdinovmax/gpax/blob/master/examples/simpleGP.ipynb

.. |sGP| image:: https://colab.research.google.com/assets/colab-badge.svg
   :target: https://colab.research.google.com/github/ziatdinovmax/gpax/blob/master/examples/GP_sGP.ipynb

.. |GPBO| image:: https://colab.research.google.com/assets/colab-badge.svg
   :target: https://colab.research.google.com/github/ziatdinovmax/gpax/blob/master/examples/gpax_GPBO.ipynb

.. |MTGPBO| image:: https://colab.research.google.com/assets/colab-badge.svg
   :target: https://colab.research.google.com/github/ziatdinovmax/gpax/blob/master/examples/GPax_MultiTaskGP_BO.ipynb

.. |hypoAL| image:: https://colab.research.google.com/assets/colab-badge.svg
   :target: https://colab.research.google.com/github/ziatdinovmax/gpax/blob/master/examples/hypoAL.ipynb
   
.. |DKL| image:: https://colab.research.google.com/assets/colab-badge.svg
   :target: https://colab.research.google.com/github/ziatdinovmax/gpax/blob/master/examples/gpax_viDKL_plasmons.ipynb

.. |VarNoiseGP| image:: https://colab.research.google.com/assets/colab-badge.svg
   :target: https://colab.research.google.com/github/ziatdinovmax/gpax/blob/master/examples/heteroskedasticGP.ipynb


================================================
FILE: docs/source/hypo.rst
================================================
Hypothesis learning
===================

.. autofunction:: gpax.hypo.step

.. autofunction:: gpax.hypo.sample_next

.. autofunction:: gpax.hypo.softmax

.. autofunction:: gpax.hypo.eps_greedy

.. autofunction:: gpax.hypo.update_record

================================================
FILE: docs/source/index.rst
================================================
GPax: Gaussian Processes for Experimental Sciences
==================================================

GPax is a small Python package for physics-based Gaussian processes (GPs) built on top of NumPyro and JAX. Its purpose is to take advantage of prior physical knowledge and different data modalities when using GPs for data reconstruction and active learning. It is a work in progress, and more models will be added in the near future.

.. image:: imgs/GPax_v2.jpg
  :alt: GPax

.. toctree::
   :maxdepth: 3
   :caption: Notes

   README.rst
   LICENSE.rst
   USAGE.rst

.. toctree::
   :glob:
   :caption: Package Content

   models
   acquisition
   kernels
   priors
   hypo
   utils

.. toctree::
   :maxdepth: 3
   :caption: Examples

   examples 


================================================
FILE: docs/source/kernels.rst
================================================
Kernels
=======

.. autofunction:: gpax.kernels.RBFKernel

.. autofunction:: gpax.kernels.MaternKernel

.. autofunction:: gpax.kernels.PeriodicKernel

.. autofunction:: gpax.kernels.NNGPKernel

.. autofunction:: gpax.kernels.MultitaskKernel

.. autofunction:: gpax.kernels.MultivariateKernel

.. autofunction:: gpax.kernels.LCMKernel

================================================
FILE: docs/source/models.rst
================================================
GPax models
===========

Gaussian Processes - Fully Bayesian Implementation
--------------------------------------------------
.. autoclass:: gpax.models.gp.ExactGP
    :members:
    :inherited-members:
    :undoc-members:
    :member-order: bysource
    :show-inheritance:

.. autoclass:: gpax.models.uigp.UIGP
    :members:
    :inherited-members:
    :undoc-members:
    :member-order: bysource
    :show-inheritance:

.. autoclass:: gpax.models.hskgp.VarNoiseGP
    :members:
    :inherited-members:
    :undoc-members:
    :member-order: bysource
    :show-inheritance:

.. autoclass:: gpax.models.mngp.MeasuredNoiseGP
    :members:
    :inherited-members:
    :undoc-members:
    :member-order: bysource
    :show-inheritance:

.. autoclass:: gpax.models.vgp.vExactGP
    :members:
    :inherited-members:
    :undoc-members:
    :member-order: bysource
    :show-inheritance:

Gaussian Processes - Approximate Bayesian
------------------------------------------
.. autoclass:: gpax.models.vigp.viGP
    :members:
    :inherited-members:
    :undoc-members:
    :member-order: bysource
    :show-inheritance:

.. autoclass:: gpax.models.sparse_gp.viSparseGP
    :members:
    :inherited-members:
    :undoc-members:
    :member-order: bysource
    :show-inheritance:

Deep Kernel Learning - Fully Bayesian Implementation
----------------------------------------------------
.. autoclass:: gpax.models.dkl.DKL
    :members:
    :inherited-members:
    :undoc-members:
    :member-order: bysource
    :show-inheritance:

Deep Kernel Learning - Approximate Bayesian
-------------------------------------------
.. autoclass:: gpax.models.vidkl.viDKL
    :members:
    :inherited-members:
    :undoc-members:
    :member-order: bysource
    :show-inheritance:

Infinite-width Bayesian Neural Networks
----------------------------------------
.. autoclass:: gpax.models.ibnn.iBNN
    :members:
    :inherited-members:
    :undoc-members:
    :member-order: bysource
    :show-inheritance:

Multi-Task Learning
--------------------
.. autoclass:: gpax.models.mtgp.MultiTaskGP
    :members:
    :inherited-members:
    :undoc-members:
    :member-order: bysource
    :show-inheritance:

.. autoclass:: gpax.models.vi_mtdkl.viMTDKL
    :members:
    :inherited-members:
    :undoc-members:
    :member-order: bysource
    :show-inheritance:

Structured Probabilistic Models
-------------------------------
.. autoclass:: gpax.models.spm.sPM
    :members:
    :inherited-members:
    :undoc-members:
    :member-order: bysource
    :show-inheritance:



================================================
FILE: docs/source/priors.rst
================================================
Priors
======

.. autofunction:: gpax.priors.normal_dist

.. autofunction:: gpax.priors.lognormal_dist

.. autofunction:: gpax.priors.halfnormal_dist

.. autofunction:: gpax.priors.gamma_dist

.. autofunction:: gpax.priors.uniform_dist

.. autofunction:: gpax.priors.auto_normal_priors

.. autofunction:: gpax.priors.auto_lognormal_priors

.. autofunction:: gpax.priors.auto_normal_kernel_priors

.. autofunction:: gpax.priors.auto_lognormal_kernel_priors





================================================
FILE: docs/source/utils.rst
================================================
Utilities
=========

Automatic function setters
--------------------------

.. autofunction:: gpax.utils.set_fn

.. autofunction:: gpax.utils.set_kernel_fn


Other utilities
---------------

.. autofunction:: gpax.utils.dviz

.. autofunction:: gpax.utils.get_keys

.. autofunction:: gpax.utils.enable_x64

================================================
FILE: examples/GP_sGP.ipynb
================================================
{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/GP_sGP.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "136rQl-Z67Xf"
      },
      "outputs": [],
      "source": [
        "# For github continuous integration\n",
        "import os\n",
        "if os.environ.get(\"CI_SMOKE\"):\n",
        "    NUM_WARMUP = 10\n",
        "    NUM_SAMPLES = 10\n",
        "else:\n",
        "    NUM_WARMUP = 2000\n",
        "    NUM_SAMPLES = 2000"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NtiDY7RcohrR"
      },
      "source": [
        "# Structured Gaussian Process\n",
        "\n",
        "This notebook compares vanilla and structured Gaussian processes for reconstructing and active learning of function characterized by a discontinuous behavior at some \"transition\" point.\n",
        "\n",
        "*Prepared by Maxim Ziatdinov (2022). Last updated in October 2023.*"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vUoeZ9Tin74Q"
      },
      "source": [
        "In the previous [example](https://colab.research.google.com/github/ziatdinovmax/gpax/blob/main/examples/simpleGP.ipynb), we have introduced Gaussian process (GP) operating in a fully Bayesian mode for reconstucting, with quantified uncertainty, an unknown function from sparse measurements. The limitation of the standard GP is that it does not usually allow for the incorporation of prior domain knowledge and can be biased toward a trivial interpolative solution. Recently, we introduced a structured Gaussian Process (sGP), where a classical GP is augmented by a structured probabilistic model of the expected system’s behavior. This approach allows us to balance the flexibility of the non-parametric GP approach with a rigid structure of prior (physical) knowledge encoded into the parametric model. Implementation-wise, this is achieved by substituting a zero prior mean function in GP with a probabilistic model of the expected system's behavior."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HdtH0tCPQ2de"
      },
      "source": [
        "## Install & Import"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "86iUwKxLO7qE"
      },
      "source": [
        "Install the latest GPax package from PyPI (this is best practice, as it installs the latest, deployed and tested version)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "VQ1rLUzqha2i"
      },
      "outputs": [],
      "source": [
        "!pip install -q gpax"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vygoK7MTjJWB"
      },
      "source": [
        "Import needed packages:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "XCoyWlKt67Xk"
      },
      "outputs": [],
      "source": [
        "try:\n",
        "    # For use on Google Colab\n",
        "    import gpax\n",
        "\n",
        "except ImportError:\n",
        "    # For use locally (where you're using the local version of gpax)\n",
        "    print(\"Assuming notebook is being run locally, attempting to import local gpax module\")\n",
        "    import sys\n",
        "    sys.path.append(\"..\")\n",
        "    import gpax"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "KtGDc11Ehh7r"
      },
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "import matplotlib.pyplot as plt\n",
        "\n",
        "gpax.utils.enable_x64()  # enable double precision"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "G6cPAvHh67Xk"
      },
      "source": [
        "Enable some pretty plotting."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "V5isV5Ho67Xl"
      },
      "outputs": [],
      "source": [
        "import matplotlib as mpl"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "gUyKDZjM67Xl"
      },
      "outputs": [],
      "source": [
        "mpl.rcParams['mathtext.fontset'] = 'stix'\n",
        "mpl.rcParams['font.family'] = 'STIXGeneral'\n",
        "mpl.rcParams['text.usetex'] = False\n",
        "plt.rc('xtick', labelsize=12)\n",
        "plt.rc('ytick', labelsize=12)\n",
        "plt.rc('axes', labelsize=12)\n",
        "mpl.rcParams['figure.dpi'] = 200"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ZSaWCRHJPukv"
      },
      "source": [
        "## Standard and structured GP"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "D6vVHZKpxse_"
      },
      "source": [
        "We consider noisy observations of a discontinuous function..."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "LAvbGDom67Xl"
      },
      "outputs": [],
      "source": [
        "def piecewise1(x: np.ndarray, params) -> np.ndarray:\n",
        "    return np.piecewise(\n",
        "        x,\n",
        "        [x < params[\"t\"], x >= params[\"t\"]],\n",
        "        [lambda x: x**params[\"beta1\"], lambda x: x**params[\"beta2\"]])\n",
        "\n",
        "\n",
        "NUM_INIT_POINTS = 15 # number of observation points\n",
        "NOISE_LEVEL = 0.1\n",
        "PARAMS = {\"t\": 1.7, \"beta1\": 4.5, \"beta2\": 2.5}\n",
        "\n",
        "np.random.seed(1)\n",
        "X = np.random.uniform(0, 3, NUM_INIT_POINTS)\n",
        "y = piecewise1(X, PARAMS) + np.random.normal(0., NOISE_LEVEL, NUM_INIT_POINTS)\n",
        "\n",
        "X_test = np.linspace(0, 3, 200)\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 454
        },
        "id": "LF2l_UcBtaDT",
        "outputId": "bd7d82d4-4d2a-482a-97c4-5d289dfe352e"
      },
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "<Figure size 1200x400 with 1 Axes>"
            ],
            "image/png": "iVBORw0KGgoAAAANSUhEUgAABDwAAAG1CAYAAAAV7eRUAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAB7CAAAewgFu0HU+AABTbUlEQVR4nO3deXxU1f3/8XcWCMuEHSSQYRVBllCRzRGNG2lRtFoFt1SsuFAxiuJe96XudYm21YrKl4grYqu1kkppFAYE1MqigKDghKWyk2EJJDm/P/jNbZaZYSaZyczceT0fjzycuetnksM1951zz0kxxhgBAAAAAADYSGqsCwAAAAAAAIg0Ag8AAAAAAGA7BB4AAAAAAMB2CDwAAAAAAIDtEHgAAAAAAADbIfAAAAAAAAC2Q+ABAAAAAABsh8ADAAAAAADYDoEHAAAAAACwHQIPAAAAAABgOwQeAAAAAADAdgg8AAAAAACA7RB4AAAAAAAA2yHwAAAAAAAAtkPgAQAAAAAAbIfAAwAAAAAA2A6BBwAAAAAAsJ30WBeA+jtw4ICWL18uSerYsaPS0/lxAgAAAACip6KiQlu3bpUkDRo0SM2aNYtxRYFxh5zAli9fruHDh8e6DAAAAABAElq8eLGGDRsW6zIC4pEWAAAAAABgO/TwSGAdO3a0Xi9evFhZWVkxrAYAAAAAYHebN2+2njSofk8ajwg8Elj1MTuysrKUnZ0dw2oAAAAAAMkk3seR5JEWAAAAAABgOwQeAAAAAICI83q9jbofUBuBBwAAAAAgojwejwoLC+V2u8Paz+12q7CwUB6PJ0qVIZkQeAAAAAAAIsbj8aioqEjl5eUqLi4OOfRwu90qLi5WeXm5ioqKCD3QYAQeAAAAAICI8Hq9VtjhE0ro4Qs7fHyhB4+3oCEIPAAAAAAAEeFwOJSbm1tnebDQo3bY4ZObmyuHwxHxGpE8CDwAAAAAABHjcrmUl5dXZ7m/0CNQ2JGXlyeXyxW1GpEcCDwAAAAAABEVSuhB2IFoS491AQAAAAAA+/GFFrVDjeLiYi1cuFBlZWV19iHsQCTRwwMAAAAAEBWBenoQdqAx0MMDOnjwoLxer/bu3auDBw+qqqoq1iUBQL2kpaWpWbNmatWqlVq2bKmUlJRYlwQAQNIL1NOjOsIORAOBRxIzxmjbtm3atm1brEsBgIioqKhQeXm5du/erebNm6tbt25KTaUzIwAAseZyuQI+xpKZmUnYgagg8Ehimzdv1u7du2ssS0lJUVpaWowqAoCGqayslDFGkrR//379+OOP6t69Oz09AACIMbfb7TfskA4/3uJ2uwk9EHEEHknqwIEDNcKO9u3bq1WrVsrIyODGAEDCqqqqktfr1ZYtW1RZWan9+/dr7969cjgcsS4NAICkFWg2lup86wk9EEn0801Su3btsl536tRJnTp1UrNmzQg7ACS01NRUtWrVSp07d7aWBfprEgAAiL5AYUdmZmadZdWnrAUigcAjSe3bt8963aZNm9gVAgBR4HA4rAB3//79Ma4GAIDkFCjsyMvL09SpU/3O3kLogUgi8EhSlZWVkqT09HTG7ABgO6mpqda1zXe9AwAAjSdY2OF7bCXQlLWEHogUAg8AAAAAQMSEEnb4EHogmgg8AAAAAAAR4fV6VVJSUme5v7DDJ1DoUVJSIq/XG/EakTwIPAAAAAAAEeFwOJSfn6+MjAxrWbCww6d26JGRkaH8/HxmWkODEHgAAAAAACLG6XRaoUcoYYePL/TwhR1OpzPKlcLu0mNdAAAAAADAXpxOpwoKCsLuoeFyuZSTk0PPDkQEPTwAJLT169frueee09dffx3rUgAAAFBNfUMLwg5ECoEHEEU33HCDHA6HUlJSrK/nnnsu6D4DBw5Uenp6jX2aN2+u2267rcH13HTTTcrMzNRTTz3V4GPF2lNPPaXBgwerZ8+euuGGG+TxeGJdUkLaunWrBg0apG7duunbb7+NdTkAAABAxBB4IGbqO+JyIo3U/Oyzz2rz5s0688wzrWU333yzFi1aFHCfFStWaNOmTRo8eLAk6cILL9SOHTv02GOPNbiel156SV6vV6+99lqDjxVr119/vZ555plYl5HwSkpKtGLFCnk8Hn300UexLgcAAACIGAIPxITH41FhYWHYc2u73W4VFhYm1F/zMzMz9e6771rvDx06pPHjx2vbtm0B9+nUqZOuueYaSdI999yj5s2bR6SWO++8U3379tWtt94akePFUpMmTXTyySfHuoyEMXfuXL/LR48erdNPP10ul0vjxo1r5KoAAACA6CHwQKPzeDwqKipSeXm5iouLQw493G63iouLVV5erqKiooQKPXyBRZMmTSQd/h7k5+erqqoq4D49e/as8d9IuPPOO7Vq1Sr9+te/jtgxYyktLS3WJSQEj8ej8ePH+13XunVrffLJJ1qwYIG6devWyJUBAAAA0UPggUbl9XqtsMMnlNDDF3b4+EKPRHq8RZIeffRRK/yYM2eOHnjggYDbNmvWrMZ/gfrYv3+/LrjgAu3YsSPWpQAAAACNisAjgJ9++inWJdiSw+FQbm5uneXBQo/aYYdPbm5uwo3gPGTIEL300kvW+wcffNDvZ6suJSUl2mXBpsrKyvSrX/1KixcvjnUpAAAAQKMj8Khl/fr1uvrqq5WdnR3yPl6vV08++aRGjhypTp06qV27dhowYIDuuecebd26NYrVJiaXy6W8vLw6y/2FHoHCjry8PLlcrqjVGE35+fm68cYbJUlVVVW69NJL6/V4zpYtW3TrrbfK5XJp5MiROuqoozRkyBA9+uij2rt3r999tm3bppdeekl33nmn3/X/93//p+HDh2vo0KE66qijrFli/v3vf0uS1q1bp/bt29eYQeaoo47SCy+8YB1j165d6tGjh7X+7rvvDvkzHThwQM8884xOOeUUnXTSSXI6nTr66KNVUFAQ0vdo1apVGj9+vDp27CiHw6GTTjpJH3zwgd9tv/nmG5133nk67rjjdMwxx1gz41x++eV+t//nP/+p888/X6NGjVK7du107LHH6sEHH6zRW8ln6dKl+u1vf6uHHnpIxhjde++9at++vfr06aM1a9YoKyurxvewQ4cOmj17trX/Dz/8oC5duljrp0yZUuP48+bN03nnnaeRI0fq2GOPVZcuXXT55Zdr48aNNba78cYbtWrVKuv90KFDNXToUF122WU1tvvPf/6jO+64Q//4xz/8fvb6/FzcbreuuOIKTZw4UZL0+eefa/To0XI4HHI6nQFnCvrxxx81YcIE/exnP1P//v2VkZGhlJQUnXLKKX63BwAAAAIyMMYYs27dOjNx4kSTnp5uJJlQvzUrVqwwvXr1Mk2aNDEvvfSSOXTokDl06JCZOXOmadmypenSpYtxu91Rqdnj8Vi1ejyesPZds2aN+eabb8yaNWuiUlsoFixYYO699946XwsWLAhpfaKRZObNm2eMMaaiosKcdtpp1s9v5MiR5uDBgzW2nzdvXsB2+Mknn5g2bdqYK6+80uzbt88YY0xZWZm5+uqrjSTTr18/88MPP1jbFxcXm7POOstq37m5uXWO+dhjj5mmTZuaRYsWWcumTZtmUlNTrbqNMWbPnj3m2GOPNZJMenq6OXDggN8au3XrZqZMmRLCd+awDRs2mAEDBpgRI0aY0tJSY4wxlZWV5s9//rNJT083rVq1MnPmzKmzn+97+Oijj5rWrVub1q1bmy5duljLJZmnnnqqxj5r1641DofD3HjjjaaystIYY8zq1avNMcccYyZMmFDnHHfddZcZO3as2b17t/U9GD16tJFkRo0aZfbv32+MMeaNN94wp556qnXeqVOnmttuu8107NjRWvbiiy+agwcPmjPPPNNa9vXXX9c5Z3l5uWndurW55ZZbaiz//e9/bySZ22+/3VRVVRljjJkxY4aRZHr06GHKyspqbP/qq68GvKbdd999pn///tb6V199tcE/lyVLlljfG0nm/PPPN0VFRaZZs2bG6XSatLQ0a93s2bNrnGvnzp2mS5cuZvz48aa8vNwYY8ymTZvMCSec4LfNHkk8XOcAAADspiH3oY0t6QOPbdu2mdtuu81cddVVZvz48TVuko5k48aNxul0Gknm2WefrbP+nXfeMZJM27Zto/ILd6IHHsYEDjWefPJJW4UdxtQMPIw53PZ69Ohh/QwLCgpqbB8o8Fi9erVxOBymZ8+e5tChQ3XWn3322UaSGTBggHUjvm/fPlNVVWWt83fzmJ2dbYYOHVpneX5+fo26jTHm7bfftur+9NNP6+zz448/mvT0dOsG+UgOHDhgBg0aZFJTU/22ySeffNJIMg6Hw3z77bc11vnq6NSpk3nrrbes5QsXLjRZWVlGkklLSzOLFy+21t11111GklmxYkWNY33yySd1Ao8333zTtGvXzuzcubPG8q+//to6d/V//xUVFaZbt25GkjnuuOPM448/bowx5umnnzYnnHCC+e6774wxxqxatcqkpqYaSea1116r85m3bNliWrRoYbZv324tKysrM02aNDGSzMcff1xj+z59+hhJZsaMGTWWBws89u3bZzZv3mwds3bg0ZCfywknnGAkmZ49e5q8vDwrgNuwYYPp2rWrkWROPfXUGvu8/PLLRpL58MMPayxfs2aNOe200+qc/0ji5ToHAABgJ4kUeCT9Iy3NmzfXQw89pJdeeklvvPGGWrduHfK+F154oTwej7p166Zrr722zvoLLrhAI0eO1M6dO20zK0akBXq8paysrM6yRH6MxZ/27dvr/fffV4sWLSRJhYWFeuutt46431133SWv16srr7xS6enpddY//vjjkqSVK1fqL3/5i6TD7TwlJUWDBw8OeNydO3dqzZo1dcavufLKK+tse/755+voo4+WJD333HN11r/xxhs65ZRT1LVr1yN+HkmaNm2ali9frtNPP119+vSps37KlCnq2rWrvF6vfve73/k9xlVXXVVjJpKRI0fq9ddflyRVVlbqscces9bt3LlTkjR//vwaxzj99NNrzIpTVVWlO++8U3l5eWrTpk2NbXNyctShQwdJqvFzS0tLU/fu3SVJ6enpuuWWW6zP4Ha7re9b37599ctf/lKSrJ9TddOnT9f48ePVrl07a1lKSoo1iG3Tpk1rbN+lSxdJCuvxqObNm6tz58466qij/K5vyM+ld+/ekqSWLVvqww8/VI8ePSRJ3bp104QJEySpxuM2UuCfS58+fZiCGAAAAGFL+sCjRYsW1k1jampqnZuaQObOnWv9Un7hhRf6vfGUpEsvvVTS4efX33333YYXbEOBQo/q7BZ2+AwePFjTpk2z3l955ZV1bgKrO3DggDUmhb8bUEnq16+fcnJyJElvv/12jXXBpnE99dRTtWfPHp1yyilavny5tTw3N7fO+Ampqam6+eabJUmzZ8/W+vXra6yfOXNmWCGfLzAI9JnS0tJ0/vnnS5L+/ve/a9++fXW28QUJtT/TkCFDJB0eg8M3DfCpp54qSSooKNCLL74oY4y1z7333mu9Xrp0qb7//nt99tlnGjlyZJ0vh8Ohrl27qqKiosZ5U1MPX1r79+8f9HNff/31kqQFCxZo5cqVNda98sormjRpUo1lLVu21Ndff62lS5dan0GSNm/erG3btkmSDh48GPSc/gRqFw35ufiO2b59e2s6Zh9f+LFly5Yay0855RSlpKTo0Ucf1QMPPKBDhw5Z66r/XAAAAIBQJH3gUV9PP/209Xr06NEBt6u+rvrsHKjJ5XIpMzPT77rMzExbhh0+F110kdULwOv16vzzzw846OiaNWt04MABSVLbtm0DHtN3k1/7JjqYZ599Vp07d9a3336rIUOG6KabbvLb08ZnwoQJOuqoo1RZWalnn33WWv7tt99q7dq11o1wKHwBSyifqby8XGvXrg352L6wZs+ePdbUrOeff77Gjx+vQ4cOadKkSTrxxBP11Vdf1dn3yy+/lHT4sy5atKjO1w8//KDS0lJ9/vnnIddTu7aBAwdKkv785z9byz/77DM1b95cI0aMqLNPz549dfzxx0s6HOL85je/0TPPPGOtrx7eNFS0fi6+AKR2rUOHDrWCtHvvvVeDBw/WvHnzwq4bAAAAkAg86qWyslIlJSXW++OOOy7gtn369LGmTv3Xv/6l7du3R72+ROR2uwPeXJeVlQWcstYuHnnkEauXyzfffKNrrrnG73bVv0d79uwJeLxOnTpJOhyghKpXr16aP3++RowYoYqKCj399NPq16+fPvzwQ7/bN2vWTDfccIOkw48++Op5/fXXdd5556lly5Yhn9v3uUL5TFJ4n6v6IyqVlZXW65kzZ+rmm29WWlqaFi5cqGHDhunmm2+2AiVJ1r/XYHU1VEFBgSRpxowZVg+JadOmBWwD0uFZWoYNG6a5c+eqsLBQjz32mPV4TSRF8+cSyOOPP64nn3xSzZo107fffqvTTjtNl112mXbt2tXgYwMAACC5EHjUw7Jly6xf7DMzM4PeaKSmpqpbt26SDt9s+f5ijP8JNPVsdf6mrLWTtLQ0vfnmm+rVq5ekw6HBn/70pzrbVR/P4fvvvw94PN8jVuHeBPfu3Vtut1svvPCCOnTooE2bNunss8+u0YOgut/+9rfKzMxUWVmZXn75ZUnSm2++GfaYNb7PFcpnksL7XNXHvGjfvr21PC0tTU888YQ+//xzjRo1SpWVlXrqqad02mmnWcFDRkaGpMO9VqIlPz9fbdu21e7du/Xmm29qz549+vjjj63H4Wp7+umndfrpp2v8+PF69NFHrUA1GqL5cwlm6tSpWrZsmc4++2xJh8OgESNG1BlfBgAAAAiGwKMe1qxZY732DRQYTPVtli1bFvJ5SktLg35t3rw5vMLjUKCww9/jLXYPPdq2bav333/f6hlRe/wNSTrmmGPUqlUrSdKiRYsCHmvr1q2SpOHDh4ddR2pqqq699lqtXbtW48aNkyTdfvvtfnsntWnTxuqJUFhYKLfbrf379+uMM84I65xDhw6VJC1ZssQaZ6M232dq27at3/E6AvENhOlyufyOtXP88cfrs88+02uvvaamTZtq4cKFeuWVVyT9r3dISUlJ0MFA58+frzfffDPkmqpr0aKFJk6cKOnwYy1vvPGGfvnLX/r9N7BkyRJNnTpVTZs21ZQpU+p1vnBE8+dyJH369NHf/vY3ffTRR2rdurXWrFljDcgLAAAAhILAox584wBI/m/Ma/PdoEoK6y+UTqcz6Fd9bmbjSaCwIy8vT1OnTvU7kGmihh6+gSSrD8Loz6BBg/Tqq68GXJ+WlqZLLrlEkvSPf/wj4KMGS5culSRrNoxQ1O6V0bp1a73++uvKysoKOj7DjTfeqKZNm2r9+vW64oordMkll1iDdobqsssuk3T438fcuXP9buP7TL/+9a/DOr5vv+ozKd1www1WEOIzYcIEaxBR39gnJ598spo0aaKKigpde+21fm/6N2zYoKuvvjroWD5Hcu211yo1NVVLlizRgw8+WGewUp+3335bxhg1b968zkCg//3vfyXVfGxHUo3tjtT+aovmz8Wfxx57rM64M2PGjNHDDz8sKbwxaQAAAAACj3qofqPk6y4fjK9bvCTt3r07KjUlmmBhh2+A0kCztyRi6OHrjbNp06Yjbjtu3DjdcccdAdffc8896tixo/bt22fdCFa3dOlSffXVVxo9erTOPffcGut841NUH6fC54MPPtCGDRtqLGvSpIk6duyotLQ0a2aN2rp06WKFJatXr67XFMzjxo1Tbm6upMOfr/Zglnv37tXMmTOVlZWlu+66y+8x/IURHo9HH3zwgX75y1/qggsusJaXl5f7HUTY1xvLN6Vqx44dlZ+fL0n68MMPdc4552j58uUyxsjr9ertt9/WqFGjdM0119R4XMYXLOzfvz+kz9+zZ0+NHTtWktS1a9eA4wL5ZoPZtWuXZsyYYZ3riSeeUGlpqaT/PX7jmwGl+pSzGzdurPE98AnULhryc6kdvFRX/dzVj2mM0fPPP19n+9o/FwAAACAUBB71kJKS4vd1INWnfAxnBgWPxxP0a/HixeEVHidCCTt87BJ6+Kb3fOONN4LeCPo89NBDGjNmjN91WVlZ+vvf/66OHTvqySef1Msvv2y1q++++06XXnqpRo0apbfeeqtG+6ysrNTChQslHR4Y1dcjwOfAgQO64IILtG7dOmvZzJkztXz5ct1+++01bpxr8z1eMXjwYGtK3HCkpqbqnXfe0dChQ7Vo0SJNmjTJCgv27NmjSy+9VGlpafrHP/6hjh071th38ODBkqTp06fX+Ezr1q3Tueeeq9GjR+v111+v82/13nvv1TvvvGO993g8+uMf/6h+/frVGDD0qaeess7x97//XTk5OWratKkyMzN14YUX6uyzz7YGb5UOhwrffPONpMNtvXqPsGCuu+46SQrYu0OqOevTZZddpuzsbLVv3147duzQFVdcIUmaNWuWOnfubE2DPWLECGucj/vvv19Lly7VjTfeqNWrV0s6/Iier+dZSUlJjWtUQ34uP/zwgyRZ0+VWV/2xwOohjCS9+OKLev75560Aa/v27XriiSfUuXNn3X777QG/NwAAAEBtBB71UP0xFn9/Ka+t+jbVH285kuzs7KBfWVlZ4RUeB7xeb40Zbnz8hR0+gUKPkpKSiMwKEU0vvviiRo4cqdtuu02SNGfOHB199NG69957g+6XmpqqmTNnqk+fPn7XDxs2TCtXrtSNN96oxx57TD179tSJJ56oq6++WjfffLP+/e9/15hKdPLkyercubM+/fRTSYdn3+jevXud7+vSpUt1zDHHqHfv3urdu7cefvhhvfTSS3rooYeC1jtw4EC1b9++Xr07fDp27KgFCxbomWee0RdffKHevXtr5MiR+vnPf66cnBytXLnSCh6q8w2y2qxZMw0dOlSDBg3SSSedpOuvv1533nmn/vrXv/qdMaa8vFzjx49Xhw4dNGDAALlcLp122mlasGBBjX/jbdu21fz583XPPfeob9++atq0qVq0aKHTTjtNs2fP1h//+Edr29/+9rfq3r27NaNIaWlp0B4b1Z1++ukaM2aMLr744oDbnHnmmXr66afVvXt3tWjRQk6nU9OnT9cjjzyigoIC9enTR+3atdOkSZM0efJkSYevV6+99pq6d++ud999V/fcc48mTpyorl27atCgQRo0aJAVcrz55pvKysqqMWBuuD+XNWvW6PLLL7cCyZUrV2r8+PEqKSnR3r17ddNNN+mFF16wtj///PM1a9Ys670xRgUFBWrbtq0GDBignJwcdevWTYsWLVJ2dvYRv48AAACAT4oJp8tBEujRo4fVrT/Qt+a9997T+eefL0nq37//EZ8rP+uss/TRRx9JOvzX4ptuuikitZaWlsrpdEo6/NfpcG4GvvvuO1VUVCg9PT3gTXW0eDweFRUVWd3ag4Ud1VXvGZKRkaH8/Hzr8yO21q1bp759+8rj8SRkEAd7iuV1DgAAwK4ach/a2OjhUQ99+/a1XocyU0r1cRsGDBgQlZoSidPpVH5+vjIyMkIOO6T/9fQg7Ig/r776qs466yzCDgAAAABxo+4cjTiiY489Vm3b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\n"
          },
          "metadata": {}
        }
      ],
      "source": [
        "_, ax = plt.subplots(1, 1, figsize=(6, 2))\n",
        "ax.scatter(X, y, alpha=0.5, c='k', marker='x', label=\"Noisy observations\")\n",
        "ax.legend()\n",
        "ax.set_xlabel(\"$x$\")\n",
        "ax.set_ylabel(\"$y$\")\n",
        "ax.set_xlim(0, 3)\n",
        "\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rPfkj1cRQLop"
      },
      "source": [
        "... and try to reconstruct this underlying function with a standard GP"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "cOtfzDCo0MMI",
        "outputId": "82dda990-6cd0-407d-d6fb-18abdadbb212"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "sample: 100%|██████████| 4000/4000 [00:13<00:00, 299.14it/s, 7 steps of size 6.22e-01. acc. prob=0.90]\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\n",
            "                 mean       std    median      5.0%     95.0%     n_eff     r_hat\n",
            "k_length[0]      0.61      0.17      0.58      0.40      0.80    549.76      1.00\n",
            "    k_scale     19.08      9.91     16.54      7.12     31.91    915.50      1.00\n",
            "      noise      0.28      0.39      0.17      0.01      0.58    555.31      1.00\n",
            "\n"
          ]
        }
      ],
      "source": [
        "# Get random number generator keys (see JAX documentation for why it is neccessary)\n",
        "rng_key, rng_key_predict = gpax.utils.get_keys()\n",
        "\n",
        "# Initialize model\n",
        "gp_model = gpax.ExactGP(1, kernel='Matern')\n",
        "\n",
        "# Run HMC to obtain posterior samples\n",
        "gp_model.fit(rng_key, X, y, num_chains=1)\n",
        "\n",
        "# Get GP prediction\n",
        "posterior_mean, f_samples = gp_model.predict(rng_key_predict, X_test, n=200)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hzSJnqOH67Xm"
      },
      "source": [
        "Plot the results"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "lnxdYcLL67Xm",
        "outputId": "584a3a74-32e5-4f13-d3e5-0d2bcdf9cfe7",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 454
        }
      },
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "<Figure size 1200x400 with 1 Axes>"
            ],
            "image/png": "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Qoj6NumigsWJk6juSXZ5srKykJycXO34r776Cn///TfuuOMO9OrV62yZeEETEhKCm266qcL26gSKk4UJyU033YSQkJCzbmNd0rlzZ3z00UfK788//zx++umnao/h4jnM6VJcXIzrrrsOf/31V32bwjAMwzAMc0GTkpKC2bNn4/jx4wCAvXv34s8//6xnqy4uWJwoh91uVz5sAKp80njkyBEkJiaidevWiIuLw4IFCyqM2bZtG+655x4MHjwY7777bp3ZfCEyYsQIjBs3rsL2ygSKqoSJcePGYcSIEXVmY11y66234uGHHwZAYtgtt9xyWp0mMjIy8MQTT6BXr17o0aMHoqKi0LlzZ8yYMQOlpaWVHpOTk4OPPvoITz31VKX7P/vsM3Tr1g1dunRBVFSU0i3k999/BwAcOHAAYWFhPp1EoqKi8P777ytzFBQUoHHjxsr+Z599tsZrstvtmDlzJvr374++ffsiISEBzZo1w6RJk2p0jZKTk3H99dcjIiICVqsVffv2VaKXTmb37t0YMWIEOnXqhBYtWigdUm6//fZKx//8888YOXIk+vTpg9DQULRu3RrPP/88HA5HhbFbt27FhAkT8MILL0AIgWnTpiEsLAzNmzdHSkoKYmJifK5heHi4z2f/0KFDiI2NVfY/9NBDPvOvWbMGI0aMQI8ePdC6dWvExsbi9ttvV9LIJA8//LBP+lOXLl3QpUsXjBkzxmfcP//8gylTpmDVqlWVrv107suff/6JcePG4c477wQAbN68GYMGDYLVakVCQkKVHWOOHj2KsWPH4pJLLkGbNm1gMpmg0WjQv3//SsczDMMwDMPUJR6PBz///DMWLVoEu93us2/dunUoKyurJ8suQgQjhBAiLy9P3H333QKA8rr33ntFfn5+hbGHDx8WRqPRZ+yVV14pvv32W7FmzRoxZcoUERgYKB599FHhdDrrzObU1FTl/KmpqbU6NiUlRezevVukpKTUkXWnZtmyZWLYsGEVXsuWLavR/gsNAGLNmjVCCCHcbrcYMGCAcv969OhR4bOyZs0aUdU/0V9++UUEBweLu+66S5SVlQkhhCguLhb33HOPACBatWolDh06pIz/6aefxNVXXy30er0AIPr161dhzldeeUUYjUaxadMmZducOXOEVqtV7BZCiKKiItG6dWsBQOj1emG32yu1MTExUTz00EM1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0QOtW7dGbGwsbr/9dhw7dsxnXEZGBhYtWoS77roLSUlJ+O2333DkyBHcfffdSEhIgMlkQtu2bfHtt98CoP8s5s+fj8suuwxBQUEIDg7G3XffDbvdXsGG9PR0vPrqq5g4cSIA4IcffkDfvn1htVqVop55eXmndX327duHO++8EwMGDEBMTAwSEhJwzz33ID09vcpjFixYgJ49e+KSSy5B+/btMXHiROTm5p7W+U93bcnJyXjiiSdw3333AQA+/PBDxMbGIjY21qebhsfjwaxZszBkyBBceumlCAkJQa9evbBo0aIqbUpLS8M999yD1q1bo1OnTujdu7dy36o75q233sIbb7xR5ZitW7fihhtuQNeuXdGpUye0bNkSjz/+uM+1njVrFr755hvl9/Hjx6NLly7o0qULbDZbrc63fPlyDB8+HL1790bLli0RExOD66+/Hps2bap0/MGDB/H000+jc+fOAIBjx45h7NixCAsLQ0hICO666y4fGyRlZWWYNm0aLrnkElxyySUICAiARqOpv/xVhmEYhmlgFBUVYdGiRfj+++/hdDp99mVnZyuRxGcFt1t15D2eioUqy3fDkJTvqCG7bJSVAUVF6quwkLbLbhs6HYkIsmWowUDbZOSEFBFkdIYUKsq/L2+DEFULD3p9g+/WAcFcsKSmpgoAAoBITU2t1bEpKSli9+7dIiUlpY6sY8qzc+dOYbFYlPsFQLRr106sXbv2lMe+9NJLAoCYPHmy8Hq9QgghFixYIACIxo0bi+LiYmXsV199JR588EHlHA899JC46qqrxMKFC8W2bdvE448/LgAIvV4vfvvtNzF69GgxZ84csX37dvH111+LuLg4AUA8+OCDypzr168X/fr1E1qtVgAQ/fr1EzNmzBB6vV4kJiYKs9msnK9t27aioKCgwhrk/k8//bTCvhUrVoj27duL5ORkIYQQXq9XTJkyRQAQUVFRYv/+/T7jPR6PuO2220R4eLjYsGGDsn3+/PnC399fOVdNON21rV69WlxzzTXKvpEjR4oPP/xQREREKNumTJkihBCirKxMDB48WEybNk14PB4hBP37S0hIEADEY489VsGuv/76SwQHB4s777xTlJWVCSGESE9PF3379lVsmjZtmjJ+8eLFon///kKj0QgAYuzYsZWud8aMGSIxMVH88ccfyrYXX3xRABDh4eFi3759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
Download .txt
gitextract_po1u8joa/

├── .flake8
├── .github/
│   └── workflows/
│       ├── ci-deploy.yml
│       ├── ci.yml
│       ├── notebook_smoke.yml
│       └── unit.yml
├── .gitignore
├── .readthedocs.yml
├── LICENSE
├── README.md
├── docs/
│   ├── Makefile
│   ├── make.bat
│   ├── requirements_rtd.txt
│   └── source/
│       ├── LICENSE.rst
│       ├── README.rst
│       ├── USAGE.rst
│       ├── acquisition.rst
│       ├── conf.py
│       ├── examples.rst
│       ├── hypo.rst
│       ├── index.rst
│       ├── kernels.rst
│       ├── models.rst
│       ├── priors.rst
│       └── utils.rst
├── examples/
│   ├── GP_sGP.ipynb
│   ├── GPax_MultiTaskGP_BO.ipynb
│   ├── MeasuredNoiseGP.ipynb
│   ├── compare_GPs.ipynb
│   ├── contrib/
│   │   ├── cBO_1D_GPax_tutorial.ipynb
│   │   └── gpax_dkl_notebookIII_molecules.ipynb
│   ├── gpax_GPBO.ipynb
│   ├── gpax_UIGP.ipynb
│   ├── gpax_hypo.ipynb
│   ├── gpax_simpleGP.ipynb
│   ├── gpax_simpleGP_tutorial.ipynb
│   ├── gpax_viDKL_plasmons.ipynb
│   ├── gpax_viGP.ipynb
│   ├── heteroskedasticGP.ipynb
│   └── simpleGP.ipynb
├── gpax/
│   ├── __init__.py
│   ├── _version.py
│   ├── acquisition/
│   │   ├── __init__.py
│   │   ├── acquisition.py
│   │   ├── base_acq.py
│   │   ├── batch_acquisition.py
│   │   ├── optimize.py
│   │   └── penalties.py
│   ├── hypo.py
│   ├── kernels/
│   │   ├── __init__.py
│   │   ├── kernels.py
│   │   └── mtkernels.py
│   ├── models/
│   │   ├── __init__.py
│   │   ├── bnn.py
│   │   ├── corgp.py
│   │   ├── dkl.py
│   │   ├── gp.py
│   │   ├── hskgp.py
│   │   ├── ibnn.py
│   │   ├── linreg.py
│   │   ├── mngp.py
│   │   ├── mtgp.py
│   │   ├── sparse_gp.py
│   │   ├── spm.py
│   │   ├── uigp.py
│   │   ├── vgp.py
│   │   ├── vi_ibnn.py
│   │   ├── vi_mtdkl.py
│   │   ├── vidkl.py
│   │   └── vigp.py
│   ├── priors/
│   │   ├── __init__.py
│   │   └── priors.py
│   └── utils/
│       ├── __init__.py
│       ├── fn.py
│       └── utils.py
├── pyproject.toml
├── scripts/
│   ├── build.sh
│   ├── install.sh
│   └── test_notebooks.sh
└── tests/
    ├── __init__.py
    ├── test_acq.py
    ├── test_bnn.py
    ├── test_corgp.py
    ├── test_dkl.py
    ├── test_func_setter.py
    ├── test_gp.py
    ├── test_hskgp.py
    ├── test_hypo.py
    ├── test_ibnn.py
    ├── test_kernels.py
    ├── test_mngp.py
    ├── test_mtgp.py
    ├── test_optimize_acq.py
    ├── test_priors.py
    ├── test_sparsegp.py
    ├── test_spm.py
    ├── test_uigp.py
    ├── test_utils.py
    ├── test_vgp.py
    ├── test_vidkl.py
    ├── test_vigp.py
    └── test_vimtdkl.py
Download .txt
SYMBOL INDEX (447 symbols across 50 files)

FILE: gpax/acquisition/acquisition.py
  function _compute_mean_and_var (line 22) | def _compute_mean_and_var(
  function _compute_penalties (line 38) | def _compute_penalties(
  function EI (line 49) | def EI(rng_key: jnp.ndarray, model: Type[ExactGP],
  function UCB (line 143) | def UCB(rng_key: jnp.ndarray, model: Type[ExactGP],
  function POI (line 227) | def POI(rng_key: jnp.ndarray, model: Type[ExactGP],
  function UE (line 314) | def UE(rng_key: jnp.ndarray, model: Type[ExactGP],
  function KG (line 397) | def KG(rng_key: jnp.ndarray,
  function Thompson (line 488) | def Thompson(rng_key: jnp.ndarray,

FILE: gpax/acquisition/base_acq.py
  function ei (line 20) | def ei(moments: Tuple[jnp.ndarray, jnp.ndarray],
  function ucb (line 74) | def ucb(moments: Tuple[jnp.ndarray, jnp.ndarray],
  function ue (line 109) | def ue(moments: Tuple[jnp.ndarray, jnp.ndarray], **kwargs) -> jnp.ndarray:
  function poi (line 134) | def poi(moments: Tuple[jnp.ndarray, jnp.ndarray],
  function kg (line 158) | def kg(model: Type[ExactGP],

FILE: gpax/acquisition/batch_acquisition.py
  function _compute_batch_acquisition (line 21) | def _compute_batch_acquisition(
  function qEI (line 62) | def qEI(rng_key: jnp.ndarray,
  function qUCB (line 119) | def qUCB(rng_key: jnp.ndarray,
  function qPOI (line 176) | def qPOI(rng_key: jnp.ndarray,
  function qKG (line 233) | def qKG(rng_key: jnp.ndarray,

FILE: gpax/acquisition/optimize.py
  function optimize_acq (line 19) | def optimize_acq(rng_key: jnp.ndarray,
  function ensure_array (line 91) | def ensure_array(x):

FILE: gpax/acquisition/penalties.py
  function compute_penalty (line 6) | def compute_penalty(X: jnp.ndarray, recent_points: jnp.ndarray,
  function penalty_point (line 37) | def penalty_point(x: jnp.ndarray, recent_points: jnp.ndarray) -> jnp.nda...
  function find_and_replace_point_indices (line 53) | def find_and_replace_point_indices(points, other_points):

FILE: gpax/hypo.py
  function step (line 21) | def step(model: Callable[[jnp.ndarray, Dict[str, jnp.ndarray]], jnp.ndar...
  function sample_next (line 102) | def sample_next(rewards: Union[np.array, jnp.array],
  function softmax (line 134) | def softmax(logits: Union[np.array, jnp.array],
  function eps_greedy (line 146) | def eps_greedy(rewards: Union[np.array, jnp.array],
  function update_record (line 159) | def update_record(record: np.array, action: int, r: Union[int, float]) -...

FILE: gpax/kernels/kernels.py
  function _sqrt (line 20) | def _sqrt(x, eps=1e-12):
  function add_jitter (line 24) | def add_jitter(x, jitter=1e-6):
  function square_scaled_distance (line 28) | def square_scaled_distance(X: jnp.ndarray, Z: jnp.ndarray,
  function RBFKernel (line 45) | def RBFKernel(X: jnp.ndarray, Z: jnp.ndarray,
  function MaternKernel (line 69) | def MaternKernel(X: jnp.ndarray, Z: jnp.ndarray,
  function PeriodicKernel (line 95) | def PeriodicKernel(X: jnp.ndarray, Z: jnp.ndarray,
  function nngp_erf (line 120) | def nngp_erf(x1: jnp.ndarray, x2: jnp.ndarray,
  function nngp_relu (line 153) | def nngp_relu(x1: jnp.ndarray, x2: jnp.ndarray,
  function NNGPKernel (line 186) | def NNGPKernel(activation: str = 'erf', depth: int = 3
  function get_kernel (line 227) | def get_kernel(kernel: Union[str, kernel_fn_type] = 'RBF', **kwargs):

FILE: gpax/kernels/mtkernels.py
  function index_kernel (line 24) | def index_kernel(indices1, indices2, params):
  function MultitaskKernel (line 66) | def MultitaskKernel(base_kernel, **kwargs1):
  function MultivariateKernel (line 130) | def MultivariateKernel(base_kernel, num_tasks, **kwargs1):
  function LCMKernel (line 197) | def LCMKernel(base_kernel, shared_input_space=True, num_tasks=None, **kw...

FILE: gpax/models/bnn.py
  class BNN (line 19) | class BNN(sPM):
    method __init__ (line 21) | def __init__(self,
    method _set_data (line 31) | def _set_data(self, X: jnp.ndarray, y: Optional[jnp.ndarray] = None
  function sample_weights (line 40) | def sample_weights(name: str, in_channels: int, out_channels: int) -> jn...
  function sample_biases (line 48) | def sample_biases(name: str, channels: int) -> jnp.ndarray:
  function get_mlp (line 55) | def get_mlp(architecture: List[int]) -> Callable[[jnp.ndarray, Dict[str,...
  function get_mlp_prior (line 68) | def get_mlp_prior(input_dim: int, output_dim: int, architecture: List[in...

FILE: gpax/models/corgp.py
  class CoregGP (line 12) | class CoregGP(ExactGP):
    method __init__ (line 38) | def __init__(self, input_dim: int, data_kernel: str,
    method model (line 54) | def model(self,
    method _sample_task_kernel_params (line 105) | def _sample_task_kernel_params(self, n_tasks, rank):

FILE: gpax/models/dkl.py
  class DKL (line 22) | class DKL(ExactGP):
    method __init__ (line 69) | def __init__(self, input_dim: int, z_dim: int = 2, kernel: str = 'RBF',
    method model (line 83) | def model(self,
    method get_mvn_posterior (line 113) | def get_mvn_posterior(self,
    method embed (line 135) | def embed(self, X_new: jnp.ndarray) -> jnp.ndarray:
    method _print_summary (line 145) | def _print_summary(self):
  function sample_weights (line 152) | def sample_weights(name: str, in_channels: int, out_channels: int) -> jn...
  function sample_biases (line 160) | def sample_biases(name: str, channels: int) -> jnp.ndarray:
  function get_mlp (line 167) | def get_mlp(architecture: List[int]) -> Callable[[jnp.ndarray, Dict[str,...
  function get_mlp_prior (line 180) | def get_mlp_prior(input_dim: int, output_dim: int, architecture: List[in...

FILE: gpax/models/gp.py
  class ExactGP (line 29) | class ExactGP:
    method __init__ (line 96) | def __init__(
    method model (line 137) | def model(self, X: jnp.ndarray, y: jnp.ndarray = None, **kwargs: float...
    method fit (line 166) | def fit(
    method _sample_noise (line 222) | def _sample_noise(self) -> jnp.ndarray:
    method _sample_kernel_params (line 229) | def _sample_kernel_params(self, output_scale=True) -> Dict[str, jnp.nd...
    method get_samples (line 249) | def get_samples(self, chain_dim: bool = False) -> Dict[str, jnp.ndarray]:
    method get_mvn_posterior (line 253) | def get_mvn_posterior(
    method _predict (line 279) | def _predict(
    method _predict_in_batches (line 295) | def _predict_in_batches(
    method predict_in_batches (line 325) | def predict_in_batches(
    method predict (line 351) | def predict(
    method sample_from_prior (line 401) | def sample_from_prior(self, rng_key: jnp.ndarray, X: jnp.ndarray, num_...
    method _set_data (line 410) | def _set_data(self, X: jnp.ndarray, y: Optional[jnp.ndarray] = None) -...
    method _set_training_data (line 416) | def _set_training_data(
    method _print_summary (line 430) | def _print_summary(self):

FILE: gpax/models/hskgp.py
  class VarNoiseGP (line 24) | class VarNoiseGP(ExactGP):
    method __init__ (line 81) | def __init__(
    method model (line 105) | def model(self, X: jnp.ndarray, y: jnp.ndarray = None, **kwargs: float...
    method _sample_noise_kernel_params (line 151) | def _sample_noise_kernel_params(self) -> Dict[str, jnp.ndarray]:
    method get_mvn_posterior (line 163) | def get_mvn_posterior(
    method get_data_var_samples (line 206) | def get_data_var_samples(self):
    method _print_summary (line 218) | def _print_summary(self):

FILE: gpax/models/ibnn.py
  class iBNN (line 20) | class iBNN(ExactGP):
    method __init__ (line 42) | def __init__(self, input_dim: int, depth: int = 3, activation: str = '...
    method _sample_kernel_params (line 54) | def _sample_kernel_params(self) -> Dict[str, jnp.ndarray]:

FILE: gpax/models/linreg.py
  class LinReg (line 9) | class LinReg:
    method __init__ (line 11) | def __init__(self):
    method model (line 15) | def model(x, y=None):
    method train (line 24) | def train(self, x, y, learning_rate=0.01, num_iterations=5000):
    method predict (line 32) | def predict(self, x_new):
    method get_params (line 38) | def get_params(self):

FILE: gpax/models/mngp.py
  class MeasuredNoiseGP (line 29) | class MeasuredNoiseGP(ExactGP):
    method __init__ (line 61) | def __init__(self,
    method model (line 74) | def model(self, X: jnp.ndarray, y: jnp.ndarray = None, measured_noise:...
    method fit (line 100) | def fit(
    method _predict (line 159) | def _predict(
    method predict (line 184) | def predict(
    method linreg (line 248) | def linreg(self, x, y, x_new, **kwargs):
    method gpreg (line 253) | def gpreg(self, x, y, x_new, **kwargs):

FILE: gpax/models/mtgp.py
  class MultiTaskGP (line 12) | class MultiTaskGP(ExactGP):
    method __init__ (line 57) | def __init__(self, input_dim: int, data_kernel: str,
    method model (line 92) | def model(self,
    method _sample_noise (line 147) | def _sample_noise(self):
    method _sample_task_kernel_params (line 159) | def _sample_task_kernel_params(self):
    method _sample_kernel_params (line 183) | def _sample_kernel_params(self):

FILE: gpax/models/sparse_gp.py
  class viSparseGP (line 25) | class viSparseGP(viGP):
    method __init__ (line 49) | def __init__(self, input_dim: int, kernel: str,
    method model (line 62) | def model(self,
    method fit (line 116) | def fit(self,
    method get_mvn_posterior (line 173) | def get_mvn_posterior(self, X_new: jnp.ndarray,

FILE: gpax/models/spm.py
  class sPM (line 29) | class sPM:
    method __init__ (line 44) | def __init__(self,
    method model (line 63) | def model(self, X: jnp.ndarray, y: jnp.ndarray = None) -> None:
    method _sample_noise (line 79) | def _sample_noise(self) -> jnp.ndarray:
    method fit (line 86) | def fit(self, rng_key: jnp.array, X: jnp.ndarray, y: jnp.ndarray,
    method get_samples (line 127) | def get_samples(self, chain_dim: bool = False) -> Dict[str, jnp.ndarray]:
    method get_param_means (line 131) | def get_param_means(self):
    method sample_from_prior (line 141) | def sample_from_prior(self, rng_key: jnp.ndarray,
    method sample_single_posterior_predictive (line 150) | def sample_single_posterior_predictive(self, rng_key, X_new, params, n...
    method _vmap_predict (line 156) | def _vmap_predict(self, rng_key: jnp.ndarray, X_new: jnp.ndarray,
    method predict (line 173) | def predict(self, rng_key: jnp.ndarray, X_new: jnp.ndarray,
    method _print_summary (line 210) | def _print_summary(self):
    method _set_data (line 213) | def _set_data(self,

FILE: gpax/models/uigp.py
  class UIGP (line 22) | class UIGP(ExactGP):
    method __init__ (line 63) | def __init__(self,
    method model (line 78) | def model(self, X: jnp.ndarray, y: jnp.ndarray = None, **kwargs: float...
    method _sample_x (line 113) | def _sample_x(self, X: jnp.ndarray) -> jnp.ndarray:
    method get_mvn_posterior (line 131) | def get_mvn_posterior(
    method _predict (line 158) | def _predict(
    method _set_data (line 177) | def _set_data(self, X: jnp.ndarray, y: Optional[jnp.ndarray] = None) -...
    method _print_summary (line 192) | def _print_summary(self):

FILE: gpax/models/vgp.py
  class vExactGP (line 23) | class vExactGP(ExactGP):
    method __init__ (line 42) | def __init__(self, input_dim: int, kernel: str,
    method model (line 55) | def model(self,
    method _sample_noise (line 92) | def _sample_noise(self, task_dim) -> jnp.ndarray:
    method _sample_kernel_params (line 101) | def _sample_kernel_params(self, task_dim: int = None) -> Dict[str, jnp...
    method _get_mvn_posterior (line 123) | def _get_mvn_posterior(self,
    method get_mvn_posterior (line 147) | def get_mvn_posterior(self,
    method predict_in_batches (line 175) | def predict_in_batches(self, rng_key: jnp.ndarray,
    method _set_data (line 198) | def _set_data(self,

FILE: gpax/models/vi_ibnn.py
  class vi_iBNN (line 20) | class vi_iBNN(viGP):
    method __init__ (line 43) | def __init__(self, input_dim: int, depth: int = 3, activation: str = '...
    method _sample_kernel_params (line 53) | def _sample_kernel_params(self) -> Dict[str, jnp.ndarray]:

FILE: gpax/models/vi_mtdkl.py
  class viMTDKL (line 25) | class viMTDKL(viDKL):
    method __init__ (line 75) | def __init__(self, input_dim: int, z_dim: int = 2, data_kernel: str = ...
    method model (line 104) | def model(self, X: jnp.ndarray, y: jnp.ndarray = None, **kwargs) -> None:
    method _sample_noise (line 163) | def _sample_noise(self):
    method _sample_task_kernel_params (line 175) | def _sample_task_kernel_params(self):
    method _sample_kernel_params (line 199) | def _sample_kernel_params(self):
    method get_mvn_posterior (line 212) | def get_mvn_posterior(self,

FILE: gpax/models/vidkl.py
  class viDKL (line 27) | class viDKL(ExactGP):
    method __init__ (line 71) | def __init__(self, input_dim: Union[int, Tuple[int]], z_dim: int = 2, ...
    method model (line 90) | def model(self, X: jnp.ndarray, y: jnp.ndarray = None, **kwargs) -> None:
    method single_fit (line 126) | def single_fit(self, rng_key: jnp.array, X: jnp.ndarray, y: jnp.ndarray,
    method fit (line 163) | def fit(self, rng_key: jnp.array, X: jnp.ndarray, y: jnp.ndarray,
    method get_mvn_posterior (line 206) | def get_mvn_posterior(self,
    method sample_from_posterior (line 238) | def sample_from_posterior(self, rng_key: jnp.ndarray,
    method get_samples (line 253) | def get_samples(self) -> Tuple[Dict['str', jnp.ndarray]]:
    method predict_in_batches (line 257) | def predict_in_batches(self, rng_key: jnp.ndarray,
    method predict (line 277) | def predict(self, rng_key: jnp.ndarray, X_new: jnp.ndarray,
    method fit_predict (line 320) | def fit_predict(self, rng_key: jnp.array, X: jnp.ndarray, y: jnp.ndarray,
    method embed (line 372) | def embed(self, X_new: jnp.ndarray) -> jnp.ndarray:
    method _print_summary (line 386) | def _print_summary(self) -> None:
  class MLP (line 400) | class MLP(hk.Module):
    method __init__ (line 402) | def __init__(self, embedim=2):
    method __call__ (line 406) | def __call__(self, x):

FILE: gpax/models/vigp.py
  class viGP (line 23) | class viGP(ExactGP):
    method __init__ (line 61) | def __init__(self, input_dim: int, kernel: str,
    method fit (line 77) | def fit(self, rng_key: jnp.array, X: jnp.ndarray, y: jnp.ndarray,
    method get_samples (line 125) | def get_samples(self) -> Dict[str, jnp.ndarray]:
    method predict_in_batches (line 129) | def predict_in_batches(self, rng_key: jnp.ndarray,
    method predict (line 153) | def predict(self, rng_key: jnp.ndarray, X_new: jnp.ndarray,
    method _print_summary (line 187) | def _print_summary(self) -> None:

FILE: gpax/priors/priors.py
  function place_normal_prior (line 18) | def place_normal_prior(param_name: str, loc: float = 0.0, scale: float =...
  function place_lognormal_prior (line 27) | def place_lognormal_prior(param_name: str, loc: float = 0.0, scale: floa...
  function place_halfnormal_prior (line 36) | def place_halfnormal_prior(param_name: str, scale: float = 1.0):
  function place_uniform_prior (line 45) | def place_uniform_prior(param_name: str,
  function place_gamma_prior (line 58) | def place_gamma_prior(param_name: str,
  function normal_dist (line 71) | def normal_dist(loc: float = None, scale: float = None
  function lognormal_dist (line 93) | def lognormal_dist(loc: float = None, scale: float = None) -> numpyro.di...
  function halfnormal_dist (line 114) | def halfnormal_dist(scale: float = None) -> numpyro.distributions.Distri...
  function gamma_dist (line 134) | def gamma_dist(c: float = None,
  function uniform_dist (line 164) | def uniform_dist(low: float = None,
  function auto_priors (line 192) | def auto_priors(func: Callable, params_begin_with: int, dist_type: str =...
  function auto_normal_priors (line 219) | def auto_normal_priors(func: Callable, loc: float = 0.0, scale: float = ...
  function auto_lognormal_priors (line 235) | def auto_lognormal_priors(func: Callable, loc: float = 0.0, scale: float...
  function auto_normal_kernel_priors (line 251) | def auto_normal_kernel_priors(kernel_fn: Callable, loc: float = 0.0, sca...
  function auto_lognormal_kernel_priors (line 267) | def auto_lognormal_kernel_priors(kernel_fn: Callable, loc: float = 0.0, ...

FILE: gpax/utils/fn.py
  function set_fn (line 21) | def set_fn(func: Callable) -> Callable:
  function set_kernel_fn (line 58) | def set_kernel_fn(func: Callable,
  function _set_noise_kernel_fn (line 119) | def _set_noise_kernel_fn(func: Callable) -> Callable:

FILE: gpax/utils/utils.py
  function enable_x64 (line 19) | def enable_x64():
  function get_keys (line 24) | def get_keys(seed: int = 0):
  function split_in_batches (line 33) | def split_in_batches(X_new: Union[onp.ndarray, jnp.ndarray],
  function split_dict (line 54) | def split_dict(data: Dict[str, jnp.ndarray], chunk_size: int
  function random_sample_dict (line 84) | def random_sample_dict(data: Dict[str, jnp.ndarray],
  function get_haiku_dict (line 105) | def get_haiku_dict(kernel_params: Dict[str, jnp.ndarray]) -> Dict[str, D...
  function dviz (line 126) | def dviz(d: Type[numpyro.distributions.Distribution], samples: int = 100...
  function preprocess_sparse_image (line 150) | def preprocess_sparse_image(sparse_image):
  function initialize_inducing_points (line 171) | def initialize_inducing_points(X, ratio=0.1, method='uniform', key=None):

FILE: tests/test_acq.py
  class mock_GP (line 22) | class mock_GP:
    method __init__ (line 23) | def __init__(self):
    method get_samples (line 26) | def get_samples(self):
  function test_base_standard_acq (line 35) | def test_base_standard_acq(base_acq):
  function test_base_acq_kg (line 45) | def test_base_acq_kg():
  function test_base_standard_acq_maximize (line 60) | def test_base_standard_acq_maximize(base_acq):
  function test_base_standard_acq_best_f (line 70) | def test_base_standard_acq_best_f(base_acq):
  function test_compute_mean_and_var (line 80) | def test_compute_mean_and_var():
  function test_acq_gp (line 94) | def test_acq_gp(acq):
  function test_acq_vidkl (line 107) | def test_acq_vidkl(acq):
  function test_acq_dkl (line 120) | def test_acq_dkl(acq):
  function test_UCB_beta (line 131) | def test_UCB_beta():
  function test_EI_gp_penalty_inv_distance (line 145) | def test_EI_gp_penalty_inv_distance():
  function test_UCB_gp_penalty_inv_distance (line 159) | def test_UCB_gp_penalty_inv_distance():
  function test_UE_gp_penalty_inv_distance (line 173) | def test_UE_gp_penalty_inv_distance():
  function test_compute_batch_acquisition (line 188) | def test_compute_batch_acquisition(maximize_distance):
  function test_batched_acq_gp (line 202) | def test_batched_acq_gp(acq, q):
  function test_acq_penalty_indices (line 215) | def test_acq_penalty_indices(acq, pen):
  function test_compute_penalty_delta (line 232) | def test_compute_penalty_delta():
  function test_compute_penalty_inverse_distance (line 240) | def test_compute_penalty_inverse_distance():
  function test_acq_error (line 250) | def test_acq_error(acq_func):

FILE: tests/test_bnn.py
  function get_dummy_data (line 15) | def get_dummy_data(feature_dim=1, target_dim=1, squeezed=False):
  function test_bnn_fit (line 23) | def test_bnn_fit():
  function test_bnn_custom_layers_fit (line 31) | def test_bnn_custom_layers_fit():
  function test_bnn_predict_with_samples (line 47) | def test_bnn_predict_with_samples():
  function test_bnn_custom_layers_predict_custom_with_samples (line 66) | def test_bnn_custom_layers_predict_custom_with_samples():
  function test_bnn_fit_predict (line 90) | def test_bnn_fit_predict(feature_dim, target_dim, squeezed):

FILE: tests/test_corgp.py
  function get_dummy_data (line 14) | def get_dummy_data():
  function attach_indices (line 20) | def attach_indices(X, num_tasks):
  function dummy_mean_fn (line 25) | def dummy_mean_fn(x, params):
  function dummy_mean_fn_priors (line 29) | def dummy_mean_fn_priors():
  function test_fit_corgp (line 37) | def test_fit_corgp(data_kernel, num_tasks):
  function test_fit_corgp_meanfn (line 46) | def test_fit_corgp_meanfn():

FILE: tests/test_dkl.py
  function get_dummy_data (line 14) | def get_dummy_data(jax_ndarray=True):
  function test_fit (line 23) | def test_fit(jax_ndarray):
  function test_get_mvn_posterior (line 31) | def test_get_mvn_posterior():
  function test_get_mvn_posterior_noiseless (line 54) | def test_get_mvn_posterior_noiseless():
  function test_jitter_fit (line 79) | def test_jitter_fit():
  function test_jitter_mvn_posterior (line 95) | def test_jitter_mvn_posterior():

FILE: tests/test_func_setter.py
  function linear_kernel_test (line 11) | def linear_kernel_test(X, Z, k_scale):
  function rbf_test (line 16) | def rbf_test(X, Z, k_length, k_scale):
  function sample_function (line 28) | def sample_function(x, a, b):
  function test_set_fn (line 32) | def test_set_fn():
  function test_set_kernel_fn (line 38) | def test_set_kernel_fn():
  function test_set_kernel_fn_with_jitter (line 54) | def test_set_kernel_fn_with_jitter():
  function test_set_noise_kernel_fn (line 71) | def test_set_noise_kernel_fn():

FILE: tests/test_gp.py
  function get_dummy_data (line 15) | def get_dummy_data(jax_ndarray=True, unsqueeze=False):
  function dummy_mean_fn (line 25) | def dummy_mean_fn(x, params):
  function dummy_mean_fn_priors (line 29) | def dummy_mean_fn_priors():
  function gp_kernel_custom_prior (line 35) | def gp_kernel_custom_prior():
  function test_fit (line 44) | def test_fit(kernel, jax_ndarray, unsqueeze):
  function test_get_samples (line 54) | def test_get_samples(kernel, jax_ndarray):
  function test_get_samples_chain_dim (line 68) | def test_get_samples_chain_dim(chain_dim, samples_dim):
  function test_sample_kernel (line 80) | def test_sample_kernel(kernel):
  function test_sample_periodic_kernel (line 91) | def test_sample_periodic_kernel():
  function test_sample_noise (line 101) | def test_sample_noise():
  function test_sample_noise_custom_prior (line 108) | def test_sample_noise_custom_prior():
  function test_sample_kernel_custom_lscale_prior (line 119) | def test_sample_kernel_custom_lscale_prior():
  function test_fit_with_custom_kernel_priors (line 131) | def test_fit_with_custom_kernel_priors(kernel):
  function test_get_mvn_posterior (line 139) | def test_get_mvn_posterior():
  function test_get_mvn_posterior_noiseless (line 155) | def test_get_mvn_posterior_noiseless():
  function test_single_sample_prediction (line 173) | def test_single_sample_prediction():
  function test_prediction (line 192) | def test_prediction(unsqueeze, n):
  function test_noiseless_prediction (line 209) | def test_noiseless_prediction():
  function test_prediction_in_batches (line 227) | def test_prediction_in_batches(batch_size, n):
  function test_fit_predict (line 245) | def test_fit_predict(kernel):
  function test_fit_predict_in_batches (line 259) | def test_fit_predict_in_batches(n):
  function test_fit_noiseless_predict_in_batches (line 273) | def test_fit_noiseless_predict_in_batches(n):
  function test_fit_with_mean_fn (line 286) | def test_fit_with_mean_fn(jax_ndarray):
  function test_fit_with_prob_mean_fn (line 295) | def test_fit_with_prob_mean_fn(jax_ndarray):
  function test_fit_predict_with_mean_fn (line 303) | def test_fit_predict_with_mean_fn():
  function test_fit_predict_with_prob_mean_fn (line 316) | def test_fit_predict_with_prob_mean_fn():
  function test_sample_from_prior (line 329) | def test_sample_from_prior():
  function test_jitter_fit (line 337) | def test_jitter_fit():
  function test_jitter_predict (line 353) | def test_jitter_predict():

FILE: tests/test_hskgp.py
  function get_dummy_data (line 16) | def get_dummy_data(unsqueeze=False):
  function noise_fn (line 24) | def noise_fn(x, params):
  function noise_fn_prior (line 28) | def noise_fn_prior():
  function test_fit (line 35) | def test_fit(noise_kernel):
  function test_fit_with_custom_noise_lscale (line 43) | def test_fit_with_custom_noise_lscale():
  function test_fit_with_noise_mean_fn (line 51) | def test_fit_with_noise_mean_fn():
  function test_fit_with_noise_and_regular_mean_fn (line 59) | def test_fit_with_noise_and_regular_mean_fn():
  function test_get_mvn_posterior (line 68) | def test_get_mvn_posterior():
  function test_get_mvn_posterior_with_mean_fn (line 87) | def test_get_mvn_posterior_with_mean_fn():
  function test_get_mvn_posterior_with_noise_and_regular_mean_fn (line 109) | def test_get_mvn_posterior_with_noise_and_regular_mean_fn():
  function test_get_noise_samples (line 133) | def test_get_noise_samples():
  function test_get_noise_samples_with_mean_fn (line 142) | def test_get_noise_samples_with_mean_fn():

FILE: tests/test_hypo.py
  function get_dummy_data (line 13) | def get_dummy_data(jax_ndarray=True):
  function model (line 21) | def model(x, params):
  function model_priors (line 25) | def model_priors():
  function test_sample_next (line 32) | def test_sample_next(method):
  function test_step (line 39) | def test_step(gp_wrap):

FILE: tests/test_ibnn.py
  function get_dummy_data (line 14) | def get_dummy_data(jax_ndarray=True, unsqueeze=False):
  function test_ibnn_fit_predict (line 26) | def test_ibnn_fit_predict(activation, depth):
  function test_viibnn_fit_predict (line 41) | def test_viibnn_fit_predict(activation, depth):

FILE: tests/test_kernels.py
  function test_data_kernel_shapes (line 16) | def test_data_kernel_shapes(kernel, dim):
  function test_periodkernel_shapes (line 25) | def test_periodkernel_shapes(dim):
  function test_data_kernel_ard_shapes (line 35) | def test_data_kernel_ard_shapes(kernel, dim):
  function test_index_kernel_shapes (line 43) | def test_index_kernel_shapes():
  function test_index_kernel_shapes_uneven_obs (line 51) | def test_index_kernel_shapes_uneven_obs():
  function test_index_kernel_computations (line 59) | def test_index_kernel_computations():
  function test_nngp_shapes (line 71) | def test_nngp_shapes(kernel, dim, depth):
  function test_NNGPKernel (line 83) | def test_NNGPKernel(activation, dim, depth):
  function test_NNGPKernel_activations (line 92) | def test_NNGPKernel_activations():
  function test_MultiTaskKernel (line 103) | def test_MultiTaskKernel():
  function test_multitask_kernel_shapes_test_noiseless (line 111) | def test_multitask_kernel_shapes_test_noiseless(data_kernel, dim):
  function test_multitask_kernel_shapes_test_noisy (line 126) | def test_multitask_kernel_shapes_test_noisy(data_kernel, dim):
  function test_multitask_kernel_shapes_train (line 142) | def test_multitask_kernel_shapes_train(data_kernel, dim):
  function test_MultiVariateKernel (line 156) | def test_MultiVariateKernel():
  function test_multivariate_kernel_shapes_test_noisy (line 167) | def test_multivariate_kernel_shapes_test_noisy(data_kernel, dim, num_tas...
  function test_multivariate_kernel_shapes_test_noiseless (line 182) | def test_multivariate_kernel_shapes_test_noiseless(data_kernel, dim, num...
  function test_multivariate_kernel_shapes_train (line 196) | def test_multivariate_kernel_shapes_train(data_kernel, dim, num_tasks, r...
  function test_LCMKernel (line 207) | def test_LCMKernel():
  function test_LCMKernel_shapes_multitask (line 216) | def test_LCMKernel_shapes_multitask(data_kernel, dim, num_latent):
  function test_LCMKernel_shapes_multivariate (line 235) | def test_LCMKernel_shapes_multivariate(data_kernel, dim, num_latent, ran...

FILE: tests/test_mngp.py
  function variable_noise (line 16) | def variable_noise(x):
  function get_dummy_data (line 19) | def get_dummy_data():
  function test_fit (line 28) | def test_fit():
  function test_get_mvn_posterior (line 36) | def test_get_mvn_posterior():
  function test_predict_single_sample (line 57) | def test_predict_single_sample(n):
  function test_predict (line 80) | def test_predict(noise_pred_fn):

FILE: tests/test_mtgp.py
  function get_dummy_data (line 14) | def get_dummy_data():
  function attach_indices (line 20) | def attach_indices(X, num_tasks):
  function dummy_mean_fn (line 25) | def dummy_mean_fn(x, params):
  function dummy_mean_fn_priors (line 29) | def dummy_mean_fn_priors():
  function test_fit_multitask (line 38) | def test_fit_multitask(data_kernel, num_tasks, num_latents):
  function test_fit_multivariate (line 50) | def test_fit_multivariate(data_kernel, num_tasks, num_latents):
  function test_fit_multitask_meanfn (line 61) | def test_fit_multitask_meanfn():
  function test_sample_kernel_custom_lscale_prior (line 71) | def test_sample_kernel_custom_lscale_prior():
  function test_sample_task_kernel_custom_W_prior (line 83) | def test_sample_task_kernel_custom_W_prior():
  function test_sample_task_kernel_custom_v_prior (line 95) | def test_sample_task_kernel_custom_v_prior():

FILE: tests/test_optimize_acq.py
  function get_inputs (line 15) | def get_inputs():
  function test_optimize_acq (line 22) | def test_optimize_acq(acq_fn):

FILE: tests/test_priors.py
  function linear_kernel_test (line 14) | def linear_kernel_test(X, Z, k_scale):
  function sample_function (line 19) | def sample_function(x, a, b):
  function test_normal_prior (line 24) | def test_normal_prior(prior):
  function test_uniform_prior (line 30) | def test_uniform_prior():
  function test_gamma_prior (line 36) | def test_gamma_prior():
  function test_normal_prior_params (line 42) | def test_normal_prior_params():
  function test_lognormal_prior_params (line 52) | def test_lognormal_prior_params():
  function test_halfnormal_prior_params (line 62) | def test_halfnormal_prior_params():
  function test_uniform_prior_params (line 71) | def test_uniform_prior_params():
  function test_gamma_prior_params (line 81) | def test_gamma_prior_params():
  function test_get_uniform_dist (line 91) | def test_get_uniform_dist():
  function test_get_uniform_dist_infer_params (line 98) | def test_get_uniform_dist_infer_params():
  function test_get_gamma_dist (line 104) | def test_get_gamma_dist():
  function test_get_normal_dist (line 111) | def test_get_normal_dist():
  function test_get_lognormal_dist (line 118) | def test_get_lognormal_dist():
  function test_get_halfnormal_dist (line 125) | def test_get_halfnormal_dist():
  function test_get_gamma_dist_infer_param (line 131) | def test_get_gamma_dist_infer_param():
  function test_get_uniform_dist_error (line 138) | def test_get_uniform_dist_error():
  function test_get_gamma_dist_error (line 147) | def test_get_gamma_dist_error():
  function test_auto_priors (line 153) | def test_auto_priors(prior_type):
  function test_auto_normal_priors (line 169) | def test_auto_normal_priors(autopriors):
  function test_auto_normal_kernel_priors (line 179) | def test_auto_normal_kernel_priors(autopriors):

FILE: tests/test_sparsegp.py
  function get_dummy_data (line 16) | def get_dummy_data(jax_ndarray=True, unsqueeze=False):
  function test_fit (line 28) | def test_fit(jax_ndarray, unsqueeze):
  function test_inducing_points_optimization (line 37) | def test_inducing_points_optimization():
  function test_get_mvn_posterior (line 47) | def test_get_mvn_posterior():

FILE: tests/test_spm.py
  function get_dummy_data (line 15) | def get_dummy_data(jax_ndarray=True):
  function model (line 23) | def model(x, params):
  function model_priors (line 27) | def model_priors():
  function test_fit (line 34) | def test_fit(jax_ndarray):
  function test_get_samples (line 42) | def test_get_samples():
  function test_prediction (line 55) | def test_prediction():
  function test_fit_predict (line 70) | def test_fit_predict():

FILE: tests/test_uigp.py
  function get_dummy_data (line 16) | def get_dummy_data():
  function test_sample_x (line 24) | def test_sample_x(n_features):
  function test_fit (line 33) | def test_fit():
  function test_fit_with_custom_sigma_x_prior (line 41) | def test_fit_with_custom_sigma_x_prior():
  function test_get_mvn_posterior (line 49) | def test_get_mvn_posterior():
  function test_predict_single_sample (line 72) | def test_predict_single_sample(noiseless):

FILE: tests/test_utils.py
  function test_sparse_img_processing (line 15) | def test_sparse_img_processing():
  function test_split_dict (line 33) | def test_split_dict():
  function test_random_sample_size (line 56) | def test_random_sample_size():
  function test_random_sample_consistency (line 69) | def test_random_sample_consistency():
  function test_random_sample_difference (line 84) | def test_random_sample_difference():
  function test_get_keys (line 99) | def test_get_keys():
  function test_get_keys_different_seeds (line 105) | def test_get_keys_different_seeds():
  function test_ratio_out_of_bounds (line 112) | def test_ratio_out_of_bounds():
  function test_invalid_method (line 120) | def test_invalid_method():
  function test_missing_key_for_random_method (line 126) | def test_missing_key_for_random_method():
  function test_output_shape (line 133) | def test_output_shape(method):
  function test_kmeans_dependency (line 143) | def test_kmeans_dependency():

FILE: tests/test_vgp.py
  function get_dummy_data (line 15) | def get_dummy_data(jax_ndarray=True, unsqueeze=False):
  function test_fit (line 29) | def test_fit(kernel, jax_ndarray, unsqueeze):
  function test_get_samples (line 39) | def test_get_samples(kernel, jax_ndarray):
  function test_get_samples_chain_dim (line 53) | def test_get_samples_chain_dim(chain_dim, samples_dim):
  function test_sample_kernel (line 65) | def test_sample_kernel(kernel):
  function test_sample_periodic_kernel (line 76) | def test_sample_periodic_kernel():
  function test_sample_noise (line 86) | def test_sample_noise():
  function test_sample_noise_custom_prior (line 93) | def test_sample_noise_custom_prior():
  function test_get_mvn_posterior (line 104) | def test_get_mvn_posterior():
  function test_get_mvn_posterior_noiseless (line 120) | def test_get_mvn_posterior_noiseless():
  function test_prediction (line 139) | def test_prediction(n):
  function test_fit_predict_in_batches (line 157) | def test_fit_predict_in_batches(n):
  function test_fit_predict_in_batches_noiseless (line 172) | def test_fit_predict_in_batches_noiseless(n):
  function test_jitter_predict (line 184) | def test_jitter_predict():

FILE: tests/test_vidkl.py
  function get_dummy_data (line 16) | def get_dummy_data(jax_ndarray=True):
  function get_dummy_image_data (line 24) | def get_dummy_image_data(jax_ndarray=True):
  function get_dummy_vector_data (line 32) | def get_dummy_vector_data(jax_ndarray=True):
  class CustomConvNet (line 38) | class CustomConvNet(hk.Module):
    method __init__ (line 39) | def __init__(self, embedim=2):
    method __call__ (line 43) | def __call__(self, x):
  function test_single_fit (line 55) | def test_single_fit(jax_ndarray):
  function test_single_fit_custom_net (line 67) | def test_single_fit_custom_net(jax_ndarray):
  function test_get_mvn_posterior (line 79) | def test_get_mvn_posterior():
  function test_get_mvn_posterior_noiseless (line 98) | def test_get_mvn_posterior_noiseless():
  function test_fit_scalar_target (line 119) | def test_fit_scalar_target():
  function test_fit_vector_target (line 130) | def test_fit_vector_target():
  function test_predict_scalar (line 144) | def test_predict_scalar():
  function test_predict_vector (line 165) | def test_predict_vector():
  function test_predict_in_batches_scalar (line 187) | def test_predict_in_batches_scalar():
  function test_predict_in_batches_vector (line 208) | def test_predict_in_batches_vector():
  function test_fit_predict_scalar (line 230) | def test_fit_predict_scalar():
  function test_fit_predict_vector (line 243) | def test_fit_predict_vector():
  function test_fit_predict_scalar_ensemble (line 256) | def test_fit_predict_scalar_ensemble():
  function test_fit_predict_vector_ensemble (line 270) | def test_fit_predict_vector_ensemble():
  function test_fit_predict_scalar_ensemble_custom_net (line 284) | def test_fit_predict_scalar_ensemble_custom_net():

FILE: tests/test_vigp.py
  function get_dummy_data (line 17) | def get_dummy_data(jax_ndarray=True, unsqueeze=False):
  function dummy_mean_fn (line 27) | def dummy_mean_fn(x, params):
  function dummy_mean_fn_priors (line 31) | def dummy_mean_fn_priors():
  function gp_kernel_custom_prior (line 37) | def gp_kernel_custom_prior():
  function test_fit (line 46) | def test_fit(kernel, jax_ndarray, unsqueeze):
  function test_get_samples (line 56) | def test_get_samples(kernel, jax_ndarray):
  function test_prediction (line 69) | def test_prediction(unsqueeze):
  function test_noiseless_prediction (line 86) | def test_noiseless_prediction():
  function test_prediction_in_batches (line 104) | def test_prediction_in_batches(unsqueeze, batch_size):
  function test_fit_predict (line 123) | def test_fit_predict(kernel):
  function test_fit_predict_in_batches (line 137) | def test_fit_predict_in_batches(batch_size):
  function test_fit_with_mean_fn (line 153) | def test_fit_with_mean_fn(jax_ndarray):
  function test_fit_with_prob_mean_fn (line 162) | def test_fit_with_prob_mean_fn(jax_ndarray):
  function test_fit_predict_with_mean_fn (line 170) | def test_fit_predict_with_mean_fn():
  function test_fit_predict_with_prob_mean_fn (line 183) | def test_fit_predict_with_prob_mean_fn():
  function test_sample_from_prior (line 196) | def test_sample_from_prior():
  function test_jitter_fit (line 204) | def test_jitter_fit():
  function test_jitter_predict (line 220) | def test_jitter_predict():
  function test_guide_type (line 236) | def test_guide_type():

FILE: tests/test_vimtdkl.py
  function get_dummy_data (line 13) | def get_dummy_data():
  function attach_indices (line 19) | def attach_indices(X, num_tasks):
  function test_fit_multitask (line 27) | def test_fit_multitask(data_kernel, num_tasks, num_latents):
  function test_fit_multitask_shared_input (line 40) | def test_fit_multitask_shared_input(data_kernel, num_tasks, num_latents):
  function test_fit_predict_multitask (line 54) | def test_fit_predict_multitask(data_kernel, num_tasks, num_latents):
Copy disabled (too large) Download .json
Condensed preview — 101 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (25,030K chars).
[
  {
    "path": ".flake8",
    "chars": 194,
    "preview": "[flake8]\nexclude =\n    .git,\n    __pycache__,\n    build,\n    dist,\n    docs/source/conf.py\nmax-line-length = 80\nshow-sou"
  },
  {
    "path": ".github/workflows/ci-deploy.yml",
    "chars": 969,
    "preview": "name: CI/Deploy\n\non:\n  push:\n    tags: [\"v*\"]\n\njobs:\n\n  unit:\n    uses: ./.github/workflows/unit.yml\n\n  notebooks:\n    u"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 223,
    "preview": "name: CI\n\non:\n\n  pull_request:\n    branches: [\"main\", \"dev/*\"]\n\n  push:\n    branches: [\"main\", \"dev/*\"]\n\njobs: \n\n  unit:"
  },
  {
    "path": ".github/workflows/notebook_smoke.yml",
    "chars": 596,
    "preview": "name: notebooks\n\nenv:\n  CI_SMOKE: True\n\non:\n  workflow_call:\n\njobs:\n  build-linux:\n    \n    strategy:\n      matrix:\n    "
  },
  {
    "path": ".github/workflows/unit.yml",
    "chars": 1389,
    "preview": "name: Unit\nenv:\n  PYTHON_MAIN_VERSION: 3.12\non:\n  workflow_call:\njobs:\n  build:\n    runs-on: ${{ matrix.os }}\n    strate"
  },
  {
    "path": ".gitignore",
    "chars": 1829,
    "preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packagi"
  },
  {
    "path": ".readthedocs.yml",
    "chars": 621,
    "preview": "# .readthedocs.yml\n# Read the Docs configuration file\n# See https://docs.readthedocs.io/en/stable/config-file/v2.html fo"
  },
  {
    "path": "LICENSE",
    "chars": 1069,
    "preview": "MIT License\n\nCopyright (c) 2024 GPax authors\n\nPermission is hereby granted, free of charge, to any person obtaining a co"
  },
  {
    "path": "README.md",
    "chars": 18329,
    "preview": "# GPax\n[![build](https://github.com/ziatdinovmax/gpax/actions/workflows/ci.yml/badge.svg)](https://github.com/ziatdinovm"
  },
  {
    "path": "docs/Makefile",
    "chars": 637,
    "preview": "# Minimal makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line, and also\n# from the "
  },
  {
    "path": "docs/make.bat",
    "chars": 763,
    "preview": "@ECHO OFF\n\npushd %~dp0\n\nREM Command file for Sphinx documentation\n\nif \"%SPHINXBUILD%\" == \"\" (\n\tset SPHINXBUILD=sphinx-bu"
  },
  {
    "path": "docs/requirements_rtd.txt",
    "chars": 208,
    "preview": "setuptools>=41.0.1\nmatplotlib>=3.2\nsphinx>=3,<7\nsphinx_autodoc_typehints>=1.11.0\nrecommonmark>=0.6.0\nsphinx_rtd_theme>=0"
  },
  {
    "path": "docs/source/LICENSE.rst",
    "chars": 1068,
    "preview": "MIT License\n\nCopyright (c) 2024 GPax authors\n\nPermission is hereby granted, free of charge, to any person obtaining a co"
  },
  {
    "path": "docs/source/README.rst",
    "chars": 487,
    "preview": "Installation\n============\n\nIf you would like to use GPax with a GPU acceleration, follow these `instructions <https://gi"
  },
  {
    "path": "docs/source/USAGE.rst",
    "chars": 14320,
    "preview": "How To Use\n==========\n\nSimple GP\n---------\n\n1D Example\n^^^^^^^^^^\n\n|Open in Colab|\n\n.. |Open in Colab| image:: https://c"
  },
  {
    "path": "docs/source/acquisition.rst",
    "chars": 500,
    "preview": "Acquisition functions\n=====================\n\n.. autofunction:: gpax.acquisition.UCB\n\n.. autofunction:: gpax.acquisition."
  },
  {
    "path": "docs/source/conf.py",
    "chars": 5293,
    "preview": "# Configuration file for the Sphinx documentation builder.\n#\n# This file only contains a selection of the most common op"
  },
  {
    "path": "docs/source/examples.rst",
    "chars": 1977,
    "preview": "Colab notebooks\n===============\n\nThe easiest way to start using GPax is via Google Colab, which is a free research tool "
  },
  {
    "path": "docs/source/hypo.rst",
    "chars": 234,
    "preview": "Hypothesis learning\n===================\n\n.. autofunction:: gpax.hypo.step\n\n.. autofunction:: gpax.hypo.sample_next\n\n.. a"
  },
  {
    "path": "docs/source/index.rst",
    "chars": 754,
    "preview": "GPax: Gaussian Processes for Experimental Sciences\n==================================================\n\nGPax is a small P"
  },
  {
    "path": "docs/source/kernels.rst",
    "chars": 333,
    "preview": "Kernels\n=======\n\n.. autofunction:: gpax.kernels.RBFKernel\n\n.. autofunction:: gpax.kernels.MaternKernel\n\n.. autofunction:"
  },
  {
    "path": "docs/source/models.rst",
    "chars": 2548,
    "preview": "GPax models\n===========\n\nGaussian Processes - Fully Bayesian Implementation\n--------------------------------------------"
  },
  {
    "path": "docs/source/priors.rst",
    "chars": 459,
    "preview": "Priors\n======\n\n.. autofunction:: gpax.priors.normal_dist\n\n.. autofunction:: gpax.priors.lognormal_dist\n\n.. autofunction:"
  },
  {
    "path": "docs/source/utils.rst",
    "chars": 304,
    "preview": "Utilities\n=========\n\nAutomatic function setters\n--------------------------\n\n.. autofunction:: gpax.utils.set_fn\n\n.. auto"
  },
  {
    "path": "examples/GP_sGP.ipynb",
    "chars": 464025,
    "preview": "{\n  \"cells\": [\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"view-in-github\",\n        \"colab_t"
  },
  {
    "path": "examples/GPax_MultiTaskGP_BO.ipynb",
    "chars": 3083235,
    "preview": "{\n  \"cells\": [\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"view-in-github\",\n        \"colab_t"
  },
  {
    "path": "examples/MeasuredNoiseGP.ipynb",
    "chars": 111425,
    "preview": "{\n  \"nbformat\": 4,\n  \"nbformat_minor\": 0,\n  \"metadata\": {\n    \"colab\": {\n      \"provenance\": [],\n      \"authorship_tag\":"
  },
  {
    "path": "examples/compare_GPs.ipynb",
    "chars": 153922,
    "preview": "{\n  \"cells\": [\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"view-in-github\",\n        \"colab_t"
  },
  {
    "path": "examples/contrib/cBO_1D_GPax_tutorial.ipynb",
    "chars": 4274924,
    "preview": "{\n  \"cells\": [\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"0QT4J9fJXbMk\"\n      },\n      \"sou"
  },
  {
    "path": "examples/contrib/gpax_dkl_notebookIII_molecules.ipynb",
    "chars": 709784,
    "preview": "{\n  \"nbformat\": 4,\n  \"nbformat_minor\": 0,\n  \"metadata\": {\n    \"colab\": {\n      \"provenance\": [],\n      \"authorship_tag\":"
  },
  {
    "path": "examples/gpax_GPBO.ipynb",
    "chars": 969033,
    "preview": "{\n  \"cells\": [\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"view-in-github\",\n        \"colab_t"
  },
  {
    "path": "examples/gpax_UIGP.ipynb",
    "chars": 280716,
    "preview": "{\n  \"nbformat\": 4,\n  \"nbformat_minor\": 0,\n  \"metadata\": {\n    \"colab\": {\n      \"provenance\": [],\n      \"include_colab_li"
  },
  {
    "path": "examples/gpax_hypo.ipynb",
    "chars": 3582251,
    "preview": "{\n  \"cells\": [\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"view-in-github\",\n        \"colab_t"
  },
  {
    "path": "examples/gpax_simpleGP.ipynb",
    "chars": 578968,
    "preview": "{\n  \"nbformat\": 4,\n  \"nbformat_minor\": 0,\n  \"metadata\": {\n    \"colab\": {\n      \"name\": \"simpleGP.ipynb\",\n      \"provenan"
  },
  {
    "path": "examples/gpax_simpleGP_tutorial.ipynb",
    "chars": 399052,
    "preview": "{\n  \"nbformat\": 4,\n  \"nbformat_minor\": 0,\n  \"metadata\": {\n    \"colab\": {\n      \"provenance\": [],\n      \"include_colab_li"
  },
  {
    "path": "examples/gpax_viDKL_plasmons.ipynb",
    "chars": 8324641,
    "preview": "{\n  \"cells\": [\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"view-in-github\",\n        \"colab_t"
  },
  {
    "path": "examples/gpax_viGP.ipynb",
    "chars": 561776,
    "preview": "{\n  \"cells\": [\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"view-in-github\",\n        \"colab_t"
  },
  {
    "path": "examples/heteroskedasticGP.ipynb",
    "chars": 568065,
    "preview": "{\n  \"nbformat\": 4,\n  \"nbformat_minor\": 0,\n  \"metadata\": {\n    \"colab\": {\n      \"provenance\": [],\n      \"include_colab_li"
  },
  {
    "path": "examples/simpleGP.ipynb",
    "chars": 472038,
    "preview": "{\n  \"nbformat\": 4,\n  \"nbformat_minor\": 0,\n  \"metadata\": {\n    \"colab\": {\n      \"name\": \"simpleGP.ipynb\",\n      \"provenan"
  },
  {
    "path": "gpax/__init__.py",
    "chars": 709,
    "preview": "from . import acquisition, kernels, priors, utils\nfrom ._version import __version__\nfrom .hypo import sample_next\nfrom ."
  },
  {
    "path": "gpax/_version.py",
    "chars": 22,
    "preview": "__version__ = '0.1.9'\n"
  },
  {
    "path": "gpax/acquisition/__init__.py",
    "chars": 245,
    "preview": "from .acquisition import UCB, EI, POI, UE, Thompson, KG\nfrom .batch_acquisition import qEI, qPOI, qUCB, qKG\nfrom .optimi"
  },
  {
    "path": "gpax/acquisition/acquisition.py",
    "chars": 22585,
    "preview": "\"\"\"\nacquisition.py\n==============\n\nAcquisition functions\n\nCreated by Maxim Ziatdinov (email: maxim.ziatdinov@ai4microsco"
  },
  {
    "path": "gpax/acquisition/base_acq.py",
    "chars": 8138,
    "preview": "\"\"\"\nbase_acq.py\n==============\n\nBase acquisition functions\n\nCreated by Maxim Ziatdinov (email: maxim.ziatdinov@ai4micros"
  },
  {
    "path": "gpax/acquisition/batch_acquisition.py",
    "chars": 11167,
    "preview": "\"\"\"\nbatch_acquisition.py\n==============\n\nBatch-mode acquisition functions\n\nCreated by Maxim Ziatdinov (email: maxim.ziat"
  },
  {
    "path": "gpax/acquisition/optimize.py",
    "chars": 3470,
    "preview": "\"\"\"\noptimize.py\n==============\n\nOptimize continuous acquisition functions\n\nCreated by Maxim Ziatdinov (email: maxim.ziat"
  },
  {
    "path": "gpax/acquisition/penalties.py",
    "chars": 2531,
    "preview": "from typing import Optional\nimport jax\nimport jax.numpy as jnp\n\n\ndef compute_penalty(X: jnp.ndarray, recent_points: jnp."
  },
  {
    "path": "gpax/hypo.py",
    "chars": 6022,
    "preview": "\"\"\"\nhypo.py\n========\n\nUtility functions for hypothesis learning based on arXiv:2112.06649\n\nCreated by Maxim Ziatdinov (e"
  },
  {
    "path": "gpax/kernels/__init__.py",
    "chars": 435,
    "preview": "from .kernels import (MaternKernel, NNGPKernel, PeriodicKernel, RBFKernel,\n                      get_kernel, nngp_erf, n"
  },
  {
    "path": "gpax/kernels/kernels.py",
    "chars": 8051,
    "preview": "\"\"\"\nkernels.py\n==========\n\nKernel functions\n\nCreated by Maxim Ziatdinov (email: maxim.ziatdinov@ai4microscopy.com)\n\"\"\"\n\n"
  },
  {
    "path": "gpax/kernels/mtkernels.py",
    "chars": 8777,
    "preview": "\"\"\"\nmtkernels.py\n==========\n\nMulti-task kernel functions\n\nCreated by Maxim Ziatdinov (email: maxim.ziatdinov@ai4microsco"
  },
  {
    "path": "gpax/models/__init__.py",
    "chars": 712,
    "preview": "from .gp import ExactGP\nfrom .vgp import vExactGP\nfrom .vigp import viGP\nfrom .hskgp import VarNoiseGP\nfrom .spm import "
  },
  {
    "path": "gpax/models/bnn.py",
    "chars": 3075,
    "preview": "\"\"\"\nbnn.py\n=======\n\nFully Bayesian MLPs\n\nCreated by Maxim Ziatdinov (email: maxim.ziatdinov@gmail.com)\n\"\"\"\n\nfrom typing "
  },
  {
    "path": "gpax/models/corgp.py",
    "chars": 4500,
    "preview": "from typing import Callable, Dict, Optional\n\nimport jax.numpy as jnp\nimport numpy as onp\nimport numpyro\nimport numpyro.d"
  },
  {
    "path": "gpax/models/dkl.py",
    "chars": 8015,
    "preview": "\"\"\"\ndkl.py\n=======\n\nFully Bayesian implementation of deep kernel learning\n\nCreated by Maxim Ziatdinov (email: maxim.ziat"
  },
  {
    "path": "gpax/models/gp.py",
    "chars": 18040,
    "preview": "\"\"\"\ngp.py\n=======\n\nFully Bayesian implementation of Gaussian process regression\n\nCreated by Maxim Ziatdinov (email: maxi"
  },
  {
    "path": "gpax/models/hskgp.py",
    "chars": 10474,
    "preview": "\"\"\"\nhskgp.py\n=========\n\nFully Bayesian implementation of heteroskedastic Gaussian process regression\n\nCreated by Maxim Z"
  },
  {
    "path": "gpax/models/ibnn.py",
    "chars": 2234,
    "preview": "\"\"\"\nibnn.py\n=======\n\nInfinite width Bayesian neural net\n\nCreated by Maxim Ziatdinov (email: maxim.ziatdinov@ai4microscop"
  },
  {
    "path": "gpax/models/linreg.py",
    "chars": 1357,
    "preview": "import jax.numpy as jnp\nimport numpyro\nimport numpyro.distributions as dist\nfrom numpyro.infer import SVI, Trace_ELBO\nfr"
  },
  {
    "path": "gpax/models/mngp.py",
    "chars": 10946,
    "preview": "\"\"\"\nmngp.py\n=======\n\nFully Bayesian Gaussian Process model that incorporates measured noise.\n\nCreated by Maxim Ziatdinov"
  },
  {
    "path": "gpax/models/mtgp.py",
    "chars": 9197,
    "preview": "from typing import Callable, Dict, Optional\n\nimport jax.numpy as jnp\nimport numpy as onp\nimport numpyro\nimport numpyro.d"
  },
  {
    "path": "gpax/models/sparse_gp.py",
    "chars": 8498,
    "preview": "\"\"\"\nsparse_gp.py\n============\n\nVariational inference implementation of sparse Gaussian process regression\n\nCreated by Ma"
  },
  {
    "path": "gpax/models/spm.py",
    "chars": 8704,
    "preview": "\"\"\"\nspm.py\n=======\n\nBayesian inference with structured probabilistic model. Serves as a wrapper\nover the NumPyro's funct"
  },
  {
    "path": "gpax/models/uigp.py",
    "chars": 8738,
    "preview": "\"\"\"\nuigp.py\n=======\n\nFully Bayesian implementation of Gaussian process regression with uncertain (stochastic) inputs\n\nCr"
  },
  {
    "path": "gpax/models/vgp.py",
    "chars": 9370,
    "preview": "\"\"\"\nvgp.py\n=======\n\nFully Bayesian implementation of Gaussian process regression for vector-valued functions\n\nCreated by"
  },
  {
    "path": "gpax/models/vi_ibnn.py",
    "chars": 2240,
    "preview": "\"\"\"\nvi_ibnn.py\n=======\n\nInfinite width Bayesian neural net (variational approximation)\n\nCreated by Maxim Ziatdinov (emai"
  },
  {
    "path": "gpax/models/vi_mtdkl.py",
    "chars": 10749,
    "preview": "\"\"\"\nvi_mtdkl.py\n========\n\nVariational inference-based implementation of multi-task deep kernel learning\n\nCreated by Maxi"
  },
  {
    "path": "gpax/models/vidkl.py",
    "chars": 17549,
    "preview": "\"\"\"\nvidkl.py\n========\n\nVariational inference-based implementation of deep kernel learning\n\nCreated by Maxim Ziatdinov (e"
  },
  {
    "path": "gpax/models/vigp.py",
    "chars": 8028,
    "preview": "\"\"\"\nvigp.py\n=======\n\nVariational inference implementation of Gaussian process regression\n\nCreated by Maxim Ziatdinov (em"
  },
  {
    "path": "gpax/priors/__init__.py",
    "chars": 21,
    "preview": "from .priors import *"
  },
  {
    "path": "gpax/priors/priors.py",
    "chars": 11008,
    "preview": "\"\"\"\npriors.py\n=========\n\nUtility functions for setting priors\n\nCreated by Maxim Ziatdinov (email: maxim.ziatdinov@gmail."
  },
  {
    "path": "gpax/utils/__init__.py",
    "chars": 76,
    "preview": "from .utils import *\nfrom .fn import *\nfrom .fn import _set_noise_kernel_fn\n"
  },
  {
    "path": "gpax/utils/fn.py",
    "chars": 5235,
    "preview": "\"\"\"\nfn.py\n=====\n\nUtilities for setting up custom mean and kernel functions\n\nCreated by Maxim Ziatdinov (email: maxim.zia"
  },
  {
    "path": "gpax/utils/utils.py",
    "chars": 7400,
    "preview": "\"\"\"\nutils.py\n========\n\nUtility functions\n\nCreated by Maxim Ziatdinov (email: maxim.ziatdinov@ai4microscopy.com)\n\"\"\"\n\nfro"
  },
  {
    "path": "pyproject.toml",
    "chars": 1581,
    "preview": "[build-system]\nrequires = [\"flit_core >=3.2,<4\"]\nbuild-backend = \"flit_core.buildapi\"\n\n[project]\nname = \"gpax\"\nauthors ="
  },
  {
    "path": "scripts/build.sh",
    "chars": 164,
    "preview": "#!/bin/bash\n\npip install flit~=3.7\npip install dunamai==1.19.2\necho \"__version__ = '$(dunamai from any --style=pep440 --"
  },
  {
    "path": "scripts/install.sh",
    "chars": 354,
    "preview": "#!/bin/bash\n\npip install toml\n\nif [ \"$1\" = \"test\" ]; then\n\tpython3 -c 'import toml; c = toml.load(\"pyproject.toml\"); pri"
  },
  {
    "path": "scripts/test_notebooks.sh",
    "chars": 182,
    "preview": "#!/bin/bash\n\npip install ipython\npip install nbformat\npip install seaborn\nfor nb in examples/*.ipynb; do\n    echo \"Runni"
  },
  {
    "path": "tests/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/test_acq.py",
    "chars": 9265,
    "preview": "import sys\nimport pytest\nimport numpy as onp\nimport jax\nimport jax.numpy as jnp\nfrom numpy.testing import assert_equal, "
  },
  {
    "path": "tests/test_bnn.py",
    "chars": 3554,
    "preview": "import sys\nimport pytest\nimport numpy as onp\nimport jax.numpy as jnp\nimport jax\nimport numpyro\nfrom numpy.testing import"
  },
  {
    "path": "tests/test_corgp.py",
    "chars": 1469,
    "preview": "import sys\nimport pytest\nimport numpy as onp\nimport jax.numpy as jnp\nimport numpyro\nfrom numpy.testing import assert_\n\ns"
  },
  {
    "path": "tests/test_dkl.py",
    "chars": 4330,
    "preview": "import sys\nimport pytest\nimport numpy as onp\nimport jax.numpy as jnp\nimport jax\nfrom numpy.testing import assert_equal, "
  },
  {
    "path": "tests/test_func_setter.py",
    "chars": 2538,
    "preview": "import sys\nimport jax.numpy as jnp\nfrom numpy.testing import assert_equal, assert_\n\nsys.path.insert(0, \"../gpax/\")\n\n\nfro"
  },
  {
    "path": "tests/test_gp.py",
    "chars": 13573,
    "preview": "import sys\nimport pytest\nimport numpy as onp\nimport jax.numpy as jnp\nimport jax\nimport numpyro\nfrom numpy.testing import"
  },
  {
    "path": "tests/test_hskgp.py",
    "chars": 4984,
    "preview": "import sys\nimport pytest\nimport numpy as onp\nimport jax.numpy as jnp\nimport jax\nimport numpyro\nimport numpyro.distributi"
  },
  {
    "path": "tests/test_hypo.py",
    "chars": 1114,
    "preview": "import sys\nimport pytest\nimport numpy as onp\nimport jax.numpy as jnp\nimport numpyro\nfrom numpy.testing import assert_\n\ns"
  },
  {
    "path": "tests/test_ibnn.py",
    "chars": 1649,
    "preview": "import sys\nimport pytest\nimport numpy as onp\nimport jax.numpy as jnp\nfrom numpy.testing import assert_equal\n\n\nsys.path.i"
  },
  {
    "path": "tests/test_kernels.py",
    "chars": 9753,
    "preview": "import sys\nimport pytest\nimport numpy as onp\nimport jax.numpy as jnp\nfrom numpy.testing import assert_equal, assert_\n\nsy"
  },
  {
    "path": "tests/test_mngp.py",
    "chars": 3159,
    "preview": "import sys\nimport pytest\nimport numpy as onp\nimport jax.numpy as jnp\nimport jax\nimport numpyro\nimport numpyro.distributi"
  },
  {
    "path": "tests/test_mtgp.py",
    "chars": 3903,
    "preview": "import sys\nimport pytest\nimport numpy as onp\nimport jax.numpy as jnp\nimport numpyro\nfrom numpy.testing import assert_\n\ns"
  },
  {
    "path": "tests/test_optimize_acq.py",
    "chars": 847,
    "preview": "import sys\nimport pytest\nimport numpy as onp\nimport jax.numpy as jnp\nfrom numpy.testing import assert_\n\nsys.path.insert("
  },
  {
    "path": "tests/test_priors.py",
    "chars": 6275,
    "preview": "import sys\nimport pytest\nimport jax.numpy as jnp\nimport numpyro\nfrom numpy.testing import assert_equal, assert_\n\nsys.pat"
  },
  {
    "path": "tests/test_sparsegp.py",
    "chars": 1874,
    "preview": "import sys\nimport pytest\nimport numpy as onp\nimport jax.numpy as jnp\nimport jax\nfrom numpy.testing import assert_equal\n\n"
  },
  {
    "path": "tests/test_spm.py",
    "chars": 2356,
    "preview": "import sys\nimport pytest\nimport numpy as onp\nimport jax.numpy as jnp\nimport jax\nimport numpyro\nfrom numpy.testing import"
  },
  {
    "path": "tests/test_uigp.py",
    "chars": 2742,
    "preview": "import sys\nimport pytest\nimport numpy as onp\nimport jax.numpy as jnp\nimport jax\nimport numpyro\nimport numpyro.distributi"
  },
  {
    "path": "tests/test_utils.py",
    "chars": 4667,
    "preview": "import sys\nimport pytest\nimport numpy as onp\nimport jax\nimport jax.numpy as jnp\nimport jax.random as jra\nimport numpyro\n"
  },
  {
    "path": "tests/test_vgp.py",
    "chars": 7274,
    "preview": "import sys\nimport pytest\nimport numpy as onp\nimport jax.numpy as jnp\nimport jax\nimport numpyro\nfrom numpy.testing import"
  },
  {
    "path": "tests/test_vidkl.py",
    "chars": 9716,
    "preview": "import sys\nimport pytest\nimport numpy as onp\nimport jax.numpy as jnp\nimport jax\nimport haiku as hk\nimport numpyro\nfrom n"
  },
  {
    "path": "tests/test_vigp.py",
    "chars": 8706,
    "preview": "import sys\nimport pytest\nimport numpy as onp\nimport jax.numpy as jnp\nimport jax\nimport numpyro\nfrom numpy.testing import"
  },
  {
    "path": "tests/test_vimtdkl.py",
    "chars": 2393,
    "preview": "import sys\nimport pytest\nimport numpy as onp\nimport jax.numpy as jnp\nfrom numpy.testing import assert_, assert_equal\n\nsy"
  }
]

About this extraction

This page contains the full source code of the ziatdinovmax/gpax GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 101 files (23.8 MB), approximately 6.2M tokens, and a symbol index with 447 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!