geopytorch 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- geopytorch-0.1.0/LICENSE +21 -0
- geopytorch-0.1.0/PKG-INFO +130 -0
- geopytorch-0.1.0/README.md +112 -0
- geopytorch-0.1.0/pyproject.toml +35 -0
- geopytorch-0.1.0/pyproject.toml.orig +33 -0
- geopytorch-0.1.0/src/geopytorch/__init__.py +29 -0
- geopytorch-0.1.0/src/geopytorch/covariance.py +179 -0
- geopytorch-0.1.0/src/geopytorch/kriging.py +577 -0
- geopytorch-0.1.0/src/geopytorch/py.typed +0 -0
- geopytorch-0.1.0/src/geopytorch/regression.py +435 -0
geopytorch-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Daniel Tinoco
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: geopytorch
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Kriging built on GPyTorch
|
|
5
|
+
Author: Daniel Tinoco
|
|
6
|
+
Author-email: Daniel Tinoco <dbtnc.ps2@gmail.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: gpytorch>=1.15.2
|
|
10
|
+
Requires-Dist: numpy>=1.26,<2 ; platform_machine == 'x86_64' and sys_platform == 'darwin'
|
|
11
|
+
Requires-Dist: numpy>=2 ; platform_machine != 'x86_64' or sys_platform != 'darwin'
|
|
12
|
+
Requires-Dist: torch>=2.2,<2.3 ; platform_machine == 'x86_64' and sys_platform == 'darwin'
|
|
13
|
+
Requires-Dist: torch>=2.4 ; platform_machine != 'x86_64' or sys_platform != 'darwin'
|
|
14
|
+
Requires-Python: >=3.12
|
|
15
|
+
Project-URL: Homepage, https://github.com/dbtnc/geopytorch
|
|
16
|
+
Project-URL: Issues, https://github.com/dbtnc/geopytorch/issues
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# GeoPyTorch
|
|
20
|
+
|
|
21
|
+
## R package
|
|
22
|
+
|
|
23
|
+
The R interface is in `r-package/geopytorch-r`. See its
|
|
24
|
+
[README](https://github.com/dbtnc/geopytorch/blob/main/r-package/geopytorch-r/README.md)
|
|
25
|
+
for how to use it from R.
|
|
26
|
+
|
|
27
|
+
## Quick start
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
import torch
|
|
31
|
+
|
|
32
|
+
from geopytorch import OrdinaryKriging, SimpleKriging
|
|
33
|
+
|
|
34
|
+
train_x = torch.tensor([[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]])
|
|
35
|
+
train_y = torch.tensor([1.2, 2.0, 0.7, 1.8])
|
|
36
|
+
target_x = torch.tensor([[0.25, 0.40], [0.75, 0.60]])
|
|
37
|
+
|
|
38
|
+
simple = SimpleKriging(mean=1.4, ard=True).fit(train_x, train_y)
|
|
39
|
+
simple_prediction = simple.predict(target_x)
|
|
40
|
+
|
|
41
|
+
ordinary = OrdinaryKriging(ard=True).fit(train_x, train_y)
|
|
42
|
+
ordinary_prediction = ordinary.predict(target_x)
|
|
43
|
+
|
|
44
|
+
print(ordinary_prediction.mean)
|
|
45
|
+
print(ordinary_prediction.standard_deviation)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Choose a covariance model with `covariance_model`:
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
ordinary = OrdinaryKriging(covariance_model="spherical").fit(train_x, train_y)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Supported models are `"gaussian"`, `"exponential"`, `"matern"`,
|
|
55
|
+
`"spherical"`, and `"wave"`.
|
|
56
|
+
|
|
57
|
+
## Covariance kernels
|
|
58
|
+
|
|
59
|
+
The built-in kernels use the geostatistical range parameter `phi` directly:
|
|
60
|
+
|
|
61
|
+
| Model | Correlation at distance `h` |
|
|
62
|
+
|---|---|
|
|
63
|
+
| Gaussian | `exp(-(h / phi) ** 2)` |
|
|
64
|
+
| Exponential | `exp(-h / phi)` |
|
|
65
|
+
| Matérn | Matérn with Bessel argument `h / phi` |
|
|
66
|
+
| Spherical | `1 - 1.5 h/phi + 0.5 (h/phi) ** 3` for `h < phi`; zero otherwise |
|
|
67
|
+
| Wave | `(phi / h) sin(h / phi)`, with value one at `h = 0` |
|
|
68
|
+
|
|
69
|
+
For Matérn, `matern_nu` is the smoothness parameter; the supported values are
|
|
70
|
+
`0.5`, `1.5`, and `2.5`. Spherical and wave kernels are restricted to at most
|
|
71
|
+
three spatial dimensions, covering the current 2D and planned 3D use cases.
|
|
72
|
+
|
|
73
|
+
`predict()` returns a `KrigingPrediction` containing the joint covariance as
|
|
74
|
+
well as marginal variance and standard deviation. It predicts the latent
|
|
75
|
+
spatial signal by default. Use `observation_noise=True` to include the fitted
|
|
76
|
+
nugget in a future noisy observation:
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
observed_prediction = ordinary.predict(target_x, observation_noise=True)
|
|
80
|
+
lower, upper = observed_prediction.confidence_region()
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Covariance parameter estimation
|
|
84
|
+
|
|
85
|
+
`OrdinaryKriging` supports both maximum likelihood and restricted maximum
|
|
86
|
+
likelihood. REML profiles the unknown constant mean out of a dense Gaussian
|
|
87
|
+
restricted-likelihood objective. L-BFGS is available for deterministic
|
|
88
|
+
likelihood optimization:
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
ordinary = OrdinaryKriging(covariance_model="exponential").fit(
|
|
92
|
+
train_x,
|
|
93
|
+
train_y,
|
|
94
|
+
likelihood_method="reml",
|
|
95
|
+
optimizer="lbfgs",
|
|
96
|
+
training_iterations=50,
|
|
97
|
+
learning_rate=1.0,
|
|
98
|
+
)
|
|
99
|
+
print(ordinary.restricted_log_likelihood_)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
REML is not exposed for `SimpleKriging`: its constant mean is known rather
|
|
103
|
+
than an unknown fixed effect. Use the default maximum-likelihood objective to
|
|
104
|
+
estimate its covariance parameters.
|
|
105
|
+
|
|
106
|
+
## Known covariance parameters
|
|
107
|
+
|
|
108
|
+
Both estimators default to a scaled Matérn-3/2 kernel and a
|
|
109
|
+
homoskedastic Gaussian likelihood. To perform classical Kriging with parameters
|
|
110
|
+
supplied by the user, construct a covariance kernel and skip likelihood
|
|
111
|
+
optimization:
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
import gpytorch
|
|
115
|
+
from geopytorch import covariance_kernel
|
|
116
|
+
|
|
117
|
+
kernel = covariance_kernel("matern", matern_nu=1.5, ard_num_dims=2)
|
|
118
|
+
kernel.initialize(outputscale=2.0)
|
|
119
|
+
kernel.base_kernel.initialize(lengthscale=torch.tensor([0.4, 0.8]))
|
|
120
|
+
|
|
121
|
+
likelihood = gpytorch.likelihoods.GaussianLikelihood()
|
|
122
|
+
likelihood.initialize(noise=0.05)
|
|
123
|
+
|
|
124
|
+
ordinary = OrdinaryKriging(kernel=kernel, likelihood=likelihood)
|
|
125
|
+
ordinary.fit(train_x, train_y, training_iterations=0)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Simple Kriging freezes its known constant mean. Ordinary Kriging uses a
|
|
129
|
+
trainable constant while fitting covariance hyperparameters, then applies the
|
|
130
|
+
exact unit-sum weight and mean-uncertainty corrections during prediction.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# GeoPyTorch
|
|
2
|
+
|
|
3
|
+
## R package
|
|
4
|
+
|
|
5
|
+
The R interface is in `r-package/geopytorch-r`. See its
|
|
6
|
+
[README](https://github.com/dbtnc/geopytorch/blob/main/r-package/geopytorch-r/README.md)
|
|
7
|
+
for how to use it from R.
|
|
8
|
+
|
|
9
|
+
## Quick start
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
import torch
|
|
13
|
+
|
|
14
|
+
from geopytorch import OrdinaryKriging, SimpleKriging
|
|
15
|
+
|
|
16
|
+
train_x = torch.tensor([[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]])
|
|
17
|
+
train_y = torch.tensor([1.2, 2.0, 0.7, 1.8])
|
|
18
|
+
target_x = torch.tensor([[0.25, 0.40], [0.75, 0.60]])
|
|
19
|
+
|
|
20
|
+
simple = SimpleKriging(mean=1.4, ard=True).fit(train_x, train_y)
|
|
21
|
+
simple_prediction = simple.predict(target_x)
|
|
22
|
+
|
|
23
|
+
ordinary = OrdinaryKriging(ard=True).fit(train_x, train_y)
|
|
24
|
+
ordinary_prediction = ordinary.predict(target_x)
|
|
25
|
+
|
|
26
|
+
print(ordinary_prediction.mean)
|
|
27
|
+
print(ordinary_prediction.standard_deviation)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Choose a covariance model with `covariance_model`:
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
ordinary = OrdinaryKriging(covariance_model="spherical").fit(train_x, train_y)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Supported models are `"gaussian"`, `"exponential"`, `"matern"`,
|
|
37
|
+
`"spherical"`, and `"wave"`.
|
|
38
|
+
|
|
39
|
+
## Covariance kernels
|
|
40
|
+
|
|
41
|
+
The built-in kernels use the geostatistical range parameter `phi` directly:
|
|
42
|
+
|
|
43
|
+
| Model | Correlation at distance `h` |
|
|
44
|
+
|---|---|
|
|
45
|
+
| Gaussian | `exp(-(h / phi) ** 2)` |
|
|
46
|
+
| Exponential | `exp(-h / phi)` |
|
|
47
|
+
| Matérn | Matérn with Bessel argument `h / phi` |
|
|
48
|
+
| Spherical | `1 - 1.5 h/phi + 0.5 (h/phi) ** 3` for `h < phi`; zero otherwise |
|
|
49
|
+
| Wave | `(phi / h) sin(h / phi)`, with value one at `h = 0` |
|
|
50
|
+
|
|
51
|
+
For Matérn, `matern_nu` is the smoothness parameter; the supported values are
|
|
52
|
+
`0.5`, `1.5`, and `2.5`. Spherical and wave kernels are restricted to at most
|
|
53
|
+
three spatial dimensions, covering the current 2D and planned 3D use cases.
|
|
54
|
+
|
|
55
|
+
`predict()` returns a `KrigingPrediction` containing the joint covariance as
|
|
56
|
+
well as marginal variance and standard deviation. It predicts the latent
|
|
57
|
+
spatial signal by default. Use `observation_noise=True` to include the fitted
|
|
58
|
+
nugget in a future noisy observation:
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
observed_prediction = ordinary.predict(target_x, observation_noise=True)
|
|
62
|
+
lower, upper = observed_prediction.confidence_region()
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Covariance parameter estimation
|
|
66
|
+
|
|
67
|
+
`OrdinaryKriging` supports both maximum likelihood and restricted maximum
|
|
68
|
+
likelihood. REML profiles the unknown constant mean out of a dense Gaussian
|
|
69
|
+
restricted-likelihood objective. L-BFGS is available for deterministic
|
|
70
|
+
likelihood optimization:
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
ordinary = OrdinaryKriging(covariance_model="exponential").fit(
|
|
74
|
+
train_x,
|
|
75
|
+
train_y,
|
|
76
|
+
likelihood_method="reml",
|
|
77
|
+
optimizer="lbfgs",
|
|
78
|
+
training_iterations=50,
|
|
79
|
+
learning_rate=1.0,
|
|
80
|
+
)
|
|
81
|
+
print(ordinary.restricted_log_likelihood_)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
REML is not exposed for `SimpleKriging`: its constant mean is known rather
|
|
85
|
+
than an unknown fixed effect. Use the default maximum-likelihood objective to
|
|
86
|
+
estimate its covariance parameters.
|
|
87
|
+
|
|
88
|
+
## Known covariance parameters
|
|
89
|
+
|
|
90
|
+
Both estimators default to a scaled Matérn-3/2 kernel and a
|
|
91
|
+
homoskedastic Gaussian likelihood. To perform classical Kriging with parameters
|
|
92
|
+
supplied by the user, construct a covariance kernel and skip likelihood
|
|
93
|
+
optimization:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
import gpytorch
|
|
97
|
+
from geopytorch import covariance_kernel
|
|
98
|
+
|
|
99
|
+
kernel = covariance_kernel("matern", matern_nu=1.5, ard_num_dims=2)
|
|
100
|
+
kernel.initialize(outputscale=2.0)
|
|
101
|
+
kernel.base_kernel.initialize(lengthscale=torch.tensor([0.4, 0.8]))
|
|
102
|
+
|
|
103
|
+
likelihood = gpytorch.likelihoods.GaussianLikelihood()
|
|
104
|
+
likelihood.initialize(noise=0.05)
|
|
105
|
+
|
|
106
|
+
ordinary = OrdinaryKriging(kernel=kernel, likelihood=likelihood)
|
|
107
|
+
ordinary.fit(train_x, train_y, training_iterations=0)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Simple Kriging freezes its known constant mean. Ordinary Kriging uses a
|
|
111
|
+
trainable constant while fitting covariance hyperparameters, then applies the
|
|
112
|
+
exact unit-sum weight and mean-uncertainty corrections during prediction.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "geopytorch"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Kriging built on GPyTorch"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
requires-python = ">=3.12"
|
|
9
|
+
dependencies = [
|
|
10
|
+
"gpytorch>=1.15.2",
|
|
11
|
+
"numpy>=1.26,<2; sys_platform == 'darwin' and platform_machine == 'x86_64'",
|
|
12
|
+
"numpy>=2; sys_platform != 'darwin' or platform_machine != 'x86_64'",
|
|
13
|
+
"torch>=2.2,<2.3; sys_platform == 'darwin' and platform_machine == 'x86_64'",
|
|
14
|
+
"torch>=2.4; sys_platform != 'darwin' or platform_machine != 'x86_64'",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[[project.authors]]
|
|
18
|
+
name = "Daniel Tinoco"
|
|
19
|
+
email = "dbtnc.ps2@gmail.com"
|
|
20
|
+
|
|
21
|
+
[project.urls]
|
|
22
|
+
Homepage = "https://github.com/dbtnc/geopytorch"
|
|
23
|
+
Issues = "https://github.com/dbtnc/geopytorch/issues"
|
|
24
|
+
|
|
25
|
+
[build-system]
|
|
26
|
+
requires = ["uv_build>=0.12.5,<0.13.0"]
|
|
27
|
+
build-backend = "uv_build"
|
|
28
|
+
|
|
29
|
+
[dependency-groups]
|
|
30
|
+
dev = [
|
|
31
|
+
"air-formatter>=0.12.0",
|
|
32
|
+
"prek>=0.5.5",
|
|
33
|
+
"pytest>=9.1.1",
|
|
34
|
+
"ruff>=0.17.0",
|
|
35
|
+
]
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "geopytorch"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Kriging built on GPyTorch"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "Daniel Tinoco", email = "dbtnc.ps2@gmail.com" }
|
|
10
|
+
]
|
|
11
|
+
requires-python = ">=3.12"
|
|
12
|
+
dependencies = [
|
|
13
|
+
"gpytorch>=1.15.2",
|
|
14
|
+
"numpy>=1.26,<2; sys_platform == 'darwin' and platform_machine == 'x86_64'",
|
|
15
|
+
"numpy>=2; sys_platform != 'darwin' or platform_machine != 'x86_64'",
|
|
16
|
+
"torch>=2.2,<2.3; sys_platform == 'darwin' and platform_machine == 'x86_64'",
|
|
17
|
+
"torch>=2.4; sys_platform != 'darwin' or platform_machine != 'x86_64'",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
[build-system]
|
|
21
|
+
requires = ["uv_build>=0.12.5,<0.13.0"]
|
|
22
|
+
build-backend = "uv_build"
|
|
23
|
+
|
|
24
|
+
[dependency-groups]
|
|
25
|
+
dev = [
|
|
26
|
+
"air-formatter>=0.12.0",
|
|
27
|
+
"prek>=0.5.5",
|
|
28
|
+
"pytest>=9.1.1",
|
|
29
|
+
"ruff>=0.17.0",
|
|
30
|
+
]
|
|
31
|
+
[project.urls]
|
|
32
|
+
Homepage = "https://github.com/dbtnc/geopytorch"
|
|
33
|
+
Issues = "https://github.com/dbtnc/geopytorch/issues"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""GeoPyTorch public API."""
|
|
2
|
+
|
|
3
|
+
from geopytorch.covariance import (
|
|
4
|
+
COVARIANCE_MODELS,
|
|
5
|
+
CovarianceModel,
|
|
6
|
+
ExponentialKernel,
|
|
7
|
+
GaussianKernel,
|
|
8
|
+
MaternKernel,
|
|
9
|
+
SphericalKernel,
|
|
10
|
+
WaveKernel,
|
|
11
|
+
covariance_kernel,
|
|
12
|
+
)
|
|
13
|
+
from geopytorch.kriging import KrigingPrediction, OrdinaryKriging, SimpleKriging
|
|
14
|
+
from geopytorch.regression import SpatialLinearModel
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"COVARIANCE_MODELS",
|
|
18
|
+
"CovarianceModel",
|
|
19
|
+
"ExponentialKernel",
|
|
20
|
+
"GaussianKernel",
|
|
21
|
+
"KrigingPrediction",
|
|
22
|
+
"MaternKernel",
|
|
23
|
+
"OrdinaryKriging",
|
|
24
|
+
"SimpleKriging",
|
|
25
|
+
"SpatialLinearModel",
|
|
26
|
+
"SphericalKernel",
|
|
27
|
+
"WaveKernel",
|
|
28
|
+
"covariance_kernel",
|
|
29
|
+
]
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# Expected inputs: Coordinate tensors and positive range parameters.
|
|
2
|
+
# Expected outputs: GPyTorch kernels for supported stationary covariance models.
|
|
3
|
+
|
|
4
|
+
"""Covariance kernels built on GPyTorch."""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from math import pi
|
|
9
|
+
from typing import Literal
|
|
10
|
+
|
|
11
|
+
import gpytorch
|
|
12
|
+
import torch
|
|
13
|
+
from torch import Tensor
|
|
14
|
+
|
|
15
|
+
type CovarianceModel = Literal[
|
|
16
|
+
"gaussian", "exponential", "matern", "spherical", "wave"
|
|
17
|
+
]
|
|
18
|
+
COVARIANCE_MODELS: tuple[CovarianceModel, ...] = (
|
|
19
|
+
"gaussian",
|
|
20
|
+
"exponential",
|
|
21
|
+
"matern",
|
|
22
|
+
"spherical",
|
|
23
|
+
"wave",
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class DistanceKernel(gpytorch.kernels.Kernel):
|
|
28
|
+
r"""Base for stationary kernels expressed through scaled distance.
|
|
29
|
+
|
|
30
|
+
``has_lengthscale`` asks GPyTorch to provide a positive trainable range,
|
|
31
|
+
including batching and optional per-coordinate ARD parameters. It does
|
|
32
|
+
not, by itself, define how that parameter enters a covariance formula.
|
|
33
|
+
This class supplies one convention shared by all subclasses:
|
|
34
|
+
|
|
35
|
+
.. math::
|
|
36
|
+
r = \left\lVert \mathbf{x}_1/\boldsymbol{\phi}
|
|
37
|
+
- \mathbf{x}_2/\boldsymbol{\phi}\right\rVert_2.
|
|
38
|
+
|
|
39
|
+
Each subclass therefore receives the same dimensionless distance ``r``
|
|
40
|
+
and states its correlation directly in terms of ``r``. Centralizing this
|
|
41
|
+
step prevents hidden, model-specific distance factors from changing the
|
|
42
|
+
geostatistical meaning of the public range parameter ``phi`` (stored by
|
|
43
|
+
GPyTorch under its standard ``lengthscale`` property).
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
has_lengthscale = True
|
|
47
|
+
|
|
48
|
+
def _scaled_distance(
|
|
49
|
+
self, x1: Tensor, x2: Tensor, *, diag: bool, **params: object
|
|
50
|
+
) -> Tensor:
|
|
51
|
+
return self.covar_dist(
|
|
52
|
+
x1.div(self.lengthscale),
|
|
53
|
+
x2.div(self.lengthscale),
|
|
54
|
+
diag=diag,
|
|
55
|
+
**params,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class GaussianKernel(DistanceKernel):
|
|
60
|
+
r"""Gaussian correlation :math:`\exp[-(h/\phi)^2]`."""
|
|
61
|
+
|
|
62
|
+
def forward(
|
|
63
|
+
self, x1: Tensor, x2: Tensor, diag: bool = False, **params: object
|
|
64
|
+
) -> Tensor:
|
|
65
|
+
distance = self._scaled_distance(x1, x2, diag=diag, **params)
|
|
66
|
+
return torch.exp(-distance.square())
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class ExponentialKernel(DistanceKernel):
|
|
70
|
+
r"""Exponential correlation :math:`\exp(-h/\phi)`."""
|
|
71
|
+
|
|
72
|
+
def forward(
|
|
73
|
+
self, x1: Tensor, x2: Tensor, diag: bool = False, **params: object
|
|
74
|
+
) -> Tensor:
|
|
75
|
+
distance = self._scaled_distance(x1, x2, diag=diag, **params)
|
|
76
|
+
return torch.exp(-distance)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class MaternKernel(DistanceKernel):
|
|
80
|
+
r"""Matérn correlation with Bessel argument :math:`h/\phi`.
|
|
81
|
+
|
|
82
|
+
The supported smoothness values match GPyTorch's exact Matérn kernel:
|
|
83
|
+
``0.5``, ``1.5``, and ``2.5``. Unlike GPyTorch's native parameterization,
|
|
84
|
+
``lengthscale`` here is the geostatistical range ``phi`` without a
|
|
85
|
+
:math:`\sqrt{2\nu}` factor.
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
def __init__(self, nu: float = 1.5, **kwargs: object) -> None:
|
|
89
|
+
if nu not in (0.5, 1.5, 2.5):
|
|
90
|
+
raise ValueError("nu must be one of 0.5, 1.5, or 2.5")
|
|
91
|
+
super().__init__(**kwargs)
|
|
92
|
+
self.nu = float(nu)
|
|
93
|
+
|
|
94
|
+
def forward(
|
|
95
|
+
self, x1: Tensor, x2: Tensor, diag: bool = False, **params: object
|
|
96
|
+
) -> Tensor:
|
|
97
|
+
distance = self._scaled_distance(x1, x2, diag=diag, **params)
|
|
98
|
+
exponential = torch.exp(-distance)
|
|
99
|
+
if self.nu == 0.5:
|
|
100
|
+
polynomial: Tensor | float = 1.0
|
|
101
|
+
elif self.nu == 1.5:
|
|
102
|
+
polynomial = 1.0 + distance
|
|
103
|
+
else:
|
|
104
|
+
polynomial = 1.0 + distance + distance.square() / 3.0
|
|
105
|
+
return polynomial * exponential
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class SphericalKernel(DistanceKernel):
|
|
109
|
+
r"""Spherical correlation with compact-support range ``phi``."""
|
|
110
|
+
|
|
111
|
+
def forward(
|
|
112
|
+
self, x1: Tensor, x2: Tensor, diag: bool = False, **params: object
|
|
113
|
+
) -> Tensor:
|
|
114
|
+
_require_at_most_three_dimensions(x1, "SphericalKernel")
|
|
115
|
+
distance = self._scaled_distance(x1, x2, diag=diag, **params)
|
|
116
|
+
within_range = 1.0 - 1.5 * distance + 0.5 * distance.pow(3)
|
|
117
|
+
return torch.where(
|
|
118
|
+
distance < 1.0, within_range, torch.zeros_like(distance)
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class WaveKernel(DistanceKernel):
|
|
123
|
+
r"""Wave correlation :math:`(\phi/h)\sin(h/\phi)`."""
|
|
124
|
+
|
|
125
|
+
def forward(
|
|
126
|
+
self, x1: Tensor, x2: Tensor, diag: bool = False, **params: object
|
|
127
|
+
) -> Tensor:
|
|
128
|
+
_require_at_most_three_dimensions(x1, "WaveKernel")
|
|
129
|
+
distance = self._scaled_distance(x1, x2, diag=diag, **params)
|
|
130
|
+
return torch.sinc(distance / pi)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def covariance_kernel(
|
|
134
|
+
covariance_model: CovarianceModel = "matern",
|
|
135
|
+
*,
|
|
136
|
+
matern_nu: float = 1.5,
|
|
137
|
+
ard_num_dims: int | None = None,
|
|
138
|
+
) -> gpytorch.kernels.ScaleKernel:
|
|
139
|
+
"""Return a scaled kernel using partial sill ``sigma^2`` and range ``phi``.
|
|
140
|
+
|
|
141
|
+
The returned ``ScaleKernel.outputscale`` is the partial sill ``sigma^2``.
|
|
142
|
+
Its base kernel's ``lengthscale`` is the range ``phi`` used directly in
|
|
143
|
+
the selected geostatistical correlation formula.
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
if covariance_model not in COVARIANCE_MODELS:
|
|
147
|
+
choices = ", ".join(COVARIANCE_MODELS)
|
|
148
|
+
raise ValueError(f"covariance_model must be one of: {choices}")
|
|
149
|
+
kernel_options = {"ard_num_dims": ard_num_dims}
|
|
150
|
+
if covariance_model == "gaussian":
|
|
151
|
+
base_kernel = GaussianKernel(**kernel_options)
|
|
152
|
+
elif covariance_model == "exponential":
|
|
153
|
+
base_kernel = ExponentialKernel(**kernel_options)
|
|
154
|
+
elif covariance_model == "matern":
|
|
155
|
+
base_kernel = MaternKernel(nu=matern_nu, **kernel_options)
|
|
156
|
+
elif covariance_model == "spherical":
|
|
157
|
+
base_kernel = SphericalKernel(**kernel_options)
|
|
158
|
+
else:
|
|
159
|
+
base_kernel = WaveKernel(**kernel_options)
|
|
160
|
+
return gpytorch.kernels.ScaleKernel(base_kernel)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _require_at_most_three_dimensions(x: Tensor, kernel_name: str) -> None:
|
|
164
|
+
if x.shape[-1] > 3:
|
|
165
|
+
raise ValueError(
|
|
166
|
+
f"{kernel_name} is positive definite only for up to 3 spatial dimensions"
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
__all__ = [
|
|
171
|
+
"COVARIANCE_MODELS",
|
|
172
|
+
"CovarianceModel",
|
|
173
|
+
"ExponentialKernel",
|
|
174
|
+
"GaussianKernel",
|
|
175
|
+
"MaternKernel",
|
|
176
|
+
"SphericalKernel",
|
|
177
|
+
"WaveKernel",
|
|
178
|
+
"covariance_kernel",
|
|
179
|
+
]
|