# Array Backends

SGN-TS abstracts array operations behind an `ArrayBackend` interface. The
default is `NumpyBackend`. When PyTorch is installed, `TorchBackend` enables
GPU-accelerated operations. Both backends expose the same set of common
operations (`zeros`, `ones`, `cat`, `pad`, `matmul`, etc.), so element code
works identically regardless of which backend is active.

## Using NumpyBackend

`NumpyBackend` is always available and is the default:

```python
from sgnts.base import NumpyBackend

backend = NumpyBackend

z = backend.zeros((2, 1024))
o = backend.ones((2, 1024))
r = backend.arange(1024)
```

## Using TorchBackend

Install PyTorch (`pip install sgn-ts[torch]`), then:

```{.python notest}
from sgnts.base import TorchBackend

backend = TorchBackend

z = backend.zeros((2, 1024))  # torch.Tensor
```

If PyTorch is not installed, importing `TorchBackend` still works but raises
an error when any operation is called.

## Setting the Backend in AdapterConfig

Elements that use `AdapterConfig` can specify which backend to use for
internal buffer operations:

```{.python notest}
from sgnts.base import AdapterConfig, TorchBackend

config = AdapterConfig(backend=TorchBackend)
```

## Converting Between Backends

Use the `Converter` transform to convert data between backends mid-pipeline:

```{.python notest}
from sgnts.transforms import Converter

# Convert from NumPy to PyTorch
conv = Converter(name="to_torch", backend=TorchBackend)
```

## Creating a Custom Backend

Subclass `ArrayBackend` and implement all required class methods:

```{.python notest}
from sgnts.base import ArrayBackend

class MyBackend(ArrayBackend):
    @staticmethod
    def zeros(shape):
        ...

    @staticmethod
    def ones(shape):
        ...

    # ... implement all required methods
```
