geopytorch 0.1.0__py3-none-any.whl
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/__init__.py +29 -0
- geopytorch/covariance.py +179 -0
- geopytorch/kriging.py +577 -0
- geopytorch/py.typed +0 -0
- geopytorch/regression.py +435 -0
- geopytorch-0.1.0.dist-info/METADATA +130 -0
- geopytorch-0.1.0.dist-info/RECORD +9 -0
- geopytorch-0.1.0.dist-info/WHEEL +4 -0
- geopytorch-0.1.0.dist-info/licenses/LICENSE +21 -0
geopytorch/__init__.py
ADDED
|
@@ -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
|
+
]
|
geopytorch/covariance.py
ADDED
|
@@ -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
|
+
]
|