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 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
+ ]
@@ -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
+ ]