pytme 0.2.0b0__cp311-cp311-macosx_14_0_arm64.whl → 0.2.2__cp311-cp311-macosx_14_0_arm64.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.
- pytme-0.2.2.data/scripts/match_template.py +1187 -0
- {pytme-0.2.0b0.data → pytme-0.2.2.data}/scripts/postprocess.py +170 -71
- {pytme-0.2.0b0.data → pytme-0.2.2.data}/scripts/preprocessor_gui.py +179 -86
- pytme-0.2.2.dist-info/METADATA +91 -0
- pytme-0.2.2.dist-info/RECORD +74 -0
- {pytme-0.2.0b0.dist-info → pytme-0.2.2.dist-info}/WHEEL +1 -1
- scripts/extract_candidates.py +126 -87
- scripts/match_template.py +596 -209
- scripts/match_template_filters.py +571 -223
- scripts/postprocess.py +170 -71
- scripts/preprocessor_gui.py +179 -86
- scripts/refine_matches.py +567 -159
- tme/__init__.py +0 -1
- tme/__version__.py +1 -1
- tme/analyzer.py +627 -855
- tme/backends/__init__.py +41 -11
- tme/backends/_jax_utils.py +185 -0
- tme/backends/cupy_backend.py +120 -225
- tme/backends/jax_backend.py +282 -0
- tme/backends/matching_backend.py +464 -388
- tme/backends/mlx_backend.py +45 -68
- tme/backends/npfftw_backend.py +256 -514
- tme/backends/pytorch_backend.py +41 -154
- tme/density.py +312 -421
- tme/extensions.cpython-311-darwin.so +0 -0
- tme/matching_data.py +366 -303
- tme/matching_exhaustive.py +279 -1521
- tme/matching_optimization.py +234 -129
- tme/matching_scores.py +884 -0
- tme/matching_utils.py +281 -387
- tme/memory.py +377 -0
- tme/orientations.py +226 -66
- tme/parser.py +3 -4
- tme/preprocessing/__init__.py +2 -0
- tme/preprocessing/_utils.py +217 -0
- tme/preprocessing/composable_filter.py +31 -0
- tme/preprocessing/compose.py +55 -0
- tme/preprocessing/frequency_filters.py +388 -0
- tme/preprocessing/tilt_series.py +1011 -0
- tme/preprocessor.py +574 -530
- tme/structure.py +495 -189
- tme/types.py +5 -3
- pytme-0.2.0b0.data/scripts/match_template.py +0 -800
- pytme-0.2.0b0.dist-info/METADATA +0 -73
- pytme-0.2.0b0.dist-info/RECORD +0 -66
- tme/helpers.py +0 -881
- tme/matching_constrained.py +0 -195
- {pytme-0.2.0b0.data → pytme-0.2.2.data}/scripts/estimate_ram_usage.py +0 -0
- {pytme-0.2.0b0.data → pytme-0.2.2.data}/scripts/preprocess.py +0 -0
- {pytme-0.2.0b0.dist-info → pytme-0.2.2.dist-info}/LICENSE +0 -0
- {pytme-0.2.0b0.dist-info → pytme-0.2.2.dist-info}/entry_points.txt +0 -0
- {pytme-0.2.0b0.dist-info → pytme-0.2.2.dist-info}/top_level.txt +0 -0
tme/backends/cupy_backend.py
CHANGED
@@ -1,59 +1,87 @@
|
|
1
|
-
""" Backend using cupy
|
2
|
-
template matching.
|
1
|
+
""" Backend using cupy for template matching.
|
3
2
|
|
4
3
|
Copyright (c) 2023 European Molecular Biology Laboratory
|
5
4
|
|
6
5
|
Author: Valentin Maurer <valentin.maurer@embl-hamburg.de>
|
7
6
|
"""
|
8
|
-
|
9
7
|
import warnings
|
10
|
-
from
|
8
|
+
from importlib.util import find_spec
|
11
9
|
from contextlib import contextmanager
|
10
|
+
from typing import Tuple, Callable, List
|
12
11
|
|
13
12
|
import numpy as np
|
14
|
-
from numpy.typing import NDArray
|
15
13
|
|
16
14
|
from .npfftw_backend import NumpyFFTWBackend
|
17
|
-
from ..types import CupyArray
|
15
|
+
from ..types import CupyArray, NDArray, shm_type
|
18
16
|
|
19
17
|
PLAN_CACHE = {}
|
18
|
+
TEXTURE_CACHE = {}
|
20
19
|
|
21
20
|
|
22
21
|
class CupyBackend(NumpyFFTWBackend):
|
23
22
|
"""
|
24
|
-
A cupy
|
23
|
+
A cupy-based matching backend.
|
25
24
|
"""
|
26
25
|
|
27
26
|
def __init__(
|
28
|
-
self,
|
27
|
+
self,
|
28
|
+
float_dtype: type = None,
|
29
|
+
complex_dtype: type = None,
|
30
|
+
int_dtype: type = None,
|
31
|
+
overflow_safe_dtype: type = None,
|
32
|
+
**kwargs,
|
29
33
|
):
|
30
34
|
import cupy as cp
|
31
35
|
from cupyx.scipy.fft import get_fft_plan
|
32
36
|
from cupyx.scipy.ndimage import affine_transform
|
33
37
|
from cupyx.scipy.ndimage import maximum_filter
|
34
38
|
|
35
|
-
|
39
|
+
float_dtype = cp.float32 if float_dtype is None else float_dtype
|
36
40
|
complex_dtype = cp.complex64 if complex_dtype is None else complex_dtype
|
37
|
-
|
41
|
+
int_dtype = cp.int32 if int_dtype is None else int_dtype
|
42
|
+
if overflow_safe_dtype is None:
|
43
|
+
overflow_safe_dtype = cp.float32
|
38
44
|
|
39
45
|
super().__init__(
|
40
46
|
array_backend=cp,
|
41
|
-
|
47
|
+
float_dtype=float_dtype,
|
42
48
|
complex_dtype=complex_dtype,
|
43
|
-
|
49
|
+
int_dtype=int_dtype,
|
50
|
+
overflow_safe_dtype=overflow_safe_dtype,
|
44
51
|
)
|
45
52
|
self.get_fft_plan = get_fft_plan
|
46
53
|
self.affine_transform = affine_transform
|
47
54
|
self.maximum_filter = maximum_filter
|
48
55
|
|
49
|
-
|
50
|
-
|
56
|
+
itype = f"int{self.datatype_bytes(int_dtype) * 8}"
|
57
|
+
ftype = f"float{self.datatype_bytes(float_dtype) * 8}"
|
51
58
|
self._max_score_over_rotations = self._array_backend.ElementwiseKernel(
|
52
|
-
f"{
|
53
|
-
f"{
|
59
|
+
f"{ftype} internal_scores, {ftype} scores, {itype} rot_index",
|
60
|
+
f"{ftype} out1, {itype} rotations",
|
54
61
|
"if (internal_scores < scores) {out1 = scores; rotations = rot_index;}",
|
55
62
|
"max_score_over_rotations",
|
56
63
|
)
|
64
|
+
self.norm_scores = cp.ElementwiseKernel(
|
65
|
+
f"{ftype} arr, {ftype} exp_sq, {ftype} sq_exp, {ftype} n_obs, {ftype} eps",
|
66
|
+
f"{ftype} out",
|
67
|
+
"""
|
68
|
+
// tmp1 = E(X)^2; tmp2 = E(X^2)
|
69
|
+
float tmp1 = sq_exp / n_obs;
|
70
|
+
float tmp2 = exp_sq / n_obs;
|
71
|
+
tmp1 *= tmp1;
|
72
|
+
|
73
|
+
tmp2 = sqrt(max(tmp2 - tmp1, 0.0));
|
74
|
+
// out = (tmp2 < eps) ? 0.0 : arr / (tmp2 * n_obs);
|
75
|
+
tmp1 = arr;
|
76
|
+
if (tmp2 < eps){
|
77
|
+
tmp1 = 0;
|
78
|
+
}
|
79
|
+
tmp2 *= n_obs;
|
80
|
+
out = tmp1 / tmp2;
|
81
|
+
""",
|
82
|
+
"norm_scores",
|
83
|
+
)
|
84
|
+
self.texture_available = find_spec("voltools") is not None
|
57
85
|
|
58
86
|
def to_backend_array(self, arr: NDArray) -> CupyArray:
|
59
87
|
current_device = self._array_backend.cuda.device.get_device_id()
|
@@ -70,35 +98,15 @@ class CupyBackend(NumpyFFTWBackend):
|
|
70
98
|
def to_cpu_array(self, arr: NDArray) -> NDArray:
|
71
99
|
return self.to_numpy_array(arr)
|
72
100
|
|
73
|
-
def
|
74
|
-
|
75
|
-
) -> CupyArray:
|
76
|
-
return shm
|
101
|
+
def from_sharedarr(self, arr: CupyArray) -> CupyArray:
|
102
|
+
return arr
|
77
103
|
|
78
104
|
@staticmethod
|
79
|
-
def
|
80
|
-
arr: CupyArray, shared_memory_handler: type = None
|
81
|
-
) -> CupyArray:
|
105
|
+
def to_sharedarr(arr: CupyArray, shared_memory_handler: type = None) -> shm_type:
|
82
106
|
return arr
|
83
107
|
|
84
|
-
def
|
85
|
-
|
86
|
-
Returns a byte-aligned array of zeros with specified shape and dtype.
|
87
|
-
|
88
|
-
Parameters
|
89
|
-
----------
|
90
|
-
shape : Tuple[int]
|
91
|
-
Desired shape for the array.
|
92
|
-
dtype : type
|
93
|
-
Desired data type for the array.
|
94
|
-
|
95
|
-
Returns
|
96
|
-
-------
|
97
|
-
NDArray
|
98
|
-
Byte-aligned array of zeros with specified shape and dtype.
|
99
|
-
"""
|
100
|
-
arr = self._array_backend.zeros(shape, dtype=dtype)
|
101
|
-
return arr
|
108
|
+
def zeros(self, *args, **kwargs):
|
109
|
+
return self._array_backend.zeros(*args, **kwargs)
|
102
110
|
|
103
111
|
def unravel_index(self, indices, shape):
|
104
112
|
return self._array_backend.unravel_index(indices=indices, dims=shape)
|
@@ -106,10 +114,10 @@ class CupyBackend(NumpyFFTWBackend):
|
|
106
114
|
def unique(self, ar, axis=None, *args, **kwargs):
|
107
115
|
if axis is None:
|
108
116
|
return self._array_backend.unique(ar=ar, axis=axis, *args, **kwargs)
|
109
|
-
warnings.warn("Axis argument not yet supported in CupY, falling back to NumPy.")
|
110
117
|
|
118
|
+
warnings.warn("Axis argument not yet supported in CupY, falling back to NumPy.")
|
111
119
|
ret = np.unique(ar=self.to_numpy_array(ar), axis=axis, *args, **kwargs)
|
112
|
-
if
|
120
|
+
if not isinstance(ret, tuple):
|
113
121
|
return self.to_backend_array(ret)
|
114
122
|
return tuple(self.to_backend_array(k) for k in ret)
|
115
123
|
|
@@ -119,40 +127,12 @@ class CupyBackend(NumpyFFTWBackend):
|
|
119
127
|
fast_ft_shape: Tuple[int],
|
120
128
|
real_dtype: type,
|
121
129
|
complex_dtype: type,
|
122
|
-
fftargs: Dict = {},
|
123
130
|
inverse_fast_shape: Tuple[int] = None,
|
124
131
|
**kwargs,
|
125
132
|
) -> Tuple[Callable, Callable]:
|
126
|
-
|
127
|
-
Build pyFFTW builder functions.
|
128
|
-
|
129
|
-
Parameters
|
130
|
-
----------
|
131
|
-
fast_shape : tuple
|
132
|
-
Tuple of integers corresponding to fast convolution shape
|
133
|
-
(see :py:meth:`CupyBackend.compute_convolution_shapes`).
|
134
|
-
fast_ft_shape : tuple
|
135
|
-
Tuple of integers corresponding to the shape of the fourier
|
136
|
-
transform array (see :py:meth:`CupyBackend.compute_convolution_shapes`).
|
137
|
-
real_dtype : dtype
|
138
|
-
Numpy dtype of the inverse fourier transform.
|
139
|
-
complex_dtype : dtype
|
140
|
-
Numpy dtype of the fourier transform.
|
141
|
-
inverse_fast_shape : tuple, optional
|
142
|
-
Output shape of the inverse Fourier transform. By default fast_shape.
|
143
|
-
fftargs : dict, optional
|
144
|
-
Dictionary passed to pyFFTW builders.
|
145
|
-
**kwargs: dict, optional
|
146
|
-
Unused keyword arguments.
|
147
|
-
|
148
|
-
Returns
|
149
|
-
-------
|
150
|
-
tuple
|
151
|
-
Tupple containing callable rfft and irfft object.
|
152
|
-
"""
|
153
|
-
cache = self._array_backend.fft.config.get_plan_cache()
|
154
|
-
cache.set_size(2)
|
133
|
+
import cupyx.scipy.fft as cufft
|
155
134
|
|
135
|
+
cache = self._array_backend.fft.config.get_plan_cache()
|
156
136
|
current_device = self._array_backend.cuda.device.get_device_id()
|
157
137
|
|
158
138
|
previous_transform = [fast_shape, fast_ft_shape]
|
@@ -161,20 +141,18 @@ class CupyBackend(NumpyFFTWBackend):
|
|
161
141
|
|
162
142
|
real_diff, cmplx_diff = True, True
|
163
143
|
if len(fast_shape) == len(previous_transform[0]):
|
164
|
-
real_diff =
|
144
|
+
real_diff = fast_shape == previous_transform[0]
|
165
145
|
if len(fast_ft_shape) == len(previous_transform[1]):
|
166
|
-
cmplx_diff =
|
167
|
-
self.sum(self.subtract(fast_ft_shape, previous_transform[1])) != 0
|
168
|
-
)
|
146
|
+
cmplx_diff = fast_ft_shape == previous_transform[1]
|
169
147
|
|
170
148
|
if real_diff or cmplx_diff:
|
171
149
|
cache.clear()
|
172
150
|
|
173
|
-
def rfftn(arr: CupyArray, out: CupyArray) ->
|
174
|
-
|
151
|
+
def rfftn(arr: CupyArray, out: CupyArray) -> CupyArray:
|
152
|
+
return cufft.rfftn(arr)
|
175
153
|
|
176
|
-
def irfftn(arr: CupyArray, out: CupyArray) ->
|
177
|
-
|
154
|
+
def irfftn(arr: CupyArray, out: CupyArray) -> CupyArray:
|
155
|
+
return cufft.irfftn(arr)
|
178
156
|
|
179
157
|
PLAN_CACHE[current_device] = [fast_shape, fast_ft_shape]
|
180
158
|
|
@@ -182,11 +160,14 @@ class CupyBackend(NumpyFFTWBackend):
|
|
182
160
|
|
183
161
|
def compute_convolution_shapes(
|
184
162
|
self, arr1_shape: Tuple[int], arr2_shape: Tuple[int]
|
185
|
-
) -> Tuple[
|
186
|
-
|
187
|
-
|
163
|
+
) -> Tuple[List[int], List[int], List[int]]:
|
164
|
+
from cupyx.scipy.fft import next_fast_len
|
165
|
+
|
166
|
+
convolution_shape = [int(x + y - 1) for x, y in zip(arr1_shape, arr2_shape)]
|
167
|
+
fast_shape = [next_fast_len(x, real=True) for x in convolution_shape]
|
168
|
+
fast_ft_shape = list(fast_shape[:-1]) + [fast_shape[-1] // 2 + 1]
|
188
169
|
|
189
|
-
#
|
170
|
+
# This almost never happens but avoid cuFFT casting errors
|
190
171
|
is_odd = fast_shape[-1] % 2
|
191
172
|
fast_shape[-1] += is_odd
|
192
173
|
fast_ft_shape[-1] += is_odd
|
@@ -212,167 +193,81 @@ class CupyBackend(NumpyFFTWBackend):
|
|
212
193
|
out = self.var(a, *args, **kwargs)
|
213
194
|
return self._array_backend.sqrt(out)
|
214
195
|
|
215
|
-
def
|
196
|
+
def _get_texture(self, arr: CupyArray, order: int = 3, prefilter: bool = False):
|
197
|
+
key = id(arr)
|
198
|
+
if key in TEXTURE_CACHE:
|
199
|
+
return TEXTURE_CACHE[key]
|
200
|
+
|
201
|
+
from voltools import StaticVolume
|
202
|
+
|
203
|
+
# Only keep template and potential corresponding mask in cache
|
204
|
+
if len(TEXTURE_CACHE) >= 2:
|
205
|
+
TEXTURE_CACHE.clear()
|
206
|
+
|
207
|
+
interpolation = "filt_bspline"
|
208
|
+
if order == 1:
|
209
|
+
interpolation = "linear"
|
210
|
+
elif order == 3 and not prefilter:
|
211
|
+
interpolation = "bspline"
|
212
|
+
|
213
|
+
current_device = self._array_backend.cuda.device.get_device_id()
|
214
|
+
TEXTURE_CACHE[key] = StaticVolume(
|
215
|
+
arr, interpolation=interpolation, device=f"gpu:{current_device}"
|
216
|
+
)
|
217
|
+
|
218
|
+
return TEXTURE_CACHE[key]
|
219
|
+
|
220
|
+
def _rigid_transform(
|
216
221
|
self,
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
out_mask: CupyArray = None,
|
224
|
-
order: int = 3,
|
222
|
+
data: CupyArray,
|
223
|
+
matrix: CupyArray,
|
224
|
+
output: CupyArray,
|
225
|
+
prefilter: bool,
|
226
|
+
order: int,
|
227
|
+
cache: bool = False,
|
225
228
|
) -> None:
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
arr : CupyArray
|
236
|
-
The input array to be rotated.
|
237
|
-
arr_mask : CupyArray, optional
|
238
|
-
The mask of `arr` that will be equivalently rotated.
|
239
|
-
rotation_matrix : CupyArray
|
240
|
-
The rotation matrix to apply [d x d].
|
241
|
-
translation : CupyArray
|
242
|
-
The translation to apply [d].
|
243
|
-
use_geometric_center : bool, optional
|
244
|
-
Whether the rotation should be centered around the geometric
|
245
|
-
or mass center. Default is mass center.
|
246
|
-
out : CupyArray, optional
|
247
|
-
The output array to write the rotation of `arr` to.
|
248
|
-
out_mask : CupyArray, optional
|
249
|
-
The output array to write the rotation of `arr_mask` to.
|
250
|
-
order : int, optional
|
251
|
-
Spline interpolation order. Has to be in the range 0-5.
|
252
|
-
|
253
|
-
Notes
|
254
|
-
-----
|
255
|
-
Only a box of size arr, arr_mask will be consisdered for interpolation
|
256
|
-
in out, out_mask.
|
257
|
-
"""
|
258
|
-
|
259
|
-
rotate_mask = arr_mask is not None
|
260
|
-
return_type = (out is None) + 2 * rotate_mask * (out_mask is None)
|
261
|
-
translation = self.zeros(arr.ndim) if translation is None else translation
|
262
|
-
|
263
|
-
center = self.divide(self.to_backend_array(arr.shape), 2)
|
264
|
-
if not use_geometric_center:
|
265
|
-
center = self.center_of_mass(arr, cutoff=0)
|
266
|
-
|
267
|
-
rotation_matrix_inverted = self.linalg.inv(rotation_matrix)
|
268
|
-
transformed_center = rotation_matrix_inverted @ center.reshape(-1, 1)
|
269
|
-
transformed_center = transformed_center.reshape(-1)
|
270
|
-
base_offset = self.subtract(center, transformed_center)
|
271
|
-
offset = self.subtract(base_offset, translation)
|
272
|
-
|
273
|
-
out = self.zeros_like(arr) if out is None else out
|
274
|
-
out_slice = tuple(slice(0, stop) for stop in arr.shape)
|
275
|
-
|
276
|
-
# Applying the prefilter leads to the creation of artifacts in the mask.
|
229
|
+
out_slice = tuple(slice(0, stop) for stop in data.shape)
|
230
|
+
if data.ndim == 3 and cache and self.texture_available:
|
231
|
+
# Device memory pool (should) come to rescue performance
|
232
|
+
temp = self.empty(data.shape, data.dtype)
|
233
|
+
texture = self._get_texture(data, order=order, prefilter=prefilter)
|
234
|
+
texture.affine(transform_m=matrix, profile=False, output=temp)
|
235
|
+
output[out_slice] = temp
|
236
|
+
return None
|
237
|
+
|
277
238
|
self.affine_transform(
|
278
|
-
input=
|
279
|
-
matrix=
|
280
|
-
offset=offset,
|
239
|
+
input=data,
|
240
|
+
matrix=matrix,
|
281
241
|
mode="constant",
|
282
|
-
output=
|
242
|
+
output=output[out_slice],
|
283
243
|
order=order,
|
284
|
-
prefilter=
|
244
|
+
prefilter=prefilter,
|
285
245
|
)
|
286
246
|
|
287
|
-
if rotate_mask:
|
288
|
-
out_mask = self.zeros_like(arr_mask) if out_mask is None else out_mask
|
289
|
-
out_mask_slice = tuple(slice(0, stop) for stop in arr_mask.shape)
|
290
|
-
self.affine_transform(
|
291
|
-
input=arr_mask,
|
292
|
-
matrix=rotation_matrix_inverted,
|
293
|
-
offset=offset,
|
294
|
-
mode="constant",
|
295
|
-
output=out_mask[out_mask_slice],
|
296
|
-
order=order,
|
297
|
-
prefilter=False,
|
298
|
-
)
|
299
|
-
|
300
|
-
match return_type:
|
301
|
-
case 0:
|
302
|
-
return None
|
303
|
-
case 1:
|
304
|
-
return out
|
305
|
-
case 2:
|
306
|
-
return out_mask
|
307
|
-
case 3:
|
308
|
-
return out, out_mask
|
309
|
-
|
310
247
|
def get_available_memory(self) -> int:
|
311
248
|
with self._array_backend.cuda.Device():
|
312
|
-
(
|
313
|
-
free_memory,
|
314
|
-
available_memory,
|
315
|
-
) = self._array_backend.cuda.runtime.memGetInfo()
|
249
|
+
free_memory, _ = self._array_backend.cuda.runtime.memGetInfo()
|
316
250
|
return free_memory
|
317
251
|
|
318
252
|
@contextmanager
|
319
253
|
def set_device(self, device_index: int):
|
320
|
-
"""
|
321
|
-
Set the active GPU device as a context.
|
322
|
-
|
323
|
-
This method sets the active GPU device for operations within the context.
|
324
|
-
|
325
|
-
Parameters
|
326
|
-
----------
|
327
|
-
device_index : int
|
328
|
-
Index of the GPU device to be set as active.
|
329
|
-
|
330
|
-
Yields
|
331
|
-
------
|
332
|
-
None
|
333
|
-
Operates as a context manager, yielding None and providing
|
334
|
-
the set GPU context for enclosed operations.
|
335
|
-
"""
|
336
254
|
with self._array_backend.cuda.Device(device_index):
|
337
255
|
yield
|
338
256
|
|
339
257
|
def device_count(self) -> int:
|
340
|
-
"""
|
341
|
-
Return the number of available GPU devices.
|
342
|
-
|
343
|
-
Returns
|
344
|
-
-------
|
345
|
-
int
|
346
|
-
Number of available GPU devices.
|
347
|
-
"""
|
348
258
|
return self._array_backend.cuda.runtime.getDeviceCount()
|
349
259
|
|
350
260
|
def max_score_over_rotations(
|
351
261
|
self,
|
352
|
-
|
353
|
-
|
354
|
-
|
262
|
+
scores: CupyArray,
|
263
|
+
max_scores: CupyArray,
|
264
|
+
rotations: CupyArray,
|
355
265
|
rotation_index: int,
|
356
|
-
):
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
Parameters
|
362
|
-
----------
|
363
|
-
score_space : CupyArray
|
364
|
-
The score space to compare against internal_scores.
|
365
|
-
internal_scores : CupyArray
|
366
|
-
The internal scores to update with maximum scores.
|
367
|
-
internal_rotations : CupyArray
|
368
|
-
The internal rotations corresponding to the maximum scores.
|
369
|
-
rotation_index : int
|
370
|
-
The index representing the current rotation.
|
371
|
-
"""
|
372
|
-
self._max_score_over_rotations(
|
373
|
-
internal_scores,
|
374
|
-
score_space,
|
266
|
+
) -> Tuple[CupyArray, CupyArray]:
|
267
|
+
return self._max_score_over_rotations(
|
268
|
+
max_scores,
|
269
|
+
scores,
|
375
270
|
rotation_index,
|
376
|
-
|
377
|
-
|
271
|
+
max_scores,
|
272
|
+
rotations,
|
378
273
|
)
|