arraybridge 0.3.7__py3-none-any.whl → 0.3.8__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.
arraybridge/__init__.py CHANGED
@@ -10,7 +10,7 @@ attribute access instead of at import time. Declaration-only consumers
10
10
  NumPy/numcodecs import cost.
11
11
  """
12
12
 
13
- __version__ = "0.3.7"
13
+ __version__ = "0.3.8"
14
14
 
15
15
  _LAZY_EXPORTS: dict[str, str] = {
16
16
  "MemoryType": ".types",
@@ -114,8 +114,50 @@ class ArrayOperations(ABC):
114
114
  def ones_like(reference: Any, shape: tuple[int, ...], dtype: Any, module: Any) -> Any:
115
115
  return module.ones(shape, dtype=dtype)
116
116
 
117
+ @classmethod
118
+ def normalize_planes(
119
+ cls,
120
+ data: Any,
121
+ dtype: Any,
122
+ scales: Sequence[float | None],
123
+ module: Any,
124
+ ) -> Any:
125
+ """Cast and scale each plane before assembling its owned output."""
126
+ return cls.stack(
127
+ tuple(
128
+ (
129
+ cls.cast(plane, dtype, module)
130
+ if scale is None
131
+ else cls.cast(plane, dtype, module) / float(scale)
132
+ )
133
+ for plane, scale in zip(data, scales, strict=True)
134
+ ),
135
+ module,
136
+ )
137
+
138
+
139
+ class MutableArrayOperations(ArrayOperations):
140
+ """Arrays whose allocated output supports native in-place arithmetic."""
141
+
142
+ @classmethod
143
+ def normalize_planes(
144
+ cls,
145
+ data: Any,
146
+ dtype: Any,
147
+ scales: Sequence[float | None],
148
+ module: Any,
149
+ ) -> Any:
150
+ # Integer division promotes the output dtype in the original recipe.
151
+ if not np.issubdtype(np.dtype(dtype), np.inexact) or len(data) == 0:
152
+ return super().normalize_planes(data, dtype, scales, module)
153
+ normalized = module.array(data, dtype=dtype, copy=True)
154
+ for index, scale in enumerate(scales):
155
+ if scale is not None:
156
+ normalized[index] /= float(scale)
157
+ return normalized
158
+
117
159
 
118
- class NumpyArrayOperations(ArrayOperations):
160
+ class NumpyArrayOperations(MutableArrayOperations):
119
161
  """Numpy native operation leaves."""
120
162
 
121
163
  @staticmethod
@@ -148,7 +190,7 @@ class NumpyArrayOperations(ArrayOperations):
148
190
  return scaled.astype(target_dtype)
149
191
 
150
192
 
151
- class CupyArrayOperations(ArrayOperations):
193
+ class CupyArrayOperations(MutableArrayOperations):
152
194
  """Cupy native operation leaves."""
153
195
 
154
196
  @staticmethod
arraybridge/types.py CHANGED
@@ -804,6 +804,20 @@ class MemoryType(_MemoryTypeFields, Enum):
804
804
  with self.device_scope(device_id, framework):
805
805
  return self._operations.stack(arrays, framework)
806
806
 
807
+ def normalize_planes(
808
+ self,
809
+ data: Any,
810
+ dtype: Any,
811
+ scales: Sequence[float | None],
812
+ module: Any | None = None,
813
+ ) -> Any:
814
+ """Normalize one owned plane stack through its native operation owner."""
815
+ if len(scales) != len(data):
816
+ raise ValueError("Normalization scales must match the leading plane axis.")
817
+ framework = module if module is not None else self.import_module()
818
+ with self._array_device_scope(data, framework):
819
+ return self._operations.normalize_planes(data, dtype, scales, framework)
820
+
807
821
  def scale_dtype(
808
822
  self,
809
823
  data: Any,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: arraybridge
3
- Version: 0.3.7
3
+ Version: 0.3.8
4
4
  Summary: Unified API for NumPy, CuPy, PyTorch, TensorFlow, JAX, and pyclesperanto with automatic memory type conversion
5
5
  Project-URL: Homepage, https://github.com/OpenHCSDev/arraybridge
6
6
  Project-URL: Documentation, https://arraybridge.readthedocs.io
@@ -1,6 +1,6 @@
1
- arraybridge/__init__.py,sha256=lmu9luoyMe9tpvuDlxSvwsYhRcFKkLKP7Smm93RndS8,3184
1
+ arraybridge/__init__.py,sha256=XXXniEG7FlzBMV3z_pHnIIHTeP4EdthtFIIRdcI9pbg,3184
2
2
  arraybridge/array_geometry.py,sha256=CopfGmFVKwV5l-lOTImhm1YVh18weUng0ReEF58qlPI,1689
3
- arraybridge/array_operations.py,sha256=3cT17uSpq9tQPj_HkxHfR8_q6C8tzygI2HiM0yuAaAk,16381
3
+ arraybridge/array_operations.py,sha256=AjeaOv9oTxfDscUCaiug8-P2_NL15FNd6YfHQgSgjTg,17739
4
4
  arraybridge/array_payload.py,sha256=6_jJwPRya0MHrUNSA9kXPlTISpLa0G74rqDValGXKx4,1079
5
5
  arraybridge/converters.py,sha256=q44E6Pg1rJz8yq6WQIPLOZPv1lqqcUcEG4Gh4D5M1_o,2649
6
6
  arraybridge/converters_registry.py,sha256=_hHtbd-3SMIKUw8fvNu3twPWJY7qHyNyQ_NhVp3eSHQ,5647
@@ -13,9 +13,9 @@ arraybridge/gpu_cleanup.py,sha256=ADI4wMLk9GIO9rJ6BJuNk3uZIyANoAqJ7VFTnLJzrbE,25
13
13
  arraybridge/oom_recovery.py,sha256=hGvOuJHVSopiIqblzoMFlqW8_oK6ZlAGF_l4pfEljeI,2403
14
14
  arraybridge/slice_processing.py,sha256=5R10OmHW8BSbJFwT1URd2Sz3P15o5EhaI2VnVUUIvkQ,4450
15
15
  arraybridge/stack_utils.py,sha256=FVikN0XG-Xryw-1p9MaSRUTZet7kLcy0gTEERSjc9r4,6915
16
- arraybridge/types.py,sha256=_RrqtA2q4ocy1huxLIDiDhoZySCQpNhorV5_7HY0S-Y,37287
16
+ arraybridge/types.py,sha256=im-DGznM7fZc4xqj6LMk71U9jcymLYriBSlYOm_zz-o,37879
17
17
  arraybridge/utils.py,sha256=RqThtYScPEOEQG491dA8b_VvUTjgcFhwLbh0erQu5Ns,4833
18
- arraybridge-0.3.7.dist-info/METADATA,sha256=Rpr8OMPyw7t9BXgM3EWf2jAm03vxUdVIPeGN3L29FmU,6124
19
- arraybridge-0.3.7.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
20
- arraybridge-0.3.7.dist-info/licenses/LICENSE,sha256=xagEoeTAj1WT64RmyR3E6HH-eTGdgXN6gqPMUUt7L_Y,1070
21
- arraybridge-0.3.7.dist-info/RECORD,,
18
+ arraybridge-0.3.8.dist-info/METADATA,sha256=yPiHOoC6ams7BN_7V1ds2uo8v7wEiN1DkADB5DJfXmk,6124
19
+ arraybridge-0.3.8.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
20
+ arraybridge-0.3.8.dist-info/licenses/LICENSE,sha256=xagEoeTAj1WT64RmyR3E6HH-eTGdgXN6gqPMUUt7L_Y,1070
21
+ arraybridge-0.3.8.dist-info/RECORD,,