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.
Files changed (46) hide show
  1. pynumerics/__init__.py +73 -0
  2. pynumerics/_bin/Microsoft.CodeAnalysis.CSharp.dll +0 -0
  3. pynumerics/_bin/Microsoft.CodeAnalysis.LICENSE.txt +27 -0
  4. pynumerics/_bin/Microsoft.CodeAnalysis.dll +0 -0
  5. pynumerics/_bin/Numerics.dll +0 -0
  6. pynumerics/_bin/pynumerics.runtimeconfig.json +15 -0
  7. pynumerics/_coverage.py +3825 -0
  8. pynumerics/_util.py +237 -0
  9. pynumerics/_version.py +40 -0
  10. pynumerics/bootstrap.py +593 -0
  11. pynumerics/callbacks.py +791 -0
  12. pynumerics/copulas.py +910 -0
  13. pynumerics/data.py +2233 -0
  14. pynumerics/differentiation.py +348 -0
  15. pynumerics/distributions.py +4043 -0
  16. pynumerics/download.py +623 -0
  17. pynumerics/enums.py +119 -0
  18. pynumerics/errors.py +245 -0
  19. pynumerics/functions.py +1142 -0
  20. pynumerics/goodness_of_fit.py +699 -0
  21. pynumerics/graphs.py +556 -0
  22. pynumerics/hypothesis_tests.py +445 -0
  23. pynumerics/identity.py +144 -0
  24. pynumerics/integration.py +677 -0
  25. pynumerics/linalg.py +1408 -0
  26. pynumerics/machine_learning.py +1335 -0
  27. pynumerics/marshal.py +733 -0
  28. pynumerics/mathematics.py +1053 -0
  29. pynumerics/mcmc.py +1406 -0
  30. pynumerics/multivariate.py +1539 -0
  31. pynumerics/ode.py +156 -0
  32. pynumerics/optimization.py +1736 -0
  33. pynumerics/probability.py +966 -0
  34. pynumerics/py.typed +0 -0
  35. pynumerics/regional.py +522 -0
  36. pynumerics/roots.py +274 -0
  37. pynumerics/runtime.py +384 -0
  38. pynumerics/sampling.py +1758 -0
  39. pynumerics/special.py +1079 -0
  40. pynumerics/statistics.py +1958 -0
  41. pynumerics/timeseries.py +1326 -0
  42. pynumerics-2.3.0.dist-info/METADATA +142 -0
  43. pynumerics-2.3.0.dist-info/RECORD +46 -0
  44. pynumerics-2.3.0.dist-info/WHEEL +5 -0
  45. pynumerics-2.3.0.dist-info/licenses/LICENSE +10 -0
  46. pynumerics-2.3.0.dist-info/top_level.txt +1 -0
pynumerics/enums.py ADDED
@@ -0,0 +1,119 @@
1
+ """Python enums mirroring the Numerics enums the wrappers accept.
2
+
3
+ Every wrapper argument typed with one of these enums also accepts the member value or
4
+ the .NET member name as a string, matched case-insensitively with underscores ignored. The
5
+ enums themselves resolve the same spellings: ``Transform("normal_z")``, ``Transform("NORMAL_Z")``
6
+ and ``Transform("NormalZ")`` are all ``Transform.NORMAL_Z``. Enums added elsewhere in the package
7
+ derive from :class:`NetEnum` to get that lookup.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import enum
13
+ from typing import Any
14
+
15
+ from pynumerics._util import fold_name
16
+
17
+
18
+ class NetEnum(enum.Enum):
19
+ """Base of the pynumerics enums: values are .NET member names, looked up by folded spelling.
20
+
21
+ A value that is not a member value exactly is matched against the member values and names
22
+ with underscores removed and case ignored, the rule ``net_enum`` applies to .NET enums, so
23
+ snake-case spellings kept in configuration files resolve.
24
+ """
25
+
26
+ @classmethod
27
+ def _missing_(cls, value: Any) -> NetEnum | None:
28
+ if not isinstance(value, str):
29
+ return None
30
+ key = fold_name(value)
31
+ for member in cls:
32
+ if fold_name(str(member.value)) == key or fold_name(member.name) == key:
33
+ return member
34
+ return None
35
+
36
+
37
+ class EstimationMethod(NetEnum):
38
+ """Parameter estimation methods (``Numerics.Distributions.ParameterEstimationMethod``)."""
39
+
40
+ MAXIMUM_LIKELIHOOD = "MaximumLikelihood"
41
+ METHOD_OF_MOMENTS = "MethodOfMoments"
42
+ METHOD_OF_LINEAR_MOMENTS = "MethodOfLinearMoments"
43
+ METHOD_OF_PERCENTILES = "MethodOfPercentiles"
44
+
45
+
46
+ class SortOrder(NetEnum):
47
+ """Sort orders (``Numerics.Data.SortOrder``)."""
48
+
49
+ ASCENDING = "Ascending"
50
+ DESCENDING = "Descending"
51
+ NONE = "None"
52
+
53
+
54
+ class Transform(NetEnum):
55
+ """Interpolation transforms (``Numerics.Data.Transform``)."""
56
+
57
+ NONE = "None"
58
+ LOGARITHMIC = "Logarithmic"
59
+ NORMAL_Z = "NormalZ"
60
+
61
+
62
+ class Extrapolation(NetEnum):
63
+ """Extrapolation sides (``Numerics.Data.ExtrapolationSides``)."""
64
+
65
+ NONE = "None"
66
+ BELOW = "Below"
67
+ ABOVE = "Above"
68
+ BOTH = "Both"
69
+
70
+
71
+ class PlottingPosition(NetEnum):
72
+ """Plotting-position formulas (``PlottingPositions.PlottingPostionType``)."""
73
+
74
+ WEIBULL = "Weibull"
75
+ MEDIAN = "Median"
76
+ BLOM = "Blom"
77
+ CUNNANE = "Cunnane"
78
+ GRINGORTEN = "Gringorten"
79
+ HAZEN = "Hazen"
80
+ KAPLAN_MEIER = "KaplanMeier"
81
+
82
+
83
+ class ImportanceDistribution(NetEnum):
84
+ """Stratification importance distributions (``Stratify.ImportanceDistribution``)."""
85
+
86
+ GUMBEL = "Gumbel"
87
+ NORMAL = "Normal"
88
+ UNIFORM = "Uniform"
89
+ LOG10_UNIFORM = "Log10Uniform"
90
+
91
+
92
+ class WeightType(NetEnum):
93
+ """Weight interpretations for weighted statistics (``Numerics.Data.Statistics.WeightType``)."""
94
+
95
+ FREQUENCY = "Frequency"
96
+ RELIABILITY = "Reliability"
97
+
98
+
99
+ class KernelType(NetEnum):
100
+ """Kernel density kernels (``Numerics.Distributions.KernelDensity.KernelType``)."""
101
+
102
+ EPANECHNIKOV = "Epanechnikov"
103
+ GAUSSIAN = "Gaussian"
104
+ TRIANGULAR = "Triangular"
105
+ UNIFORM = "Uniform"
106
+
107
+
108
+ class AutocorrelationType(NetEnum):
109
+ """Autocorrelation function kinds (``Numerics.Data.Statistics.Autocorrelation.Type``)."""
110
+
111
+ CORRELATION = "Correlation"
112
+ COVARIANCE = "Covariance"
113
+ PARTIAL = "Partial"
114
+
115
+
116
+ __all__ = [
117
+ "AutocorrelationType", "EstimationMethod", "Extrapolation", "ImportanceDistribution", "KernelType", "NetEnum",
118
+ "PlottingPosition", "SortOrder", "Transform", "WeightType",
119
+ ]
pynumerics/errors.py ADDED
@@ -0,0 +1,245 @@
1
+ """Map the exceptions Numerics throws onto the Python exceptions callers expect.
2
+
3
+ pythonnet raises a .NET exception as a Python exception of the .NET type, which ``except ValueError``
4
+ does not catch. Every public wrapper in this package translates them, keeping the .NET message
5
+ text exactly and chaining the .NET exception as the cause:
6
+
7
+ ======================================================== ========================
8
+ .NET exception Python exception
9
+ ======================================================== ========================
10
+ ``ArgumentException`` (``ArgumentOutOfRangeException``) ``ValueError``
11
+ ``OverflowException`` ``OverflowError``
12
+ ``DivideByZeroException`` ``ZeroDivisionError``
13
+ ``ArithmeticException`` (any other) ``ArithmeticError``
14
+ ``NotImplementedException``, ``NotSupportedException`` ``NotImplementedError``
15
+ any other ``System.Exception`` ``RuntimeError``
16
+ ======================================================== ========================
17
+
18
+ A ``TargetInvocationException``, or an ``AggregateException`` with one inner exception, is
19
+ translated by its inner exception. A Python exception, including one raised inside a Python
20
+ callback that Numerics invoked, propagates unchanged.
21
+
22
+ :func:`net_errors` applies the translation to a block of code, :func:`translated` to a function,
23
+ and :func:`translate_public` to every public function and class of a module.
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ import enum
29
+ import functools
30
+ import inspect
31
+ from collections.abc import Callable, Iterator, MutableMapping
32
+ from contextlib import contextmanager
33
+ from typing import Any, TypeVar
34
+
35
+ from pynumerics import runtime
36
+
37
+ F = TypeVar("F", bound=Callable[..., Any])
38
+
39
+ _MARKER = "__net_errors__"
40
+
41
+ _WRAPPED_DUNDERS = frozenset({"__init__", "__call__", "__getitem__", "__setitem__", "__len__", "__contains__",
42
+ "__iter__", "__eq__", "__hash__"})
43
+ """Special methods that call into .NET in the wrappers and so are translated as well."""
44
+
45
+
46
+ def _system() -> Any:
47
+ """Return the ``System`` namespace, or None while the runtime is not running."""
48
+ if not runtime.is_initialized():
49
+ return None
50
+ import System # noqa: PLC0415 - the runtime is running
51
+
52
+ return System
53
+
54
+
55
+ def translate(error: BaseException) -> BaseException | None:
56
+ """Return the Python exception for a .NET exception.
57
+
58
+ Parameters
59
+ ----------
60
+ error : BaseException
61
+ The raised exception.
62
+
63
+ Returns
64
+ -------
65
+ BaseException or None
66
+ A new ``ValueError``, ``OverflowError``, ``ZeroDivisionError``, ``ArithmeticError``,
67
+ ``NotImplementedError`` or ``RuntimeError`` carrying the .NET message, or None when
68
+ ``error`` is not a .NET exception.
69
+ """
70
+ system = _system()
71
+ if system is None or not isinstance(error, system.Exception):
72
+ return None
73
+ inner = error
74
+ while True:
75
+ if isinstance(inner, system.Reflection.TargetInvocationException) and inner.InnerException is not None:
76
+ inner = inner.InnerException
77
+ elif isinstance(inner, system.AggregateException) and inner.InnerExceptions.Count == 1:
78
+ inner = inner.InnerExceptions[0]
79
+ else:
80
+ break
81
+ message = str(inner.Message)
82
+ if isinstance(inner, system.ArgumentException):
83
+ return ValueError(message)
84
+ if isinstance(inner, system.OverflowException):
85
+ return OverflowError(message)
86
+ if isinstance(inner, system.DivideByZeroException):
87
+ return ZeroDivisionError(message)
88
+ if isinstance(inner, system.ArithmeticException):
89
+ return ArithmeticError(message)
90
+ if isinstance(inner, (system.NotImplementedException, system.NotSupportedException)):
91
+ return NotImplementedError(message)
92
+ return RuntimeError(message)
93
+
94
+
95
+ @contextmanager
96
+ def net_errors() -> Iterator[None]:
97
+ """Re-raise .NET exceptions raised in the block as their Python counterparts.
98
+
99
+ Yields
100
+ ------
101
+ None
102
+ Nothing; the body runs inside the translation.
103
+
104
+ Examples
105
+ --------
106
+ >>> from pynumerics.distributions import Normal
107
+ >>> from pynumerics.errors import net_errors
108
+ >>> try:
109
+ ... with net_errors():
110
+ ... Normal().net.InverseCDF(1.5)
111
+ ... except ValueError as error:
112
+ ... print("refused")
113
+ refused
114
+ """
115
+ try:
116
+ yield
117
+ except Exception as error:
118
+ mapped = translate(error)
119
+ if mapped is None:
120
+ raise
121
+ raise mapped from error
122
+
123
+
124
+ def translated(func: F) -> F:
125
+ """Return ``func`` wrapped so that .NET exceptions it raises surface as Python exceptions.
126
+
127
+ The wrapper keeps the name, docstring and signature of ``func`` (``functools.wraps``) and adds
128
+ one Python call to a call that does not raise. Wrapping an already translated function
129
+ returns it unchanged.
130
+
131
+ Parameters
132
+ ----------
133
+ func : callable
134
+ The function to wrap.
135
+
136
+ Returns
137
+ -------
138
+ callable
139
+ The wrapped function.
140
+ """
141
+ if getattr(func, _MARKER, False):
142
+ return func
143
+
144
+ @functools.wraps(func)
145
+ def wrapper(*args: Any, **kwargs: Any) -> Any:
146
+ try:
147
+ return func(*args, **kwargs)
148
+ except Exception as error:
149
+ mapped = translate(error)
150
+ if mapped is None:
151
+ raise
152
+ raise mapped from error
153
+
154
+ setattr(wrapper, _MARKER, True)
155
+ return wrapper # type: ignore[return-value]
156
+
157
+
158
+ def is_translated(obj: Any) -> bool:
159
+ """Return whether a function, property or class member translates .NET exceptions.
160
+
161
+ Parameters
162
+ ----------
163
+ obj : object
164
+ A function, ``property``, ``classmethod`` or ``staticmethod``.
165
+
166
+ Returns
167
+ -------
168
+ bool
169
+ True when every function the object runs is wrapped by :func:`translated`.
170
+ """
171
+ if isinstance(obj, property):
172
+ return all(f is None or getattr(f, _MARKER, False) for f in (obj.fget, obj.fset, obj.fdel))
173
+ if isinstance(obj, (classmethod, staticmethod)):
174
+ return bool(getattr(obj.__func__, _MARKER, False))
175
+ return bool(getattr(obj, _MARKER, False))
176
+
177
+
178
+ def _translate_member(value: Any) -> Any:
179
+ """Return a class-dictionary entry with its functions wrapped by :func:`translated`."""
180
+ if isinstance(value, property):
181
+ if is_translated(value):
182
+ return value
183
+ return property(*(None if f is None else translated(f) for f in (value.fget, value.fset, value.fdel)),
184
+ doc=value.__doc__)
185
+ if isinstance(value, (classmethod, staticmethod)):
186
+ return value if is_translated(value) else type(value)(translated(value.__func__))
187
+ if inspect.isfunction(value):
188
+ return translated(value)
189
+ return value
190
+
191
+
192
+ def translate_class(klass: type) -> type:
193
+ """Wrap the methods and properties a class defines so .NET exceptions surface as Python exceptions.
194
+
195
+ Covers the functions, properties, class methods and static methods in the class's own
196
+ dictionary whose names are public, plus ``__init__``, ``__call__``, ``__getitem__``,
197
+ ``__setitem__``, ``__len__``, ``__contains__``, ``__iter__``, ``__eq__`` and ``__hash__``.
198
+ Enums and exception classes are returned unchanged.
199
+
200
+ Parameters
201
+ ----------
202
+ klass : type
203
+ The class to update in place.
204
+
205
+ Returns
206
+ -------
207
+ type
208
+ ``klass``.
209
+ """
210
+ if issubclass(klass, (enum.Enum, BaseException)):
211
+ return klass
212
+ for name, value in list(vars(klass).items()):
213
+ if (name.startswith("_") and name not in _WRAPPED_DUNDERS) or value is None:
214
+ continue
215
+ member = _translate_member(value)
216
+ if member is not value:
217
+ setattr(klass, name, member)
218
+ return klass
219
+
220
+
221
+ def translate_public(namespace: MutableMapping[str, Any]) -> None:
222
+ """Apply :func:`translated` and :func:`translate_class` to the public objects a module defines.
223
+
224
+ Called at the end of a wrapper module as ``translate_public(globals())``. The objects are
225
+ the module's ``__all__`` (or every public name when it has none) whose ``__module__`` is the
226
+ module itself; re-exported objects are left to their own module.
227
+
228
+ Parameters
229
+ ----------
230
+ namespace : MutableMapping
231
+ The module's ``globals()``.
232
+ """
233
+ module = namespace.get("__name__")
234
+ names = namespace.get("__all__") or [n for n in list(namespace) if not n.startswith("_")]
235
+ for name in names:
236
+ obj = namespace.get(name)
237
+ if getattr(obj, "__module__", None) != module:
238
+ continue
239
+ if inspect.isclass(obj):
240
+ translate_class(obj)
241
+ elif inspect.isfunction(obj):
242
+ namespace[name] = translated(obj)
243
+
244
+
245
+ __all__ = ["is_translated", "net_errors", "translate", "translate_class", "translate_public", "translated"]