{ "info": { "author": "Wessel Bruinsma", "author_email": "wessel.p.bruinsma@gmail.com", "bugtrack_url": null, "classifiers": [], "description": "# [Stheno](https://github.com/wesselb/stheno)\n\n[![CI](https://github.com/wesselb/stheno/workflows/CI/badge.svg?branch=master)](https://github.com/wesselb/stheno/actions?query=workflow%3ACI)\n[![Coverage Status](https://coveralls.io/repos/github/wesselb/stheno/badge.svg?branch=master)](https://coveralls.io/github/wesselb/stheno?branch=master)\n[![Latest Docs](https://img.shields.io/badge/docs-latest-blue.svg)](https://wesselb.github.io/stheno)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n\nStheno is an implementation of Gaussian process modelling in Python. See \nalso [Stheno.jl](https://github.com/willtebbutt/Stheno.jl).\n\n[Check out our post about linear models with Stheno and JAX.](https://wesselb.github.io/2021/01/19/linear-models-with-stheno-and-jax.html)\n\nContents:\n\n* [Nonlinear Regression in 20 Seconds](#nonlinear-regression-in-20-seconds)\n* [Installation](#installation)\n* [Manual](#manual)\n - [AutoGrad, TensorFlow, PyTorch, or JAX? Your Choice!](#autograd-tensorflow-pytorch-or-jax-your-choice)\n - [Model Design](#model-design)\n - [Finite-Dimensional Distributions](#finite-dimensional-distributions)\n - [Prior and Posterior Measures](#prior-and-posterior-measures)\n - [Inducing Points](#inducing-points)\n - [Kernels and Means](#kernels-and-means)\n - [Batched Computation](#batched-computation)\n - [Important Remarks](#important-remarks)\n* [Examples](#examples)\n - [Simple Regression](#simple-regression)\n - [Hyperparameter Optimisation with Varz](#hyperparameter-optimisation-with-varz)\n - [Hyperparameter Optimisation with PyTorch](#hyperparameter-optimisation-with-pytorch)\n - [Decomposition of Prediction](#decomposition-of-prediction)\n - [Learn a Function, Incorporating Prior Knowledge About Its Form](#learn-a-function-incorporating-prior-knowledge-about-its-form)\n - [Multi-Output Regression](#multi-output-regression)\n - [Approximate Integration](#approximate-integration)\n - [Bayesian Linear Regression](#bayesian-linear-regression)\n - [GPAR](#gpar)\n - [A GP-RNN Model](#a-gp-rnn-model)\n - [Approximate Multiplication Between GPs](#approximate-multiplication-between-gps)\n - [Sparse Regression](#sparse-regression)\n - [Smoothing with Nonparametric Basis Functions](#smoothing-with-nonparametric-basis-functions)\n\n## Nonlinear Regression in 20 Seconds\n\n```python\n>>> import numpy as np\n\n>>> from stheno import GP, EQ\n\n>>> x = np.linspace(0, 2, 10) # Some points to predict at\n\n>>> y = x ** 2 # Some observations\n\n>>> f = GP(EQ()) # Construct Gaussian process.\n\n>>> f_post = f | (f(x), y) # Compute the posterior.\n\n>>> pred = f_post(np.array([1, 2, 3])) # Predict!\n\n>>> pred.mean\n\n\n>>> pred.var\n\n```\n\n[These custom matrix types are there to accelerate the underlying linear algebra.](#important-remarks)\nTo get vanilla NumPy/AutoGrad/TensorFlow/PyTorch/JAX arrays, use `B.dense`:\n\n```python\n>>> from lab import B\n\n>>> B.dense(pred.mean)\narray([[1.00000068],\n [3.99999999],\n [8.4825932 ]])\n\n>>> B.dense(pred.var)\narray([[ 8.03246358e-13, 7.77156117e-16, -4.57690943e-09],\n [ 7.77156117e-16, 9.99866856e-13, 2.77333267e-10],\n [-4.57690943e-09, 2.77333267e-10, 3.31283378e-03]])\n```\n\nMoar?! Then read on!\n\n## Installation\n\nSee [the instructions here](https://gist.github.com/wesselb/4b44bf87f3789425f96e26c4308d0adc).\nThen simply\n\n```\npip install stheno\n```\n\n## Manual\n\nNote: [here](https://wesselb.github.io/stheno) is a nicely rendered and more\nreadable version of the docs.\n\n### AutoGrad, TensorFlow, PyTorch, or JAX? Your Choice!\n\n```python\nfrom stheno.autograd import GP, EQ\n```\n\n```python\nfrom stheno.tensorflow import GP, EQ\n```\n\n```python\nfrom stheno.torch import GP, EQ\n```\n\n```python\nfrom stheno.jax import GP, EQ\n```\n\n### Model Design\n\nThe basic building block is a `f = GP(mean=0, kernel, measure=prior)`, which takes\nin [a _mean_, a _kernel_](#kernels-and-means), and a _measure_.\nThe mean and kernel of a GP can be extracted with `f.mean` and `f.kernel`.\nThe measure should be thought of as a big joint distribution that assigns a mean and\na kernel to every variable `f`.\nA measure can be created with `prior = Measure()`.\nA GP `f` can have different means and kernels under different measures.\nFor example, under some _prior_ measure, `f` can have an `EQ()` kernel; but, under some\n_posterior_ measure, `f` has a kernel that is determined by the posterior distribution\nof a GP.\n[We will see later how posterior measures can be constructed.](#prior-and-posterior-measures)\nThe measure with which a `f = GP(kernel, measure=prior)` is constructed can be\nextracted with `f.measure == prior`.\nIf the keyword argument `measure` is not set, then automatically a new measure is\ncreated, which afterwards can be extracted with `f.measure`.\n\nDefinition, where `prior = Measure()`:\n\n```python\nf = GP(kernel)\n\nf = GP(mean, kernel)\n\nf = GP(kernel, measure=prior)\n\nf = GP(mean, kernel, measure=prior)\n```\n\nGPs that are associated to the same measure can be combined into new GPs, which is\nthe primary mechanism used to build cool models.\n\nHere's an example model:\n\n```python\n>>> prior = Measure()\n\n>>> f1 = GP(lambda x: x ** 2, EQ(), measure=prior)\n\n>>> f1\nGP(, EQ())\n\n>>> f2 = GP(Linear(), measure=prior)\n\n>>> f2\nGP(0, Linear())\n\n>>> f_sum = f1 + f2\n\n>>> f_sum\nGP(, EQ() + Linear())\n\n>>> f_sum + GP(EQ()) # Not valid: `GP(EQ())` belongs to a new measure!\nAssertionError: Processes GP(, EQ() + Linear()) and GP(0, EQ()) are associated to different measures.\n```\n\nTo avoid setting the keyword `measure` for every `GP` that you create, you can enter\na measure as a context:\n\n```python\n>>> with Measure() as prior:\n f1 = GP(lambda x: x ** 2, EQ())\n f2 = GP(Linear())\n f_sum = f1 + f2\n\n>>> prior == f1.measure == f2.measure == f_sum.measure\nTrue\n```\n\n\n\n#### Compositional Design\n\n* Add and subtract GPs and other objects.\n\n Example:\n \n ```python\n >>> GP(EQ(), measure=prior) + GP(Exp(), measure=prior)\n GP(0, EQ() + Exp())\n\n >>> GP(EQ(), measure=prior) + GP(EQ(), measure=prior)\n GP(0, 2 * EQ())\n \n >>> GP(EQ()) + 1\n GP(1, EQ())\n \n >>> GP(EQ()) + 0\n GP(0, EQ())\n \n >>> GP(EQ()) + (lambda x: x ** 2)\n GP(, EQ())\n\n >>> GP(2, EQ(), measure=prior) - GP(1, EQ(), measure=prior)\n GP(1, 2 * EQ())\n ```\n \n* Multiply GPs and other objects.\n\n *Warning:*\n The product of two GPs it *not* a Gaussian process.\n Stheno approximates the resulting process by moment matching.\n\n Example:\n \n ```python\n >>> GP(1, EQ(), measure=prior) * GP(1, Exp(), measure=prior)\n GP( + + -1 * 1, * Exp() + * EQ() + EQ() * Exp())\n \n >>> 2 * GP(EQ())\n GP(2, 2 * EQ())\n \n >>> 0 * GP(EQ())\n GP(0, 0)\n\n >>> (lambda x: x) * GP(EQ())\n GP(0, * EQ())\n ```\n \n* Shift GPs.\n\n Example:\n \n ```python\n >>> GP(EQ()).shift(1)\n GP(0, EQ() shift 1) \n ```\n \n* Stretch GPs.\n\n Example:\n \n ```python\n >>> GP(EQ()).stretch(2)\n GP(0, EQ() > 2)\n ```\n \n* Select particular input dimensions.\n\n Example:\n \n ```python\n >>> GP(EQ()).select(1, 3)\n GP(0, EQ() : [1, 3])\n ```\n \n* Transform the input.\n\n Example:\n \n ```python\n >>> GP(EQ()).transform(f)\n GP(0, EQ() transform f)\n ```\n \n* Numerically take the derivative of a GP.\n The argument specifies which dimension to take the derivative with respect\n to.\n \n Example:\n \n ```python\n >>> GP(EQ()).diff(1)\n GP(0, d(1) EQ())\n ```\n \n* Construct a finite difference estimate of the derivative of a GP.\n See `Measure.diff_approx` for a description of the arguments.\n \n Example:\n \n ```python\n >>> GP(EQ()).diff_approx(deriv=1, order=2)\n GP(50000000.0 * (0.5 * EQ() + 0.5 * ((-0.5 * (EQ() shift (0.0001414213562373095, 0))) shift (0, -0.0001414213562373095)) + 0.5 * ((-0.5 * (EQ() shift (0, 0.0001414213562373095))) shift (-0.0001414213562373095, 0))), 0)\n ```\n \n* Construct the Cartesian product of a collection of GPs.\n\n Example:\n \n ```python\n >>> prior = Measure()\n\n >>> f1, f2 = GP(EQ(), measure=prior), GP(EQ(), measure=prior)\n\n >>> cross(f1, f2)\n GP(MultiOutputMean(0, 0), MultiOutputKernel(EQ(), EQ()))\n ```\n\n#### Displaying GPs\n\nGPs have a `display` method that accepts a formatter.\n\nExample:\n\n```python\n>>> print(GP(2.12345 * EQ()).display(lambda x: f\"{x:.2f}\"))\nGP(2.12 * EQ(), 0)\n```\n\n#### Properties of GPs\n\n[Properties of kernels](https://github.com/wesselb/mlkernels#properties-of-kernels-and-means)\ncan be queried on GPs directly.\n\nExample:\n\n```python\n>>> GP(EQ()).stationary\nTrue\n```\n\n#### Naming GPs\n\nIt is possible to give a name to a GP.\nNames must be strings.\nA measure then behaves like a two-way dictionary between GPs and their names.\n\nExample:\n\n```python\n>>> prior = Measure()\n\n>>> p = GP(EQ(), name=\"name\", measure=prior)\n\n>>> p.name\n'name'\n\n>>> p.name = \"alternative_name\"\n\n>>> prior[\"alternative_name\"]\nGP(0, EQ())\n\n>>> prior[p]\n'alternative_name'\n```\n\n### Finite-Dimensional Distributions\n\nSimply call a GP to construct a finite-dimensional distribution at some inputs.\nYou can give a second argument, which specifies the variance of additional additive\nnoise.\nAfter constructing a finite-dimensional distribution, you can compute the mean,\nthe variance, sample, or compute a logpdf.\n\nDefinition, where `f` is a `GP`:\n\n```python\nf(x) # No additional noise\n\nf(x, noise) # Additional noise with variance `noise`\n```\n\nThings you can do with a finite-dimensional distribution:\n\n* \n Use `f(x).mean` to compute the mean.\n \n* \n Use `f(x).var` to compute the variance.\n \n* \n Use `f(x).mean_var` to compute simultaneously compute the mean and variance.\n This can be substantially more efficient than calling first `f(x).mean` and then\n `f(x).var`.\n\n* \n Use `Normal.sample` to sample.\n\n Definition:\n \n ```python\n f(x).sample() # Produce one sample.\n \n f(x).sample(n) # Produce `n` samples.\n \n f(x).sample(noise=noise) # Produce one samples with additional noise variance `noise`.\n \n f(x).sample(n, noise=noise) # Produce `n` samples with additional noise variance `noise`.\n ```\n \n* \n Use `f(x).logpdf(y)` to compute the logpdf of some data `y`.\n \n* \n Use `means, variances = f(x).marginals()` to efficiently compute the marginal means\n and marginal variances.\n \n Example:\n\n ```python\n >>> f(x).marginals()\n (array([0., 0., 0.]), np.array([1., 1., 1.]))\n ```\n \n* \n Use `means, lowers, uppers = f(x).marginal_credible_bounds()` to efficiently compute\n the means and the marginal lower and upper 95% central credible region bounds.\n\n Example:\n\n ```python\n >>> f(x).marginal_credible_bounds()\n (array([0., 0., 0.]), array([-1.96, -1.96, -1.96]), array([1.96, 1.96, 1.96]))\n ```\n \n* \n Use `Measure.logpdf` to compute the joint logpdf of multiple observations.\n\n Definition, where `prior = Measure()`:\n\n ```python\n prior.logpdf(f(x), y)\n\n prior.logpdf((f1(x1), y1), (f2(x2), y2), ...)\n ```\n \n* \n Use `Measure.sample` to jointly sample multiple observations.\n\n Definition, where `prior = Measure()`:\n\n ```python\n sample = prior.sample(f(x))\n\n sample1, sample2, ... = prior.sample(f1(x1), f2(x2), ...)\n ```\n\nExample:\n\n```python\n>>> prior = Measure()\n\n>>> f = GP(EQ(), measure=prior)\n\n>>> x = np.array([0., 1., 2.])\n\n>>> f(x) # FDD without noise.\n\n\n>>> f(x, 0.1) # FDD with noise.\n>\n\n>>> f(x).mean\narray([[0.],\n [0.],\n [0.]])\n\n>>> f(x).var\n\n \n>>> y1 = f(x).sample()\n\n>>> y1\narray([[-0.45172746],\n [ 0.46581948],\n [ 0.78929767]])\n \n>>> f(x).logpdf(y1)\n-2.811609567720761\n\n>>> y2 = f(x).sample(2)\narray([[-0.43771276, -2.36741858],\n [ 0.86080043, -1.22503079],\n [ 2.15779126, -0.75319405]]\n\n>>> f(x).logpdf(y2)\n array([-4.82949038, -5.40084225])\n```\n\n### Prior and Posterior Measures\n\nConditioning a _prior_ measure on observations gives a _posterior_ measure.\nTo condition a measure on observations, use `Measure.__or__`.\n\nDefinition, where `prior = Measure()` and `f*` are `GP`s:\n\n```python\npost = prior | (f(x, [noise]), y)\n\npost = prior | ((f1(x1, [noise1]), y1), (f2(x2, [noise2]), y2), ...)\n```\n\nYou can then obtain a posterior process with `post(f)` and a finite-dimensional\ndistribution under the posterior with `post(f(x))`.\nAlternatively, the posterior of a process `f` can be obtained by conditioning `f`\ndirectly.\n\nDefinition, where and `f*` are `GP`s:\n\n```python\nf_post = f | (f(x, [noise]), y)\n\nf_post = f | ((f1(x1, [noise1]), y1), (f2(x2, [noise2]), y2), ...)\n```\n\nLet's consider an example.\nFirst, build a model and sample some values.\n\n```python\n>>> prior = Measure()\n\n>>> f = GP(EQ(), measure=prior)\n\n>>> x = np.array([0., 1., 2.])\n\n>>> y = f(x).sample()\n```\n\nThen compute the posterior measure.\n\n```python\n>>> post = prior | (f(x), y)\n\n>>> post(f)\nGP(PosteriorMean(), PosteriorKernel())\n\n>>> post(f).mean(x)\n\n\n>>> post(f).kernel(x)\n\n\n>>> post(f(x))\n>\n\n>>> post(f(x)).mean\n\n\n>>> post(f(x)).var\n\n```\n\nWe can also obtain the posterior by conditioning `f` directly:\n\n```python\n>>> f_post = f | (f(x), y)\n\n>>> f_post\nGP(PosteriorMean(), PosteriorKernel())\n\n>>> f_post.mean(x)\n\n\n>>> f_post.kernel(x)\n\n\n>>> f_post(x)\n>\n\n>>> f_post(x).mean\n\n\n>>> f_post(x).var\n\n```\n\nWe can further extend our model by building on the posterior.\n\n```python\n>>> g = GP(Linear(), measure=post)\n\n>>> f_sum = post(f) + g\n\n>>> f_sum\nGP(PosteriorMean(), PosteriorKernel() + Linear())\n```\n\nHowever, what we cannot do is mixing the prior and posterior.\n\n```python\n>>> f + g\nAssertionError: Processes GP(0, EQ()) and GP(0, Linear()) are associated to different measures.\n```\n\n### Inducing Points\n\nStheno supports pseudo-point approximations of posterior distributions with\nvarious approximation methods:\n\n1. The Variational Free Energy (VFE;\n [Titsias, 2009](http://proceedings.mlr.press/v5/titsias09a/titsias09a.pdf))\n approximation.\n To use the VFE approximation, use `PseudoObs`.\n\n2. The Fully Independent Training Conditional (FITC;\n [Snelson & Ghahramani, 2006](http://www.gatsby.ucl.ac.uk/~snelson/SPGP_up.pdf))\n approximation. \n To use the FITC approximation, use `PseudoObsFITC`.\n \n3. The Deterministic Training Conditional (DTC;\n [Csato & Opper, 2002](https://direct.mit.edu/neco/article/14/3/641/6594/Sparse-On-Line-Gaussian-Processes);\n [Seeger et al., 2003](http://proceedings.mlr.press/r4/seeger03a/seeger03a.pdf))\n approximation.\n To use the DTC approximation, use `PseudoObsDTC`.\n\nThe VFE approximation (`PseudoObs`) is the approximation recommended to use.\nThe following definitions and examples will use the VFE approximation with `PseudoObs`,\nbut every instance of `PseudoObs` can be swapped out for `PseudoObsFITC` or \n`PseudoObsDTC`.\n\nDefinition:\n\n```python\nobs = PseudoObs(\n u(z), # FDD of inducing points\n (f(x, [noise]), y) # Observed data\n)\n \nobs = PseudoObs(u(z), f(x, [noise]), y)\n\nobs = PseudoObs(u(z), (f1(x1, [noise1]), y1), (f2(x2, [noise2]), y2), ...)\n\nobs = PseudoObs((u1(z1), u2(z2), ...), f(x, [noise]), y)\n\nobs = PseudoObs((u1(z1), u2(z2), ...), (f1(x1, [noise1]), y1), (f2(x2, [noise2]), y2), ...)\n```\n\nThe approximate posterior measure can be constructed with `prior | obs`\nwhere `prior = Measure()` is the measure of your model.\nTo quantify the quality of the approximation, you can compute the ELBO with \n`obs.elbo(prior)`.\n\nLet's consider an example.\nFirst, build a model and sample some noisy observations.\n\n```python\n>>> prior = Measure()\n\n>>> f = GP(EQ(), measure=prior)\n\n>>> x_obs = np.linspace(0, 10, 2000)\n\n>>> y_obs = f(x_obs, 1).sample()\n```\n\nOuch, computing the logpdf is quite slow:\n\n```python\n>>> %timeit f(x_obs, 1).logpdf(y_obs)\n219 ms \u00b1 35.7 ms per loop (mean \u00b1 std. dev. of 7 runs, 10 loops each)\n```\n\nLet's try to use inducing points to speed this up.\n\n```python\n>>> x_ind = np.linspace(0, 10, 100)\n\n>>> u = f(x_ind) # FDD of inducing points.\n\n>>> %timeit PseudoObs(u, f(x_obs, 1), y_obs).elbo(prior)\n9.8 ms \u00b1 181 \u00b5s per loop (mean \u00b1 std. dev. of 7 runs, 100 loops each)\n```\n\nMuch better.\nAnd the approximation is good:\n\n```python\n>>> PseudoObs(u, f(x_obs, 1), y_obs).elbo(prior) - f(x_obs, 1).logpdf(y_obs)\n-3.537934389896691e-10\n```\n\nWe finally construct the approximate posterior measure:\n\n```python\n>>> post_approx = prior | PseudoObs(u, f(x_obs, 1), y_obs)\n\n>>> post_approx(f(x_obs)).mean\n\n```\n\n\n### Kernels and Means\n\nSee [MLKernels](https://github.com/wesselb/mlkernels).\n\n\n### Batched Computation\n\nStheno supports batched computation.\nSee [MLKernels](https://github.com/wesselb/mlkernels/#usage) for a description of how\nmeans and kernels work with batched computation.\n\nExample:\n\n```python\n>>> f = GP(EQ())\n\n>>> x = np.random.randn(16, 100, 1)\n\n>>> y = f(x, 1).sample()\n\n>>> logpdf = f(x, 1).logpdf(y)\n\n>>> y.shape\n(16, 100, 1)\n\n>>> f(x, 1).logpdf(y).shape\n(16,)\n```\n\n\n### Important Remarks\n\nStheno uses [LAB](https://github.com/wesselb/lab) to provide an implementation that is\nbackend agnostic.\nMoreover, Stheno uses [an extension of LAB](https://github.com/wesselb/matrix) to\naccelerate linear algebra with structured linear algebra primitives.\nYou will encounter these primitives:\n\n```python\n>>> k = 2 * Delta()\n\n>>> x = np.linspace(0, 5, 10)\n\n>>> k(x)\n\n```\n\nIf you're using [LAB](https://github.com/wesselb/lab) to further process these matrices,\nthen there is absolutely no need to worry:\nthese structured matrix types know how to add, multiply, and do other linear algebra\noperations.\n\n```python\n>>> import lab as B\n\n>>> B.matmul(k(x), k(x))\n\n```\n\nIf you're not using [LAB](https://github.com/wesselb/lab), you can convert these\nstructured primitives to regular NumPy/TensorFlow/PyTorch/JAX arrays by calling\n`B.dense` (`B` is from [LAB](https://github.com/wesselb/lab)):\n\n```python\n>>> import lab as B\n\n>>> B.dense(k(x))\narray([[2., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n [0., 2., 0., 0., 0., 0., 0., 0., 0., 0.],\n [0., 0., 2., 0., 0., 0., 0., 0., 0., 0.],\n [0., 0., 0., 2., 0., 0., 0., 0., 0., 0.],\n [0., 0., 0., 0., 2., 0., 0., 0., 0., 0.],\n [0., 0., 0., 0., 0., 2., 0., 0., 0., 0.],\n [0., 0., 0., 0., 0., 0., 2., 0., 0., 0.],\n [0., 0., 0., 0., 0., 0., 0., 2., 0., 0.],\n [0., 0., 0., 0., 0., 0., 0., 0., 2., 0.],\n [0., 0., 0., 0., 0., 0., 0., 0., 0., 2.]])\n```\n\nFurthermore, before computing a Cholesky decomposition, Stheno always adds a minuscule\ndiagonal to prevent the Cholesky decomposition from failing due to positive\nindefiniteness caused by numerical noise.\nYou can change the magnitude of this diagonal by changing `B.epsilon`:\n\n```python\n>>> import lab as B\n\n>>> B.epsilon = 1e-12 # Default regularisation\n\n>>> B.epsilon = 1e-8 # Strong regularisation\n```\n\n\n## Examples\n\nThe examples make use of [Varz](https://github.com/wesselb/varz) and some\nutility from [WBML](https://github.com/wesselb/wbml).\n\n\n### Simple Regression\n\n![Prediction](https://raw.githubusercontent.com/wesselb/stheno/master/readme_example1_simple_regression.png)\n\n```python\nimport matplotlib.pyplot as plt\nfrom wbml.plot import tweak\n\nfrom stheno import B, GP, EQ\n\n# Define points to predict at.\nx = B.linspace(0, 10, 100)\nx_obs = B.linspace(0, 7, 20)\n\n# Construct a prior.\nf = GP(EQ().periodic(5.0))\n\n# Sample a true, underlying function and noisy observations.\nf_true, y_obs = f.measure.sample(f(x), f(x_obs, 0.5))\n\n# Now condition on the observations to make predictions.\nf_post = f | (f(x_obs, 0.5), y_obs)\nmean, lower, upper = f_post(x).marginal_credible_bounds()\n\n# Plot result.\nplt.plot(x, f_true, label=\"True\", style=\"test\")\nplt.scatter(x_obs, y_obs, label=\"Observations\", style=\"train\", s=20)\nplt.plot(x, mean, label=\"Prediction\", style=\"pred\")\nplt.fill_between(x, lower, upper, style=\"pred\")\ntweak()\nplt.savefig(\"readme_example1_simple_regression.png\")\nplt.show()\n```\n\n### Hyperparameter Optimisation with Varz\n\n![Prediction](https://raw.githubusercontent.com/wesselb/stheno/master/readme_example12_optimisation_varz.png)\n\n```python\nimport lab as B\nimport matplotlib.pyplot as plt\nimport torch\nfrom varz import Vars, minimise_l_bfgs_b, parametrised, Positive\nfrom wbml.plot import tweak\n\nfrom stheno.torch import EQ, GP\n\n# Increase regularisation because PyTorch defaults to 32-bit floats.\nB.epsilon = 1e-6\n\n# Define points to predict at.\nx = torch.linspace(0, 2, 100)\nx_obs = torch.linspace(0, 2, 50)\n\n# Sample a true, underlying function and observations with observation noise `0.05`.\nf_true = torch.sin(5 * x)\ny_obs = torch.sin(5 * x_obs) + 0.05**0.5 * torch.randn(50)\n\n\ndef model(vs):\n \"\"\"Construct a model with learnable parameters.\"\"\"\n p = vs.struct # Varz handles positivity (and other) constraints.\n kernel = p.variance.positive() * EQ().stretch(p.scale.positive())\n return GP(kernel), p.noise.positive()\n\n\n@parametrised\ndef model_alternative(vs, scale: Positive, variance: Positive, noise: Positive):\n \"\"\"Equivalent to :func:`model`, but with `@parametrised`.\"\"\"\n kernel = variance * EQ().stretch(scale)\n return GP(kernel), noise\n\n\nvs = Vars(torch.float32)\nf, noise = model(vs)\n\n# Condition on observations and make predictions before optimisation.\nf_post = f | (f(x_obs, noise), y_obs)\nprior_before = f, noise\npred_before = f_post(x, noise).marginal_credible_bounds()\n\n\ndef objective(vs):\n f, noise = model(vs)\n evidence = f(x_obs, noise).logpdf(y_obs)\n return -evidence\n\n\n# Learn hyperparameters.\nminimise_l_bfgs_b(objective, vs)\n\nf, noise = model(vs)\n\n# Condition on observations and make predictions after optimisation.\nf_post = f | (f(x_obs, noise), y_obs)\nprior_after = f, noise\npred_after = f_post(x, noise).marginal_credible_bounds()\n\n\ndef plot_prediction(prior, pred):\n f, noise = prior\n mean, lower, upper = pred\n plt.scatter(x_obs, y_obs, label=\"Observations\", style=\"train\", s=20)\n plt.plot(x, f_true, label=\"True\", style=\"test\")\n plt.plot(x, mean, label=\"Prediction\", style=\"pred\")\n plt.fill_between(x, lower, upper, style=\"pred\")\n plt.ylim(-2, 2)\n plt.text(\n 0.02,\n 0.02,\n f\"var = {f.kernel.factor(0):.2f}, \"\n f\"scale = {f.kernel.factor(1).stretches[0]:.2f}, \"\n f\"noise = {noise:.2f}\",\n transform=plt.gca().transAxes,\n )\n tweak()\n\n\n# Plot result.\nplt.figure(figsize=(10, 4))\nplt.subplot(1, 2, 1)\nplt.title(\"Before optimisation\")\nplot_prediction(prior_before, pred_before)\nplt.subplot(1, 2, 2)\nplt.title(\"After optimisation\")\nplot_prediction(prior_after, pred_after)\nplt.savefig(\"readme_example12_optimisation_varz.png\")\nplt.show()\n```\n\n### Hyperparameter Optimisation with PyTorch\n\n![Prediction](https://raw.githubusercontent.com/wesselb/stheno/master/readme_example13_optimisation_torch.png)\n\n```python\nimport lab as B\nimport matplotlib.pyplot as plt\nimport torch\nfrom wbml.plot import tweak\n\nfrom stheno.torch import EQ, GP\n\n# Increase regularisation because PyTorch defaults to 32-bit floats.\nB.epsilon = 1e-6\n\n# Define points to predict at.\nx = torch.linspace(0, 2, 100)\nx_obs = torch.linspace(0, 2, 50)\n\n# Sample a true, underlying function and observations with observation noise `0.05`.\nf_true = torch.sin(5 * x)\ny_obs = torch.sin(5 * x_obs) + 0.05**0.5 * torch.randn(50)\n\n\nclass Model(torch.nn.Module):\n \"\"\"A GP model with learnable parameters.\"\"\"\n\n def __init__(self, init_var=0.3, init_scale=1, init_noise=0.2):\n super().__init__()\n # Ensure that the parameters are positive and make them learnable.\n self.log_var = torch.nn.Parameter(torch.log(torch.tensor(init_var)))\n self.log_scale = torch.nn.Parameter(torch.log(torch.tensor(init_scale)))\n self.log_noise = torch.nn.Parameter(torch.log(torch.tensor(init_noise)))\n\n def construct(self):\n self.var = torch.exp(self.log_var)\n self.scale = torch.exp(self.log_scale)\n self.noise = torch.exp(self.log_noise)\n kernel = self.var * EQ().stretch(self.scale)\n return GP(kernel), self.noise\n\n\nmodel = Model()\nf, noise = model.construct()\n\n# Condition on observations and make predictions before optimisation.\nf_post = f | (f(x_obs, noise), y_obs)\nprior_before = f, noise\npred_before = f_post(x, noise).marginal_credible_bounds()\n\n# Perform optimisation.\nopt = torch.optim.Adam(model.parameters(), lr=5e-2)\nfor _ in range(1000):\n opt.zero_grad()\n f, noise = model.construct()\n loss = -f(x_obs, noise).logpdf(y_obs)\n loss.backward()\n opt.step()\n\nf, noise = model.construct()\n\n# Condition on observations and make predictions after optimisation.\nf_post = f | (f(x_obs, noise), y_obs)\nprior_after = f, noise\npred_after = f_post(x, noise).marginal_credible_bounds()\n\n\ndef plot_prediction(prior, pred):\n f, noise = prior\n mean, lower, upper = pred\n plt.scatter(x_obs, y_obs, label=\"Observations\", style=\"train\", s=20)\n plt.plot(x, f_true, label=\"True\", style=\"test\")\n plt.plot(x, mean, label=\"Prediction\", style=\"pred\")\n plt.fill_between(x, lower, upper, style=\"pred\")\n plt.ylim(-2, 2)\n plt.text(\n 0.02,\n 0.02,\n f\"var = {f.kernel.factor(0):.2f}, \"\n f\"scale = {f.kernel.factor(1).stretches[0]:.2f}, \"\n f\"noise = {noise:.2f}\",\n transform=plt.gca().transAxes,\n )\n tweak()\n\n\n# Plot result.\nplt.figure(figsize=(10, 4))\nplt.subplot(1, 2, 1)\nplt.title(\"Before optimisation\")\nplot_prediction(prior_before, pred_before)\nplt.subplot(1, 2, 2)\nplt.title(\"After optimisation\")\nplot_prediction(prior_after, pred_after)\nplt.savefig(\"readme_example13_optimisation_torch.png\")\nplt.show()\n```\n\n### Decomposition of Prediction\n\n![Prediction](https://raw.githubusercontent.com/wesselb/stheno/master/readme_example2_decomposition.png)\n\n```python\nimport matplotlib.pyplot as plt\nfrom wbml.plot import tweak\n\nfrom stheno import Measure, GP, EQ, RQ, Linear, Delta, Exp, B\n\nB.epsilon = 1e-10\n\n# Define points to predict at.\nx = B.linspace(0, 10, 200)\nx_obs = B.linspace(0, 7, 50)\n\n\nwith Measure() as prior:\n # Construct a latent function consisting of four different components.\n f_smooth = GP(EQ())\n f_wiggly = GP(RQ(1e-1).stretch(0.5))\n f_periodic = GP(EQ().periodic(1.0))\n f_linear = GP(Linear())\n f = f_smooth + f_wiggly + f_periodic + 0.2 * f_linear\n\n # Let the observation noise consist of a bit of exponential noise.\n e_indep = GP(Delta())\n e_exp = GP(Exp())\n e = e_indep + 0.3 * e_exp\n\n # Sum the latent function and observation noise to get a model for the observations.\n y = f + 0.5 * e\n\n# Sample a true, underlying function and observations.\n(\n f_true_smooth,\n f_true_wiggly,\n f_true_periodic,\n f_true_linear,\n f_true,\n y_obs,\n) = prior.sample(f_smooth(x), f_wiggly(x), f_periodic(x), f_linear(x), f(x), y(x_obs))\n\n# Now condition on the observations and make predictions for the latent function and\n# its various components.\npost = prior | (y(x_obs), y_obs)\n\npred_smooth = post(f_smooth(x))\npred_wiggly = post(f_wiggly(x))\npred_periodic = post(f_periodic(x))\npred_linear = post(f_linear(x))\npred_f = post(f(x))\n\n\n# Plot results.\ndef plot_prediction(x, f, pred, x_obs=None, y_obs=None):\n plt.plot(x, f, label=\"True\", style=\"test\")\n if x_obs is not None:\n plt.scatter(x_obs, y_obs, label=\"Observations\", style=\"train\", s=20)\n mean, lower, upper = pred.marginal_credible_bounds()\n plt.plot(x, mean, label=\"Prediction\", style=\"pred\")\n plt.fill_between(x, lower, upper, style=\"pred\")\n tweak()\n\n\nplt.figure(figsize=(10, 6))\n\nplt.subplot(3, 1, 1)\nplt.title(\"Prediction\")\nplot_prediction(x, f_true, pred_f, x_obs, y_obs)\n\nplt.subplot(3, 2, 3)\nplt.title(\"Smooth Component\")\nplot_prediction(x, f_true_smooth, pred_smooth)\n\nplt.subplot(3, 2, 4)\nplt.title(\"Wiggly Component\")\nplot_prediction(x, f_true_wiggly, pred_wiggly)\n\nplt.subplot(3, 2, 5)\nplt.title(\"Periodic Component\")\nplot_prediction(x, f_true_periodic, pred_periodic)\n\nplt.subplot(3, 2, 6)\nplt.title(\"Linear Component\")\nplot_prediction(x, f_true_linear, pred_linear)\n\nplt.savefig(\"readme_example2_decomposition.png\")\nplt.show()\n```\n\n### Learn a Function, Incorporating Prior Knowledge About Its Form\n\n![Prediction](https://raw.githubusercontent.com/wesselb/stheno/master/readme_example3_parametric.png)\n\n```python\nimport matplotlib.pyplot as plt\nimport tensorflow as tf\nimport wbml.out as out\nfrom varz.spec import parametrised, Positive\nfrom varz.tensorflow import Vars, minimise_l_bfgs_b\nfrom wbml.plot import tweak\n\nfrom stheno.tensorflow import B, Measure, GP, EQ, Delta\n\n# Define points to predict at.\nx = B.linspace(tf.float64, 0, 5, 100)\nx_obs = B.linspace(tf.float64, 0, 3, 20)\n\n\n@parametrised\ndef model(\n vs,\n u_var: Positive = 0.5,\n u_scale: Positive = 0.5,\n noise: Positive = 0.5,\n alpha: Positive = 1.2,\n):\n with Measure():\n # Random fluctuation:\n u = GP(u_var * EQ().stretch(u_scale))\n # Construct model.\n f = u + (lambda x: x**alpha)\n return f, noise\n\n\n# Sample a true, underlying function and observations.\nvs = Vars(tf.float64)\nf_true = x**1.8 + B.sin(2 * B.pi * x)\nf, y = model(vs)\npost = f.measure | (f(x), f_true)\ny_obs = post(f(x_obs)).sample()\n\n\ndef objective(vs):\n f, noise = model(vs)\n evidence = f(x_obs, noise).logpdf(y_obs)\n return -evidence\n\n\n# Learn hyperparameters.\nminimise_l_bfgs_b(objective, vs, jit=True)\nf, noise = model(vs)\n\n# Print the learned parameters.\nout.kv(\"Prior\", f.display(out.format))\nvs.print()\n\n# Condition on the observations to make predictions.\nf_post = f | (f(x_obs, noise), y_obs)\nmean, lower, upper = f_post(x).marginal_credible_bounds()\n\n# Plot result.\nplt.plot(x, B.squeeze(f_true), label=\"True\", style=\"test\")\nplt.scatter(x_obs, B.squeeze(y_obs), label=\"Observations\", style=\"train\", s=20)\nplt.plot(x, mean, label=\"Prediction\", style=\"pred\")\nplt.fill_between(x, lower, upper, style=\"pred\")\ntweak()\n\nplt.savefig(\"readme_example3_parametric.png\")\nplt.show()\n```\n\n### Multi-Output Regression\n\n![Prediction](https://raw.githubusercontent.com/wesselb/stheno/master/readme_example4_multi-output.png)\n\n```python\nimport matplotlib.pyplot as plt\nfrom wbml.plot import tweak\n\nfrom stheno import B, Measure, GP, EQ, Delta\n\n\nclass VGP:\n \"\"\"A vector-valued GP.\"\"\"\n\n def __init__(self, ps):\n self.ps = ps\n\n def __add__(self, other):\n return VGP([f + g for f, g in zip(self.ps, other.ps)])\n\n def lmatmul(self, A):\n m, n = A.shape\n ps = [0 for _ in range(m)]\n for i in range(m):\n for j in range(n):\n ps[i] += A[i, j] * self.ps[j]\n return VGP(ps)\n\n\n# Define points to predict at.\nx = B.linspace(0, 10, 100)\nx_obs = B.linspace(0, 10, 10)\n\n# Model parameters:\nm = 2\np = 4\nH = B.randn(p, m)\n\n\nwith Measure() as prior:\n # Construct latent functions.\n us = VGP([GP(EQ()) for _ in range(m)])\n\n # Construct multi-output prior.\n fs = us.lmatmul(H)\n\n # Construct noise.\n e = VGP([GP(0.5 * Delta()) for _ in range(p)])\n\n # Construct observation model.\n ys = e + fs\n\n# Sample a true, underlying function and observations.\nsamples = prior.sample(*(p(x) for p in fs.ps), *(p(x_obs) for p in ys.ps))\nfs_true, ys_obs = samples[:p], samples[p:]\n\n# Compute the posterior and make predictions.\npost = prior.condition(*((p(x_obs), y_obs) for p, y_obs in zip(ys.ps, ys_obs)))\npreds = [post(p(x)) for p in fs.ps]\n\n\n# Plot results.\ndef plot_prediction(x, f, pred, x_obs=None, y_obs=None):\n plt.plot(x, f, label=\"True\", style=\"test\")\n if x_obs is not None:\n plt.scatter(x_obs, y_obs, label=\"Observations\", style=\"train\", s=20)\n mean, lower, upper = pred.marginal_credible_bounds()\n plt.plot(x, mean, label=\"Prediction\", style=\"pred\")\n plt.fill_between(x, lower, upper, style=\"pred\")\n tweak()\n\n\nplt.figure(figsize=(10, 6))\nfor i in range(4):\n plt.subplot(2, 2, i + 1)\n plt.title(f\"Output {i + 1}\")\n plot_prediction(x, fs_true[i], preds[i], x_obs, ys_obs[i])\nplt.savefig(\"readme_example4_multi-output.png\")\nplt.show()\n```\n\n### Approximate Integration\n\n![Prediction](https://raw.githubusercontent.com/wesselb/stheno/master/readme_example5_integration.png)\n\n```python\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport tensorflow as tf\nimport wbml.plot\n\nfrom stheno.tensorflow import B, Measure, GP, EQ, Delta\n\n# Define points to predict at.\nx = B.linspace(tf.float64, 0, 10, 200)\nx_obs = B.linspace(tf.float64, 0, 10, 10)\n\nwith Measure() as prior:\n # Construct a model.\n f = 0.7 * GP(EQ()).stretch(1.5)\n e = 0.2 * GP(Delta())\n\n # Construct derivatives.\n df = f.diff()\n ddf = df.diff()\n dddf = ddf.diff() + e\n\n# Fix the integration constants.\nzero = B.cast(tf.float64, 0)\none = B.cast(tf.float64, 1)\nprior = prior | ((f(zero), one), (df(zero), zero), (ddf(zero), -one))\n\n# Sample observations.\ny_obs = B.sin(x_obs) + 0.2 * B.randn(*x_obs.shape)\n\n# Condition on the observations to make predictions.\npost = prior | (dddf(x_obs), y_obs)\n\n# And make predictions.\npred_iiif = post(f)(x)\npred_iif = post(df)(x)\npred_if = post(ddf)(x)\npred_f = post(dddf)(x)\n\n\n# Plot result.\ndef plot_prediction(x, f, pred, x_obs=None, y_obs=None):\n plt.plot(x, f, label=\"True\", style=\"test\")\n if x_obs is not None:\n plt.scatter(x_obs, y_obs, label=\"Observations\", style=\"train\", s=20)\n mean, lower, upper = pred.marginal_credible_bounds()\n plt.plot(x, mean, label=\"Prediction\", style=\"pred\")\n plt.fill_between(x, lower, upper, style=\"pred\")\n wbml.plot.tweak()\n\n\nplt.figure(figsize=(10, 6))\n\nplt.subplot(2, 2, 1)\nplt.title(\"Function\")\nplot_prediction(x, np.sin(x), pred_f, x_obs=x_obs, y_obs=y_obs)\n\nplt.subplot(2, 2, 2)\nplt.title(\"Integral of Function\")\nplot_prediction(x, -np.cos(x), pred_if)\n\nplt.subplot(2, 2, 3)\nplt.title(\"Second Integral of Function\")\nplot_prediction(x, -np.sin(x), pred_iif)\n\nplt.subplot(2, 2, 4)\nplt.title(\"Third Integral of Function\")\nplot_prediction(x, np.cos(x), pred_iiif)\n\nplt.savefig(\"readme_example5_integration.png\")\nplt.show()\n```\n\n### Bayesian Linear Regression\n\n![Prediction](https://raw.githubusercontent.com/wesselb/stheno/master/readme_example6_blr.png)\n\n```python\nimport matplotlib.pyplot as plt\nimport wbml.out as out\nfrom wbml.plot import tweak\n\nfrom stheno import B, Measure, GP\n\nB.epsilon = 1e-10 # Very slightly regularise.\n\n# Define points to predict at.\nx = B.linspace(0, 10, 200)\nx_obs = B.linspace(0, 10, 10)\n\nwith Measure() as prior:\n # Construct a linear model.\n slope = GP(1)\n intercept = GP(5)\n f = slope * (lambda x: x) + intercept\n\n# Sample a slope, intercept, underlying function, and observations.\ntrue_slope, true_intercept, f_true, y_obs = prior.sample(\n slope(0), intercept(0), f(x), f(x_obs, 0.2)\n)\n\n# Condition on the observations to make predictions.\npost = prior | (f(x_obs, 0.2), y_obs)\nmean, lower, upper = post(f(x)).marginal_credible_bounds()\n\nout.kv(\"True slope\", true_slope[0, 0])\nout.kv(\"Predicted slope\", post(slope(0)).mean[0, 0])\nout.kv(\"True intercept\", true_intercept[0, 0])\nout.kv(\"Predicted intercept\", post(intercept(0)).mean[0, 0])\n\n# Plot result.\nplt.plot(x, f_true, label=\"True\", style=\"test\")\nplt.scatter(x_obs, y_obs, label=\"Observations\", style=\"train\", s=20)\nplt.plot(x, mean, label=\"Prediction\", style=\"pred\")\nplt.fill_between(x, lower, upper, style=\"pred\")\ntweak()\n\nplt.savefig(\"readme_example6_blr.png\")\nplt.show()\n```\n\n### GPAR\n\n![Prediction](https://raw.githubusercontent.com/wesselb/stheno/master/readme_example7_gpar.png)\n\n```python\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport tensorflow as tf\nfrom varz.spec import parametrised, Positive\nfrom varz.tensorflow import Vars, minimise_l_bfgs_b\nfrom wbml.plot import tweak\n\nfrom stheno.tensorflow import B, GP, EQ\n\n# Define points to predict at.\nx = B.linspace(tf.float64, 0, 10, 200)\nx_obs1 = B.linspace(tf.float64, 0, 10, 30)\ninds2 = np.random.permutation(len(x_obs1))[:10]\nx_obs2 = B.take(x_obs1, inds2)\n\n# Construction functions to predict and observations.\nf1_true = B.sin(x)\nf2_true = B.sin(x) ** 2\n\ny1_obs = B.sin(x_obs1) + 0.1 * B.randn(*x_obs1.shape)\ny2_obs = B.sin(x_obs2) ** 2 + 0.1 * B.randn(*x_obs2.shape)\n\n\n@parametrised\ndef model(\n vs,\n var1: Positive = 1,\n scale1: Positive = 1,\n noise1: Positive = 0.1,\n var2: Positive = 1,\n scale2: Positive = 1,\n noise2: Positive = 0.1,\n):\n # Build layers:\n f1 = GP(var1 * EQ().stretch(scale1))\n f2 = GP(var2 * EQ().stretch(scale2))\n return (f1, noise1), (f2, noise2)\n\n\ndef objective(vs):\n (f1, noise1), (f2, noise2) = model(vs)\n x1 = x_obs1\n x2 = B.stack(x_obs2, B.take(y1_obs, inds2), axis=1)\n evidence = f1(x1, noise1).logpdf(y1_obs) + f2(x2, noise2).logpdf(y2_obs)\n return -evidence\n\n\n# Learn hyperparameters.\nvs = Vars(tf.float64)\nminimise_l_bfgs_b(objective, vs)\n\n# Compute posteriors.\n(f1, noise1), (f2, noise2) = model(vs)\nx1 = x_obs1\nx2 = B.stack(x_obs2, B.take(y1_obs, inds2), axis=1)\nf1_post = f1 | (f1(x1, noise1), y1_obs)\nf2_post = f2 | (f2(x2, noise2), y2_obs)\n\n# Predict first output.\nmean1, lower1, upper1 = f1_post(x).marginal_credible_bounds()\n\n# Predict second output with Monte Carlo.\nsamples = [\n f2_post(B.stack(x, f1_post(x).sample()[:, 0], axis=1)).sample()[:, 0]\n for _ in range(100)\n]\nmean2 = np.mean(samples, axis=0)\nlower2 = np.percentile(samples, 2.5, axis=0)\nupper2 = np.percentile(samples, 100 - 2.5, axis=0)\n\n# Plot result.\nplt.figure()\n\nplt.subplot(2, 1, 1)\nplt.title(\"Output 1\")\nplt.plot(x, f1_true, label=\"True\", style=\"test\")\nplt.scatter(x_obs1, y1_obs, label=\"Observations\", style=\"train\", s=20)\nplt.plot(x, mean1, label=\"Prediction\", style=\"pred\")\nplt.fill_between(x, lower1, upper1, style=\"pred\")\ntweak()\n\nplt.subplot(2, 1, 2)\nplt.title(\"Output 2\")\nplt.plot(x, f2_true, label=\"True\", style=\"test\")\nplt.scatter(x_obs2, y2_obs, label=\"Observations\", style=\"train\", s=20)\nplt.plot(x, mean2, label=\"Prediction\", style=\"pred\")\nplt.fill_between(x, lower2, upper2, style=\"pred\")\ntweak()\n\nplt.savefig(\"readme_example7_gpar.png\")\nplt.show()\n```\n\n### A GP-RNN Model\n\n![Prediction](https://raw.githubusercontent.com/wesselb/stheno/master/readme_example8_gp-rnn.png)\n\n```python\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport tensorflow as tf\nfrom varz.spec import parametrised, Positive\nfrom varz.tensorflow import Vars, minimise_adam\nfrom wbml.net import rnn as rnn_constructor\nfrom wbml.plot import tweak\n\nfrom stheno.tensorflow import B, Measure, GP, EQ\n\n# Increase regularisation because we are dealing with `tf.float32`s.\nB.epsilon = 1e-6\n\n# Construct points which to predict at.\nx = B.linspace(tf.float32, 0, 1, 100)[:, None]\ninds_obs = B.range(0, int(0.75 * len(x))) # Train on the first 75% only.\nx_obs = B.take(x, inds_obs)\n\n# Construct function and observations.\n# Draw random modulation functions.\na_true = GP(1e-2 * EQ().stretch(0.1))(x).sample()\nb_true = GP(1e-2 * EQ().stretch(0.1))(x).sample()\n# Construct the true, underlying function.\nf_true = (1 + a_true) * B.sin(2 * np.pi * 7 * x) + b_true\n# Add noise.\ny_true = f_true + 0.1 * B.randn(*f_true.shape)\n\n# Normalise and split.\nf_true = (f_true - B.mean(y_true)) / B.std(y_true)\ny_true = (y_true - B.mean(y_true)) / B.std(y_true)\ny_obs = B.take(y_true, inds_obs)\n\n\n@parametrised\ndef model(vs, a_scale: Positive = 0.1, b_scale: Positive = 0.1, noise: Positive = 0.01):\n # Construct an RNN.\n f_rnn = rnn_constructor(\n output_size=1, widths=(10,), nonlinearity=B.tanh, final_dense=True\n )\n\n # Set the weights for the RNN.\n num_weights = f_rnn.num_weights(input_size=1)\n weights = Vars(tf.float32, source=vs.get(shape=(num_weights,), name=\"rnn\"))\n f_rnn.initialise(input_size=1, vs=weights)\n\n with Measure():\n # Construct GPs that modulate the RNN.\n a = GP(1e-2 * EQ().stretch(a_scale))\n b = GP(1e-2 * EQ().stretch(b_scale))\n\n # GP-RNN model:\n f_gp_rnn = (1 + a) * (lambda x: f_rnn(x)) + b\n\n return f_rnn, f_gp_rnn, noise, a, b\n\n\ndef objective_rnn(vs):\n f_rnn, _, _, _, _ = model(vs)\n return B.mean((f_rnn(x_obs) - y_obs) ** 2)\n\n\ndef objective_gp_rnn(vs):\n _, f_gp_rnn, noise, _, _ = model(vs)\n evidence = f_gp_rnn(x_obs, noise).logpdf(y_obs)\n return -evidence\n\n\n# Pretrain the RNN.\nvs = Vars(tf.float32)\nminimise_adam(objective_rnn, vs, rate=5e-3, iters=1000, trace=True, jit=True)\n\n# Jointly train the RNN and GPs.\nminimise_adam(objective_gp_rnn, vs, rate=1e-3, iters=1000, trace=True, jit=True)\n\n_, f_gp_rnn, noise, a, b = model(vs)\n\n# Condition.\npost = f_gp_rnn.measure | (f_gp_rnn(x_obs, noise), y_obs)\n\n# Predict and plot results.\nplt.figure(figsize=(10, 6))\n\nplt.subplot(2, 1, 1)\nplt.title(\"$(1 + a)\\\\cdot {}$RNN${} + b$\")\nplt.plot(x, f_true, label=\"True\", style=\"test\")\nplt.scatter(x_obs, y_obs, label=\"Observations\", style=\"train\", s=20)\nmean, lower, upper = post(f_gp_rnn(x)).marginal_credible_bounds()\nplt.plot(x, mean, label=\"Prediction\", style=\"pred\")\nplt.fill_between(x, lower, upper, style=\"pred\")\ntweak()\n\nplt.subplot(2, 2, 3)\nplt.title(\"$a$\")\nmean, lower, upper = post(a(x)).marginal_credible_bounds()\nplt.plot(x, mean, label=\"Prediction\", style=\"pred\")\nplt.fill_between(x, lower, upper, style=\"pred\")\ntweak()\n\nplt.subplot(2, 2, 4)\nplt.title(\"$b$\")\nmean, lower, upper = post(b(x)).marginal_credible_bounds()\nplt.plot(x, mean, label=\"Prediction\", style=\"pred\")\nplt.fill_between(x, lower, upper, style=\"pred\")\ntweak()\n\nplt.savefig(f\"readme_example8_gp-rnn.png\")\nplt.show()\n```\n\n### Approximate Multiplication Between GPs\n\n![Prediction](https://raw.githubusercontent.com/wesselb/stheno/master/readme_example9_product.png)\n\n```python\nimport matplotlib.pyplot as plt\nfrom wbml.plot import tweak\n\nfrom stheno import B, Measure, GP, EQ\n\n# Define points to predict at.\nx = B.linspace(0, 10, 100)\n\nwith Measure() as prior:\n f1 = GP(3, EQ())\n f2 = GP(3, EQ())\n\n # Compute the approximate product.\n f_prod = f1 * f2\n\n# Sample two functions.\ns1, s2 = prior.sample(f1(x), f2(x))\n\n# Predict.\nf_prod_post = f_prod | ((f1(x), s1), (f2(x), s2))\nmean, lower, upper = f_prod_post(x).marginal_credible_bounds()\n\n# Plot result.\nplt.plot(x, s1, label=\"Sample 1\", style=\"train\")\nplt.plot(x, s2, label=\"Sample 2\", style=\"train\", ls=\"--\")\nplt.plot(x, s1 * s2, label=\"True product\", style=\"test\")\nplt.plot(x, mean, label=\"Approximate posterior\", style=\"pred\")\nplt.fill_between(x, lower, upper, style=\"pred\")\ntweak()\n\nplt.savefig(\"readme_example9_product.png\")\nplt.show()\n```\n\n### Sparse Regression\n\n![Prediction](https://raw.githubusercontent.com/wesselb/stheno/master/readme_example10_sparse.png)\n\n```python\nimport matplotlib.pyplot as plt\nimport wbml.out as out\nfrom wbml.plot import tweak\n\nfrom stheno import B, GP, EQ, PseudoObs\n\n# Define points to predict at.\nx = B.linspace(0, 10, 100)\nx_obs = B.linspace(0, 7, 50_000)\nx_ind = B.linspace(0, 10, 20)\n\n# Construct a prior.\nf = GP(EQ().periodic(2 * B.pi))\n\n# Sample a true, underlying function and observations.\nf_true = B.sin(x)\ny_obs = B.sin(x_obs) + B.sqrt(0.5) * B.randn(*x_obs.shape)\n\n# Compute a pseudo-point approximation of the posterior.\nobs = PseudoObs(f(x_ind), (f(x_obs, 0.5), y_obs))\n\n# Compute the ELBO.\nout.kv(\"ELBO\", obs.elbo(f.measure))\n\n# Compute the approximate posterior.\nf_post = f | obs\n\n# Make predictions with the approximate posterior.\nmean, lower, upper = f_post(x).marginal_credible_bounds()\n\n# Plot result.\nplt.plot(x, f_true, label=\"True\", style=\"test\")\nplt.scatter(\n x_obs,\n y_obs,\n label=\"Observations\",\n style=\"train\",\n c=\"tab:green\",\n alpha=0.35,\n)\nplt.scatter(\n x_ind,\n obs.mu(f.measure)[:, 0],\n label=\"Inducing Points\",\n style=\"train\",\n s=20,\n)\nplt.plot(x, mean, label=\"Prediction\", style=\"pred\")\nplt.fill_between(x, lower, upper, style=\"pred\")\ntweak()\n\nplt.savefig(\"readme_example10_sparse.png\")\nplt.show()\n```\n\n### Smoothing with Nonparametric Basis Functions\n\n![Prediction](https://raw.githubusercontent.com/wesselb/stheno/master/readme_example11_nonparametric_basis.png)\n\n```python\nimport matplotlib.pyplot as plt\nfrom wbml.plot import tweak\n\nfrom stheno import B, Measure, GP, EQ\n\n# Define points to predict at.\nx = B.linspace(0, 10, 100)\nx_obs = B.linspace(0, 10, 20)\n\nwith Measure() as prior:\n w = lambda x: B.exp(-(x**2) / 0.5) # Basis function\n b = [(w * GP(EQ())).shift(xi) for xi in x_obs] # Weighted basis functions\n f = sum(b)\n\n# Sample a true, underlying function and observations.\nf_true, y_obs = prior.sample(f(x), f(x_obs, 0.2))\n\n# Condition on the observations to make predictions.\npost = prior | (f(x_obs, 0.2), y_obs)\n\n# Plot result.\nfor i, bi in enumerate(b):\n mean, lower, upper = post(bi(x)).marginal_credible_bounds()\n kw_args = {\"label\": \"Basis functions\"} if i == 0 else {}\n plt.plot(x, mean, style=\"pred2\", **kw_args)\nplt.plot(x, f_true, label=\"True\", style=\"test\")\nplt.scatter(x_obs, y_obs, label=\"Observations\", style=\"train\", s=20)\nmean, lower, upper = post(f(x)).marginal_credible_bounds()\nplt.plot(x, mean, label=\"Prediction\", style=\"pred\")\nplt.fill_between(x, lower, upper, style=\"pred\")\ntweak()\n\nplt.savefig(\"readme_example11_nonparametric_basis.png\")\nplt.show()\n```\n\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/wesselb/stheno", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "stheno", "package_url": "https://pypi.org/project/stheno/", "platform": null, "project_url": "https://pypi.org/project/stheno/", "project_urls": { "Homepage": "https://github.com/wesselb/stheno" }, "release_url": "https://pypi.org/project/stheno/1.3.10/", "requires_dist": null, "requires_python": ">=3.6", "summary": "Implementation of Gaussian processes in Python", "version": "1.3.10", "yanked": false, "yanked_reason": null }, "last_serial": 13587356, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "0e7eb91fc4847bfb04edfe19145e586e", "sha256": "79ccae8ed2af368f2e9447ae6bcdb0fa0b5a57156d9a039094061b059634704c" }, "downloads": -1, "filename": "stheno-0.1.0.tar.gz", "has_sig": false, "md5_digest": "0e7eb91fc4847bfb04edfe19145e586e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 81652, "upload_time": "2019-06-13T16:34:42", "upload_time_iso_8601": "2019-06-13T16:34:42.741004Z", "url": "https://files.pythonhosted.org/packages/e8/c9/cea39d93a98e4cfeb9dfd0a1706bb204c57b4149d937fbf7acd2fb46ecc1/stheno-0.1.0.tar.gz", "yanked": false, "yanked_reason": null } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "1c4fed8161175b3977b17cdffcad357d", "sha256": "cb61e79c4395095a0948ff3994705600f1c9ec775be1559d73a801cfc301b46e" }, "downloads": -1, "filename": "stheno-0.1.1.tar.gz", "has_sig": false, "md5_digest": "1c4fed8161175b3977b17cdffcad357d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 81793, "upload_time": "2019-06-13T18:01:05", "upload_time_iso_8601": "2019-06-13T18:01:05.124637Z", "url": "https://files.pythonhosted.org/packages/c2/cd/44a247bbc5b94c3c471b019df367f1bb831e7d6b29f89020c00b10cddfd1/stheno-0.1.1.tar.gz", "yanked": false, "yanked_reason": null } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "ebbe1abbdd58191823f686f5668b435e", "sha256": "45611ff2cfa73e0359c32e5a58131aa7f39e1d4470489500a27ce82bedf5c27d" }, "downloads": -1, "filename": "stheno-0.2.0.tar.gz", "has_sig": false, "md5_digest": "ebbe1abbdd58191823f686f5668b435e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 82741, "upload_time": "2019-07-09T22:39:30", "upload_time_iso_8601": "2019-07-09T22:39:30.078236Z", "url": "https://files.pythonhosted.org/packages/7f/2f/8b764ab13da65a317c841d53760dcad5ae0e3187d75ea26ae2a9f416c0f0/stheno-0.2.0.tar.gz", "yanked": false, "yanked_reason": null } ], "0.3.0": [ { "comment_text": "", "digests": { "md5": "381e780633cef528f3cb56bb181794b9", "sha256": "a0e4c0fdf3d777f211055892c0ca61be79b8aa2cb04728f1ae333996a52dd00e" }, "downloads": -1, "filename": "stheno-0.3.0.tar.gz", "has_sig": false, "md5_digest": "381e780633cef528f3cb56bb181794b9", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 82986, "upload_time": "2019-10-29T17:46:58", "upload_time_iso_8601": "2019-10-29T17:46:58.351706Z", "url": "https://files.pythonhosted.org/packages/0b/22/5714d04977e1421ba2de94677e0b0ec64634e1d59f47bae6d78a9001f962/stheno-0.3.0.tar.gz", "yanked": false, "yanked_reason": null } ], "0.3.1": [ { "comment_text": "", "digests": { "md5": "9808443c9002956691f810d54f521b67", "sha256": "f19f4ade979d9055ea5c90e018912be8d8785ffe47e4513f1e484c7ab50f711e" }, "downloads": -1, "filename": "stheno-0.3.1.tar.gz", "has_sig": false, "md5_digest": "9808443c9002956691f810d54f521b67", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 83790, "upload_time": "2019-10-31T18:03:42", "upload_time_iso_8601": "2019-10-31T18:03:42.892326Z", "url": "https://files.pythonhosted.org/packages/2f/50/d2191c365f27c028ac8bd016082da1c97b3d6177d81dd9bb94920991e6ff/stheno-0.3.1.tar.gz", "yanked": false, "yanked_reason": null } ], "0.3.2": [ { "comment_text": "", "digests": { "md5": "51f5c119cbf37d019657adb239637b81", "sha256": "ebb60594247bbbd13e4952dd8572949192aa0e7d326ab52cb0ddee51c18a0379" }, "downloads": -1, "filename": "stheno-0.3.2.tar.gz", "has_sig": false, "md5_digest": "51f5c119cbf37d019657adb239637b81", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 83803, "upload_time": "2019-10-31T18:13:16", "upload_time_iso_8601": "2019-10-31T18:13:16.811216Z", "url": "https://files.pythonhosted.org/packages/95/69/cb5d628d2f564e2fa91204f06ef3345524cad792fb2cb61bb2203eecefdb/stheno-0.3.2.tar.gz", "yanked": false, "yanked_reason": null } ], "0.3.3": [ { "comment_text": "", "digests": { "md5": "dac1cd1786c7c6ba0e4f934f3bfd4be7", "sha256": "838784a3c2e46e59de02920cb5c5af7fe57b5a7f0c4032feeb3489b21e46ade0" }, "downloads": -1, "filename": "stheno-0.3.3.tar.gz", "has_sig": false, "md5_digest": "dac1cd1786c7c6ba0e4f934f3bfd4be7", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 84107, "upload_time": "2019-11-05T13:50:11", "upload_time_iso_8601": "2019-11-05T13:50:11.188124Z", "url": "https://files.pythonhosted.org/packages/1f/fa/6235acb89bbb42bc4cedb4257199886fa8cd25077c199ec9106a574842bc/stheno-0.3.3.tar.gz", "yanked": false, "yanked_reason": null } ], "0.3.4": [ { "comment_text": "", "digests": { "md5": "1c58cbf3a203be0e6bc72ecf096f61a2", "sha256": "06ab4cc75c3ad9097ba8608d11c982054793df707f8857628f3418e9a58d1100" }, "downloads": -1, "filename": "stheno-0.3.4.tar.gz", "has_sig": false, "md5_digest": "1c58cbf3a203be0e6bc72ecf096f61a2", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 83671, "upload_time": "2019-11-06T00:03:53", "upload_time_iso_8601": "2019-11-06T00:03:53.230289Z", "url": "https://files.pythonhosted.org/packages/49/43/fa874aca9767e1e047ff5223259f84827d53bbba880c34c6d47b2d26c7ac/stheno-0.3.4.tar.gz", "yanked": false, "yanked_reason": null } ], "0.4.0": [ { "comment_text": "", "digests": { "md5": "f253a2a178092c8fa2a712466ff7b54a", "sha256": "733a74c34f55e1e429873990b68ba9e3da5b6cd26595d8660dc19189612e3cc4" }, "downloads": -1, "filename": "stheno-0.4.0.tar.gz", "has_sig": false, "md5_digest": "f253a2a178092c8fa2a712466ff7b54a", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 63477, "upload_time": "2020-12-01T00:27:12", "upload_time_iso_8601": "2020-12-01T00:27:12.212049Z", "url": "https://files.pythonhosted.org/packages/0d/a4/577b0da2182546a6027867f521bbd1a1c8aafd10e27b28ae875d1680b35c/stheno-0.4.0.tar.gz", "yanked": false, "yanked_reason": null } ], "0.4.2": [ { "comment_text": "", "digests": { "md5": "c2009d427ae01119bc2b1dbe419262c8", "sha256": "48fd1f4d3664cbba79eb8b76c5061979781d3ea0dee2c8fca18792d4d596514a" }, "downloads": -1, "filename": "stheno-0.4.2.tar.gz", "has_sig": false, "md5_digest": "c2009d427ae01119bc2b1dbe419262c8", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 65443, "upload_time": "2020-12-03T13:17:37", "upload_time_iso_8601": "2020-12-03T13:17:37.371637Z", "url": "https://files.pythonhosted.org/packages/94/33/3578cacb78ba4fde060218192629372015c23b9071065f5f26295ba56f40/stheno-0.4.2.tar.gz", "yanked": false, "yanked_reason": null } ], "0.4.3": [ { "comment_text": "", "digests": { "md5": "0218fef99d550876853c5d0054797c88", "sha256": "b2b23683b0e52f912dd92fe24d0cf74ebffde750c1c7d0395542e90df8a1676e" }, "downloads": -1, "filename": "stheno-0.4.3.tar.gz", "has_sig": false, "md5_digest": "0218fef99d550876853c5d0054797c88", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 66260, "upload_time": "2020-12-03T19:06:48", "upload_time_iso_8601": "2020-12-03T19:06:48.395748Z", "url": "https://files.pythonhosted.org/packages/3c/a7/a4cc6d4df01ab34d75b73cc9456b917d052380097ae8ca8d9c22c238c320/stheno-0.4.3.tar.gz", "yanked": false, "yanked_reason": null } ], "0.4.4": [ { "comment_text": "", "digests": { "md5": "2bc95c2718943451a2f0487d1e4d411b", "sha256": "c4a78ac803b782f1672bc1c9c55c6aa6ebbd94a709f88521d3f5dce4144c3d66" }, "downloads": -1, "filename": "stheno-0.4.4.tar.gz", "has_sig": false, "md5_digest": "2bc95c2718943451a2f0487d1e4d411b", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 66057, "upload_time": "2021-01-15T12:57:51", "upload_time_iso_8601": "2021-01-15T12:57:51.120133Z", "url": "https://files.pythonhosted.org/packages/06/4a/a96fcb70b95a7b91bef2c8e93ee720d2ae7d121e409c89127f1bfb9e7ff1/stheno-0.4.4.tar.gz", "yanked": false, "yanked_reason": null } ], "1.0.0": [ { "comment_text": "", "digests": { "md5": "84a9d71b2bd3cd3719b8004a886e23c9", "sha256": "1cad21982a217cda8eafb31935d344c92b8c1ea41cc67ac8f79e96d6fa8f75cf" }, "downloads": -1, "filename": "stheno-1.0.0.tar.gz", "has_sig": false, "md5_digest": "84a9d71b2bd3cd3719b8004a886e23c9", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 67136, "upload_time": "2021-04-22T07:29:00", "upload_time_iso_8601": "2021-04-22T07:29:00.115053Z", "url": "https://files.pythonhosted.org/packages/8d/bf/4655176d0c576bbee1a96c1d3da9f5ac4e747a6d936cf29f23ac3f62a587/stheno-1.0.0.tar.gz", "yanked": false, "yanked_reason": null } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "58990e1e275dc024ec87fa93f9a33605", "sha256": "68e9235529a34cbe18f27207fd70336e6a5711831b05416635f214604bd99eb8" }, "downloads": -1, "filename": "stheno-1.1.0.tar.gz", "has_sig": false, "md5_digest": "58990e1e275dc024ec87fa93f9a33605", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 52007, "upload_time": "2021-05-17T19:26:29", "upload_time_iso_8601": "2021-05-17T19:26:29.266784Z", "url": "https://files.pythonhosted.org/packages/a1/c9/cc74ba480ce80771723abc39f6378007de16c1c59f1d5e4c234d6c9a8f31/stheno-1.1.0.tar.gz", "yanked": false, "yanked_reason": null } ], "1.1.1": [ { "comment_text": "", "digests": { "md5": "4f3d0a6b2fd8b778f2d8f3a13c0a6b1e", "sha256": "ceba6898982fba67d0e7e8c818abf8d2f29c555897e1951c66ab000719a17f10" }, "downloads": -1, "filename": "stheno-1.1.1.tar.gz", "has_sig": false, "md5_digest": "4f3d0a6b2fd8b778f2d8f3a13c0a6b1e", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 52090, "upload_time": "2021-06-24T17:37:04", "upload_time_iso_8601": "2021-06-24T17:37:04.221481Z", "url": "https://files.pythonhosted.org/packages/b9/62/bc31c83c6d896ee018fa6d8a4a619f50864972e53ded075dd428b9d68c4a/stheno-1.1.1.tar.gz", "yanked": false, "yanked_reason": null } ], "1.1.2": [ { "comment_text": "", "digests": { "md5": "6eaa94cfe745adfcdaab166204ea0571", "sha256": "c7c6143f9140dc862449f8b2eb56b06ee510e1f03238d5d087573eee00876a92" }, "downloads": -1, "filename": "stheno-1.1.2.tar.gz", "has_sig": false, "md5_digest": "6eaa94cfe745adfcdaab166204ea0571", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 53822, "upload_time": "2021-07-03T18:01:31", "upload_time_iso_8601": "2021-07-03T18:01:31.373790Z", "url": "https://files.pythonhosted.org/packages/0b/e0/8bfe923b3edeacc64e6fce90fb3ba4f3e380eb3cc3aa53ca18851360b0c1/stheno-1.1.2.tar.gz", "yanked": false, "yanked_reason": null } ], "1.1.3": [ { "comment_text": "", "digests": { "md5": "61811c1df0aa1ad66595d4b0b541535d", "sha256": "7b1191ca8c82f67fdca73e11ad760e0dffa8f887e1dbe73eb62371069cc5b85d" }, "downloads": -1, "filename": "stheno-1.1.3.tar.gz", "has_sig": false, "md5_digest": "61811c1df0aa1ad66595d4b0b541535d", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 53855, "upload_time": "2021-07-03T19:39:04", "upload_time_iso_8601": "2021-07-03T19:39:04.371599Z", "url": "https://files.pythonhosted.org/packages/03/4e/aeab1038a224b37e5754c9e578d3af65a029d88d083c81a5da216cef5f4b/stheno-1.1.3.tar.gz", "yanked": false, "yanked_reason": null } ], "1.1.4": [ { "comment_text": "", "digests": { "md5": "fca66aba5cb14595ae8822e4429030ec", "sha256": "c85d7767422512920fcd1c5ededc53c0d9d9e9a0588dad3b7d21e4d46d99cc56" }, "downloads": -1, "filename": "stheno-1.1.4.tar.gz", "has_sig": false, "md5_digest": "fca66aba5cb14595ae8822e4429030ec", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 1004213, "upload_time": "2021-08-25T10:01:36", "upload_time_iso_8601": "2021-08-25T10:01:36.046583Z", "url": "https://files.pythonhosted.org/packages/10/a6/1252d50f3e88dfb25567994118b2b2b84f477c28c722bc0b991fc22a4577/stheno-1.1.4.tar.gz", "yanked": false, "yanked_reason": null } ], "1.1.5": [ { "comment_text": "", "digests": { "md5": "f7fc1f3fe28448572407b48b77dc9d61", "sha256": "526b27ecf68487c5df927a3773b8b329c25f705a3a7cdaafb0a93cc9c3c47a36" }, "downloads": -1, "filename": "stheno-1.1.5.tar.gz", "has_sig": false, "md5_digest": "f7fc1f3fe28448572407b48b77dc9d61", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 1006423, "upload_time": "2021-08-25T10:15:28", "upload_time_iso_8601": "2021-08-25T10:15:28.315781Z", "url": "https://files.pythonhosted.org/packages/a3/00/7b9d5e3e3b2c552037f52424497a83dc60a84db683e65e57f40ec0006696/stheno-1.1.5.tar.gz", "yanked": false, "yanked_reason": null } ], "1.1.6": [ { "comment_text": "", "digests": { "md5": "a6fc5a34cd3d336db00ec4fe08cb7ea7", "sha256": "d653b7e79fd9d9ecf92421e0742a806e7837457e94d7bd5f6a92242342ff44dc" }, "downloads": -1, "filename": "stheno-1.1.6.tar.gz", "has_sig": false, "md5_digest": "a6fc5a34cd3d336db00ec4fe08cb7ea7", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 1006950, "upload_time": "2021-08-27T15:01:30", "upload_time_iso_8601": "2021-08-27T15:01:30.347699Z", "url": "https://files.pythonhosted.org/packages/90/21/915fa877e945338e1a0ce3656a355b3c762c38c51ee6c340dd4ce9b36504/stheno-1.1.6.tar.gz", "yanked": false, "yanked_reason": null } ], "1.1.7": [ { "comment_text": "", "digests": { "md5": "7f565990f198c32fa88824662b86edf5", "sha256": "a9fd47f06ddd72d091a763a02c8074d0693ba3f52bd992f60fdbd938e68a2fb5" }, "downloads": -1, "filename": "stheno-1.1.7.tar.gz", "has_sig": false, "md5_digest": "7f565990f198c32fa88824662b86edf5", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 1006985, "upload_time": "2021-08-28T14:23:40", "upload_time_iso_8601": "2021-08-28T14:23:40.623856Z", "url": "https://files.pythonhosted.org/packages/17/8a/c6b603fb2d46d885aa601e005496820b64eff71420c286d0be1e1d4eb774/stheno-1.1.7.tar.gz", "yanked": false, "yanked_reason": null } ], "1.2.0": [ { "comment_text": "", "digests": { "md5": "003b850bb8b9043838ecf8173a728163", "sha256": "320efad57d44f52f0baaddc937eefd36ea279def080ea19b870ab062206a4ef4" }, "downloads": -1, "filename": "stheno-1.2.0.tar.gz", "has_sig": false, "md5_digest": "003b850bb8b9043838ecf8173a728163", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 1007352, "upload_time": "2021-10-31T22:16:31", "upload_time_iso_8601": "2021-10-31T22:16:31.060067Z", "url": "https://files.pythonhosted.org/packages/bf/f7/143349603910e95c7f7e8bbe1582998908241cbaaa95b7566011e89f6b9e/stheno-1.2.0.tar.gz", "yanked": false, "yanked_reason": null } ], "1.2.1": [ { "comment_text": "", "digests": { "md5": "e710075859e7d266b81d6edad797e33f", "sha256": "4099a59a52a40a61b4c51e03455d0ab92c48f1c5bde47e95d546323650ec3836" }, "downloads": -1, "filename": "stheno-1.2.1.tar.gz", "has_sig": false, "md5_digest": "e710075859e7d266b81d6edad797e33f", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 1007281, "upload_time": "2021-11-01T15:42:14", "upload_time_iso_8601": "2021-11-01T15:42:14.693636Z", "url": "https://files.pythonhosted.org/packages/45/9f/bc67c55e9ee100e8da0ea9a365fb82dd9d1161e2c7d031f4dd42ad1221e4/stheno-1.2.1.tar.gz", "yanked": false, "yanked_reason": null } ], "1.3.0": [ { "comment_text": "", "digests": { "md5": "9af997e42727d87cdb4a9851cebb24e2", "sha256": "8bd2897c3c8f511ac35cbbf0259f3a4013b10b16e897dbed5d8dcd615360762a" }, "downloads": -1, "filename": "stheno-1.3.0.tar.gz", "has_sig": false, "md5_digest": "9af997e42727d87cdb4a9851cebb24e2", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 1009707, "upload_time": "2021-11-18T12:13:21", "upload_time_iso_8601": "2021-11-18T12:13:21.784794Z", "url": "https://files.pythonhosted.org/packages/3f/17/60c0d359e56d769a548499586b368fddf0235f130fcc3a49f9040c910b5d/stheno-1.3.0.tar.gz", "yanked": false, "yanked_reason": null } ], "1.3.1": [ { "comment_text": "", "digests": { "md5": "59ebc64e2d3680c5e1aef144df52351a", "sha256": "a5dfec1c4394305d2cdf711d22d1a2d2bf9dbd4364b5081969e0f2bc299ba675" }, "downloads": -1, "filename": "stheno-1.3.1.tar.gz", "has_sig": false, "md5_digest": "59ebc64e2d3680c5e1aef144df52351a", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 1164721, "upload_time": "2021-12-14T16:11:13", "upload_time_iso_8601": "2021-12-14T16:11:13.111646Z", "url": "https://files.pythonhosted.org/packages/79/5b/04fb8204e92fdf0e734c6c1470013a5dfc8b971745c4fe0ac2595dd2657d/stheno-1.3.1.tar.gz", "yanked": false, "yanked_reason": null } ], "1.3.10": [ { "comment_text": "", "digests": { "md5": "b6a32bd98c6b21533ac88443684f33e0", "sha256": "b5bbb9aac8148bdb7f73cc8b301b7096d9332e2a52707a9867c80878d005732c" }, "downloads": -1, "filename": "stheno-1.3.10.tar.gz", "has_sig": false, "md5_digest": "b6a32bd98c6b21533ac88443684f33e0", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 1168625, "upload_time": "2022-04-22T07:08:53", "upload_time_iso_8601": "2022-04-22T07:08:53.441793Z", "url": "https://files.pythonhosted.org/packages/60/1a/0516d5efc490253d6784f462d98aebe00f4261fccaf2524368e9ff1b538c/stheno-1.3.10.tar.gz", "yanked": false, "yanked_reason": null } ], "1.3.2": [ { "comment_text": "", "digests": { "md5": "d2c822f6b77d3c0bd2271892ef32f57b", "sha256": "a222bf3b719f04bafa01a0b3ff4692256c882b4d5a0eec7d2d7fba45a14e1193" }, "downloads": -1, "filename": "stheno-1.3.2.tar.gz", "has_sig": false, "md5_digest": "d2c822f6b77d3c0bd2271892ef32f57b", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 1165864, "upload_time": "2021-12-16T21:25:45", "upload_time_iso_8601": "2021-12-16T21:25:45.209180Z", "url": "https://files.pythonhosted.org/packages/54/95/a00196210176d060c3b668c6f5ddfc85b1e8d16ba9ceee3b4a835d9e7470/stheno-1.3.2.tar.gz", "yanked": false, "yanked_reason": null } ], "1.3.3": [ { "comment_text": "", "digests": { "md5": "ffb3ee0af9f4b1dc0fe18f17b5ab98d9", "sha256": "a16c183e6fa837248eb81c6bd18627ed2fca59f982258b0eb6b889c03cb3b01a" }, "downloads": -1, "filename": "stheno-1.3.3.tar.gz", "has_sig": false, "md5_digest": "ffb3ee0af9f4b1dc0fe18f17b5ab98d9", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 1165996, "upload_time": "2021-12-17T12:20:36", "upload_time_iso_8601": "2021-12-17T12:20:36.732900Z", "url": "https://files.pythonhosted.org/packages/60/3b/c9bfedcaff34e6cac5f8cf89b3c4073df35c46acad4b98ce6ca7df5d7fc5/stheno-1.3.3.tar.gz", "yanked": false, "yanked_reason": null } ], "1.3.4": [ { "comment_text": "", "digests": { "md5": "ba10e4b3321ac9307866aad2e05f1323", "sha256": "c3f667621c970539d9b86210949ea91e678f4f88c0d57cb8fee2bf51c76f224e" }, "downloads": -1, "filename": "stheno-1.3.4.tar.gz", "has_sig": false, "md5_digest": "ba10e4b3321ac9307866aad2e05f1323", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 1166096, "upload_time": "2022-03-10T13:58:02", "upload_time_iso_8601": "2022-03-10T13:58:02.387572Z", "url": "https://files.pythonhosted.org/packages/07/a6/31b81685070c66d4cd8979fdb53f031b5809a8b5bd0677e2951be147fdba/stheno-1.3.4.tar.gz", "yanked": false, "yanked_reason": null } ], "1.3.5": [ { "comment_text": "", "digests": { "md5": "1bce9818151d6423bc6fd22c9d3de112", "sha256": "9c6092b62fbb926729d57774f4d6aa91c1679dab0f30855a7d1697d0ca7c0e5e" }, "downloads": -1, "filename": "stheno-1.3.5.tar.gz", "has_sig": false, "md5_digest": "1bce9818151d6423bc6fd22c9d3de112", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 1166188, "upload_time": "2022-03-28T20:30:43", "upload_time_iso_8601": "2022-03-28T20:30:43.338701Z", "url": "https://files.pythonhosted.org/packages/a8/10/91e799ba4ce292fd69d0b0d6bd8369035f7a77d337a264589869c59150fa/stheno-1.3.5.tar.gz", "yanked": false, "yanked_reason": null } ], "1.3.6": [ { "comment_text": "", "digests": { "md5": "d37d24d55482706a2a413f3ba0ad5131", "sha256": "d2d4e1bd727916d2e938092aaead3b0125923b92af1480a58370ba90cc616b91" }, "downloads": -1, "filename": "stheno-1.3.6.tar.gz", "has_sig": false, "md5_digest": "d37d24d55482706a2a413f3ba0ad5131", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 1166917, "upload_time": "2022-04-01T19:26:04", "upload_time_iso_8601": "2022-04-01T19:26:04.981178Z", "url": "https://files.pythonhosted.org/packages/c0/2c/0207d50a1632f021d93238292d02d1193f4acc6323a21bd5ab56943a5794/stheno-1.3.6.tar.gz", "yanked": false, "yanked_reason": null } ], "1.3.7": [ { "comment_text": "", "digests": { "md5": "09e42d08add4996a19d3d3b5c3386b30", "sha256": "9d27d2ef8ea89e9daa890edb1ebe0a8341f4cfb7c8fdca69735ae5efadccb480" }, "downloads": -1, "filename": "stheno-1.3.7.tar.gz", "has_sig": false, "md5_digest": "09e42d08add4996a19d3d3b5c3386b30", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 1168275, "upload_time": "2022-04-16T15:45:47", "upload_time_iso_8601": "2022-04-16T15:45:47.287821Z", "url": "https://files.pythonhosted.org/packages/ae/d2/02fbb75ba42c9a91cfe03c51ebbfdb359b4d64ca4740ca8bde8d560c0744/stheno-1.3.7.tar.gz", "yanked": false, "yanked_reason": null } ], "1.3.8": [ { "comment_text": "", "digests": { "md5": "b86ff4a548dae9e48791bb88413ab2d9", "sha256": "761882ad2b56cf277e6e5e71f81f54e7ab7004a64bedf3edbb1dd00130b1de37" }, "downloads": -1, "filename": "stheno-1.3.8.tar.gz", "has_sig": false, "md5_digest": "b86ff4a548dae9e48791bb88413ab2d9", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 1168599, "upload_time": "2022-04-16T16:07:23", "upload_time_iso_8601": "2022-04-16T16:07:23.094527Z", "url": "https://files.pythonhosted.org/packages/7b/27/64de6d3829f13742e18017f8c5a884d207a56d795d0bfdd0353374e16258/stheno-1.3.8.tar.gz", "yanked": false, "yanked_reason": null } ], "1.3.9": [ { "comment_text": "", "digests": { "md5": "395ec2a0676741b638910214b715247e", "sha256": "b9815111f450d79f9960b15e99be9f1ae5cdc897ea467f0a34e81ad0539fb39e" }, "downloads": -1, "filename": "stheno-1.3.9.tar.gz", "has_sig": false, "md5_digest": "395ec2a0676741b638910214b715247e", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 1168645, "upload_time": "2022-04-19T11:59:18", "upload_time_iso_8601": "2022-04-19T11:59:18.873941Z", "url": "https://files.pythonhosted.org/packages/19/73/b565dd077fc382baeb4d9954ad9a655bde58fc3da1b66b447bc395ded79e/stheno-1.3.9.tar.gz", "yanked": false, "yanked_reason": null } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "b6a32bd98c6b21533ac88443684f33e0", "sha256": "b5bbb9aac8148bdb7f73cc8b301b7096d9332e2a52707a9867c80878d005732c" }, "downloads": -1, "filename": "stheno-1.3.10.tar.gz", "has_sig": false, "md5_digest": "b6a32bd98c6b21533ac88443684f33e0", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 1168625, "upload_time": "2022-04-22T07:08:53", "upload_time_iso_8601": "2022-04-22T07:08:53.441793Z", "url": "https://files.pythonhosted.org/packages/60/1a/0516d5efc490253d6784f462d98aebe00f4261fccaf2524368e9ff1b538c/stheno-1.3.10.tar.gz", "yanked": false, "yanked_reason": null } ], "vulnerabilities": [] }