Metadata-Version: 2.4
Name: arraybridge
Version: 0.4.1
Summary: Unified API for NumPy, CuPy, PyTorch, TensorFlow, JAX, and pyclesperanto with automatic memory type conversion
Project-URL: Homepage, https://github.com/OpenHCSDev/arraybridge
Project-URL: Documentation, https://arraybridge.readthedocs.io
Project-URL: Repository, https://github.com/OpenHCSDev/arraybridge
Project-URL: Issues, https://github.com/OpenHCSDev/arraybridge/issues
Author-email: Tristan Simas <tristan.simas@mail.mcgill.ca>
License: MIT
License-File: LICENSE
Keywords: array,conversion,cupy,gpu,jax,numpy,pytorch,tensor,tensorflow
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Requires-Dist: metaclass-registry>=0.1.5
Requires-Dist: numpy>=1.20
Requires-Dist: python-introspect>=0.1.11
Provides-Extra: all
Requires-Dist: cupy>=10.0; extra == 'all'
Requires-Dist: jax>=0.3; extra == 'all'
Requires-Dist: jaxlib>=0.3; extra == 'all'
Requires-Dist: pyclesperanto>=0.10; extra == 'all'
Requires-Dist: tensorflow>=2.8; extra == 'all'
Requires-Dist: torch>=1.10; extra == 'all'
Provides-Extra: cupy
Requires-Dist: cupy>=10.0; extra == 'cupy'
Provides-Extra: dev
Requires-Dist: black>=23.0; extra == 'dev'
Requires-Dist: build>=1.0; extra == 'dev'
Requires-Dist: dill>=0.3.8; extra == 'dev'
Requires-Dist: mypy>=1.0; extra == 'dev'
Requires-Dist: packaging>=23.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Requires-Dist: twine>=5.0; extra == 'dev'
Provides-Extra: docs
Requires-Dist: sphinx-autodoc-typehints>=1.25; extra == 'docs'
Requires-Dist: sphinx-rtd-theme>=2.0; extra == 'docs'
Requires-Dist: sphinx>=7.0; extra == 'docs'
Provides-Extra: gpu
Requires-Dist: cucim-cu12<26.0.0,>=25.6.0; extra == 'gpu'
Requires-Dist: cupy-cuda12x<14.0.0,>=13.3.0; extra == 'gpu'
Requires-Dist: jax-cuda12-pjrt<0.6.0,>=0.5.3; extra == 'gpu'
Requires-Dist: jax-cuda12-plugin<0.6.0,>=0.5.3; extra == 'gpu'
Requires-Dist: jax<0.6.0,>=0.5.3; extra == 'gpu'
Requires-Dist: jaxlib<0.6.0,>=0.5.3; extra == 'gpu'
Requires-Dist: pyclesperanto>=0.17.1; extra == 'gpu'
Requires-Dist: tensorflow-probability[tf]<0.26.0,>=0.25.0; extra == 'gpu'
Requires-Dist: tensorflow<2.20.0,>=2.19.0; extra == 'gpu'
Requires-Dist: torch<2.8.0,>=2.6.0; extra == 'gpu'
Requires-Dist: torchvision<0.23.0,>=0.21.0; extra == 'gpu'
Provides-Extra: jax
Requires-Dist: jax>=0.3; extra == 'jax'
Requires-Dist: jaxlib>=0.3; extra == 'jax'
Provides-Extra: pyclesperanto
Requires-Dist: pyclesperanto>=0.10; extra == 'pyclesperanto'
Provides-Extra: tensorflow
Requires-Dist: tensorflow>=2.8; extra == 'tensorflow'
Provides-Extra: torch
Requires-Dist: torch>=1.10; extra == 'torch'
Description-Content-Type: text/markdown

# arraybridge

ArrayBridge provides explicit conversion and shared lifecycle utilities for
NumPy, CuPy, PyTorch, TensorFlow, JAX, and pyclesperanto arrays.

Core dependencies are NumPy and metaclass-registry. Other frameworks are
optional.

## Quick start

```python
import numpy as np

from arraybridge import convert_memory, detect_memory_type

value = np.arange(6).reshape(2, 3)
assert detect_memory_type(value) == "numpy"

copy = convert_memory(
    value,
    source_type="numpy",
    target_type="numpy",
    gpu_id=0,
)
```

`convert_memory` requires the declared source type, target type, and device id.
The source and target `MemoryType` declarations perform conversion directly.
The device id is required even for CPU conversions so call sites have one
stable signature. A GPU target must declare that identifier as available;
ArrayBridge does not silently place the value on the CPU.

## Declarative decorators

```python
from arraybridge import numpy

@numpy
def normalize(image):
    return image / max(float(image.max()), 1.0)
```

The framework decorators attach `input_memory_type`, `output_memory_type`, and
`execution_memory_type` metadata, provide dtype/slice runtime parameters, and
add framework-specific stream/OOM handling where supported. They do **not**
convert inputs or outputs between frameworks and do not accept a `gpu_id`
argument. A host runtime must call `convert_memory` at the boundary it plans and
scope execution using the execution declaration.

## Stack utilities

```python
import numpy as np

from arraybridge import stack_slices, unstack_slices

slices = [np.zeros((8, 8)), np.ones((8, 8))]
stack = stack_slices(slices, memory_type="numpy", gpu_id=0)
restored = unstack_slices(stack, memory_type="numpy", gpu_id=0)
```

`stack_slices` requires non-empty 2D inputs. `unstack_slices` requires a 3D
array. Both validate shape and use explicit target memory/device declarations.

## Installation

```bash
pip install arraybridge
pip install "arraybridge[torch]"
pip install "arraybridge[cupy]"
```

Documentation: <https://arraybridge.readthedocs.io>

### Native array geometry

`MemoryType.reshape(array, shape)` and `MemoryType.broadcast_to(array, shape)`
operate in the array's framework and device. `MemoryType.ones_like(reference,
shape=..., dtype=...)` allocates on the reference's device; omitting `shape`
retains its shape. Reshape and broadcast preserve views where the backend can
represent them. Broadcasting is not a promise of a writable, independent buffer.

These operations never silently project pixels to NumPy. Pyclesperanto cannot
provide native changed-shape reshape or broadcasting, so those requests raise
`NotImplementedError`. Its native ones allocation supports one to three
dimensions and its supported integer/float32 dtypes; boolean allocation is
explicitly unsupported. Existing conversion and disk boundaries remain separate.

### Writing an operation once for every framework

`ArrayOperations.for_memory(memory_type)` returns that framework's operations
leaf: one registered subclass per `MemoryType`, holding only the primitives its
library does differently (`max`, `min`, `mean`, `sum`, `astype`,
`prepend_axis`, `linspace`, `ones`, `assign`, `outer`, `floor`, `accepts`).
Code written against the leaf runs natively in each framework:

```python
from arraybridge import MemoryType
from arraybridge.array_operations import ArrayOperations


def max_projection(ops, stack):
    return ops.prepend_axis(ops.max(stack, 0))


ops = ArrayOperations.for_memory(MemoryType.TORCH)
```

`ops.module` is the framework, imported on first use. Each leaf keeps its
library's numeric rules: torch, JAX and TensorFlow take means in float32, and
pyclesperanto reduces only along the leading axis.
