fdatools 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.
fdatools/__init__.py ADDED
@@ -0,0 +1,107 @@
1
+ """fdatools: functional data analysis for Python.
2
+
3
+ A clean-room, production-grade Python implementation of the functional data
4
+ analysis toolkit described in Ramsay & Silverman, *Functional Data Analysis*.
5
+
6
+ Examples
7
+ --------
8
+ >>> import numpy as np
9
+ >>> import fdatools as fdt
10
+ >>> basis = fdt.BSpline(domain=(0.0, 1.0), n_basis=5)
11
+ >>> basis(np.array([0.0, 0.5, 1.0])).shape
12
+ (3, 5)
13
+ """
14
+
15
+ from typing import TYPE_CHECKING, Any
16
+
17
+ from fdatools import datasets, density, profiling, sparse, stats
18
+ from fdatools.basis import (
19
+ Basis,
20
+ BSpline,
21
+ Constant,
22
+ Exponential,
23
+ Fourier,
24
+ Monomial,
25
+ Polygonal,
26
+ Power,
27
+ )
28
+ from fdatools.core import LDO, BiFData, FData, inprod
29
+ from fdatools.decomposition import FCCA, FPCA
30
+ from fdatools.density import DensityResult, IntensityResult, fit_density, fit_intensity
31
+ from fdatools.dynamics import PDA, PDAStability, phase_plane
32
+ from fdatools.io import from_pandas, read_rds, to_pandas, to_xarray
33
+ from fdatools.profiling import ODEModel, ProfiledODE, profile_ode
34
+ from fdatools.registration import Registrator, landmark_register, register
35
+ from fdatools.regression import FRegress, LinmodResult, fregress, linmod
36
+ from fdatools.smoothing import Smoother, SmoothResult, smooth
37
+ from fdatools.sparse import PACE, SparseCov, sparse_cov, sparse_mean
38
+
39
+ if TYPE_CHECKING:
40
+ from fdatools import nn as nn
41
+
42
+ __all__ = [
43
+ "FCCA",
44
+ "FPCA",
45
+ "LDO",
46
+ "PACE",
47
+ "PDA",
48
+ "BSpline",
49
+ "Basis",
50
+ "BiFData",
51
+ "Constant",
52
+ "DensityResult",
53
+ "Exponential",
54
+ "FData",
55
+ "FRegress",
56
+ "Fourier",
57
+ "IntensityResult",
58
+ "LinmodResult",
59
+ "Monomial",
60
+ "ODEModel",
61
+ "PDAStability",
62
+ "Polygonal",
63
+ "Power",
64
+ "ProfiledODE",
65
+ "Registrator",
66
+ "SmoothResult",
67
+ "Smoother",
68
+ "SparseCov",
69
+ "__version__",
70
+ "datasets",
71
+ "density",
72
+ "fit_density",
73
+ "fit_intensity",
74
+ "fregress",
75
+ "from_pandas",
76
+ "inprod",
77
+ "landmark_register",
78
+ "linmod",
79
+ "phase_plane",
80
+ "profile_ode",
81
+ "profiling",
82
+ "read_rds",
83
+ "register",
84
+ "smooth",
85
+ "sparse",
86
+ "sparse_cov",
87
+ "sparse_mean",
88
+ "stats",
89
+ "to_pandas",
90
+ "to_xarray",
91
+ ]
92
+
93
+ __version__ = "1.1.0"
94
+
95
+
96
+ def __getattr__(name: str) -> Any:
97
+ """Import the optional :mod:`fdatools.nn` module on first access.
98
+
99
+ ``import fdatools`` never imports PyTorch; ``fdatools.nn`` loads it lazily.
100
+ """
101
+ if name == "nn":
102
+ import importlib
103
+
104
+ module = importlib.import_module("fdatools.nn")
105
+ globals()["nn"] = module
106
+ return module
107
+ raise AttributeError(f"module 'fdatools' has no attribute {name!r}")
fdatools/_backend.py ADDED
@@ -0,0 +1,219 @@
1
+ """Array-API dispatch for fdatools.
2
+
3
+ This is the *only* module (together with :mod:`fdatools._linalg`) that is allowed to
4
+ import NumPy directly. Every other module obtains its array namespace through
5
+ :func:`array_namespace` and calls ``xp.*`` functions, so that a NumPy input
6
+ produces a NumPy output and a PyTorch input produces a PyTorch output with
7
+ gradients flowing through.
8
+
9
+ Examples
10
+ --------
11
+ >>> import numpy as np
12
+ >>> from fdatools import _backend as be
13
+ >>> xp = be.array_namespace(np.zeros(3))
14
+ >>> be.asarray([1, 2, 3]).dtype
15
+ dtype('float64')
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ from types import ModuleType
21
+ from typing import Any, cast
22
+
23
+ import array_api_compat
24
+ import numpy as np
25
+
26
+ __all__ = [
27
+ "array_namespace",
28
+ "asarray",
29
+ "default_namespace",
30
+ "is_torch",
31
+ "result_namespace",
32
+ "to_numpy",
33
+ ]
34
+
35
+ _DEFAULT_NAMESPACE: ModuleType = array_api_compat.array_namespace(np.empty(0))
36
+
37
+
38
+ def default_namespace() -> ModuleType:
39
+ """Return the fallback array namespace (NumPy).
40
+
41
+ Returns
42
+ -------
43
+ module
44
+ The array-API compatible NumPy namespace.
45
+
46
+ Examples
47
+ --------
48
+ >>> from fdatools._backend import default_namespace
49
+ >>> default_namespace().__name__.endswith("numpy")
50
+ True
51
+ """
52
+ return _DEFAULT_NAMESPACE
53
+
54
+
55
+ def array_namespace(*xs: Any) -> ModuleType:
56
+ """Return the array-API namespace shared by ``xs``.
57
+
58
+ Python scalars, ``None`` and plain sequences are ignored; if no argument is an
59
+ array the NumPy namespace is returned. If any argument is a
60
+ :class:`torch.Tensor` the PyTorch namespace is returned, so tensors in give
61
+ tensors out.
62
+
63
+ Parameters
64
+ ----------
65
+ *xs : object
66
+ Candidate arrays, scalars or ``None``.
67
+
68
+ Returns
69
+ -------
70
+ module
71
+ An array-API compatible namespace.
72
+
73
+ Raises
74
+ ------
75
+ TypeError
76
+ If ``xs`` mixes arrays from two different array libraries.
77
+
78
+ Examples
79
+ --------
80
+ >>> import numpy as np
81
+ >>> from fdatools._backend import array_namespace
82
+ >>> array_namespace(np.zeros(2), 1.0).__name__.endswith("numpy")
83
+ True
84
+ """
85
+ arrays = [x for x in xs if array_api_compat.is_array_api_obj(x)]
86
+ if not arrays:
87
+ return _DEFAULT_NAMESPACE
88
+ namespace: ModuleType = array_api_compat.array_namespace(*arrays)
89
+ return namespace
90
+
91
+
92
+ def result_namespace(*xs: Any) -> ModuleType:
93
+ """Return the namespace an operation over ``xs`` should compute in.
94
+
95
+ Unlike :func:`array_namespace`, a NumPy operand does not conflict with a
96
+ third-party one: NumPy data is promotable, so mixing NumPy coefficients with
97
+ a PyTorch argument gives the PyTorch namespace (and a differentiable
98
+ result). Two different non-NumPy libraries still conflict.
99
+
100
+ Parameters
101
+ ----------
102
+ *xs : object
103
+ Candidate arrays, scalars or ``None``.
104
+
105
+ Returns
106
+ -------
107
+ module
108
+ An array-API compatible namespace.
109
+
110
+ Raises
111
+ ------
112
+ TypeError
113
+ If ``xs`` mixes arrays from two different non-NumPy libraries.
114
+
115
+ Examples
116
+ --------
117
+ >>> import numpy as np
118
+ >>> from fdatools._backend import result_namespace
119
+ >>> result_namespace(np.zeros(2), None).__name__.endswith("numpy")
120
+ True
121
+ """
122
+ spaces = [
123
+ array_api_compat.array_namespace(x) for x in xs if array_api_compat.is_array_api_obj(x)
124
+ ]
125
+ foreign = [space for space in spaces if space is not _DEFAULT_NAMESPACE]
126
+ if not foreign:
127
+ return _DEFAULT_NAMESPACE
128
+ if any(space is not foreign[0] for space in foreign[1:]):
129
+ raise TypeError(f"cannot mix array namespaces {sorted({s.__name__ for s in foreign})}")
130
+ return cast("ModuleType", foreign[0])
131
+
132
+
133
+ def asarray(x: Any, xp: ModuleType | None = None, dtype: Any = float) -> Any:
134
+ """Convert ``x`` to an array in namespace ``xp``.
135
+
136
+ Parameters
137
+ ----------
138
+ x : array_like
139
+ Value to convert. Arrays are returned unchanged when the namespace and
140
+ dtype already match, so autograd graphs are preserved.
141
+ xp : module, optional
142
+ Target namespace. Defaults to the namespace of ``x``.
143
+ dtype : dtype-like, optional
144
+ Target dtype. The default, the builtin :class:`float`, maps to the
145
+ namespace's ``float64``. Pass ``None`` to keep ``x``'s dtype.
146
+
147
+ Returns
148
+ -------
149
+ array
150
+ ``x`` as an array of namespace ``xp``.
151
+
152
+ Examples
153
+ --------
154
+ >>> from fdatools._backend import asarray
155
+ >>> asarray([1, 2, 3]).dtype
156
+ dtype('float64')
157
+ """
158
+ if xp is None:
159
+ xp = array_namespace(x)
160
+ resolved = xp.float64 if dtype is float else dtype
161
+ if array_api_compat.is_array_api_obj(x) and array_namespace(x) is xp:
162
+ if resolved is None or x.dtype == resolved:
163
+ return x
164
+ return xp.astype(x, resolved)
165
+ if isinstance(x, np.ndarray) and not x.flags.writeable:
166
+ x = np.array(x)
167
+ if resolved is None:
168
+ return xp.asarray(x)
169
+ return xp.asarray(x, dtype=resolved)
170
+
171
+
172
+ def to_numpy(x: Any) -> np.ndarray[Any, np.dtype[Any]]:
173
+ """Convert ``x`` to a NumPy array, detaching autograd tensors if needed.
174
+
175
+ Parameters
176
+ ----------
177
+ x : array_like
178
+ Array from any supported backend, or anything :func:`numpy.asarray`
179
+ accepts.
180
+
181
+ Returns
182
+ -------
183
+ numpy.ndarray
184
+ A NumPy view or copy of ``x``.
185
+
186
+ Examples
187
+ --------
188
+ >>> from fdatools._backend import to_numpy
189
+ >>> to_numpy([1.0, 2.0]).tolist()
190
+ [1.0, 2.0]
191
+ """
192
+ if array_api_compat.is_torch_array(x):
193
+ return np.asarray(x.detach().cpu().numpy())
194
+ return np.asarray(x)
195
+
196
+
197
+ def is_torch(x: Any) -> bool:
198
+ """Return whether ``x`` is a PyTorch tensor.
199
+
200
+ Does not import PyTorch if it has not been imported already.
201
+
202
+ Parameters
203
+ ----------
204
+ x : object
205
+ Candidate value.
206
+
207
+ Returns
208
+ -------
209
+ bool
210
+ ``True`` if ``x`` is a :class:`torch.Tensor`.
211
+
212
+ Examples
213
+ --------
214
+ >>> import numpy as np
215
+ >>> from fdatools._backend import is_torch
216
+ >>> is_torch(np.zeros(2))
217
+ False
218
+ """
219
+ return bool(array_api_compat.is_torch_array(x))
@@ -0,0 +1 @@
1
+ {"subjects": ["boy1", "boy2", "boy3", "boy4", "boy5", "boy6", "boy7", "boy8", "boy9", "boy10", "boy11", "boy12", "boy13", "boy14", "boy15", "boy16", "boy17", "boy18", "boy19", "boy20", "boy21", "boy22", "boy23", "boy24", "boy25", "boy26", "boy27", "boy28", "boy29", "boy30", "boy31", "boy32", "boy33", "boy34", "boy35", "boy36", "boy37", "boy38", "boy39"], "variables": ["Hip Angle", "Knee Angle"]}
Binary file
@@ -0,0 +1 @@
1
+ {}
Binary file
@@ -0,0 +1 @@
1
+ {}
Binary file
@@ -0,0 +1,4 @@
1
+ """Private helpers of fdatools.
2
+
3
+ Nothing in this package is public API; modules here may change without notice.
4
+ """