Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/scipy/fft/_backend.py: 58%
36 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-12 06:31 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-12 06:31 +0000
1import scipy._lib.uarray as ua
2from . import _fftlog
3from . import _pocketfft
6class _ScipyBackend:
7 """The default backend for fft calculations
9 Notes
10 -----
11 We use the domain ``numpy.scipy`` rather than ``scipy`` because ``uarray``
12 treats the domain as a hierarchy. This means the user can install a single
13 backend for ``numpy`` and have it implement ``numpy.scipy.fft`` as well.
14 """
15 __ua_domain__ = "numpy.scipy.fft"
17 @staticmethod
18 def __ua_function__(method, args, kwargs):
20 fn = getattr(_pocketfft, method.__name__, None)
21 if fn is None:
22 fn = getattr(_fftlog, method.__name__, None)
23 if fn is None:
24 return NotImplemented
25 return fn(*args, **kwargs)
28_named_backends = {
29 'scipy': _ScipyBackend,
30}
33def _backend_from_arg(backend):
34 """Maps strings to known backends and validates the backend"""
36 if isinstance(backend, str):
37 try:
38 backend = _named_backends[backend]
39 except KeyError as e:
40 raise ValueError('Unknown backend {}'.format(backend)) from e
42 if backend.__ua_domain__ != 'numpy.scipy.fft':
43 raise ValueError('Backend does not implement "numpy.scipy.fft"')
45 return backend
48def set_global_backend(backend, coerce=False, only=False, try_last=False):
49 """Sets the global fft backend
51 This utility method replaces the default backend for permanent use. It
52 will be tried in the list of backends automatically, unless the
53 ``only`` flag is set on a backend. This will be the first tried
54 backend outside the :obj:`set_backend` context manager.
56 Parameters
57 ----------
58 backend : {object, 'scipy'}
59 The backend to use.
60 Can either be a ``str`` containing the name of a known backend
61 {'scipy'} or an object that implements the uarray protocol.
62 coerce : bool
63 Whether to coerce input types when trying this backend.
64 only : bool
65 If ``True``, no more backends will be tried if this fails.
66 Implied by ``coerce=True``.
67 try_last : bool
68 If ``True``, the global backend is tried after registered backends.
70 Raises
71 ------
72 ValueError: If the backend does not implement ``numpy.scipy.fft``.
74 Notes
75 -----
76 This will overwrite the previously set global backend, which, by default, is
77 the SciPy implementation.
79 Examples
80 --------
81 We can set the global fft backend:
83 >>> from scipy.fft import fft, set_global_backend
84 >>> set_global_backend("scipy") # Sets global backend. "scipy" is the default backend.
85 >>> fft([1]) # Calls the global backend
86 array([1.+0.j])
87 """
88 backend = _backend_from_arg(backend)
89 ua.set_global_backend(backend, coerce=coerce, only=only, try_last=try_last)
92def register_backend(backend):
93 """
94 Register a backend for permanent use.
96 Registered backends have the lowest priority and will be tried after the
97 global backend.
99 Parameters
100 ----------
101 backend : {object, 'scipy'}
102 The backend to use.
103 Can either be a ``str`` containing the name of a known backend
104 {'scipy'} or an object that implements the uarray protocol.
106 Raises
107 ------
108 ValueError: If the backend does not implement ``numpy.scipy.fft``.
110 Examples
111 --------
112 We can register a new fft backend:
114 >>> from scipy.fft import fft, register_backend, set_global_backend
115 >>> class NoopBackend: # Define an invalid Backend
116 ... __ua_domain__ = "numpy.scipy.fft"
117 ... def __ua_function__(self, func, args, kwargs):
118 ... return NotImplemented
119 >>> set_global_backend(NoopBackend()) # Set the invalid backend as global
120 >>> register_backend("scipy") # Register a new backend
121 >>> fft([1]) # The registered backend is called because the global backend returns `NotImplemented`
122 array([1.+0.j])
123 >>> set_global_backend("scipy") # Restore global backend to default
125 """
126 backend = _backend_from_arg(backend)
127 ua.register_backend(backend)
130def set_backend(backend, coerce=False, only=False):
131 """Context manager to set the backend within a fixed scope.
133 Upon entering the ``with`` statement, the given backend will be added to
134 the list of available backends with the highest priority. Upon exit, the
135 backend is reset to the state before entering the scope.
137 Parameters
138 ----------
139 backend : {object, 'scipy'}
140 The backend to use.
141 Can either be a ``str`` containing the name of a known backend
142 {'scipy'} or an object that implements the uarray protocol.
143 coerce : bool, optional
144 Whether to allow expensive conversions for the ``x`` parameter. e.g.,
145 copying a NumPy array to the GPU for a CuPy backend. Implies ``only``.
146 only : bool, optional
147 If only is ``True`` and this backend returns ``NotImplemented``, then a
148 BackendNotImplemented error will be raised immediately. Ignoring any
149 lower priority backends.
151 Examples
152 --------
153 >>> import scipy.fft as fft
154 >>> with fft.set_backend('scipy', only=True):
155 ... fft.fft([1]) # Always calls the scipy implementation
156 array([1.+0.j])
157 """
158 backend = _backend_from_arg(backend)
159 return ua.set_backend(backend, coerce=coerce, only=only)
162def skip_backend(backend):
163 """Context manager to skip a backend within a fixed scope.
165 Within the context of a ``with`` statement, the given backend will not be
166 called. This covers backends registered both locally and globally. Upon
167 exit, the backend will again be considered.
169 Parameters
170 ----------
171 backend : {object, 'scipy'}
172 The backend to skip.
173 Can either be a ``str`` containing the name of a known backend
174 {'scipy'} or an object that implements the uarray protocol.
176 Examples
177 --------
178 >>> import scipy.fft as fft
179 >>> fft.fft([1]) # Calls default SciPy backend
180 array([1.+0.j])
181 >>> with fft.skip_backend('scipy'): # We explicitly skip the SciPy backend
182 ... fft.fft([1]) # leaving no implementation available
183 Traceback (most recent call last):
184 ...
185 BackendNotImplementedError: No selected backends had an implementation ...
186 """
187 backend = _backend_from_arg(backend)
188 return ua.skip_backend(backend)
191set_global_backend('scipy', try_last=True)