pygeoinf 1.0.8__py3-none-any.whl → 1.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.
- pygeoinf/__init__.py +5 -1
- pygeoinf/direct_sum.py +113 -85
- pygeoinf/forward_problem.py +33 -32
- pygeoinf/gaussian_measure.py +97 -71
- pygeoinf/hilbert_space.py +517 -241
- pygeoinf/inversion.py +16 -4
- pygeoinf/linear_bayesian.py +57 -36
- pygeoinf/linear_forms.py +169 -0
- pygeoinf/linear_optimisation.py +34 -23
- pygeoinf/linear_solvers.py +74 -247
- pygeoinf/operators.py +175 -36
- pygeoinf/random_matrix.py +36 -32
- pygeoinf/symmetric_space/circle.py +347 -202
- pygeoinf/symmetric_space/sphere.py +335 -435
- pygeoinf/symmetric_space/symmetric_space.py +330 -142
- {pygeoinf-1.0.8.dist-info → pygeoinf-1.1.0.dist-info}/METADATA +1 -1
- pygeoinf-1.1.0.dist-info/RECORD +20 -0
- pygeoinf/forms.py +0 -168
- pygeoinf/symmetric_space/line.py +0 -384
- pygeoinf-1.0.8.dist-info/RECORD +0 -21
- {pygeoinf-1.0.8.dist-info → pygeoinf-1.1.0.dist-info}/LICENSE +0 -0
- {pygeoinf-1.0.8.dist-info → pygeoinf-1.1.0.dist-info}/WHEEL +0 -0
pygeoinf/forms.py
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Module defining the LinearForm class.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from __future__ import annotations
|
|
6
|
-
from typing import Callable, Optional, Any, TYPE_CHECKING
|
|
7
|
-
|
|
8
|
-
import numpy as np
|
|
9
|
-
|
|
10
|
-
# This block only runs for type checkers, not at runtime
|
|
11
|
-
if TYPE_CHECKING:
|
|
12
|
-
from .hilbert_space import HilbertSpace, EuclideanSpace
|
|
13
|
-
from .operators import LinearOperator
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class LinearForm:
|
|
17
|
-
"""
|
|
18
|
-
Represents a linear form, which is a linear functional that maps
|
|
19
|
-
vectors from a Hilbert space to a scalar value (a real number).
|
|
20
|
-
"""
|
|
21
|
-
|
|
22
|
-
def __init__(
|
|
23
|
-
self,
|
|
24
|
-
domain: "HilbertSpace",
|
|
25
|
-
/,
|
|
26
|
-
*,
|
|
27
|
-
mapping: Optional[Callable[[Any], float]] = None,
|
|
28
|
-
components: Optional[np.ndarray] = None,
|
|
29
|
-
) -> None:
|
|
30
|
-
"""
|
|
31
|
-
Initializes the LinearForm.
|
|
32
|
-
|
|
33
|
-
A form can be defined either by its mapping or its component vector.
|
|
34
|
-
|
|
35
|
-
Args:
|
|
36
|
-
domain (HilbertSpace): The Hilbert space on which the form is defined.
|
|
37
|
-
mapping (callable, optional): A function defining the action of the form.
|
|
38
|
-
components (np.ndarray, optional): The component representation of
|
|
39
|
-
the form.
|
|
40
|
-
"""
|
|
41
|
-
|
|
42
|
-
self._domain: "HilbertSpace" = domain
|
|
43
|
-
self._components: Optional[np.ndarray] = components
|
|
44
|
-
self._mapping: Callable[[Any], float]
|
|
45
|
-
|
|
46
|
-
if components is None:
|
|
47
|
-
if mapping is None:
|
|
48
|
-
raise AssertionError("Neither mapping nor components specified.")
|
|
49
|
-
else:
|
|
50
|
-
self._mapping = mapping
|
|
51
|
-
else:
|
|
52
|
-
if mapping is None:
|
|
53
|
-
self._mapping = self._mapping_from_components
|
|
54
|
-
else:
|
|
55
|
-
self._mapping = mapping
|
|
56
|
-
|
|
57
|
-
@staticmethod
|
|
58
|
-
def from_linear_operator(operator: "LinearOperator") -> "LinearForm":
|
|
59
|
-
"""
|
|
60
|
-
Creates a LinearForm from an operator that maps to a 1D Euclidean space.
|
|
61
|
-
"""
|
|
62
|
-
from .hilbert_space import EuclideanSpace
|
|
63
|
-
|
|
64
|
-
assert operator.codomain == EuclideanSpace(1)
|
|
65
|
-
return LinearForm(operator.domain, mapping=lambda x: operator(x)[0])
|
|
66
|
-
|
|
67
|
-
@property
|
|
68
|
-
def domain(self) -> "HilbertSpace":
|
|
69
|
-
"""The Hilbert space on which the form is defined."""
|
|
70
|
-
return self._domain
|
|
71
|
-
|
|
72
|
-
@property
|
|
73
|
-
def components_stored(self) -> bool:
|
|
74
|
-
"""True if the form's component vector is cached."""
|
|
75
|
-
return self._components is not None
|
|
76
|
-
|
|
77
|
-
@property
|
|
78
|
-
def components(self) -> np.ndarray:
|
|
79
|
-
"""
|
|
80
|
-
The component vector of the form.
|
|
81
|
-
|
|
82
|
-
The components are computed and cached on first access if not
|
|
83
|
-
provided during initialization.
|
|
84
|
-
"""
|
|
85
|
-
if self.components_stored:
|
|
86
|
-
return self._components
|
|
87
|
-
else:
|
|
88
|
-
self.store_components()
|
|
89
|
-
return self.components
|
|
90
|
-
|
|
91
|
-
def store_components(self) -> None:
|
|
92
|
-
"""Computes and caches the component vector of the form."""
|
|
93
|
-
if not self.components_stored:
|
|
94
|
-
self._components = np.zeros(self.domain.dim)
|
|
95
|
-
cx = np.zeros(self.domain.dim)
|
|
96
|
-
for i in range(self.domain.dim):
|
|
97
|
-
cx[i] = 1
|
|
98
|
-
x = self.domain.from_components(cx)
|
|
99
|
-
self._components[i] = self(x)
|
|
100
|
-
cx[i] = 0
|
|
101
|
-
|
|
102
|
-
@property
|
|
103
|
-
def as_linear_operator(self) -> "LinearOperator":
|
|
104
|
-
"""
|
|
105
|
-
Represents the linear form as a LinearOperator mapping to a
|
|
106
|
-
1D Euclidean space.
|
|
107
|
-
"""
|
|
108
|
-
from .hilbert_space import EuclideanSpace
|
|
109
|
-
from .operators import LinearOperator
|
|
110
|
-
|
|
111
|
-
return LinearOperator(
|
|
112
|
-
self.domain,
|
|
113
|
-
EuclideanSpace(1),
|
|
114
|
-
lambda x: np.array([self(x)]),
|
|
115
|
-
dual_mapping=lambda y: y * self,
|
|
116
|
-
)
|
|
117
|
-
|
|
118
|
-
def __call__(self, x: Any) -> float:
|
|
119
|
-
"""Applies the linear form to a vector."""
|
|
120
|
-
return self._mapping(x)
|
|
121
|
-
|
|
122
|
-
def __neg__(self) -> "LinearForm":
|
|
123
|
-
"""Returns the additive inverse of the form."""
|
|
124
|
-
if self.components_stored:
|
|
125
|
-
return LinearForm(self.domain, components=-self._components)
|
|
126
|
-
else:
|
|
127
|
-
return LinearForm(self.domain, mapping=lambda x: -self(x))
|
|
128
|
-
|
|
129
|
-
def __mul__(self, a: float) -> "LinearForm":
|
|
130
|
-
"""Returns the product of the form and a scalar."""
|
|
131
|
-
if self.components_stored:
|
|
132
|
-
return LinearForm(self.domain, components=a * self._components)
|
|
133
|
-
else:
|
|
134
|
-
return LinearForm(self.domain, mapping=lambda x: a * self(x))
|
|
135
|
-
|
|
136
|
-
def __rmul__(self, a: float) -> "LinearForm":
|
|
137
|
-
"""Returns the product of the form and a scalar."""
|
|
138
|
-
return self * a
|
|
139
|
-
|
|
140
|
-
def __truediv__(self, a: float) -> "LinearForm":
|
|
141
|
-
"""Returns the division of the form by a scalar."""
|
|
142
|
-
return self * (1.0 / a)
|
|
143
|
-
|
|
144
|
-
def __add__(self, other: "LinearForm") -> "LinearForm":
|
|
145
|
-
"""Returns the sum of this form and another."""
|
|
146
|
-
if self.components_stored and other.components_stored:
|
|
147
|
-
return LinearForm(
|
|
148
|
-
self.domain, components=self.components + other.components
|
|
149
|
-
)
|
|
150
|
-
else:
|
|
151
|
-
return LinearForm(self.domain, mapping=lambda x: self(x) + other(x))
|
|
152
|
-
|
|
153
|
-
def __sub__(self, other: "LinearForm") -> "LinearForm":
|
|
154
|
-
"""Returns the difference between this form and another."""
|
|
155
|
-
if self.components_stored and other.components_stored:
|
|
156
|
-
return LinearForm(
|
|
157
|
-
self.domain, components=self.components - other.components
|
|
158
|
-
)
|
|
159
|
-
else:
|
|
160
|
-
return LinearForm(self.domain, mapping=lambda x: self(x) - other(x))
|
|
161
|
-
|
|
162
|
-
def __str__(self) -> str:
|
|
163
|
-
"""Returns the string representation of the form's components."""
|
|
164
|
-
return self.components.__str__()
|
|
165
|
-
|
|
166
|
-
def _mapping_from_components(self, x: Any) -> float:
|
|
167
|
-
"""Implements the action of the form using its cached components."""
|
|
168
|
-
return np.dot(self._components, self.domain.to_components(x))
|
pygeoinf/symmetric_space/line.py
DELETED
|
@@ -1,384 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Sobolev spaces for functions on a line.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from __future__ import annotations
|
|
6
|
-
from typing import Callable, Any, Tuple, Optional
|
|
7
|
-
import matplotlib.pyplot as plt
|
|
8
|
-
import numpy as np
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
from matplotlib.figure import Figure
|
|
12
|
-
from matplotlib.axes import Axes
|
|
13
|
-
from pygeoinf.operators import LinearOperator
|
|
14
|
-
from pygeoinf.forms import LinearForm
|
|
15
|
-
from pygeoinf.gaussian_measure import GaussianMeasure
|
|
16
|
-
|
|
17
|
-
from pygeoinf.operators import LinearOperator
|
|
18
|
-
from pygeoinf.gaussian_measure import GaussianMeasure
|
|
19
|
-
from pygeoinf.symmetric_space.symmetric_space import SymmetricSpaceSobolev
|
|
20
|
-
from pygeoinf.symmetric_space.circle import Sobolev as CircleSobolev
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
class Sobolev(SymmetricSpaceSobolev):
|
|
24
|
-
"""
|
|
25
|
-
Implementation of the Sobolev space H^s on a finite line interval.
|
|
26
|
-
|
|
27
|
-
This class models functions on an interval [x0, x1] by mapping the problem
|
|
28
|
-
to a periodic domain (a circle) with padding. This avoids explicit
|
|
29
|
-
boundary conditions by using smooth tapers.
|
|
30
|
-
"""
|
|
31
|
-
|
|
32
|
-
def __init__(
|
|
33
|
-
self,
|
|
34
|
-
kmax: int,
|
|
35
|
-
order: float,
|
|
36
|
-
scale: float,
|
|
37
|
-
/,
|
|
38
|
-
*,
|
|
39
|
-
x0: float = 0.0,
|
|
40
|
-
x1: float = 1.0,
|
|
41
|
-
) -> None:
|
|
42
|
-
"""
|
|
43
|
-
Args:
|
|
44
|
-
kmax: The maximum Fourier degree for the underlying circle representation.
|
|
45
|
-
order: The Sobolev order, controlling function smoothness.
|
|
46
|
-
scale: The Sobolev length-scale.
|
|
47
|
-
x0: The left boundary of the interval. Defaults to 0.0.
|
|
48
|
-
x1: The right boundary of the interval. Defaults to 1.0.
|
|
49
|
-
|
|
50
|
-
Raises:
|
|
51
|
-
ValueError: If `x0 >= x1` or if `scale <= 0` when `order` is non-zero.
|
|
52
|
-
"""
|
|
53
|
-
|
|
54
|
-
if x0 >= x1:
|
|
55
|
-
raise ValueError("Invalid interval parameters: x0 must be less than x1.")
|
|
56
|
-
if order != 0 and scale <= 0:
|
|
57
|
-
raise ValueError("Length-scale must be positive for non-L2 spaces.")
|
|
58
|
-
|
|
59
|
-
self._kmax: int = kmax
|
|
60
|
-
self._x0: float = x0
|
|
61
|
-
self._x1: float = x1
|
|
62
|
-
|
|
63
|
-
# Work out the padding.
|
|
64
|
-
padding_scale: float = 5 * scale if scale > 0 else 0.1 * (x1 - x0)
|
|
65
|
-
number_of_points: int = 2 * kmax
|
|
66
|
-
width: float = x1 - x0
|
|
67
|
-
self._start_index: int = int(
|
|
68
|
-
number_of_points * padding_scale / (width + 2 * padding_scale)
|
|
69
|
-
)
|
|
70
|
-
self._finish_index: int = 2 * kmax - self._start_index + 1
|
|
71
|
-
self._padding_length: float = (
|
|
72
|
-
self._start_index * width / (number_of_points - 2 * self._start_index)
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
self._jac: float = (width + 2 * self._padding_length) / (2 * np.pi)
|
|
76
|
-
self._ijac: float = 1.0 / self._jac
|
|
77
|
-
self._sqrt_jac: float = np.sqrt(self._jac)
|
|
78
|
-
self._isqrt_jac: float = 1.0 / self._sqrt_jac
|
|
79
|
-
|
|
80
|
-
# Set up the related Sobolev space on the unit circle.
|
|
81
|
-
circle_scale: float = scale * self._ijac
|
|
82
|
-
self._circle_space: CircleSobolev = CircleSobolev(kmax, order, circle_scale)
|
|
83
|
-
|
|
84
|
-
super().__init__(
|
|
85
|
-
order,
|
|
86
|
-
scale,
|
|
87
|
-
self._circle_space.dim,
|
|
88
|
-
self._to_components,
|
|
89
|
-
self._from_components,
|
|
90
|
-
self._inner_product,
|
|
91
|
-
self._to_dual,
|
|
92
|
-
self._from_dual,
|
|
93
|
-
vector_multiply=lambda u1, u2: u1 * u2,
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
@staticmethod
|
|
97
|
-
def from_sobolev_parameters(
|
|
98
|
-
order: float,
|
|
99
|
-
scale: float,
|
|
100
|
-
/,
|
|
101
|
-
*,
|
|
102
|
-
x0: float = 0.0,
|
|
103
|
-
x1: float = 1.0,
|
|
104
|
-
rtol: float = 1e-8,
|
|
105
|
-
power_of_two: bool = False,
|
|
106
|
-
) -> "Sobolev":
|
|
107
|
-
"""
|
|
108
|
-
Creates an instance with `kmax` selected based on the Sobolev parameters.
|
|
109
|
-
|
|
110
|
-
Args:
|
|
111
|
-
order: The Sobolev order.
|
|
112
|
-
scale: The Sobolev length-scale.
|
|
113
|
-
x0: The left boundary of the interval. Defaults to 0.0.
|
|
114
|
-
x1: The right boundary of the interval. Defaults to 1.0.
|
|
115
|
-
rtol: Relative tolerance for truncation error assessment.
|
|
116
|
-
power_of_two: If True, `kmax` is set to the next power of two.
|
|
117
|
-
|
|
118
|
-
Returns:
|
|
119
|
-
An instance of the Sobolev class with an appropriate `kmax`.
|
|
120
|
-
"""
|
|
121
|
-
if x0 >= x1:
|
|
122
|
-
raise ValueError("Invalid interval parameters")
|
|
123
|
-
|
|
124
|
-
circle_scale = scale / (x1 - x0)
|
|
125
|
-
circle_space = CircleSobolev.from_sobolev_parameters(
|
|
126
|
-
order, circle_scale, rtol=rtol, power_of_two=power_of_two
|
|
127
|
-
)
|
|
128
|
-
kmax = circle_space.kmax
|
|
129
|
-
return Sobolev(kmax, order, scale, x0=x0, x1=x1)
|
|
130
|
-
|
|
131
|
-
@property
|
|
132
|
-
def kmax(self) -> int:
|
|
133
|
-
"""The maximum Fourier degree of the underlying circle representation."""
|
|
134
|
-
return self._kmax
|
|
135
|
-
|
|
136
|
-
@property
|
|
137
|
-
def x0(self) -> float:
|
|
138
|
-
"""The left boundary point of the interval."""
|
|
139
|
-
return self._x0
|
|
140
|
-
|
|
141
|
-
@property
|
|
142
|
-
def x1(self) -> float:
|
|
143
|
-
"""The right boundary point of the interval."""
|
|
144
|
-
return self._x1
|
|
145
|
-
|
|
146
|
-
@property
|
|
147
|
-
def width(self) -> float:
|
|
148
|
-
"""The width of the interval, `x1 - x0`."""
|
|
149
|
-
return self._x1 - self._x0
|
|
150
|
-
|
|
151
|
-
@property
|
|
152
|
-
def point_spacing(self) -> float:
|
|
153
|
-
"""The spacing between grid points on the interval."""
|
|
154
|
-
return self._circle_space.angle_spacing * self._jac
|
|
155
|
-
|
|
156
|
-
def computational_points(self) -> np.ndarray:
|
|
157
|
-
"""Returns the grid points on the full computational domain, including padding."""
|
|
158
|
-
return self._x0 - self._padding_length + self._jac * self._circle_space.angles()
|
|
159
|
-
|
|
160
|
-
def points(self) -> np.ndarray:
|
|
161
|
-
"""Returns the grid points within the primary interval `[x0, x1]`."""
|
|
162
|
-
return self.computational_points()[self._start_index : self._finish_index]
|
|
163
|
-
|
|
164
|
-
def project_function(self, f: Callable[[float], float]) -> np.ndarray:
|
|
165
|
-
"""
|
|
166
|
-
Returns an element of the space by projecting a given function.
|
|
167
|
-
|
|
168
|
-
The function `f` is evaluated at the computational grid points and
|
|
169
|
-
multiplied by a smooth tapering function.
|
|
170
|
-
|
|
171
|
-
Args:
|
|
172
|
-
f: A function that takes a position `x` and returns a value.
|
|
173
|
-
"""
|
|
174
|
-
return np.fromiter(
|
|
175
|
-
(f(x) * self._taper(x) for x in self.computational_points()), float
|
|
176
|
-
)
|
|
177
|
-
|
|
178
|
-
def random_point(self) -> float:
|
|
179
|
-
"""Returns a random point within the interval `[x0, x1]`."""
|
|
180
|
-
return np.random.uniform(self._x0, self._x1)
|
|
181
|
-
|
|
182
|
-
def plot(
|
|
183
|
-
self,
|
|
184
|
-
u: np.ndarray,
|
|
185
|
-
fig: Optional[Figure] = None,
|
|
186
|
-
ax: Optional[Axes] = None,
|
|
187
|
-
/,
|
|
188
|
-
*,
|
|
189
|
-
computational_domain: bool = False,
|
|
190
|
-
**kwargs,
|
|
191
|
-
) -> Tuple[Figure, Axes]:
|
|
192
|
-
"""
|
|
193
|
-
Makes a simple plot of a function from the space.
|
|
194
|
-
|
|
195
|
-
Args:
|
|
196
|
-
u: The vector representing the function to be plotted.
|
|
197
|
-
fig: An existing Matplotlib Figure object. Defaults to None.
|
|
198
|
-
ax: An existing Matplotlib Axes object. Defaults to None.
|
|
199
|
-
computational_domain: If True, plot the whole computational
|
|
200
|
-
domain including the tapered padding. Defaults to False.
|
|
201
|
-
**kwargs: Keyword arguments forwarded to `ax.plot()`.
|
|
202
|
-
|
|
203
|
-
Returns:
|
|
204
|
-
A tuple (figure, axes) containing the plot objects.
|
|
205
|
-
"""
|
|
206
|
-
figsize = kwargs.pop("figsize", (10, 8))
|
|
207
|
-
|
|
208
|
-
if fig is None:
|
|
209
|
-
fig = plt.figure(figsize=figsize)
|
|
210
|
-
if ax is None:
|
|
211
|
-
ax = fig.add_subplot()
|
|
212
|
-
|
|
213
|
-
if computational_domain:
|
|
214
|
-
ax.plot(self.computational_points(), u, **kwargs)
|
|
215
|
-
else:
|
|
216
|
-
ax.plot(self.points(), u[self._start_index : self._finish_index], **kwargs)
|
|
217
|
-
|
|
218
|
-
return fig, ax
|
|
219
|
-
|
|
220
|
-
def plot_pointwise_bounds(
|
|
221
|
-
self,
|
|
222
|
-
u: np.ndarray,
|
|
223
|
-
u_bound: np.ndarray,
|
|
224
|
-
fig: Optional[Figure] = None,
|
|
225
|
-
ax: Optional[Axes] = None,
|
|
226
|
-
/,
|
|
227
|
-
*,
|
|
228
|
-
computational_domain: bool = False,
|
|
229
|
-
**kwargs,
|
|
230
|
-
) -> Tuple[Figure, Axes]:
|
|
231
|
-
"""
|
|
232
|
-
Plots a function with pointwise error bounds.
|
|
233
|
-
|
|
234
|
-
Args:
|
|
235
|
-
u: The vector representing the mean function.
|
|
236
|
-
u_bound: A vector giving pointwise standard deviations.
|
|
237
|
-
fig: An existing Matplotlib Figure object. Defaults to None.
|
|
238
|
-
ax: An existing Matplotlib Axes object. Defaults to None.
|
|
239
|
-
computational_domain: If True, plot the whole computational domain.
|
|
240
|
-
**kwargs: Keyword arguments forwarded to `ax.fill_between()`.
|
|
241
|
-
|
|
242
|
-
Returns:
|
|
243
|
-
A tuple (figure, axes) containing the plot objects.
|
|
244
|
-
"""
|
|
245
|
-
figsize = kwargs.pop("figsize", (10, 8))
|
|
246
|
-
|
|
247
|
-
if fig is None:
|
|
248
|
-
fig = plt.figure(figsize=figsize)
|
|
249
|
-
if ax is None:
|
|
250
|
-
ax = fig.add_subplot()
|
|
251
|
-
|
|
252
|
-
if computational_domain:
|
|
253
|
-
ax.fill_between(
|
|
254
|
-
self.computational_points(), u - u_bound, u + u_bound, **kwargs
|
|
255
|
-
)
|
|
256
|
-
else:
|
|
257
|
-
ax.fill_between(
|
|
258
|
-
self.points(),
|
|
259
|
-
u[self._start_index : self._finish_index]
|
|
260
|
-
- u_bound[self._start_index : self._finish_index],
|
|
261
|
-
u[self._start_index : self._finish_index]
|
|
262
|
-
+ u_bound[self._start_index : self._finish_index],
|
|
263
|
-
**kwargs,
|
|
264
|
-
)
|
|
265
|
-
|
|
266
|
-
return fig, ax
|
|
267
|
-
|
|
268
|
-
def invariant_automorphism(self, f: Callable[[float], float]) -> "LinearOperator":
|
|
269
|
-
A = self._circle_space.invariant_automorphism(lambda k: f(self._ijac * k))
|
|
270
|
-
return LinearOperator.formally_self_adjoint(self, A)
|
|
271
|
-
|
|
272
|
-
def invariant_gaussian_measure(
|
|
273
|
-
self, f: Callable[[float], float], /, *, expectation: Optional[Any] = None
|
|
274
|
-
) -> "GaussianMeasure":
|
|
275
|
-
mu = self._circle_space.invariant_gaussian_measure(
|
|
276
|
-
lambda k: f(self._ijac * k), expectation=expectation
|
|
277
|
-
)
|
|
278
|
-
covariance = LinearOperator.self_adjoint(self, mu.covariance)
|
|
279
|
-
return GaussianMeasure(
|
|
280
|
-
covariance=covariance, expectation=expectation, sample=mu.sample
|
|
281
|
-
)
|
|
282
|
-
|
|
283
|
-
def dirac(self, point: float) -> "LinearForm":
|
|
284
|
-
theta = self._inverse_transformation(point)
|
|
285
|
-
up = self._circle_space.dirac(theta)
|
|
286
|
-
cp = self._circle_space.dual.to_components(up) * self._isqrt_jac
|
|
287
|
-
return self.dual.from_components(cp)
|
|
288
|
-
|
|
289
|
-
def __eq__(self, other: object) -> bool:
|
|
290
|
-
"""
|
|
291
|
-
Checks for mathematical equality with another Sobolev space on a line.
|
|
292
|
-
|
|
293
|
-
Two spaces are considered equal if they are of the same type and have
|
|
294
|
-
the same defining parameters (kmax, order, scale, x0, and x1).
|
|
295
|
-
"""
|
|
296
|
-
|
|
297
|
-
if not isinstance(other, Sobolev):
|
|
298
|
-
return NotImplemented
|
|
299
|
-
|
|
300
|
-
return (
|
|
301
|
-
self.kmax == other.kmax
|
|
302
|
-
and self.order == other.order
|
|
303
|
-
and self.scale == other.scale
|
|
304
|
-
and self.x0 == other.x0
|
|
305
|
-
and self.x1 == other.x1
|
|
306
|
-
)
|
|
307
|
-
|
|
308
|
-
# =============================================================#
|
|
309
|
-
# Private methods #
|
|
310
|
-
# =============================================================#
|
|
311
|
-
|
|
312
|
-
def _step(self, x: float) -> float:
|
|
313
|
-
if x > 0:
|
|
314
|
-
return np.exp(-1.0 / x)
|
|
315
|
-
else:
|
|
316
|
-
return 0.0
|
|
317
|
-
|
|
318
|
-
def _bump_up(self, x: float, x1: float, x2: float) -> float:
|
|
319
|
-
s1 = self._step(x - x1)
|
|
320
|
-
s2 = self._step(x2 - x)
|
|
321
|
-
return s1 / (s1 + s2)
|
|
322
|
-
|
|
323
|
-
def _bump_down(self, x: float, x1: float, x2: float) -> float:
|
|
324
|
-
s1 = self._step(x2 - x)
|
|
325
|
-
s2 = self._step(x - x1)
|
|
326
|
-
return s1 / (s1 + s2)
|
|
327
|
-
|
|
328
|
-
def _taper(self, x: float) -> float:
|
|
329
|
-
s1 = self._bump_up(x, self._x0 - self._padding_length, self._x0)
|
|
330
|
-
s2 = self._bump_down(x, self._x1, self._x1 + self._padding_length)
|
|
331
|
-
return s1 * s2
|
|
332
|
-
|
|
333
|
-
def _transformation(self, th: float) -> float:
|
|
334
|
-
return self._x0 - self._padding_length + self._jac * th
|
|
335
|
-
|
|
336
|
-
def _inverse_transformation(self, x: float) -> float:
|
|
337
|
-
return (x - self._x0 + self._padding_length) * self._ijac
|
|
338
|
-
|
|
339
|
-
def _to_components(self, u: np.ndarray) -> np.ndarray:
|
|
340
|
-
c = self._circle_space.to_components(u)
|
|
341
|
-
c *= self._sqrt_jac
|
|
342
|
-
return c
|
|
343
|
-
|
|
344
|
-
def _from_components(self, c: np.ndarray) -> np.ndarray:
|
|
345
|
-
u = self._circle_space.from_components(c)
|
|
346
|
-
u *= self._isqrt_jac
|
|
347
|
-
return u
|
|
348
|
-
|
|
349
|
-
def _inner_product(self, u1: np.ndarray, u2: np.ndarray) -> float:
|
|
350
|
-
return self._jac * self._circle_space.inner_product(u1, u2)
|
|
351
|
-
|
|
352
|
-
def _to_dual(self, u: np.ndarray) -> "LinearForm":
|
|
353
|
-
up = self._circle_space.to_dual(u)
|
|
354
|
-
cp = self._circle_space.dual.to_components(up) * self._sqrt_jac
|
|
355
|
-
return self.dual.from_components(cp)
|
|
356
|
-
|
|
357
|
-
def _from_dual(self, up: "LinearForm") -> np.ndarray:
|
|
358
|
-
cp = self.dual.to_components(up)
|
|
359
|
-
vp = self._circle_space.dual.from_components(cp) * self._isqrt_jac
|
|
360
|
-
return self._circle_space.from_dual(vp)
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
class Lebesgue(Sobolev):
|
|
364
|
-
"""
|
|
365
|
-
Implementation of the Lebesgue space L^2 on a line.
|
|
366
|
-
|
|
367
|
-
This is a special case of the Sobolev space with order `s=0`.
|
|
368
|
-
"""
|
|
369
|
-
|
|
370
|
-
def __init__(
|
|
371
|
-
self,
|
|
372
|
-
kmax: int,
|
|
373
|
-
/,
|
|
374
|
-
*,
|
|
375
|
-
x0: float = 0.0,
|
|
376
|
-
x1: float = 1.0,
|
|
377
|
-
) -> None:
|
|
378
|
-
"""
|
|
379
|
-
Args:
|
|
380
|
-
kmax: The maximum Fourier degree for the underlying representation.
|
|
381
|
-
x0: The left boundary of the interval. Defaults to 0.0.
|
|
382
|
-
x1: The right boundary of the interval. Defaults to 1.0.
|
|
383
|
-
"""
|
|
384
|
-
super().__init__(kmax, 0.0, 1.0, x0=x0, x1=x1)
|
pygeoinf-1.0.8.dist-info/RECORD
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
pygeoinf/__init__.py,sha256=PsUfD2hfc-eoIz6fHSC-Mn3MHflaU07W2mHT6fLYKr0,1076
|
|
2
|
-
pygeoinf/direct_sum.py,sha256=_ZMtK8EQ02nWpU0yYSqeEieR3ZHZgIyN8fgo9jqkm5k,15867
|
|
3
|
-
pygeoinf/forms.py,sha256=X3vftbjkUKb4m21BDg-Z5umlc1ibAl47ml40i1Fv33E,5815
|
|
4
|
-
pygeoinf/forward_problem.py,sha256=4V40qvHN4qAu8CXsxGAuJ5F9oukqXbXbGCARFpBYaD0,9546
|
|
5
|
-
pygeoinf/gaussian_measure.py,sha256=UEFViRtLYU730U4upV33KB_ksg78tpW0dwGVFgt1hOw,21595
|
|
6
|
-
pygeoinf/hilbert_space.py,sha256=m0wbzm2XIITs8KenwrNrgvRKilsf-KrX6SR0ylKyhLg,14342
|
|
7
|
-
pygeoinf/inversion.py,sha256=0O1ZVZSyvHaS63XovMtAmhwQwnl0OBfiSD9JwEt95bg,2560
|
|
8
|
-
pygeoinf/linear_bayesian.py,sha256=9PQWq3nzNN2KR5fDbDqE8rv0mszIe53_7M40jeD_26U,8374
|
|
9
|
-
pygeoinf/linear_optimisation.py,sha256=C2kA1QZC4BlSF0txfpr2_c3A2lCAIklijqY8sgs5OZE,10316
|
|
10
|
-
pygeoinf/linear_solvers.py,sha256=ieRscHbI7On_4E0h_U-CAKOGlMYKwB2W-dR-Gh4Iwp4,17481
|
|
11
|
-
pygeoinf/operators.py,sha256=SZRmzUL6KiJA1fh5PoWqLwyDYWDo5ooJ_CbMD3TCvFA,24912
|
|
12
|
-
pygeoinf/random_matrix.py,sha256=d6apC9Sd5ud-QgLnvvXaURdar3LiYJPwz-CYbDojH54,7545
|
|
13
|
-
pygeoinf/symmetric_space/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
-
pygeoinf/symmetric_space/circle.py,sha256=TWjQwX42EvZ4-zOIJKATo8lVg0YbXRaQgxVzj6xXYlM,12467
|
|
15
|
-
pygeoinf/symmetric_space/line.py,sha256=FoZL5qVEVWzOkWwhbmwsg3D_0ceX9Nj8L8OJXQevtr4,13203
|
|
16
|
-
pygeoinf/symmetric_space/sphere.py,sha256=YezUyB3TfsY6Bb0M6hVVXSA00HDkcyO8I-FMy_I0lOA,24215
|
|
17
|
-
pygeoinf/symmetric_space/symmetric_space.py,sha256=E-8lXZmW5WWaHgX-YTu--NwV6dXP3M7hIP3J3H6uv3U,9067
|
|
18
|
-
pygeoinf-1.0.8.dist-info/LICENSE,sha256=GrTQnKJemVi69FSbHprq60KN0OJGsOSR-joQoTq-oD8,1501
|
|
19
|
-
pygeoinf-1.0.8.dist-info/METADATA,sha256=9kra1ONFxBefYI7LkLzHM2NYkax8RwhHtrGbJT3lZY4,14375
|
|
20
|
-
pygeoinf-1.0.8.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
|
21
|
-
pygeoinf-1.0.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|