imops 0.8.1__cp38-cp38-win_amd64.whl → 0.8.3__cp38-cp38-win_amd64.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.

Potentially problematic release.


This version of imops might be problematic. Click here for more details.

Files changed (53) hide show
  1. _build_utils.py +87 -0
  2. imops/__init__.py +1 -0
  3. imops/__version__.py +1 -1
  4. imops/backend.py +14 -10
  5. imops/box.py +20 -29
  6. imops/crop.py +18 -2
  7. imops/interp1d.py +16 -13
  8. imops/measure.py +12 -9
  9. imops/morphology.py +155 -35
  10. imops/numeric.py +376 -0
  11. imops/pad.py +41 -5
  12. imops/radon.py +9 -7
  13. imops/src/_backprojection.c +83 -83
  14. imops/src/_backprojection.cp38-win_amd64.pyd +0 -0
  15. imops/src/_fast_backprojection.c +98 -98
  16. imops/src/_fast_backprojection.cp38-win_amd64.pyd +0 -0
  17. imops/src/_fast_measure.c +98 -98
  18. imops/src/_fast_measure.cp38-win_amd64.pyd +0 -0
  19. imops/src/_fast_morphology.c +2783 -1568
  20. imops/src/_fast_morphology.cp38-win_amd64.pyd +0 -0
  21. imops/src/_fast_morphology.pyx +315 -131
  22. imops/src/_fast_numeric.c +20547 -4998
  23. imops/src/_fast_numeric.cp38-win_amd64.pyd +0 -0
  24. imops/src/_fast_numeric.pyx +208 -30
  25. imops/src/_fast_radon.c +98 -98
  26. imops/src/_fast_radon.cp38-win_amd64.pyd +0 -0
  27. imops/src/_fast_zoom.c +5947 -3344
  28. imops/src/_fast_zoom.cp38-win_amd64.pyd +0 -0
  29. imops/src/_fast_zoom.pyx +1 -0
  30. imops/src/_measure.c +83 -83
  31. imops/src/_measure.cp38-win_amd64.pyd +0 -0
  32. imops/src/_morphology.c +2768 -1553
  33. imops/src/_morphology.cp38-win_amd64.pyd +0 -0
  34. imops/src/_morphology.pyx +315 -131
  35. imops/src/_numeric.c +20532 -4983
  36. imops/src/_numeric.cp38-win_amd64.pyd +0 -0
  37. imops/src/_numeric.pyx +208 -30
  38. imops/src/_radon.c +83 -83
  39. imops/src/_radon.cp38-win_amd64.pyd +0 -0
  40. imops/src/_zoom.c +5932 -3329
  41. imops/src/_zoom.cp38-win_amd64.pyd +0 -0
  42. imops/src/_zoom.pyx +1 -0
  43. imops/utils.py +113 -13
  44. imops/zoom.py +9 -9
  45. {imops-0.8.1.dist-info → imops-0.8.3.dist-info}/METADATA +40 -19
  46. imops-0.8.3.dist-info/RECORD +60 -0
  47. {imops-0.8.1.dist-info → imops-0.8.3.dist-info}/WHEEL +1 -1
  48. imops-0.8.3.dist-info/top_level.txt +2 -0
  49. _pyproject_build.py +0 -49
  50. imops/_numeric.py +0 -124
  51. imops-0.8.1.dist-info/RECORD +0 -60
  52. imops-0.8.1.dist-info/top_level.txt +0 -2
  53. {imops-0.8.1.dist-info → imops-0.8.3.dist-info}/LICENSE +0 -0
Binary file
imops/src/_zoom.pyx CHANGED
@@ -17,6 +17,7 @@ from libc.math cimport floor, sqrt
17
17
 
18
18
  ctypedef cython.floating FLOAT
19
19
  ctypedef fused NUM:
20
+ np.uint8_t
20
21
  short
21
22
  int
22
23
  long long
imops/utils.py CHANGED
@@ -1,39 +1,92 @@
1
1
  import os
2
+ from contextlib import contextmanager
2
3
  from itertools import permutations
3
- from typing import Callable, Optional, Sequence, Union
4
+ from typing import Callable, Optional, Sequence, Tuple, Union
4
5
  from warnings import warn
5
6
 
6
7
  import numpy as np
7
8
 
8
- from .backend import BACKEND2NUM_THREADS_VAR_NAME, SINGLE_THREADED_BACKENDS, Backend
9
+ from .backend import BACKEND_NAME2ENV_NUM_THREADS_VAR_NAME, SINGLE_THREADED_BACKENDS, Backend
9
10
 
10
11
 
11
12
  AxesLike = Union[int, Sequence[int]]
12
13
  AxesParams = Union[float, Sequence[float]]
13
14
 
14
15
  ZOOM_SRC_DIM = 4
16
+ # TODO: define imops-specific environment variable like `OMP_NUM_THREADS`?
17
+ IMOPS_NUM_THREADS = None
15
18
 
16
19
 
17
- def normalize_num_threads(num_threads: int, backend: Backend):
20
+ def set_num_threads(num_threads: int) -> int:
21
+ assert isinstance(num_threads, int) or num_threads is None, 'Number of threads must be int value or None.'
22
+ global IMOPS_NUM_THREADS
23
+ current = IMOPS_NUM_THREADS
24
+ IMOPS_NUM_THREADS = num_threads
25
+ return current
26
+
27
+
28
+ @contextmanager
29
+ def imops_num_threads(num_threads: int):
30
+ previous = set_num_threads(num_threads)
31
+ try:
32
+ yield
33
+ finally:
34
+ set_num_threads(previous)
35
+
36
+
37
+ def normalize_num_threads(num_threads: int, backend: Backend, warn_stacklevel: int = 1) -> int:
38
+ """Calculate the effective number of threads"""
39
+
40
+ global IMOPS_NUM_THREADS
18
41
  if backend.name in SINGLE_THREADED_BACKENDS:
19
42
  if num_threads != -1:
20
- warn(f'"{backend.name}" backend is single-threaded. Setting `num_threads` has no effect.')
43
+ warn(
44
+ f'"{backend.name}" backend is single-threaded. Setting `num_threads` has no effect.',
45
+ stacklevel=warn_stacklevel,
46
+ )
21
47
  return 1
48
+
49
+ env_num_threads_var_name = BACKEND_NAME2ENV_NUM_THREADS_VAR_NAME[backend.name]
50
+ # here we also handle the case `env_num_threads_var_name`=" " gracefully
51
+ env_num_threads = os.environ.get(env_num_threads_var_name, '').strip()
52
+ env_num_threads = int(env_num_threads) if env_num_threads else None
53
+ # TODO: maybe let user set the absolute maximum number of threads?
54
+ num_available_cpus = len(os.sched_getaffinity(0))
55
+
56
+ max_num_threads = min(filter(bool, [IMOPS_NUM_THREADS, env_num_threads, num_available_cpus]))
57
+
22
58
  if num_threads >= 0:
23
59
  # FIXME
24
60
  if backend.name == 'Numba':
25
61
  warn(
26
62
  'Setting `num_threads` has no effect with "Numba" backend. '
27
- 'Use `NUMBA_NUM_THREADS` environment variable.'
63
+ 'Use `NUMBA_NUM_THREADS` environment variable.',
64
+ stacklevel=warn_stacklevel,
28
65
  )
29
- return num_threads
30
-
31
- num_threads_var_name = BACKEND2NUM_THREADS_VAR_NAME[backend.name]
32
- # here we also handle the case `num_threads_var`=" " gracefully
33
- env_num_threads = os.environ.get(num_threads_var_name, '').strip()
34
- max_threads = int(env_num_threads) if env_num_threads else len(os.sched_getaffinity(0))
35
-
36
- return max_threads + num_threads + 1
66
+ return num_threads
67
+
68
+ if num_threads > max_num_threads:
69
+ if max_num_threads == IMOPS_NUM_THREADS:
70
+ warn(
71
+ f'Required number of threads ({num_threads}) is greater than `IMOPS_NUM_THREADS` '
72
+ f'({IMOPS_NUM_THREADS}). Using {IMOPS_NUM_THREADS} threads.',
73
+ stacklevel=warn_stacklevel,
74
+ )
75
+ elif max_num_threads == env_num_threads:
76
+ warn(
77
+ f'Required number of threads ({num_threads}) is greater than `{env_num_threads_var_name}` '
78
+ f'({env_num_threads}). Using {env_num_threads} threads.',
79
+ stacklevel=warn_stacklevel,
80
+ )
81
+ else:
82
+ warn(
83
+ f'Required number of threads ({num_threads}) is greater than number of available CPU-s '
84
+ f'({num_available_cpus}). Using {num_available_cpus} threads.',
85
+ stacklevel=warn_stacklevel,
86
+ )
87
+ return min(num_threads, max_num_threads)
88
+
89
+ return max_num_threads + num_threads + 1
37
90
 
38
91
 
39
92
  def get_c_contiguous_permutaion(array: np.ndarray) -> Optional[np.ndarray]:
@@ -104,3 +157,50 @@ def composition_args(f: Callable, g: Callable) -> Callable:
104
157
  return f(g(*args), *args[1:])
105
158
 
106
159
  return inner
160
+
161
+
162
+ def morphology_composition_args(f, g) -> Callable:
163
+ def wrapper(
164
+ image: np.ndarray,
165
+ footprint: np.ndarray,
166
+ output: np.ndarray,
167
+ num_threads: int,
168
+ ):
169
+ temp = np.empty_like(image, dtype=bool)
170
+ temp = g(image, footprint, temp, num_threads)
171
+
172
+ return f(temp, footprint, output, num_threads)
173
+
174
+ return wrapper
175
+
176
+
177
+ def build_slices(start: Sequence[int], stop: Sequence[int] = None, step: Sequence[int] = None) -> Tuple[slice, ...]:
178
+ """
179
+ Returns a tuple of slices built from `start` and `stop` with `step`.
180
+
181
+ Examples
182
+ --------
183
+ >>> build_slices([1, 2, 3], [4, 5, 6])
184
+ (slice(1, 4), slice(2, 5), slice(3, 6))
185
+ >>> build_slices([10, 11])
186
+ (slice(10), slice(11))
187
+ """
188
+
189
+ check_len(*filter(lambda x: x is not None, [start, stop, step]))
190
+
191
+ if stop is None and step is None:
192
+ return tuple(map(slice, start))
193
+
194
+ args = [
195
+ start,
196
+ stop if stop is not None else [None for _ in start],
197
+ step if step is not None else [None for _ in start],
198
+ ]
199
+
200
+ return tuple(map(slice, *args))
201
+
202
+
203
+ def check_len(*args) -> None:
204
+ lengths = list(map(len, args))
205
+ if any(length != lengths[0] for length in lengths):
206
+ raise ValueError(f'Arguments of equal length are required: {", ".join(map(str, lengths))}')
imops/zoom.py CHANGED
@@ -81,7 +81,7 @@ def zoom(
81
81
  """
82
82
  Rescale `x` according to `scale_factor` along the `axis`.
83
83
 
84
- Uses a fast parallelizable implementation for fp32 / fp64 (and int16-32-64 if order == 0) inputs,
84
+ Uses a fast parallelizable implementation for fp32 / fp64 (and bool-int16-32-64 if order == 0) inputs,
85
85
  ndim <= 4 and order = 0 or 1.
86
86
 
87
87
  Parameters
@@ -120,6 +120,7 @@ def zoom(
120
120
  if callable(fill_value):
121
121
  fill_value = fill_value(x)
122
122
 
123
+ # TODO: does `fill_value/cval` change anythng?
123
124
  return _zoom(x, scale_factor, order=order, cval=fill_value, num_threads=num_threads, backend=backend)
124
125
 
125
126
 
@@ -135,7 +136,7 @@ def zoom_to_shape(
135
136
  """
136
137
  Rescale `x` to match `shape` along the `axis`.
137
138
 
138
- Uses a fast parallelizable implementation for fp32 / fp64 (and int16-32-64 if order == 0) inputs,
139
+ Uses a fast parallelizable implementation for fp32 / fp64 (and bool-int16-32-64 if order == 0) inputs,
139
140
  ndim <= 4 and order = 0 or 1.
140
141
 
141
142
  Parameters
@@ -197,7 +198,7 @@ def _zoom(
197
198
  backend: BackendLike = None,
198
199
  ) -> np.ndarray:
199
200
  """
200
- Faster parallelizable version of `scipy.ndimage.zoom` for fp32 / fp64 (and int16-32-64 if order == 0) inputs.
201
+ Faster parallelizable version of `scipy.ndimage.zoom` for fp32 / fp64 (and bool-int16-32-64 if order == 0) inputs.
201
202
 
202
203
  Works faster only for ndim <= 4. Shares interface with `scipy.ndimage.zoom`
203
204
  except for
@@ -207,7 +208,7 @@ def _zoom(
207
208
 
208
209
  See `https://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.zoom.html`
209
210
  """
210
- backend = resolve_backend(backend)
211
+ backend = resolve_backend(backend, warn_stacklevel=4)
211
212
  if backend.name not in ('Scipy', 'Numba', 'Cython'):
212
213
  raise ValueError(f'Unsupported backend "{backend.name}".')
213
214
 
@@ -215,7 +216,7 @@ def _zoom(
215
216
  dtype = input.dtype
216
217
  cval = np.dtype(dtype).type(cval)
217
218
  zoom = fill_by_indices(np.ones(input.ndim, 'float64'), zoom, range(input.ndim))
218
- num_threads = normalize_num_threads(num_threads, backend)
219
+ num_threads = normalize_num_threads(num_threads, backend, warn_stacklevel=4)
219
220
 
220
221
  if backend.name == 'Scipy':
221
222
  return scipy_zoom(
@@ -227,7 +228,7 @@ def _zoom(
227
228
  or (
228
229
  dtype not in (np.float32, np.float64)
229
230
  if order == 1
230
- else dtype not in (np.float32, np.float64, np.int16, np.int32, np.int64)
231
+ else dtype not in (bool, np.float32, np.float64, np.int16, np.int32, np.int64)
231
232
  )
232
233
  or ndim > 4
233
234
  or output is not None
@@ -235,10 +236,9 @@ def _zoom(
235
236
  or grid_mode
236
237
  ):
237
238
  warn(
238
- 'Fast zoom is only supported for ndim<=4, dtype=fp32 or fp64 (and int16-32-64 if order == 0), output=None, '
239
- "order=0 or 1, mode='constant', grid_mode=False. Falling back to scipy's implementation.",
239
+ 'Fast zoom is only supported for ndim<=4, dtype=fp32 or fp64 (and bool-int16-32-64 if order == 0), '
240
+ "output=None, order=0 or 1, mode='constant', grid_mode=False. Falling back to scipy's implementation.",
240
241
  )
241
-
242
242
  return scipy_zoom(
243
243
  input, zoom, output=output, order=order, mode=mode, cval=cval, prefilter=prefilter, grid_mode=grid_mode
244
244
  )
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: imops
3
- Version: 0.8.1
3
+ Version: 0.8.3
4
4
  Summary: Efficient parallelizable algorithms for multidimensional arrays to speed up your data pipelines
5
5
  Home-page: https://github.com/neuro-ml/imops
6
- Download-URL: https://github.com/neuro-ml/imops/archive/v0.8.1.tar.gz
6
+ Download-URL: https://github.com/neuro-ml/imops/archive/v0.8.3.tar.gz
7
7
  Author: maxme1, vovaf709, talgat
8
8
  Author-email: maxme1 <maxs987@gmail.com>, vovaf709 <vovaf709@yandex.ru>, talgat <saparov2130@gmail.com>
9
9
  License: MIT License
@@ -44,12 +44,13 @@ Classifier: Programming Language :: Python :: 3.11
44
44
  Requires-Python: >=3.6
45
45
  Description-Content-Type: text/markdown
46
46
  License-File: LICENSE
47
- Requires-Dist: scipy (<2.0.0,>=1.0)
47
+ Requires-Dist: scipy <2.0.0,>=1.0
48
+ Requires-Dist: scikit-image
48
49
  Requires-Dist: connected-components-3d
49
50
  Requires-Dist: fastremap
50
51
  Requires-Dist: dataclasses ; python_version < "3.7"
51
- Requires-Dist: numpy (<2.0.0,>=1.7) ; python_version < "3.8"
52
- Requires-Dist: numpy (<2.0.0,>=1.22) ; python_version >= "3.8"
52
+ Requires-Dist: numpy <2.0.0,>=1.7 ; python_version < "3.8"
53
+ Requires-Dist: numpy <2.0.0,>=1.22 ; python_version >= "3.8"
53
54
  Provides-Extra: all
54
55
  Requires-Dist: numba ; extra == 'all'
55
56
  Provides-Extra: numba
@@ -62,7 +63,9 @@ Requires-Dist: numba ; extra == 'numba'
62
63
 
63
64
  # Imops
64
65
 
65
- Efficient parallelizable algorithms for multidimensional arrays to speed up your data pipelines. Docs are [here](https://neuro-ml.github.io/imops/).
66
+ Efficient parallelizable algorithms for multidimensional arrays to speed up your data pipelines.
67
+ - [Documentation](https://neuro-ml.github.io/imops/)
68
+ - [Benchmarks](https://neuro-ml.github.io/imops/benchmarks/)
66
69
 
67
70
  # Install
68
71
 
@@ -71,15 +74,33 @@ pip install imops # default install with Cython backend
71
74
  pip install imops[numba] # additionally install Numba backend
72
75
  ```
73
76
 
77
+ # How fast is it?
78
+
79
+ Time comparisons (ms) for Intel(R) Xeon(R) Silver 4114 CPU @ 2.20GHz using 8 threads. All inputs are C-contiguous NumPy arrays. For morphology functions `bool` dtype is used and `float64` for all others.
80
+ | function / backend | Scipy() | Cython(fast=False) | Cython(fast=True) | Numba() |
81
+ |:----------------------:|:-----------:|:----------------------:|:---------------------:|:-----------:|
82
+ | `zoom(..., order=0)` | 2072 | 1114 | **867** | 3590 |
83
+ | `zoom(..., order=1)` | 6527 | 596 | **575** | 3757 |
84
+ | `interp1d` | 780 | 149 | **146** | 420 |
85
+ | `radon` | 59711 | 5982 | **4837** | - |
86
+ | `inverse_radon` | 52928 | 8254 | **6535** | - |
87
+ | `binary_dilation` | 2207 | 310 | **298** | - |
88
+ | `binary_erosion` | 2296 | 326 | **304** | - |
89
+ | `binary_closing` | 4158 | 544 | **469** | - |
90
+ | `binary_opening` | 4410 | 567 | **522** | - |
91
+ | `center_of_mass` | 2237 | **64** | **64** | - |
92
+
93
+ We use [`airspeed velocity`](https://asv.readthedocs.io/en/stable/) to benchmark our code. For detailed results visit [benchmark page](https://neuro-ml.github.io/imops/benchmarks/).
94
+
74
95
  # Features
75
96
 
76
- ## Fast Radon transform
97
+ ### Fast Radon transform
77
98
 
78
99
  ```python
79
100
  from imops import radon, inverse_radon
80
101
  ```
81
102
 
82
- ## Fast linear/bilinear/trilinear zoom
103
+ ### Fast 0/1-order zoom
83
104
 
84
105
  ```python
85
106
  from imops import zoom, zoom_to_shape
@@ -90,20 +111,20 @@ y = zoom(x, 2, axis=[0, 1])
90
111
  # without the need to compute the scale factor
91
112
  z = zoom_to_shape(x, (4, 120, 67))
92
113
  ```
93
- Works faster only for `ndim<=3, dtype=float32 or float64, output=None, order=1, mode='constant', grid_mode=False`
94
- ## Fast 1d linear interpolation
114
+ Works faster only for `ndim<=4, dtype=float32 or float64 (and bool-int16-32-64 if order == 0), output=None, order=0 or 1, mode='constant', grid_mode=False`
115
+ ### Fast 1d linear interpolation
95
116
 
96
117
  ```python
97
118
  from imops import interp1d # same as `scipy.interpolate.interp1d`
98
119
  ```
99
- Works faster only for `ndim<=3, dtype=float32 or float64, order=1 or 'linear'`
100
- ## Fast binary morphology
120
+ Works faster only for `ndim<=3, dtype=float32 or float64, order=1`
121
+ ### Fast binary morphology
101
122
 
102
123
  ```python
103
124
  from imops import binary_dilation, binary_erosion, binary_opening, binary_closing
104
125
  ```
105
126
  These functions mimic `scikit-image` counterparts
106
- ## Padding
127
+ ### Padding
107
128
 
108
129
  ```python
109
130
  from imops import pad, pad_to_shape
@@ -116,7 +137,7 @@ y = pad(x, 10, axis=[0, 1])
116
137
  z = pad_to_shape(x, (4, 120, 67), ratio=0.25)
117
138
  ```
118
139
 
119
- ## Cropping
140
+ ### Cropping
120
141
 
121
142
  ```python
122
143
  from imops import crop_to_shape
@@ -128,7 +149,7 @@ from imops import crop_to_shape
128
149
  z = crop_to_shape(x, (4, 120, 67), ratio=0.25)
129
150
  ```
130
151
 
131
- ## Labeling
152
+ ### Labeling
132
153
 
133
154
  ```python
134
155
  from imops import label
@@ -138,7 +159,7 @@ labeled, num_components = label(x, background=1, return_num=True)
138
159
  ```
139
160
 
140
161
  # Backends
141
- For `zoom`, `zoom_to_shape`, `interp1d`, `radon`, `inverse_radon` you can specify which backend to use. Backend can be specified by a string or by an instance of `Backend` class. The latter allows you to customize some backend options:
162
+ For all heavy image routines except `label` you can specify which backend to use. Backend can be specified by a string or by an instance of `Backend` class. The latter allows you to customize some backend options:
142
163
  ```python
143
164
  from imops import Cython, Numba, Scipy, zoom
144
165
 
@@ -159,10 +180,9 @@ with imops_backend('Cython'): # sets Cython backend via context manager
159
180
  ```
160
181
  Note that for `Numba` backend setting `num_threads` argument has no effect for now and you should use `NUMBA_NUM_THREADS` environment variable.
161
182
  Available backends:
162
- | | Scipy | Cython | Numba |
163
- |-------------------|---------|---------|---------|
183
+ | function / backend | Scipy | Cython | Numba |
184
+ |:-------------------:|:---------:|:---------:|:---------:|
164
185
  | `zoom` | &check; | &check; | &check; |
165
- | `zoom_to_shape` | &check; | &check; | &check; |
166
186
  | `interp1d` | &check; | &check; | &check; |
167
187
  | `radon` | &cross; | &check; | &cross; |
168
188
  | `inverse_radon` | &cross; | &check; | &cross; |
@@ -170,6 +190,7 @@ Available backends:
170
190
  | `binary_erosion` | &check; | &check; | &cross; |
171
191
  | `binary_closing` | &check; | &check; | &cross; |
172
192
  | `binary_opening` | &check; | &check; | &cross; |
193
+ | `center_of_mass` | &check; | &check; | &cross; |
173
194
 
174
195
  # Acknowledgements
175
196
 
@@ -0,0 +1,60 @@
1
+ _build_utils.py,sha256=bxDoFEVfZgjl-yxMv5a-A7jncCD362m4RTpn5SyRgB4,3262
2
+ imops/__init__.py,sha256=QAqK6FnQnOjdDwSXzhnJNB2ur3cGUNbP3ZdLc_VoIEY,514
3
+ imops/__version__.py,sha256=lPOlZg8rjdgN8DyBl7I1rkzxiXOhafW_7RzlMGnvNo8,23
4
+ imops/_configs.py,sha256=6hBY2O4YSaQC_avvqI-dmhZkPMl4p39KQIPtqx5MAh0,734
5
+ imops/backend.py,sha256=8x6Zq9hetOt9_RDcytNNBJZBLNXgQd7ob2dh4WQuuqM,2598
6
+ imops/box.py,sha256=NbYsPKQ8fCGxSm5up0TyqERJ-5iWmnzHLo4Smv9eesk,1865
7
+ imops/crop.py,sha256=hCgwxDgNdIo9m0gleMB3oOUNA7tQurhYNhE5S39tMlE,4055
8
+ imops/interp1d.py,sha256=CSPJ77isqGOJTN-_C--iyz-3qJhpL4dE9i5VdJgSFDE,8400
9
+ imops/measure.py,sha256=YJ5hBDH6iW1hgqm6fi6FIURBKmeZjVfr7LSINOHgFrM,8657
10
+ imops/morphology.py,sha256=KG3RCCicsX7WHsBj4mH6iaJ0dy6tW9cGJJvD4fDisBQ,12723
11
+ imops/numeric.py,sha256=yiSjPTUD2w177LOBD_39_BHh9n8uKbSsHJDchNVsKRY,13650
12
+ imops/pad.py,sha256=OXy_r4X7hOPBU4NSH3B-8ZpxfcY1t6FFMgMSopULpv8,9314
13
+ imops/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
+ imops/radon.py,sha256=TWsgZvWRapBbU7MVr1fRdpVXCvi6-kt8fxroyQc44ek,9211
15
+ imops/testing.py,sha256=Qiy_Qn7bd7MIXoaZr4T_6r0jQWVRJFwR2z12c_Zwt30,1708
16
+ imops/utils.py,sha256=nfrMUU0OhPgK5UapD9GNC1StPxX3cKbob54kiuf4_qs,6890
17
+ imops/zoom.py,sha256=wl8wt7yoX5V4Mn7sMefV1Fy9KEetqMEdRHLdhT90o6o,9955
18
+ imops/src/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
+ imops/src/_backprojection.c,sha256=pq-WMMTwAzP0sRV-nlq_kw3u-1153p7XOHNcJCeE7Ak,1025929
20
+ imops/src/_backprojection.cp38-win_amd64.pyd,sha256=BBCtObthgwgS3pz1IFRpA85poqrAlExEKduoYoEbWkk,167424
21
+ imops/src/_backprojection.pyx,sha256=xngEJtJ6czjoBRBKL6tu5S7nt6ZgcsE82xDGdCIfagE,2724
22
+ imops/src/_fast_backprojection.c,sha256=7ZUD2XghoMmsWlmLq4jdInzY6KJB44sq1suf-HbX-cM,1036419
23
+ imops/src/_fast_backprojection.cp38-win_amd64.pyd,sha256=Lpp9szhOl47XcLGYMIHt5GAPhZI4BkWTzHJAhUENSDo,168448
24
+ imops/src/_fast_backprojection.pyx,sha256=xngEJtJ6czjoBRBKL6tu5S7nt6ZgcsE82xDGdCIfagE,2724
25
+ imops/src/_fast_measure.c,sha256=m0P3agPPDh8-CmPe15skOkAvK3c-jLLBC0mv7J4QpFE,1336697
26
+ imops/src/_fast_measure.cp38-win_amd64.pyd,sha256=rKLhKAIZ8cYw9KbNfN9aMfgZps8JpROyLdtNfJ15l9I,247808
27
+ imops/src/_fast_measure.pyx,sha256=JzZ26PptkVT08OemSFaJakc4jf7xYocPqV8jfrYi_wA,2737
28
+ imops/src/_fast_morphology.c,sha256=MhxKB1_SOQjVnbUrj9SEzP55bSo9LqLSsi3yk3AzaOI,971940
29
+ imops/src/_fast_morphology.cp38-win_amd64.pyd,sha256=40uz8eRvkV1hrgH_vSvWjizF2XZHnxHImtIAY4xGVTw,138752
30
+ imops/src/_fast_morphology.pyx,sha256=QwFrPQ6M-bJDVQNCCtKK7FR3KOr5cZSx_CBvxh9THXM,9538
31
+ imops/src/_fast_numeric.c,sha256=WaEYKryduT3Si92q1T--oOQLnofGIYdbsC5vL71OKm0,2107476
32
+ imops/src/_fast_numeric.cp38-win_amd64.pyd,sha256=1IGaTJSj5z_iuS4zH0fYWlpOKB0jC1rwsykBwKc2KxE,372224
33
+ imops/src/_fast_numeric.pyx,sha256=c8q3KlL8mDe0wsz72ooeqhffk1iqvA0Org7NWW5RbYo,8221
34
+ imops/src/_fast_radon.c,sha256=aeoMDfPqYG6xyeTLH-q7YPuiF7stGCj5v__gIRgmuZY,1190410
35
+ imops/src/_fast_radon.cp38-win_amd64.pyd,sha256=XrqXqMdPUpsq3cMKNBaRqqon2FobNlytALmEISdKsNs,218624
36
+ imops/src/_fast_radon.pyx,sha256=pu8EZplCjIDz9HqBcAit8nj2lDgXpmdhU61_4CfdGWI,2987
37
+ imops/src/_fast_zoom.c,sha256=2nb0GTWAHsrvUPdlf1CRhznPapPMsISPB3WJrLXgUOk,2145404
38
+ imops/src/_fast_zoom.cp38-win_amd64.pyd,sha256=AJx2tNryILkyAbmYqeTTumLv-ptfA-4Ct6MvAg54gfE,384000
39
+ imops/src/_fast_zoom.pyx,sha256=Dd5MDelALAh4-3QhnzfzKTB5Gmi2lVERrbyYj-q8kVQ,23091
40
+ imops/src/_measure.c,sha256=u3o9ozqfWnrn0PxRrY5l7LEvZEEzkfj4JMuTn0MKcSw,1324916
41
+ imops/src/_measure.cp38-win_amd64.pyd,sha256=7NE6k_uIkxrOG54-6s1pr0nJ14XchF67npcLOED8UPk,247296
42
+ imops/src/_measure.pyx,sha256=JzZ26PptkVT08OemSFaJakc4jf7xYocPqV8jfrYi_wA,2737
43
+ imops/src/_morphology.c,sha256=ntlYexi4kFK85mMvUkWSlKMf-Fwix05M18NvVEVyYAQ,960908
44
+ imops/src/_morphology.cp38-win_amd64.pyd,sha256=FrunwBtfVZOXFgwuTAbGDZN2h-xHWpSAuJA3E8VSp_g,138240
45
+ imops/src/_morphology.pyx,sha256=QwFrPQ6M-bJDVQNCCtKK7FR3KOr5cZSx_CBvxh9THXM,9538
46
+ imops/src/_numba_zoom.py,sha256=OmMj7mCFkV2P0FaWVXFuYpfzMBQ3Ks60YiHQURes5wQ,16857
47
+ imops/src/_numeric.c,sha256=pxoAtM5-ZGaBVyWd8HBARI7_LnX6_n7kNt6vS1p_JmI,2091727
48
+ imops/src/_numeric.cp38-win_amd64.pyd,sha256=LQSCiIQMRUUNxvfkAkK6Su5jHp5HHbx8r4X-JHnCyeo,371712
49
+ imops/src/_numeric.pyx,sha256=c8q3KlL8mDe0wsz72ooeqhffk1iqvA0Org7NWW5RbYo,8221
50
+ imops/src/_radon.c,sha256=TdmwLBra4NsH9qtX--0OC6XaTfzN8ApZxDovOC3J9kU,1178982
51
+ imops/src/_radon.cp38-win_amd64.pyd,sha256=M53brb_kxuy2FabVYGDpEYUTfFms9pbv49foklPCfHc,218112
52
+ imops/src/_radon.pyx,sha256=pu8EZplCjIDz9HqBcAit8nj2lDgXpmdhU61_4CfdGWI,2987
53
+ imops/src/_zoom.c,sha256=Yli60QHVVNFUJ2ycnbEW_Hbnz15-tRcG_J_xg_rCL4U,2126517
54
+ imops/src/_zoom.cp38-win_amd64.pyd,sha256=WTUdgTaqX60pZgX-b81SPNNHtcKmhx2uM4Yny7Dv_F8,383488
55
+ imops/src/_zoom.pyx,sha256=Dd5MDelALAh4-3QhnzfzKTB5Gmi2lVERrbyYj-q8kVQ,23091
56
+ imops-0.8.3.dist-info/LICENSE,sha256=x7oyYZPKDTt8KoTitcNJLBWhueke5YEOopdr0XjyvBc,1085
57
+ imops-0.8.3.dist-info/METADATA,sha256=tDl7xwD4lJ6Yx_X7wYRKFuv-_QmBlXMHivDQCOnT_K8,9048
58
+ imops-0.8.3.dist-info/WHEEL,sha256=KplWMgwSZbeAOumvxNxIrVbNPnn_LVzfBH7l38jDCVM,100
59
+ imops-0.8.3.dist-info/top_level.txt,sha256=jd2uO-zsYvKeqkZbjEjtkGqCca0IEXEiEuoyr3nsHB0,19
60
+ imops-0.8.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.40.0)
2
+ Generator: bdist_wheel (0.41.2)
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp38-cp38-win_amd64
5
5
 
@@ -0,0 +1,2 @@
1
+ _build_utils
2
+ imops
_pyproject_build.py DELETED
@@ -1,49 +0,0 @@
1
- import shutil
2
- from pathlib import Path
3
-
4
- from setuptools import Extension
5
- from setuptools.command.build_py import build_py
6
-
7
-
8
- class NumpyImport:
9
- def __repr__(self):
10
- import numpy as np
11
-
12
- return np.get_include()
13
-
14
- __fspath__ = __repr__
15
-
16
-
17
- class PyprojectBuild(build_py):
18
- def run(self):
19
- self.run_command('build_ext')
20
- return super().run()
21
-
22
- def initialize_options(self):
23
- super().initialize_options()
24
-
25
- name = 'imops'
26
- args = ['-fopenmp']
27
-
28
- if self.distribution.ext_modules is None:
29
- self.distribution.ext_modules = []
30
-
31
- # Cython extension and .pyx source file names must be the same to compile
32
- # https://stackoverflow.com/questions/8024805/cython-compiled-c-extension-importerror-dynamic-module-does-not-define-init-fu
33
- modules = ['backprojection', 'measure', 'morphology', 'numeric', 'radon', 'zoom']
34
- for module in modules:
35
- src_dir = Path(__file__).parent / name / 'src'
36
- shutil.copyfile(src_dir / f'_{module}.pyx', src_dir / f'_fast_{module}.pyx')
37
-
38
- for module in modules:
39
- for prefix, additional_args in zip(['', 'fast_'], [[], ['-ffast-math']]):
40
- self.distribution.ext_modules.append(
41
- Extension(
42
- f'{name}.src._{prefix}{module}',
43
- [f'{name}/src/_{prefix}{module}.pyx'],
44
- include_dirs=[NumpyImport()],
45
- extra_compile_args=args + additional_args,
46
- extra_link_args=args + additional_args,
47
- define_macros=[('NPY_NO_DEPRECATED_API', 'NPY_1_7_API_VERSION')],
48
- )
49
- )
imops/_numeric.py DELETED
@@ -1,124 +0,0 @@
1
- from warnings import warn
2
-
3
- import numpy as np
4
-
5
- from .backend import BackendLike, resolve_backend
6
- from .src._fast_numeric import (
7
- _parallel_pointwise_mul as cython_fast_parallel_pointwise_mul,
8
- _parallel_sum as cython_fast_parallel_sum,
9
- )
10
- from .src._numeric import _parallel_pointwise_mul as cython_parallel_pointwise_mul, _parallel_sum as cython_parallel_sum
11
- from .utils import normalize_num_threads
12
-
13
-
14
- def _sum(nums: np.ndarray, num_threads: int = -1, backend: BackendLike = None) -> float:
15
- """
16
- Parallel sum of flat numpy array
17
-
18
- Parameters
19
- ----------
20
- nums: np.ndarray
21
- 1-dimensional array
22
- num_threads: int
23
- the number of threads to use for computation. Default = the cpu count. If negative value passed
24
- cpu count + num_threads + 1 threads will be used
25
- backend: BackendLike
26
- which backend to use. `cython` and `scipy` (primarly for benchmarking) are available,
27
- `cython` is used by default
28
-
29
- Returns
30
- -------
31
- sum: float
32
-
33
- Examples
34
- --------
35
- >>> s = _sum(x, num_threads=1)
36
- >>> s = _sum(x, num_threads=8, backend=Cython(fast=True)) # ffast-math compiled version
37
- """
38
- ndim = nums.ndim
39
-
40
- if ndim != 1:
41
- raise ValueError(f'Input must be 1-dimensional instead of {ndim}-dimensional.')
42
-
43
- backend = resolve_backend(backend)
44
- if backend.name not in ('Cython', 'Scipy'):
45
- raise ValueError(f'Unsupported backend "{backend.name}"')
46
-
47
- num_threads = normalize_num_threads(num_threads, backend)
48
-
49
- if backend.name == 'Scipy':
50
- return nums.sum()
51
-
52
- if backend.name == 'Cython':
53
- src_parallel_sum = cython_fast_parallel_sum if backend.fast else cython_parallel_sum
54
-
55
- return src_parallel_sum(nums, num_threads)
56
-
57
-
58
- def _mul(nums1: np.ndarray, nums2: np.ndarray, num_threads: int = -1, backend: BackendLike = None) -> np.ndarray:
59
- """
60
- Parallel pointwise multiplication of 2 numpy arrays (aka x * y). Works faster only for ndim <= 3.
61
-
62
- Parameters
63
- ----------
64
- nums1: np.ndarray
65
- nums2: np.ndarray
66
- num_threads: int
67
- the number of threads to use for computation. Default = the cpu count. If negative value passed
68
- cpu count + num_threads + 1 threads will be used
69
- backend: BackendLike
70
- which backend to use. `cython` and `scipy` (primarly for benchmarking) are available,
71
- `cython` is used by default
72
-
73
- Returns
74
- -------
75
- multiplied: np.ndarray
76
- result of nums1 * nums2
77
-
78
- Examples
79
- --------
80
- >>> mul = _mul(nums1, nums2, num_threads=8)
81
- >>> mul = _mul(np.ones((2, 3)), np.ones((1, 3))) # broadcasting, mul.shape == (2, 3)
82
- >>> mul = _mul(nums1, nums2, backend=Cython(fast=True)) # ffast-math compiled version
83
- """
84
- if not nums1.size and not nums2.size:
85
- return np.array([], dtype=nums1.dtype)
86
- if bool(nums1.size) ^ bool(nums2.size):
87
- raise ValueError('One of the arrays is empty, hence pointwise multiplication cannot be performed.')
88
- if len(nums1.shape) != len(nums2.shape):
89
- raise ValueError('Both arrays must have the same number of dimensions for pointwise multiplication.')
90
- for dim1, dim2 in zip(nums1.shape, nums2.shape):
91
- if dim1 != dim2 and dim1 != 1 and dim2 != 1:
92
- raise ValueError(f'Arrays of shapes {nums1.shape} and {nums2.shape} are not broadcastable.')
93
-
94
- if nums1.ndim > 3:
95
- warn('Parallel pointwise multiplication is only supported for ndim<=3. Falling back to naive x * y.')
96
-
97
- return nums1 * nums2
98
-
99
- backend = resolve_backend(backend)
100
- if backend.name not in ('Cython', 'Scipy'):
101
- raise ValueError(f'Unsupported backend "{backend.name}"')
102
-
103
- num_threads = normalize_num_threads(num_threads, backend)
104
-
105
- if backend.name == 'Scipy':
106
- return nums1 * nums2
107
-
108
- if backend.name == 'Cython':
109
- src_parallel_pointwise_mul = (
110
- cython_fast_parallel_pointwise_mul if backend.fast else cython_parallel_pointwise_mul
111
- )
112
-
113
- n_dummy = 3 - nums1.ndim
114
-
115
- if n_dummy:
116
- nums1 = nums1[(None,) * n_dummy]
117
- nums2 = nums2[(None,) * n_dummy]
118
-
119
- out = src_parallel_pointwise_mul(nums1, nums2, np.maximum(nums1.shape, nums2.shape), num_threads)
120
-
121
- if n_dummy:
122
- out = out[(0,) * n_dummy]
123
-
124
- return out