pynumerics 2.3.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.
- pynumerics/__init__.py +73 -0
- pynumerics/_bin/Microsoft.CodeAnalysis.CSharp.dll +0 -0
- pynumerics/_bin/Microsoft.CodeAnalysis.LICENSE.txt +27 -0
- pynumerics/_bin/Microsoft.CodeAnalysis.dll +0 -0
- pynumerics/_bin/Numerics.dll +0 -0
- pynumerics/_bin/pynumerics.runtimeconfig.json +15 -0
- pynumerics/_coverage.py +3825 -0
- pynumerics/_util.py +237 -0
- pynumerics/_version.py +40 -0
- pynumerics/bootstrap.py +593 -0
- pynumerics/callbacks.py +791 -0
- pynumerics/copulas.py +910 -0
- pynumerics/data.py +2233 -0
- pynumerics/differentiation.py +348 -0
- pynumerics/distributions.py +4043 -0
- pynumerics/download.py +623 -0
- pynumerics/enums.py +119 -0
- pynumerics/errors.py +245 -0
- pynumerics/functions.py +1142 -0
- pynumerics/goodness_of_fit.py +699 -0
- pynumerics/graphs.py +556 -0
- pynumerics/hypothesis_tests.py +445 -0
- pynumerics/identity.py +144 -0
- pynumerics/integration.py +677 -0
- pynumerics/linalg.py +1408 -0
- pynumerics/machine_learning.py +1335 -0
- pynumerics/marshal.py +733 -0
- pynumerics/mathematics.py +1053 -0
- pynumerics/mcmc.py +1406 -0
- pynumerics/multivariate.py +1539 -0
- pynumerics/ode.py +156 -0
- pynumerics/optimization.py +1736 -0
- pynumerics/probability.py +966 -0
- pynumerics/py.typed +0 -0
- pynumerics/regional.py +522 -0
- pynumerics/roots.py +274 -0
- pynumerics/runtime.py +384 -0
- pynumerics/sampling.py +1758 -0
- pynumerics/special.py +1079 -0
- pynumerics/statistics.py +1958 -0
- pynumerics/timeseries.py +1326 -0
- pynumerics-2.3.0.dist-info/METADATA +142 -0
- pynumerics-2.3.0.dist-info/RECORD +46 -0
- pynumerics-2.3.0.dist-info/WHEEL +5 -0
- pynumerics-2.3.0.dist-info/licenses/LICENSE +10 -0
- pynumerics-2.3.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1053 @@
|
|
|
1
|
+
"""Numerical utilities of ``Numerics.Tools`` and fast Fourier transforms of ``Numerics.Mathematics.Fourier``.
|
|
2
|
+
|
|
3
|
+
``expm1`` and ``log1p`` call ``Tools.Expm1`` and ``Tools.Log1p``; an array crosses once through
|
|
4
|
+
their ``IList<double>`` overloads. The fast Fourier transforms (``fft``, ``real_fft``,
|
|
5
|
+
``bluestein_fft``, ``fft_convolve``, ``fft_correlation`` and ``fft_autocorrelation``) call
|
|
6
|
+
``Numerics.Mathematics.Fourier``, and the other utilities of ``Numerics.Tools`` (``log_sum_exp``,
|
|
7
|
+
distances, scaling, masked reductions, sequences, compression and the :data:`constants`) are
|
|
8
|
+
wrapped one to one. Special functions are in :mod:`pynumerics.special`, linear algebra in
|
|
9
|
+
:mod:`pynumerics.linalg`, root finding in :mod:`pynumerics.roots`, optimization in
|
|
10
|
+
:mod:`pynumerics.optimization` and link functions in :mod:`pynumerics.functions`.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
import numpy as np
|
|
18
|
+
|
|
19
|
+
from pynumerics._util import (
|
|
20
|
+
bind,
|
|
21
|
+
bind_list,
|
|
22
|
+
broadcast_loop,
|
|
23
|
+
cached_overload,
|
|
24
|
+
evaluate,
|
|
25
|
+
loop,
|
|
26
|
+
namespace,
|
|
27
|
+
overload,
|
|
28
|
+
)
|
|
29
|
+
from pynumerics.errors import translate_public
|
|
30
|
+
from pynumerics.marshal import (
|
|
31
|
+
_bytes_from_net,
|
|
32
|
+
_bytes_to_net,
|
|
33
|
+
to_net_doubles,
|
|
34
|
+
to_net_ints,
|
|
35
|
+
to_net_matrix,
|
|
36
|
+
to_numpy_doubles,
|
|
37
|
+
to_numpy_ints,
|
|
38
|
+
to_numpy_matrix,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _tools(name: str, x: Any) -> Any:
|
|
43
|
+
"""Evaluate ``Tools.Expm1`` or ``Tools.Log1p`` on a scalar or an array.
|
|
44
|
+
|
|
45
|
+
The scalar overload is bound once per process; an array crosses once into the
|
|
46
|
+
``IList<double>`` overload. Every value is the scalar member's.
|
|
47
|
+
"""
|
|
48
|
+
scalar = cached_overload(f"Tools.{name}(double)", lambda: bind(getattr(namespace("Numerics").Tools, name)))
|
|
49
|
+
vector = cached_overload(f"Tools.{name}(IList<double>)",
|
|
50
|
+
lambda: bind_list(getattr(namespace("Numerics").Tools, name)))
|
|
51
|
+
return evaluate(x, scalar, vector)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def expm1(x: Any) -> Any:
|
|
55
|
+
"""Return exp(x) − 1 accurately near zero (``Tools.Expm1``).
|
|
56
|
+
|
|
57
|
+
Parameters
|
|
58
|
+
----------
|
|
59
|
+
x : float or array_like
|
|
60
|
+
Arguments.
|
|
61
|
+
|
|
62
|
+
Returns
|
|
63
|
+
-------
|
|
64
|
+
float or numpy.ndarray
|
|
65
|
+
The values exp(x) − 1, shaped like ``x``.
|
|
66
|
+
"""
|
|
67
|
+
return _tools("Expm1", x)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def log1p(x: Any) -> Any:
|
|
71
|
+
"""Return log(1 + x) accurately near zero (``Tools.Log1p``).
|
|
72
|
+
|
|
73
|
+
Parameters
|
|
74
|
+
----------
|
|
75
|
+
x : float or array_like
|
|
76
|
+
Arguments.
|
|
77
|
+
|
|
78
|
+
Returns
|
|
79
|
+
-------
|
|
80
|
+
float or numpy.ndarray
|
|
81
|
+
The values log(1 + x), shaped like ``x``.
|
|
82
|
+
"""
|
|
83
|
+
return _tools("Log1p", x)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _tools_member(name: str, *types: str) -> Any:
|
|
87
|
+
"""Return the ``Numerics.Tools`` overload of ``name`` taking ``types``, bound once per process."""
|
|
88
|
+
return cached_overload(f"Tools.{name}({', '.join(types)})",
|
|
89
|
+
lambda: overload(getattr(namespace("Numerics").Tools, name), *types))
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class NumericsConstants:
|
|
93
|
+
"""The numerical constants of ``Numerics.Tools``.
|
|
94
|
+
|
|
95
|
+
Each property reads the .NET constant, so the values are the ones the loaded assembly uses.
|
|
96
|
+
Use the module instance ``constants``.
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
@property
|
|
100
|
+
def double_machine_epsilon(self) -> float:
|
|
101
|
+
"""``Tools.DoubleMachineEpsilon``, the unit roundoff 2**-53 as Numerics writes it."""
|
|
102
|
+
return float(namespace("Numerics").Tools.DoubleMachineEpsilon)
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def single_machine_epsilon(self) -> float:
|
|
106
|
+
"""``Tools.SingleMachineEpsilon``, the single-precision unit roundoff 2**-24 widened from float32."""
|
|
107
|
+
return float(namespace("Numerics").Tools.SingleMachineEpsilon)
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def euler(self) -> float:
|
|
111
|
+
"""``Tools.Euler``, the Euler-Mascheroni constant."""
|
|
112
|
+
return float(namespace("Numerics").Tools.Euler)
|
|
113
|
+
|
|
114
|
+
@property
|
|
115
|
+
def golden_ratio(self) -> float:
|
|
116
|
+
"""``Tools.GoldenRatio``, (1 + sqrt(5)) / 2."""
|
|
117
|
+
return float(namespace("Numerics").Tools.GoldenRatio)
|
|
118
|
+
|
|
119
|
+
@property
|
|
120
|
+
def log_sqrt_2pi(self) -> float:
|
|
121
|
+
"""``Tools.LogSqrt2PI``, log(sqrt(2 pi))."""
|
|
122
|
+
return float(namespace("Numerics").Tools.LogSqrt2PI)
|
|
123
|
+
|
|
124
|
+
@property
|
|
125
|
+
def sqrt_2pi(self) -> float:
|
|
126
|
+
"""``Tools.Sqrt2PI``, sqrt(2 pi)."""
|
|
127
|
+
return float(namespace("Numerics").Tools.Sqrt2PI)
|
|
128
|
+
|
|
129
|
+
@property
|
|
130
|
+
def sqrt2(self) -> float:
|
|
131
|
+
"""``Tools.Sqrt2``, sqrt(2)."""
|
|
132
|
+
return float(namespace("Numerics").Tools.Sqrt2)
|
|
133
|
+
|
|
134
|
+
@property
|
|
135
|
+
def log2(self) -> float:
|
|
136
|
+
"""``Tools.Log2``, log(2)."""
|
|
137
|
+
return float(namespace("Numerics").Tools.Log2)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
constants = NumericsConstants()
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def copy_sign(x: Any, y: Any) -> Any:
|
|
144
|
+
"""Return the magnitude of ``x`` with the sign of ``y`` (``Tools.CopySign``).
|
|
145
|
+
|
|
146
|
+
Unlike ``math.copysign``, the sign test is ``y >= 0``, so ``y = -0.0`` gives a positive result.
|
|
147
|
+
|
|
148
|
+
Parameters
|
|
149
|
+
----------
|
|
150
|
+
x, y : float or array_like
|
|
151
|
+
Magnitudes and sign sources; arrays broadcast.
|
|
152
|
+
|
|
153
|
+
Returns
|
|
154
|
+
-------
|
|
155
|
+
float or numpy.ndarray
|
|
156
|
+
The values, in the broadcast shape.
|
|
157
|
+
"""
|
|
158
|
+
return broadcast_loop(_tools_member("CopySign", "Double", "Double"), x, y)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def is_finite(x: float) -> bool:
|
|
162
|
+
"""Return whether ``x`` is neither NaN nor infinite (``Tools.IsFinite``).
|
|
163
|
+
|
|
164
|
+
Parameters
|
|
165
|
+
----------
|
|
166
|
+
x : float
|
|
167
|
+
The value.
|
|
168
|
+
|
|
169
|
+
Returns
|
|
170
|
+
-------
|
|
171
|
+
bool
|
|
172
|
+
True for a finite value.
|
|
173
|
+
"""
|
|
174
|
+
return bool(_tools_member("IsFinite", "Double")(float(x)))
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def is_power_of_two(n: int) -> bool:
|
|
178
|
+
"""Return whether ``n`` is a positive power of 2 (``Tools.IsPowerOfTwo``).
|
|
179
|
+
|
|
180
|
+
Parameters
|
|
181
|
+
----------
|
|
182
|
+
n : int
|
|
183
|
+
A 32-bit integer.
|
|
184
|
+
|
|
185
|
+
Returns
|
|
186
|
+
-------
|
|
187
|
+
bool
|
|
188
|
+
True when ``n`` is 1, 2, 4, ...
|
|
189
|
+
"""
|
|
190
|
+
return bool(_tools_member("IsPowerOfTwo", "Int32")(int(n)))
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def next_power_of_two(n: int) -> int:
|
|
194
|
+
"""Return the smallest power of 2 at least ``n``, or 1 for ``n < 1`` (``Tools.NextPowerOfTwo``).
|
|
195
|
+
|
|
196
|
+
Parameters
|
|
197
|
+
----------
|
|
198
|
+
n : int
|
|
199
|
+
A 32-bit integer.
|
|
200
|
+
|
|
201
|
+
Returns
|
|
202
|
+
-------
|
|
203
|
+
int
|
|
204
|
+
The power of 2.
|
|
205
|
+
"""
|
|
206
|
+
return int(_tools_member("NextPowerOfTwo", "Int32")(int(n)))
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def clamp(x: Any, minimum: float, maximum: float) -> Any:
|
|
210
|
+
"""Clamp values to the inclusive range [minimum, maximum] (``Tools.Clamp``).
|
|
211
|
+
|
|
212
|
+
Parameters
|
|
213
|
+
----------
|
|
214
|
+
x : float or array_like
|
|
215
|
+
The values.
|
|
216
|
+
minimum, maximum : float
|
|
217
|
+
The bounds.
|
|
218
|
+
|
|
219
|
+
Returns
|
|
220
|
+
-------
|
|
221
|
+
float or numpy.ndarray
|
|
222
|
+
The clamped values, shaped like ``x``; NaN passes through.
|
|
223
|
+
"""
|
|
224
|
+
member = _tools_member("Clamp", "Double", "Double", "Double")
|
|
225
|
+
lo, hi = float(minimum), float(maximum)
|
|
226
|
+
return loop(x, lambda v: member(v, lo, hi))
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def hypot(a: Any, b: Any) -> Any:
|
|
230
|
+
"""Return sqrt(a**2 + b**2) without destructive underflow or overflow (``Tools.Hypot``).
|
|
231
|
+
|
|
232
|
+
Parameters
|
|
233
|
+
----------
|
|
234
|
+
a, b : float or array_like
|
|
235
|
+
The two values; arrays broadcast.
|
|
236
|
+
|
|
237
|
+
Returns
|
|
238
|
+
-------
|
|
239
|
+
float or numpy.ndarray
|
|
240
|
+
The Euclidean norms, in the broadcast shape; within 2 ulps of the exact value. Special values follow
|
|
241
|
+
IEEE 754 and ``numpy.hypot``: an infinite argument gives ``inf`` even when the other is NaN.
|
|
242
|
+
"""
|
|
243
|
+
return broadcast_loop(_tools_member("Hypot", "Double", "Double"), a, b)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def sign(a: Any, b: Any) -> Any:
|
|
247
|
+
"""Return the magnitude of ``a`` with the sign of ``b`` (``Tools.Sign``, the Fortran ``SIGN``).
|
|
248
|
+
|
|
249
|
+
Parameters
|
|
250
|
+
----------
|
|
251
|
+
a, b : float or array_like
|
|
252
|
+
Magnitudes and sign sources (``b >= 0`` counts as positive); arrays broadcast.
|
|
253
|
+
|
|
254
|
+
Returns
|
|
255
|
+
-------
|
|
256
|
+
float or numpy.ndarray
|
|
257
|
+
The values, in the broadcast shape.
|
|
258
|
+
"""
|
|
259
|
+
return broadcast_loop(_tools_member("Sign", "Double", "Double"), a, b)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def sqr(a: Any) -> Any:
|
|
263
|
+
"""Return ``a * a`` (``Tools.Sqr``).
|
|
264
|
+
|
|
265
|
+
Parameters
|
|
266
|
+
----------
|
|
267
|
+
a : float or array_like
|
|
268
|
+
The values.
|
|
269
|
+
|
|
270
|
+
Returns
|
|
271
|
+
-------
|
|
272
|
+
float or numpy.ndarray
|
|
273
|
+
The squares, shaped like ``a``.
|
|
274
|
+
"""
|
|
275
|
+
return loop(a, _tools_member("Sqr", "Double"))
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def power(a: Any, b: Any) -> Any:
|
|
279
|
+
"""Raise ``a`` to the integer power ``b`` by repeated squaring (``Tools.Pow``).
|
|
280
|
+
|
|
281
|
+
Parameters
|
|
282
|
+
----------
|
|
283
|
+
a : float or array_like
|
|
284
|
+
Bases.
|
|
285
|
+
b : int or array_like of int
|
|
286
|
+
Integer exponents; arrays broadcast with ``a``.
|
|
287
|
+
|
|
288
|
+
Returns
|
|
289
|
+
-------
|
|
290
|
+
float or numpy.ndarray
|
|
291
|
+
The powers; ``0 ** -k`` is +inf.
|
|
292
|
+
"""
|
|
293
|
+
return broadcast_loop(_tools_member("Pow", "Double", "Int32"), a, b, kinds=(float, int))
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def log10(x: Any) -> Any:
|
|
297
|
+
"""Return the guarded base-10 logarithm (``Tools.Log10``).
|
|
298
|
+
|
|
299
|
+
Values in [0, 1e-16) are raised to 1e-16, so ``log10(0)`` is -16 rather than -inf.
|
|
300
|
+
|
|
301
|
+
Parameters
|
|
302
|
+
----------
|
|
303
|
+
x : float or array_like
|
|
304
|
+
The values.
|
|
305
|
+
|
|
306
|
+
Returns
|
|
307
|
+
-------
|
|
308
|
+
float or numpy.ndarray
|
|
309
|
+
The logarithms, shaped like ``x``.
|
|
310
|
+
"""
|
|
311
|
+
return loop(x, _tools_member("Log10", "Double"))
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def log(x: Any) -> Any:
|
|
315
|
+
"""Return the guarded natural logarithm (``Tools.Log``).
|
|
316
|
+
|
|
317
|
+
Values in [0, 1e-16), including -0.0, are raised to 1e-16, so ``log(0)`` is about -36.84
|
|
318
|
+
rather than -inf.
|
|
319
|
+
|
|
320
|
+
Parameters
|
|
321
|
+
----------
|
|
322
|
+
x : float or array_like
|
|
323
|
+
The values.
|
|
324
|
+
|
|
325
|
+
Returns
|
|
326
|
+
-------
|
|
327
|
+
float or numpy.ndarray
|
|
328
|
+
The logarithms, shaped like ``x``.
|
|
329
|
+
"""
|
|
330
|
+
return loop(x, _tools_member("Log", "Double"))
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def point_distance(x1: float, y1: float, x2: float, y2: float) -> float:
|
|
334
|
+
"""Return the Euclidean distance between two points of the plane (``Tools.Distance`` of four doubles).
|
|
335
|
+
|
|
336
|
+
Parameters
|
|
337
|
+
----------
|
|
338
|
+
x1, y1 : float
|
|
339
|
+
The first point.
|
|
340
|
+
x2, y2 : float
|
|
341
|
+
The second point.
|
|
342
|
+
|
|
343
|
+
Returns
|
|
344
|
+
-------
|
|
345
|
+
float
|
|
346
|
+
The distance sqrt((x2 - x1)**2 + (y2 - y1)**2).
|
|
347
|
+
"""
|
|
348
|
+
member = _tools_member("Distance", "Double", "Double", "Double", "Double")
|
|
349
|
+
return float(member(float(x1), float(y1), float(x2), float(y2)))
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def distance(x: Any, y: Any) -> float:
|
|
353
|
+
"""Return the Euclidean distance ||x - y|| (``Tools.Distance`` of two lists).
|
|
354
|
+
|
|
355
|
+
Parameters
|
|
356
|
+
----------
|
|
357
|
+
x, y : array_like
|
|
358
|
+
The points, one coordinate per element.
|
|
359
|
+
|
|
360
|
+
Returns
|
|
361
|
+
-------
|
|
362
|
+
float
|
|
363
|
+
The distance.
|
|
364
|
+
"""
|
|
365
|
+
member = _tools_member("Distance", "IList[Double]", "IList[Double]")
|
|
366
|
+
return float(member(to_net_doubles(x), to_net_doubles(y)))
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def normalized_distance(x: Any, y: Any, lower: Any, upper: Any) -> float:
|
|
370
|
+
"""Return the Euclidean distance after min-max scaling each coordinate (``Tools.NormalizedDistance``).
|
|
371
|
+
|
|
372
|
+
A coordinate with ``upper - lower <= 0`` (or NaN) contributes nothing.
|
|
373
|
+
|
|
374
|
+
Parameters
|
|
375
|
+
----------
|
|
376
|
+
x, y : array_like
|
|
377
|
+
The points.
|
|
378
|
+
lower, upper : array_like
|
|
379
|
+
The bounds of each coordinate.
|
|
380
|
+
|
|
381
|
+
Returns
|
|
382
|
+
-------
|
|
383
|
+
float
|
|
384
|
+
The normalized distance.
|
|
385
|
+
"""
|
|
386
|
+
tools = namespace("Numerics").Tools
|
|
387
|
+
return float(tools.NormalizedDistance(to_net_doubles(x), to_net_doubles(y), to_net_doubles(lower),
|
|
388
|
+
to_net_doubles(upper)))
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def weighted_distance(x: Any, y: Any, weights: Any) -> float:
|
|
392
|
+
"""Return the weighted Euclidean distance sqrt(sum w (x - y)**2) (``Tools.WeightedDistance``).
|
|
393
|
+
|
|
394
|
+
Parameters
|
|
395
|
+
----------
|
|
396
|
+
x, y : array_like
|
|
397
|
+
The points.
|
|
398
|
+
weights : array_like
|
|
399
|
+
One weight per coordinate.
|
|
400
|
+
|
|
401
|
+
Returns
|
|
402
|
+
-------
|
|
403
|
+
float
|
|
404
|
+
The weighted distance.
|
|
405
|
+
"""
|
|
406
|
+
tools = namespace("Numerics").Tools
|
|
407
|
+
return float(tools.WeightedDistance(to_net_doubles(x), to_net_doubles(y), to_net_doubles(weights)))
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
def normalize(values: Any) -> np.ndarray:
|
|
411
|
+
"""Scale values to [0, 1] by their minimum and maximum (``Tools.Normalize``).
|
|
412
|
+
|
|
413
|
+
Empty input, input holding NaN, or constant input gives zeros.
|
|
414
|
+
|
|
415
|
+
Parameters
|
|
416
|
+
----------
|
|
417
|
+
values : array_like
|
|
418
|
+
The values.
|
|
419
|
+
|
|
420
|
+
Returns
|
|
421
|
+
-------
|
|
422
|
+
numpy.ndarray
|
|
423
|
+
(values - min) / (max - min).
|
|
424
|
+
"""
|
|
425
|
+
return to_numpy_doubles(namespace("Numerics").Tools.Normalize(to_net_doubles(values)))
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
def denormalize(values: Any, minimum: float, maximum: float) -> np.ndarray:
|
|
429
|
+
"""Invert :func:`normalize` with the original minimum and maximum (``Tools.Denormalize``).
|
|
430
|
+
|
|
431
|
+
Parameters
|
|
432
|
+
----------
|
|
433
|
+
values : array_like
|
|
434
|
+
Normalized values.
|
|
435
|
+
minimum, maximum : float
|
|
436
|
+
The minimum and maximum of the original data.
|
|
437
|
+
|
|
438
|
+
Returns
|
|
439
|
+
-------
|
|
440
|
+
numpy.ndarray
|
|
441
|
+
The values times (maximum - minimum) plus minimum.
|
|
442
|
+
"""
|
|
443
|
+
return to_numpy_doubles(namespace("Numerics").Tools.Denormalize(to_net_doubles(values), float(minimum),
|
|
444
|
+
float(maximum)))
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
def standardize(values: Any) -> np.ndarray:
|
|
448
|
+
"""Return the z-scores (values - mean) / sd with the sample standard deviation (``Tools.Standardize``).
|
|
449
|
+
|
|
450
|
+
A zero or NaN standard deviation gives zeros.
|
|
451
|
+
|
|
452
|
+
Parameters
|
|
453
|
+
----------
|
|
454
|
+
values : array_like
|
|
455
|
+
The values.
|
|
456
|
+
|
|
457
|
+
Returns
|
|
458
|
+
-------
|
|
459
|
+
numpy.ndarray
|
|
460
|
+
The standardized values.
|
|
461
|
+
"""
|
|
462
|
+
return to_numpy_doubles(namespace("Numerics").Tools.Standardize(to_net_doubles(values)))
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
def destandardize(values: Any, mean: float, standard_deviation: float) -> np.ndarray:
|
|
466
|
+
"""Invert :func:`standardize` with the original mean and standard deviation (``Tools.Destandardize``).
|
|
467
|
+
|
|
468
|
+
Parameters
|
|
469
|
+
----------
|
|
470
|
+
values : array_like
|
|
471
|
+
Standardized values.
|
|
472
|
+
mean, standard_deviation : float
|
|
473
|
+
The moments of the original data.
|
|
474
|
+
|
|
475
|
+
Returns
|
|
476
|
+
-------
|
|
477
|
+
numpy.ndarray
|
|
478
|
+
The values times standard_deviation plus mean.
|
|
479
|
+
"""
|
|
480
|
+
return to_numpy_doubles(namespace("Numerics").Tools.Destandardize(to_net_doubles(values), float(mean),
|
|
481
|
+
float(standard_deviation)))
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
def _masked(name: str, values: Any, indicators: Any, use_complement: bool) -> float:
|
|
485
|
+
"""Call ``Tools.<name>`` on doubles, or on doubles with 0/1 indicators and the complement flag."""
|
|
486
|
+
if indicators is None:
|
|
487
|
+
return float(_tools_member(name, "IList[Double]")(to_net_doubles(values)))
|
|
488
|
+
member = _tools_member(name, "IList[Double]", "IList[Int32]", "Boolean")
|
|
489
|
+
return float(member(to_net_doubles(values), to_net_ints(indicators), bool(use_complement)))
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
def sum_values(values: Any, indicators: Any = None, use_complement: bool = False) -> float:
|
|
493
|
+
"""Return the sum of the values, optionally of those an indicator selects (``Tools.Sum``).
|
|
494
|
+
|
|
495
|
+
Integer input without indicators is summed by the ``IList<int>`` overload.
|
|
496
|
+
|
|
497
|
+
Parameters
|
|
498
|
+
----------
|
|
499
|
+
values : array_like
|
|
500
|
+
The values.
|
|
501
|
+
indicators : array_like of int, optional
|
|
502
|
+
0 or 1 per value; with ``use_complement`` False the values marked 1 are summed, with it True
|
|
503
|
+
those marked 0. None sums every value.
|
|
504
|
+
use_complement : bool, optional
|
|
505
|
+
Select the values marked 0; default False.
|
|
506
|
+
|
|
507
|
+
Returns
|
|
508
|
+
-------
|
|
509
|
+
float
|
|
510
|
+
The sum.
|
|
511
|
+
"""
|
|
512
|
+
if indicators is None and np.asarray(values).dtype.kind in "iub":
|
|
513
|
+
return float(_tools_member("Sum", "IList[Int32]")(to_net_ints(values)))
|
|
514
|
+
return _masked("Sum", values, indicators, use_complement)
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
def _compensated_sum_member(*types: str) -> Any:
|
|
518
|
+
"""Return the ``Tools.CompensatedSum`` overload taking ``types``, bound once per process."""
|
|
519
|
+
return cached_overload(
|
|
520
|
+
f"Tools.CompensatedSum({', '.join(types)})",
|
|
521
|
+
lambda: overload(namespace("Numerics").Tools.CompensatedSum, *types))
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
def compensated_sum(values: Any, indicators: Any = None, use_complement: bool = False, *, indices: Any = None,
|
|
525
|
+
start: int = 0, count: Any = None, kahan: bool = False) -> float:
|
|
526
|
+
"""Return the compensated (Neumaier) sum of the values (``Tools.CompensatedSum``).
|
|
527
|
+
|
|
528
|
+
Optionally of those an indicator selects, or of the gathered values ``values[indices[i]]``
|
|
529
|
+
for i in [``start``, ``start + count``).
|
|
530
|
+
|
|
531
|
+
Parameters
|
|
532
|
+
----------
|
|
533
|
+
values : array_like
|
|
534
|
+
The values.
|
|
535
|
+
indicators : array_like of int, optional
|
|
536
|
+
0 or 1 per value, as for :func:`sum_values`. None sums every value.
|
|
537
|
+
use_complement : bool, optional
|
|
538
|
+
Select the values marked 0; default False.
|
|
539
|
+
indices : array_like of int, optional
|
|
540
|
+
Zero-based positions in ``values`` to gather and sum, in this order; a position may repeat.
|
|
541
|
+
Not combined with ``indicators``.
|
|
542
|
+
start : int, optional
|
|
543
|
+
The first entry of ``indices`` to use; default 0.
|
|
544
|
+
count : int, optional
|
|
545
|
+
The number of entries of ``indices`` to use; default all from ``start`` on.
|
|
546
|
+
kahan : bool, optional
|
|
547
|
+
Use classic Kahan summation instead of Neumaier's method; default False. Kahan's
|
|
548
|
+
``a = v - c; f = t + a; c = (f - t) - a; t = f`` is reproduced bit for bit, for reproducing
|
|
549
|
+
results of the classic Kahan loop; Neumaier's method is the more accurate. A final infinite
|
|
550
|
+
sum is returned as is, and any value added after the sum becomes infinite gives NaN.
|
|
551
|
+
|
|
552
|
+
Returns
|
|
553
|
+
-------
|
|
554
|
+
float
|
|
555
|
+
The compensated sum. As for :func:`sum_values`, an empty input (or an empty range of
|
|
556
|
+
``indices``) gives NaN, where :func:`math.fsum` gives 0, and indicators of a different
|
|
557
|
+
length from the values give NaN. A NaN, or both infinities, give NaN and a single
|
|
558
|
+
infinity is returned, the IEEE sum; :func:`math.fsum` raises ``ValueError`` for both
|
|
559
|
+
infinities and ``OverflowError`` for an intermediate overflow, which returns the infinity here.
|
|
560
|
+
|
|
561
|
+
Raises
|
|
562
|
+
------
|
|
563
|
+
ValueError
|
|
564
|
+
If both ``indicators`` and ``indices`` are given, or the range or a gathered index is out of bounds.
|
|
565
|
+
|
|
566
|
+
Notes
|
|
567
|
+
-----
|
|
568
|
+
Neumaier's improvement of Kahan summation keeps a running correction of the exact rounding
|
|
569
|
+
error of each addition, so the error is bounded by 2u|s| + O(n u²) Σ|x_i| and stays small when
|
|
570
|
+
a term exceeds the running sum. The input crosses into Numerics once.
|
|
571
|
+
"""
|
|
572
|
+
extra = ("Boolean",) if kahan else ()
|
|
573
|
+
flag = (True,) if kahan else ()
|
|
574
|
+
if indices is not None:
|
|
575
|
+
if indicators is not None:
|
|
576
|
+
raise ValueError("Give either indicators or indices, not both.")
|
|
577
|
+
net_indices = to_net_ints(indices)
|
|
578
|
+
take = int(net_indices.Length) - int(start) if count is None else int(count)
|
|
579
|
+
member = _compensated_sum_member("IList[Double]", "IList[Int32]", "Int32", "Int32", *extra)
|
|
580
|
+
return float(member(to_net_doubles(values), net_indices, int(start), take, *flag))
|
|
581
|
+
if indicators is None:
|
|
582
|
+
return float(_compensated_sum_member("IList[Double]", *extra)(to_net_doubles(values), *flag))
|
|
583
|
+
member = _compensated_sum_member("IList[Double]", "IList[Int32]", "Boolean", *extra)
|
|
584
|
+
return float(member(to_net_doubles(values), to_net_ints(indicators), bool(use_complement), *flag))
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
def compensated_cumulative_sum(values: Any, kahan: bool = False) -> np.ndarray:
|
|
588
|
+
"""Return the compensated (Neumaier) running sums of the values (``Tools.CompensatedCumulativeSum``).
|
|
589
|
+
|
|
590
|
+
Parameters
|
|
591
|
+
----------
|
|
592
|
+
values : array_like
|
|
593
|
+
The values.
|
|
594
|
+
kahan : bool, optional
|
|
595
|
+
Use classic Kahan summation instead of Neumaier's method, as in :func:`compensated_sum`;
|
|
596
|
+
entry i is then the Kahan running sum t after value i. Default False.
|
|
597
|
+
|
|
598
|
+
Returns
|
|
599
|
+
-------
|
|
600
|
+
numpy.ndarray
|
|
601
|
+
Entry i is :func:`compensated_sum` of the first i + 1 values, bit for bit; empty for empty input.
|
|
602
|
+
"""
|
|
603
|
+
types = ("IList[Double]", "Boolean") if kahan else ("IList[Double]",)
|
|
604
|
+
member = cached_overload(
|
|
605
|
+
f"Tools.CompensatedCumulativeSum({', '.join(types)})",
|
|
606
|
+
lambda: overload(namespace("Numerics").Tools.CompensatedCumulativeSum, *types))
|
|
607
|
+
return to_numpy_doubles(member(to_net_doubles(values), True) if kahan else member(to_net_doubles(values)))
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
def sum_product(values1: Any, values2: Any) -> float:
|
|
611
|
+
"""Return sum(values1 * values2) (``Tools.SumProduct``).
|
|
612
|
+
|
|
613
|
+
Parameters
|
|
614
|
+
----------
|
|
615
|
+
values1, values2 : array_like
|
|
616
|
+
Equal-length values.
|
|
617
|
+
|
|
618
|
+
Returns
|
|
619
|
+
-------
|
|
620
|
+
float
|
|
621
|
+
The sum of the products.
|
|
622
|
+
"""
|
|
623
|
+
return float(namespace("Numerics").Tools.SumProduct(to_net_doubles(values1), to_net_doubles(values2)))
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
def mean_values(values: Any, indicators: Any = None, use_complement: bool = False) -> float:
|
|
627
|
+
"""Return the arithmetic mean, optionally of the values an indicator selects (``Tools.Mean``).
|
|
628
|
+
|
|
629
|
+
Parameters
|
|
630
|
+
----------
|
|
631
|
+
values : array_like
|
|
632
|
+
The values.
|
|
633
|
+
indicators : array_like of int, optional
|
|
634
|
+
0 or 1 per value, as for :func:`sum_values`.
|
|
635
|
+
use_complement : bool, optional
|
|
636
|
+
Select the values marked 0; default False.
|
|
637
|
+
|
|
638
|
+
Returns
|
|
639
|
+
-------
|
|
640
|
+
float
|
|
641
|
+
The mean.
|
|
642
|
+
"""
|
|
643
|
+
return _masked("Mean", values, indicators, use_complement)
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
def product(values: Any, indicators: Any = None, use_complement: bool = False) -> float:
|
|
647
|
+
"""Return the product, optionally of the values an indicator selects (``Tools.Product``).
|
|
648
|
+
|
|
649
|
+
Parameters
|
|
650
|
+
----------
|
|
651
|
+
values : array_like
|
|
652
|
+
The values.
|
|
653
|
+
indicators : array_like of int, optional
|
|
654
|
+
0 or 1 per value, as for :func:`sum_values`.
|
|
655
|
+
use_complement : bool, optional
|
|
656
|
+
Select the values marked 0; default False.
|
|
657
|
+
|
|
658
|
+
Returns
|
|
659
|
+
-------
|
|
660
|
+
float
|
|
661
|
+
The product.
|
|
662
|
+
"""
|
|
663
|
+
return _masked("Product", values, indicators, use_complement)
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
def min_value(values: Any, indicators: Any = None, use_complement: bool = False) -> float:
|
|
667
|
+
"""Return the smallest value, optionally of those an indicator selects (``Tools.Min``).
|
|
668
|
+
|
|
669
|
+
Empty input or input holding NaN gives NaN.
|
|
670
|
+
|
|
671
|
+
Parameters
|
|
672
|
+
----------
|
|
673
|
+
values : array_like
|
|
674
|
+
The values.
|
|
675
|
+
indicators : array_like of int, optional
|
|
676
|
+
0 or 1 per value, as for :func:`sum_values`.
|
|
677
|
+
use_complement : bool, optional
|
|
678
|
+
Select the values marked 0; default False.
|
|
679
|
+
|
|
680
|
+
Returns
|
|
681
|
+
-------
|
|
682
|
+
float
|
|
683
|
+
The minimum.
|
|
684
|
+
"""
|
|
685
|
+
return _masked("Min", values, indicators, use_complement)
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
def max_value(values: Any, indicators: Any = None, use_complement: bool = False) -> float:
|
|
689
|
+
"""Return the largest value, optionally of those an indicator selects (``Tools.Max``).
|
|
690
|
+
|
|
691
|
+
Empty input or input holding NaN gives NaN.
|
|
692
|
+
|
|
693
|
+
Parameters
|
|
694
|
+
----------
|
|
695
|
+
values : array_like
|
|
696
|
+
The values.
|
|
697
|
+
indicators : array_like of int, optional
|
|
698
|
+
0 or 1 per value, as for :func:`sum_values`.
|
|
699
|
+
use_complement : bool, optional
|
|
700
|
+
Select the values marked 0; default False.
|
|
701
|
+
|
|
702
|
+
Returns
|
|
703
|
+
-------
|
|
704
|
+
float
|
|
705
|
+
The maximum.
|
|
706
|
+
"""
|
|
707
|
+
return _masked("Max", values, indicators, use_complement)
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
def min_max(values: Any) -> tuple[float, float]:
|
|
711
|
+
"""Return the minimum and the maximum in one pass (``Tools.MinMax``).
|
|
712
|
+
|
|
713
|
+
Parameters
|
|
714
|
+
----------
|
|
715
|
+
values : array_like
|
|
716
|
+
The values.
|
|
717
|
+
|
|
718
|
+
Returns
|
|
719
|
+
-------
|
|
720
|
+
tuple of float
|
|
721
|
+
``(minimum, maximum)``; both NaN for empty input or input holding NaN.
|
|
722
|
+
"""
|
|
723
|
+
low, high = namespace("Numerics").Tools.MinMax(to_net_doubles(values), 0.0, 0.0)
|
|
724
|
+
return float(low), float(high)
|
|
725
|
+
|
|
726
|
+
|
|
727
|
+
def arg_min(values: Any) -> int:
|
|
728
|
+
"""Return the index of the smallest value, ignoring NaN (``Tools.ArgMin``).
|
|
729
|
+
|
|
730
|
+
Parameters
|
|
731
|
+
----------
|
|
732
|
+
values : array_like
|
|
733
|
+
The values.
|
|
734
|
+
|
|
735
|
+
Returns
|
|
736
|
+
-------
|
|
737
|
+
int
|
|
738
|
+
The zero-based index of the first minimum, or -1 when every value is NaN or there are none.
|
|
739
|
+
"""
|
|
740
|
+
return int(namespace("Numerics").Tools.ArgMin(to_net_doubles(values)))
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
def arg_max(values: Any) -> int:
|
|
744
|
+
"""Return the index of the largest value, ignoring NaN (``Tools.ArgMax``).
|
|
745
|
+
|
|
746
|
+
Parameters
|
|
747
|
+
----------
|
|
748
|
+
values : array_like
|
|
749
|
+
The values.
|
|
750
|
+
|
|
751
|
+
Returns
|
|
752
|
+
-------
|
|
753
|
+
int
|
|
754
|
+
The zero-based index of the first maximum, or -1 when every value is NaN or there are none.
|
|
755
|
+
"""
|
|
756
|
+
return int(namespace("Numerics").Tools.ArgMax(to_net_doubles(values)))
|
|
757
|
+
|
|
758
|
+
|
|
759
|
+
def log_sum_exp(values: Any, v: Any = None, *, axis: int | None = None) -> Any:
|
|
760
|
+
"""Return log(sum(exp(values))) without overflow (``Tools.LogSumExp``).
|
|
761
|
+
|
|
762
|
+
With one argument the whole array is reduced in one crossing by the ``IList<double>``
|
|
763
|
+
overload; with ``axis`` a two-dimensional array is reduced along that axis in one crossing by
|
|
764
|
+
the ``(double[,], int)`` overload; with two arguments, log(exp(values) + exp(v)) is evaluated
|
|
765
|
+
pairwise by the ``(double, double)`` overload, broadcasting arrays. The evaluation and the
|
|
766
|
+
special values are those of ``scipy.special.logsumexp``.
|
|
767
|
+
|
|
768
|
+
Parameters
|
|
769
|
+
----------
|
|
770
|
+
values : array_like or float
|
|
771
|
+
Log values to reduce, or the first log value of each pair.
|
|
772
|
+
v : float or array_like, optional
|
|
773
|
+
The second log value of each pair.
|
|
774
|
+
axis : int, optional
|
|
775
|
+
0 or 1 (or -2 or -1): reduce a two-dimensional ``values`` over its rows, giving one value
|
|
776
|
+
per column, or over its columns, giving one value per row. None, the default, reduces
|
|
777
|
+
every value.
|
|
778
|
+
|
|
779
|
+
Returns
|
|
780
|
+
-------
|
|
781
|
+
float or numpy.ndarray
|
|
782
|
+
The reduction, the reductions along ``axis``, or the pairwise values. An empty reduction
|
|
783
|
+
and a reduction of -inf values give -inf, any +inf gives +inf, and NaN propagates.
|
|
784
|
+
|
|
785
|
+
Raises
|
|
786
|
+
------
|
|
787
|
+
ValueError
|
|
788
|
+
If ``axis`` is given with ``v``, or ``values`` is not two-dimensional, or ``axis`` is not
|
|
789
|
+
one of 0, 1, -2 and -1.
|
|
790
|
+
TypeError
|
|
791
|
+
If ``axis`` is a bool or not an integer.
|
|
792
|
+
"""
|
|
793
|
+
if axis is not None:
|
|
794
|
+
if v is not None:
|
|
795
|
+
raise ValueError("Give either v or axis, not both.")
|
|
796
|
+
if isinstance(axis, bool) or not isinstance(axis, (int, np.integer)):
|
|
797
|
+
raise TypeError(f"axis must be an integer; got {type(axis).__name__}.")
|
|
798
|
+
if axis not in (0, 1, -2, -1):
|
|
799
|
+
raise ValueError(f"axis must be 0, 1, -2 or -1; got {axis}.")
|
|
800
|
+
array = np.asarray(values, dtype=np.float64)
|
|
801
|
+
if array.ndim != 2:
|
|
802
|
+
raise ValueError(f"axis needs a 2-D array; got shape {array.shape}.")
|
|
803
|
+
return to_numpy_doubles(namespace("Numerics").Tools.LogSumExp(to_net_matrix(array), int(axis) % 2))
|
|
804
|
+
if v is None:
|
|
805
|
+
return float(_tools_member("LogSumExp", "IList[Double]")(to_net_doubles(values)))
|
|
806
|
+
return broadcast_loop(_tools_member("LogSumExp", "Double", "Double"), values, v)
|
|
807
|
+
|
|
808
|
+
|
|
809
|
+
def sequence(start: float, end: float, step: float = 1) -> np.ndarray:
|
|
810
|
+
"""Return start, start + step, ... up to and including ``end`` (``Tools.Sequence``).
|
|
811
|
+
|
|
812
|
+
Integer arguments use the ``int`` overload and give int32 values; any float argument uses
|
|
813
|
+
the ``double`` overload, which accumulates ``v += step``. A zero step gives an empty array.
|
|
814
|
+
|
|
815
|
+
Parameters
|
|
816
|
+
----------
|
|
817
|
+
start, end : int or float
|
|
818
|
+
The first value and the inclusive limit.
|
|
819
|
+
step : int or float, optional
|
|
820
|
+
The increment (negative counts down); default 1.
|
|
821
|
+
|
|
822
|
+
Returns
|
|
823
|
+
-------
|
|
824
|
+
numpy.ndarray
|
|
825
|
+
The sequence, int32 or float64.
|
|
826
|
+
"""
|
|
827
|
+
if all(isinstance(a, (int, np.integer)) and not isinstance(a, bool) for a in (start, end, step)):
|
|
828
|
+
member = _tools_member("Sequence", "Int32", "Int32", "Int32")
|
|
829
|
+
return to_numpy_ints(member(int(start), int(end), int(step)))
|
|
830
|
+
member = _tools_member("Sequence", "Double", "Double", "Double")
|
|
831
|
+
return to_numpy_doubles(member(float(start), float(end), float(step)))
|
|
832
|
+
|
|
833
|
+
|
|
834
|
+
def compress(data: bytes) -> bytes:
|
|
835
|
+
"""Compress bytes with the .NET raw deflate stream at the optimal level (``Tools.Compress``).
|
|
836
|
+
|
|
837
|
+
The output is a raw deflate stream, which ``zlib.decompress(out, -15)`` also reads.
|
|
838
|
+
|
|
839
|
+
Parameters
|
|
840
|
+
----------
|
|
841
|
+
data : bytes
|
|
842
|
+
The bytes to compress.
|
|
843
|
+
|
|
844
|
+
Returns
|
|
845
|
+
-------
|
|
846
|
+
bytes
|
|
847
|
+
The compressed bytes.
|
|
848
|
+
"""
|
|
849
|
+
source = _bytes_to_net(np.frombuffer(bytes(data), dtype=np.uint8), "bytes")
|
|
850
|
+
return _bytes_from_net(namespace("Numerics").Tools.Compress(source), np.uint8).tobytes()
|
|
851
|
+
|
|
852
|
+
|
|
853
|
+
def decompress(data: bytes) -> bytes:
|
|
854
|
+
"""Inflate a raw deflate stream (``Tools.Decompress``).
|
|
855
|
+
|
|
856
|
+
Parameters
|
|
857
|
+
----------
|
|
858
|
+
data : bytes
|
|
859
|
+
Bytes from :func:`compress` or any raw deflate stream.
|
|
860
|
+
|
|
861
|
+
Returns
|
|
862
|
+
-------
|
|
863
|
+
bytes
|
|
864
|
+
The decompressed bytes.
|
|
865
|
+
"""
|
|
866
|
+
source = _bytes_to_net(np.frombuffer(bytes(data), dtype=np.uint8), "bytes")
|
|
867
|
+
return _bytes_from_net(namespace("Numerics").Tools.Decompress(source), np.uint8).tobytes()
|
|
868
|
+
|
|
869
|
+
|
|
870
|
+
def _complex_to_net(values: Any) -> Any:
|
|
871
|
+
"""Copy a 1-D complex array into a ``System.Double[]`` of interleaved real and imaginary parts."""
|
|
872
|
+
array = np.ascontiguousarray(values, dtype=np.complex128)
|
|
873
|
+
if array.ndim != 1:
|
|
874
|
+
raise ValueError(f"Expected a 1-D array; got shape {array.shape}.")
|
|
875
|
+
return to_net_doubles(array.view(np.float64))
|
|
876
|
+
|
|
877
|
+
|
|
878
|
+
def _fourier() -> Any:
|
|
879
|
+
"""Return ``Numerics.Mathematics.Fourier`` after starting the runtime."""
|
|
880
|
+
return namespace("Numerics.Mathematics").Fourier
|
|
881
|
+
|
|
882
|
+
|
|
883
|
+
def fft(values: Any, inverse: bool = False) -> np.ndarray:
|
|
884
|
+
"""Return the discrete Fourier transform of a power-of-2 complex sequence (``Fourier.FFT``).
|
|
885
|
+
|
|
886
|
+
Numerics uses the Numerical Recipes conventions: the forward transform is
|
|
887
|
+
H(k) = sum h(j) exp(+2 pi i j k / n), which equals ``n * numpy.fft.ifft(values)``, and the
|
|
888
|
+
inverse transform returns n times the inverse DFT, which equals ``numpy.fft.fft(values)``.
|
|
889
|
+
The array crosses once each way as interleaved doubles.
|
|
890
|
+
|
|
891
|
+
Parameters
|
|
892
|
+
----------
|
|
893
|
+
values : array_like of complex
|
|
894
|
+
The sequence; its length must be a power of 2.
|
|
895
|
+
inverse : bool, optional
|
|
896
|
+
Compute the (unnormalized) inverse transform; default False.
|
|
897
|
+
|
|
898
|
+
Returns
|
|
899
|
+
-------
|
|
900
|
+
numpy.ndarray
|
|
901
|
+
The complex transform.
|
|
902
|
+
|
|
903
|
+
Raises
|
|
904
|
+
------
|
|
905
|
+
ValueError
|
|
906
|
+
If the length is not a power of 2 (raised by Numerics).
|
|
907
|
+
"""
|
|
908
|
+
data = _complex_to_net(values)
|
|
909
|
+
_fourier().FFT(data, bool(inverse))
|
|
910
|
+
return to_numpy_doubles(data).view(np.complex128)
|
|
911
|
+
|
|
912
|
+
|
|
913
|
+
def bluestein_fft(values: Any, inverse: bool = False) -> np.ndarray:
|
|
914
|
+
"""Return the discrete Fourier transform of a complex sequence of any length (``Fourier.BluesteinFFT``).
|
|
915
|
+
|
|
916
|
+
The conventions are those of :func:`fft`; a length that is not a power of 2 is transformed
|
|
917
|
+
with Bluestein's chirp-z convolution.
|
|
918
|
+
|
|
919
|
+
Parameters
|
|
920
|
+
----------
|
|
921
|
+
values : array_like of complex
|
|
922
|
+
The sequence, of any positive length.
|
|
923
|
+
inverse : bool, optional
|
|
924
|
+
Compute the (unnormalized) inverse transform; default False.
|
|
925
|
+
|
|
926
|
+
Returns
|
|
927
|
+
-------
|
|
928
|
+
numpy.ndarray
|
|
929
|
+
The complex transform.
|
|
930
|
+
|
|
931
|
+
Raises
|
|
932
|
+
------
|
|
933
|
+
ValueError
|
|
934
|
+
If the sequence is empty (raised by Numerics).
|
|
935
|
+
"""
|
|
936
|
+
member = _fourier().BluesteinFFT
|
|
937
|
+
data = _complex_to_net(values)
|
|
938
|
+
member(data, bool(inverse))
|
|
939
|
+
return to_numpy_doubles(data).view(np.complex128)
|
|
940
|
+
|
|
941
|
+
|
|
942
|
+
def real_fft(values: Any, inverse: bool = False) -> np.ndarray:
|
|
943
|
+
"""Return the packed transform of a power-of-2 real sequence (``Fourier.RealFFT``).
|
|
944
|
+
|
|
945
|
+
The forward result holds the positive-frequency half of the :func:`fft` of the real input:
|
|
946
|
+
element 0 is H(0), element 1 is H(n/2) (both real), and elements 2k, 2k + 1 are the real and
|
|
947
|
+
imaginary parts of H(k) for k = 1 .. n/2 - 1. With ``inverse`` a packed array is turned back
|
|
948
|
+
into the real sequence times n/2.
|
|
949
|
+
|
|
950
|
+
Parameters
|
|
951
|
+
----------
|
|
952
|
+
values : array_like
|
|
953
|
+
The real sequence (or packed transform); its length must be a power of 2.
|
|
954
|
+
inverse : bool, optional
|
|
955
|
+
Compute the inverse transform; default False.
|
|
956
|
+
|
|
957
|
+
Returns
|
|
958
|
+
-------
|
|
959
|
+
numpy.ndarray
|
|
960
|
+
The packed transform, or the unscaled inverse.
|
|
961
|
+
|
|
962
|
+
Raises
|
|
963
|
+
------
|
|
964
|
+
ValueError
|
|
965
|
+
If the length is not a power of 2 (raised by Numerics).
|
|
966
|
+
"""
|
|
967
|
+
data = to_net_doubles(values)
|
|
968
|
+
_fourier().RealFFT(data, bool(inverse))
|
|
969
|
+
return to_numpy_doubles(data)
|
|
970
|
+
|
|
971
|
+
|
|
972
|
+
def fft_convolve(values1: Any, values2: Any) -> np.ndarray:
|
|
973
|
+
"""Return the full linear convolution of two real sequences by FFT (``Fourier.Convolve``).
|
|
974
|
+
|
|
975
|
+
The same quantity as ``numpy.convolve(values1, values2, mode="full")``, with an absolute
|
|
976
|
+
round-off of about machine epsilon times log2(n) times the largest output.
|
|
977
|
+
|
|
978
|
+
Parameters
|
|
979
|
+
----------
|
|
980
|
+
values1, values2 : array_like
|
|
981
|
+
The sequences, each of length at least 1.
|
|
982
|
+
|
|
983
|
+
Returns
|
|
984
|
+
-------
|
|
985
|
+
numpy.ndarray
|
|
986
|
+
The convolution, of length ``len(values1) + len(values2) - 1``.
|
|
987
|
+
|
|
988
|
+
Raises
|
|
989
|
+
------
|
|
990
|
+
ValueError
|
|
991
|
+
If either sequence is empty (raised by Numerics).
|
|
992
|
+
"""
|
|
993
|
+
member = _fourier().Convolve
|
|
994
|
+
return to_numpy_doubles(member(to_net_doubles(values1), to_net_doubles(values2)))
|
|
995
|
+
|
|
996
|
+
|
|
997
|
+
def fft_correlation(values1: Any, values2: Any) -> np.ndarray:
|
|
998
|
+
"""Return the circular cross-correlation of two real power-of-2 sequences (``Fourier.Correlation``).
|
|
999
|
+
|
|
1000
|
+
Element k is the sum over j of values1[(j + k) mod n] * values2[j], in wraparound order: lags
|
|
1001
|
+
0 .. n/2 - 1 first, then the negative lags -n/2 .. -1. This is not a normalized correlation
|
|
1002
|
+
coefficient.
|
|
1003
|
+
|
|
1004
|
+
Parameters
|
|
1005
|
+
----------
|
|
1006
|
+
values1, values2 : array_like
|
|
1007
|
+
Equal-length real sequences whose length is a power of 2.
|
|
1008
|
+
|
|
1009
|
+
Returns
|
|
1010
|
+
-------
|
|
1011
|
+
numpy.ndarray
|
|
1012
|
+
The correlation at each lag.
|
|
1013
|
+
|
|
1014
|
+
Raises
|
|
1015
|
+
------
|
|
1016
|
+
ValueError
|
|
1017
|
+
If the lengths are not equal powers of 2 (raised by Numerics).
|
|
1018
|
+
"""
|
|
1019
|
+
return to_numpy_doubles(_fourier().Correlation(to_net_doubles(values1), to_net_doubles(values2)))
|
|
1020
|
+
|
|
1021
|
+
|
|
1022
|
+
def fft_autocorrelation(series: Any, lag_max: int) -> np.ndarray:
|
|
1023
|
+
"""Return the sample autocorrelation function by FFT (``Fourier.Autocorrelation``).
|
|
1024
|
+
|
|
1025
|
+
r(k) = sum (x_t - mean)(x_(t+k) - mean) / sum (x_t - mean)**2, the linear (not circular)
|
|
1026
|
+
estimate that ``statsmodels.tsa.stattools.acf`` also computes.
|
|
1027
|
+
|
|
1028
|
+
Parameters
|
|
1029
|
+
----------
|
|
1030
|
+
series : array_like
|
|
1031
|
+
The series.
|
|
1032
|
+
lag_max : int
|
|
1033
|
+
The largest lag.
|
|
1034
|
+
|
|
1035
|
+
Returns
|
|
1036
|
+
-------
|
|
1037
|
+
numpy.ndarray
|
|
1038
|
+
A ``(lag_max + 1, 2)`` array: the lags 0 .. lag_max in column 0 and r(k) in column 1.
|
|
1039
|
+
"""
|
|
1040
|
+
return to_numpy_matrix(_fourier().Autocorrelation(to_net_doubles(series), int(lag_max)))
|
|
1041
|
+
|
|
1042
|
+
|
|
1043
|
+
__all__ = [
|
|
1044
|
+
"NumericsConstants", "arg_max", "arg_min", "bluestein_fft", "clamp", "compensated_cumulative_sum",
|
|
1045
|
+
"compensated_sum", "compress", "constants", "copy_sign",
|
|
1046
|
+
"decompress", "denormalize", "destandardize", "distance", "expm1", "fft", "fft_autocorrelation", "fft_convolve",
|
|
1047
|
+
"fft_correlation", "hypot", "is_finite", "is_power_of_two", "log", "log10", "log1p", "log_sum_exp", "max_value",
|
|
1048
|
+
"mean_values", "min_max", "min_value", "next_power_of_two", "normalize", "normalized_distance", "point_distance",
|
|
1049
|
+
"power", "product", "real_fft", "sequence", "sign", "sqr", "standardize", "sum_product", "sum_values",
|
|
1050
|
+
"weighted_distance",
|
|
1051
|
+
]
|
|
1052
|
+
|
|
1053
|
+
translate_public(globals())
|