arraybridge 0.3.7__tar.gz → 0.3.8__tar.gz

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.
Files changed (91) hide show
  1. {arraybridge-0.3.7 → arraybridge-0.3.8}/PKG-INFO +1 -1
  2. {arraybridge-0.3.7 → arraybridge-0.3.8}/src/arraybridge/__init__.py +1 -1
  3. {arraybridge-0.3.7 → arraybridge-0.3.8}/src/arraybridge/array_operations.py +44 -2
  4. {arraybridge-0.3.7 → arraybridge-0.3.8}/src/arraybridge/types.py +14 -0
  5. {arraybridge-0.3.7 → arraybridge-0.3.8}/tests/test_native_geometry.py +15 -0
  6. {arraybridge-0.3.7 → arraybridge-0.3.8}/.github/workflows/ci.yml +0 -0
  7. {arraybridge-0.3.7 → arraybridge-0.3.8}/.github/workflows/coverage-pages.yml +0 -0
  8. {arraybridge-0.3.7 → arraybridge-0.3.8}/.github/workflows/gpu-tests.yml +0 -0
  9. {arraybridge-0.3.7 → arraybridge-0.3.8}/.github/workflows/publish.yml +0 -0
  10. {arraybridge-0.3.7 → arraybridge-0.3.8}/.gitignore +0 -0
  11. {arraybridge-0.3.7 → arraybridge-0.3.8}/.readthedocs.yml +0 -0
  12. {arraybridge-0.3.7 → arraybridge-0.3.8}/ADDING_NEW_FRAMEWORKS.md +0 -0
  13. {arraybridge-0.3.7 → arraybridge-0.3.8}/CONTRIBUTING.md +0 -0
  14. {arraybridge-0.3.7 → arraybridge-0.3.8}/LICENSE +0 -0
  15. {arraybridge-0.3.7 → arraybridge-0.3.8}/README.md +0 -0
  16. {arraybridge-0.3.7 → arraybridge-0.3.8}/TESTING.md +0 -0
  17. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/Makefile +0 -0
  18. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/archive/CI_ARTIFACT_UPDATE.md +0 -0
  19. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/archive/CI_CUPY_FIX.md +0 -0
  20. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/archive/CI_IMPROVEMENTS.md +0 -0
  21. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/archive/CONFLICT_VISUALIZATION.md +0 -0
  22. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/archive/COVERAGE_AUDIT_PLAN.md +0 -0
  23. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/archive/DEPLOYMENT_SUMMARY.md +0 -0
  24. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/archive/GPU_TESTING_SETUP.md +0 -0
  25. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/archive/MERGE_CONFLICT_RESOLUTION.md +0 -0
  26. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/archive/MIGRATION_SUMMARY.md +0 -0
  27. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/archive/QUICK_FIX_GUIDE.txt +0 -0
  28. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/archive/README.md +0 -0
  29. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/archive/RESOLVED_FILES.md +0 -0
  30. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/ci-cd.md +0 -0
  31. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/source/.gitignore +0 -0
  32. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/source/Makefile +0 -0
  33. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/source/README.md +0 -0
  34. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/source/advanced_topics.rst +0 -0
  35. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/source/api_reference.rst +0 -0
  36. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/source/ci-cd.rst +0 -0
  37. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/source/conf.py +0 -0
  38. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/source/contributing.rst +0 -0
  39. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/source/converters.rst +0 -0
  40. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/source/decorators.rst +0 -0
  41. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/source/examples/basic_conversion.rst +0 -0
  42. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/source/examples/decorators.rst +0 -0
  43. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/source/examples/index.rst +0 -0
  44. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/source/examples/multi_framework.rst +0 -0
  45. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/source/gpu_features.rst +0 -0
  46. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/source/index.rst +0 -0
  47. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/source/installation.rst +0 -0
  48. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/source/quickstart.rst +0 -0
  49. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/source/release_035_validation.rst +0 -0
  50. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/source/release_036_validation.rst +0 -0
  51. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/source/stack_utils.rst +0 -0
  52. {arraybridge-0.3.7 → arraybridge-0.3.8}/docs/source/user_guide.rst +0 -0
  53. {arraybridge-0.3.7 → arraybridge-0.3.8}/paper.bib +0 -0
  54. {arraybridge-0.3.7 → arraybridge-0.3.8}/paper.md +0 -0
  55. {arraybridge-0.3.7 → arraybridge-0.3.8}/pyproject.toml +0 -0
  56. {arraybridge-0.3.7 → arraybridge-0.3.8}/scripts/release.py +0 -0
  57. {arraybridge-0.3.7 → arraybridge-0.3.8}/scripts/update_version.py +0 -0
  58. {arraybridge-0.3.7 → arraybridge-0.3.8}/scripts/verify_release_ready.py +0 -0
  59. {arraybridge-0.3.7 → arraybridge-0.3.8}/src/arraybridge/array_geometry.py +0 -0
  60. {arraybridge-0.3.7 → arraybridge-0.3.8}/src/arraybridge/array_payload.py +0 -0
  61. {arraybridge-0.3.7 → arraybridge-0.3.8}/src/arraybridge/converters.py +0 -0
  62. {arraybridge-0.3.7 → arraybridge-0.3.8}/src/arraybridge/converters_registry.py +0 -0
  63. {arraybridge-0.3.7 → arraybridge-0.3.8}/src/arraybridge/decorators.py +0 -0
  64. {arraybridge-0.3.7 → arraybridge-0.3.8}/src/arraybridge/dtype_scaling.py +0 -0
  65. {arraybridge-0.3.7 → arraybridge-0.3.8}/src/arraybridge/exceptions.py +0 -0
  66. {arraybridge-0.3.7 → arraybridge-0.3.8}/src/arraybridge/framework_config.py +0 -0
  67. {arraybridge-0.3.7 → arraybridge-0.3.8}/src/arraybridge/framework_ops.py +0 -0
  68. {arraybridge-0.3.7 → arraybridge-0.3.8}/src/arraybridge/gpu_cleanup.py +0 -0
  69. {arraybridge-0.3.7 → arraybridge-0.3.8}/src/arraybridge/oom_recovery.py +0 -0
  70. {arraybridge-0.3.7 → arraybridge-0.3.8}/src/arraybridge/slice_processing.py +0 -0
  71. {arraybridge-0.3.7 → arraybridge-0.3.8}/src/arraybridge/stack_utils.py +0 -0
  72. {arraybridge-0.3.7 → arraybridge-0.3.8}/src/arraybridge/utils.py +0 -0
  73. {arraybridge-0.3.7 → arraybridge-0.3.8}/tests/__init__.py +0 -0
  74. {arraybridge-0.3.7 → arraybridge-0.3.8}/tests/conftest.py +0 -0
  75. {arraybridge-0.3.7 → arraybridge-0.3.8}/tests/test_array_geometry.py +0 -0
  76. {arraybridge-0.3.7 → arraybridge-0.3.8}/tests/test_callable_dtype_default.py +0 -0
  77. {arraybridge-0.3.7 → arraybridge-0.3.8}/tests/test_converters.py +0 -0
  78. {arraybridge-0.3.7 → arraybridge-0.3.8}/tests/test_converters_registry.py +0 -0
  79. {arraybridge-0.3.7 → arraybridge-0.3.8}/tests/test_decorators.py +0 -0
  80. {arraybridge-0.3.7 → arraybridge-0.3.8}/tests/test_dtype_scaling.py +0 -0
  81. {arraybridge-0.3.7 → arraybridge-0.3.8}/tests/test_durable_decorator_context.py +0 -0
  82. {arraybridge-0.3.7 → arraybridge-0.3.8}/tests/test_exceptions.py +0 -0
  83. {arraybridge-0.3.7 → arraybridge-0.3.8}/tests/test_framework_config.py +0 -0
  84. {arraybridge-0.3.7 → arraybridge-0.3.8}/tests/test_gpu_cleanup.py +0 -0
  85. {arraybridge-0.3.7 → arraybridge-0.3.8}/tests/test_integration.py +0 -0
  86. {arraybridge-0.3.7 → arraybridge-0.3.8}/tests/test_oom_recovery.py +0 -0
  87. {arraybridge-0.3.7 → arraybridge-0.3.8}/tests/test_registry_integration.py +0 -0
  88. {arraybridge-0.3.7 → arraybridge-0.3.8}/tests/test_slice_processing.py +0 -0
  89. {arraybridge-0.3.7 → arraybridge-0.3.8}/tests/test_stack_utils.py +0 -0
  90. {arraybridge-0.3.7 → arraybridge-0.3.8}/tests/test_types.py +0 -0
  91. {arraybridge-0.3.7 → arraybridge-0.3.8}/tests/test_utils.py +0 -0
@@ -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
@@ -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
@@ -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,
@@ -63,3 +63,18 @@ def test_pycles_geometry_rejects_host_fallback():
63
63
  PYCLESPERANTO_OPERATIONS.broadcast_to(source, (4, 2, 3), None)
64
64
  with pytest.raises(NotImplementedError, match="dtype"):
65
65
  PYCLESPERANTO_OPERATIONS.ones_like(source, (2, 3), bool, None)
66
+
67
+
68
+ @pytest.mark.parametrize("dtype", (np.float32, np.complex64, np.int32))
69
+ def test_normalize_planes_preserves_source_and_division_dtype(dtype):
70
+ source = np.arange(24, dtype=dtype).reshape(2, 3, 4)[:, :, ::-1]
71
+ original = source.copy()
72
+ expected = np.stack((source[0] / 3.0, source[1]))
73
+ actual = MemoryType.NUMPY.normalize_planes(source, dtype, (3.0, None))
74
+ np.testing.assert_array_equal(actual, expected)
75
+ np.testing.assert_array_equal(source, original)
76
+ assert actual.dtype == expected.dtype
77
+ assert not np.shares_memory(actual, source)
78
+ for scales in ((3.0,), (3.0, None, 2.0)):
79
+ with pytest.raises(ValueError, match="leading plane axis"):
80
+ MemoryType.NUMPY.normalize_planes(source, dtype, scales)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes