backends¶
Backend abstraction for CPU/GPU operations.
Supports NumPy (CPU-only) and PyTorch (CPU/CUDA/MPS) backends for linear algebra operations. Enables transparent acceleration while maintaining NumPy-first development.
Attributes:
| Name | Type | Description |
|---|---|---|
BATCH_WORKING_SET_CEILING_GB |
Classes:
| Name | Description |
|---|---|
Backend | Backend abstraction for numerical operations. |
Methods:
| Name | Description |
|---|---|
assert_array_almost_equal | Test array equality with automatic precision adjustment for MPS backend. |
auto_batch_size | Split n_items into batches that fit a memory budget. |
auto_n_jobs_for_arrays | Memory-aware joblib worker count for a per-item map over arrays. |
auto_select_backend | Automatically select backend based on problem size. |
check_gpu_available | Check if GPU acceleration is available. |
compute_oom_safe | Run fn(*arrays) with reactive out-of-memory recovery. |
device_memory_budget | Usable memory budget in GB for a backend’s device. |
empty_device_cache | Release cached device memory. No-op without torch or a GPU. |
gb_to_bytes | Convert a GB budget to bytes — the package’s one GB↔bytes conversion. |
is_oom_error | True if exc is a device out-of-memory error (CUDA or MPS). |
resolve_backend | Coerce a backend specifier into a Backend instance. |
Classes¶
Backend¶
Backend(backend: str = 'numpy')Backend abstraction for numerical operations.
Provides a unified interface for NumPy and PyTorch operations, enabling transparent GPU acceleration when available.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
backend | str | Backend type: ‘numpy’, ‘torch’, or ‘auto’ - ‘numpy’: CPU-only using NumPy - ‘torch’: PyTorch with automatic device detection (cuda/mps/cpu) - ‘auto’: Automatically select best available backend | ‘numpy’ |
Attributes:
| Name | Type | Description |
|---|---|---|
name | str | Backend identifier (e.g., ‘numpy’, ‘torch-cuda’, ‘torch-mps’) |
device | str | Device type (‘cpu’, ‘cuda’, or ‘mps’) |
xp | module | Array library module (numpy or torch) |
Methods:
| Name | Description |
|---|---|
asarray | Convert input to a backend array. |
asarray_like | Convert x to an array matching ref’s dtype (and device for torch). |
check_arrays | Coerce all inputs to the same dtype (and device) as the first. |
concatenate | Concatenate arrays along an axis. |
copy | Return an independent copy of the array. |
dtype_to_str | Normalize a dtype (numpy, torch, or string) to its string name. |
expand_dims | Insert a new axis. |
flatnonzero | Return indices of non-zero elements in the flattened array. |
full | Create array filled with fill_value. |
full_like | Create array filled with fill_value, optionally with a different shape. |
matmul | Matrix multiplication. |
ones_like | Create ones array, optionally with a different shape. |
sort | Sort along an axis, returning values only. |
svd | Compute Singular Value Decomposition. |
to_cpu | Transfer array to CPU. No-op for numpy. |
to_device | Transfer array to backend device. |
to_gpu | Transfer array to GPU. No-op for numpy. |
to_numpy | Convert array back to NumPy. |
zeros_like | Create zeros array, optionally with a different shape. |
Methods¶
asarray¶
asarray(x, dtype = None, device = None)Convert input to a backend array.
Handles numpy arrays, lists, and torch tensors. Places result on the backend’s device (or an explicit device).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x | Input data (array-like, tensor, list). | required | |
dtype | Desired dtype as string, numpy, or torch dtype. If None, inferred from input. | None | |
device | Target device string (e.g. “cpu”, “cuda”). Ignored for numpy backend. If None, uses the backend’s default device. | None |
Returns:
| Type | Description |
|---|---|
| Backend array (numpy ndarray or torch Tensor). |
asarray_like¶
asarray_like(x, ref)Convert x to an array matching ref’s dtype (and device for torch).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x | Input data. | required | |
ref | Reference array whose dtype/device to match. | required |
Returns:
| Type | Description |
|---|---|
| Backend array with same dtype/device as ref. |
check_arrays¶
check_arrays(*inputs)Coerce all inputs to the same dtype (and device) as the first.
None values are passed through. Lists of arrays are converted element-wise.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*inputs | Arrays, lists of arrays, or None. | () |
Returns:
| Name | Type | Description |
|---|---|---|
list | Converted arrays in the same order as inputs. |
concatenate¶
concatenate(arrays, axis = 0)Concatenate arrays along an axis.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
arrays | Sequence of arrays. | required | |
axis | Axis to concatenate along (default 0). | 0 |
copy¶
copy(array)Return an independent copy of the array.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
array | Input array. | required |
dtype_to_str¶
dtype_to_str(dtype)Normalize a dtype (numpy, torch, or string) to its string name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dtype | Data type to convert (str, numpy dtype, torch dtype, or None). | required |
Returns:
| Type | Description |
|---|---|
| str or None: e.g. “float32”, “float64”, or None if input was None. |
expand_dims¶
expand_dims(array, axis)Insert a new axis.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
array | Input array. | required | |
axis | Position of the new axis. | required |
flatnonzero¶
flatnonzero(array)Return indices of non-zero elements in the flattened array.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
array | Input array. | required |
full¶
full(shape, fill_value, dtype = None)Create array filled with fill_value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
shape | Output shape (int or tuple). | required | |
fill_value | Scalar fill value. | required | |
dtype | Output dtype. If None, inferred by the backend. | None |
full_like¶
full_like(array, fill_value, shape = None, dtype = None, device = None)Create array filled with fill_value, optionally with a different shape.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
array | Reference array for dtype inference. | required | |
fill_value | Scalar fill value. | required | |
shape | Output shape. If None, uses array.shape. | None | |
dtype | Output dtype. If None, uses array.dtype. | None | |
device | Target device (torch only). If None, uses array’s device. | None |
matmul¶
matmul(A, B)Matrix multiplication.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
A | array | First matrix | required |
B | array | Second matrix | required |
Returns:
| Name | Type | Description |
|---|---|---|
array | Result of A @ B |
ones_like¶
ones_like(array, shape = None, dtype = None, device = None)Create ones array, optionally with a different shape.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
array | Reference array for dtype inference. | required | |
shape | Output shape. If None, uses array.shape. | None | |
dtype | Output dtype. If None, uses array.dtype. | None | |
device | Target device (torch only). If None, uses array’s device. | None |
sort¶
sort(array, axis = -1)Sort along an axis, returning values only.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
array | Input array. | required | |
axis | Axis to sort along (default -1). | -1 |
svd¶
svd(X, full_matrices = False)Compute Singular Value Decomposition.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X | array | Input matrix (n_samples, n_features) | required |
full_matrices | bool, default=False | If False, returns reduced SVD | False |
Returns:
| Name | Type | Description |
|---|---|---|
tuple | (U, s, Vt) where: - U (array): Left singular vectors - s (array): Singular values - Vt (array): Right singular vectors (transposed) |
to_cpu¶
to_cpu(array)Transfer array to CPU. No-op for numpy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
array | Input array or tensor. | required |
Returns:
| Type | Description |
|---|---|
| Array on CPU. |
to_device¶
to_device(arr: np.ndarray)Transfer array to backend device.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
arr | ndarray | Input numpy array | required |
Returns:
| Name | Type | Description |
|---|---|---|
array | Array on device (numpy array or torch tensor) |
to_gpu¶
to_gpu(array, device = None)Transfer array to GPU. No-op for numpy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
array | Input array or tensor. | required | |
device | Target device (defaults to backend’s device). | None |
Returns:
| Type | Description |
|---|---|
| Array on GPU device. |
to_numpy¶
to_numpy(arr)Convert array back to NumPy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
arr | ndarray or Tensor | Array to convert | required |
Returns:
| Type | Description |
|---|---|
| np.ndarray: NumPy array |
zeros_like¶
zeros_like(array, shape = None, dtype = None, device = None)Create zeros array, optionally with a different shape.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
array | Reference array for dtype inference. | required | |
shape | Output shape. If None, uses array.shape. | None | |
dtype | Output dtype. If None, uses array.dtype. | None | |
device | Target device (torch only). If None, uses array’s device. | None |
Methods¶
assert_array_almost_equal¶
assert_array_almost_equal(x, y, decimal = 6, err_msg = '', verbose = True, backend = None)Test array equality with automatic precision adjustment for MPS backend.
This utility automatically reduces precision expectations for torch-mps backend due to float32 precision limitations, preventing test failures while maintaining realistic precision checks for other backends.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x | First array to compare | required | |
y | Second array to compare | required | |
decimal | Desired decimal precision (default: 6) | 6 | |
err_msg | Error message prefix | ‘’ | |
verbose | Whether to print detailed error messages | True | |
backend | Backend instance (optional). If None, attempts to detect from x/y. | None |
Returns:
| Type | Description |
|---|---|
| None (raises AssertionError if arrays don’t match) |
auto_batch_size¶
auto_batch_size(n_items: int, bytes_per_item: float, *, budget_gb: float, overhead: float = 1.0, min_batch: int = 1) -> tuple[int, int]Split n_items into batches that fit a memory budget.
The one batch calculator for the package. Callers supply only the
per-item working-set estimate (bytes_per_item) and an algorithm’s
allocation overhead factor; the clamp/ceil policy lives here.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_items | int | Total number of items (permutations, targets, ...). | required |
bytes_per_item | float | Dominant working-set size of one item in bytes. | required |
budget_gb | float | Memory budget from device_memory_budget. | required |
overhead | float | Multiplier for intermediate allocations (e.g. 3.0 when the computation holds ~3x the input working set). | 1.0 |
min_batch | int | Smallest batch worth dispatching (amortizes launch and transfer overhead). Never exceeds n_items. | 1 |
Returns:
| Type | Description |
|---|---|
int | tuple[int, int]: (batch_size, n_batches) with |
int | batch_size * n_batches >= n_items. |
auto_n_jobs_for_arrays¶
auto_n_jobs_for_arrays(arrays, *, max_memory_gb: float | None = None, min_jobs: int = 1) -> intMemory-aware joblib worker count for a per-item map over arrays.
Sizes workers by the largest item (each worker pickles its item), using
the same measured budget as the device batching layer. None entries are
ignored; an empty list returns min_jobs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
arrays | Iterable of numpy arrays (None entries allowed). | required | |
max_memory_gb | float | None | Explicit memory budget in GB. None (default) measures available system RAM with headroom via device_memory_budget. | None |
min_jobs | int | Minimum number of workers (default: 1). | 1 |
Returns:
| Name | Type | Description |
|---|---|---|
int | int | Worker count for joblib.Parallel(n_jobs=...). |
auto_select_backend¶
auto_select_backend(n_samples: int, n_features: int, cv: int = 1) -> BackendAutomatically select backend based on problem size.
Uses heuristics to decide between NumPy (CPU) and PyTorch (GPU) based on the computational workload. Small problems use NumPy to avoid GPU transfer overhead. Large problems prefer GPU when available.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_samples | int | Number of samples in dataset | required |
n_features | int | Number of features in dataset | required |
cv | int, default=1 | Number of cross-validation folds (multiplies effective size) | 1 |
Returns:
| Name | Type | Description |
|---|---|---|
Backend | Backend | Selected backend instance |
Notes
Selection criteria:
Small problems (< 10M elements): Use NumPy
Large problems (> 30M elements): Use GPU if available
Cross-validation: Prefer GPU even for medium problems
check_gpu_available¶
check_gpu_available() -> tuple[bool, dict[str, Any]]Check if GPU acceleration is available.
Returns:
| Name | Type | Description |
|---|---|---|
tuple | tuple [ bool , dict [ str , Any ]] | (available, info) where: - available (bool): True if GPU (CUDA or MPS) is available - info (dict): Dictionary with keys: - ‘backend’: ‘torch’ or ‘numpy’ - ‘device’: ‘cpu’, ‘cuda’, or ‘mps’ - ‘device_name’: Human-readable device name |
compute_oom_safe¶
compute_oom_safe(fn, *arrays, min_chunk: int = 1)Run fn(*arrays) with reactive out-of-memory recovery.
All arrays must share their axis-0 length, and fn must map them to
a numpy array whose axis 0 corresponds row-for-row to its inputs. On a
device OOM the cache is emptied, the arrays are split in half along
axis 0, and the halves are retried recursively; partial results are
concatenated along axis 0.
Because splitting reuses the already generated inputs rather than
re-drawing them, recovery never changes which permutations a seeded
result is computed from — RNG-consuming input generation stays outside
this function. For a row-independent fn the recovered output matches
the unsplit computation to within floating-point reduction order
(backends may block reductions differently per batch shape; observed
differences are ~1 float32 ulp).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fn | Callable mapping the arrays to a numpy result (axis-0 aligned). | required | |
*arrays | Input arrays sharing axis-0 length. | () | |
min_chunk | int | Chunk size below which an OOM is considered fatal. | 1 |
Returns:
| Type | Description |
|---|---|
np.ndarray: fn’s result, possibly assembled from retried chunks. |
device_memory_budget¶
device_memory_budget(backend: Backend | None = None, max_gpu_memory_gb: float | None = None, *, cap_for_batching: bool = False) -> floatUsable memory budget in GB for a backend’s device.
An explicit max_gpu_memory_gb always wins, uncapped. Otherwise the
budget is measured at call time: free CUDA memory (with headroom) on
CUDA devices; available system RAM (with headroom) for CPU and MPS,
which share unified/system memory. When nothing can be measured the
conservative 4 GB fallback applies.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
backend | Backend | None | Resolved Backend whose device the work runs on. None is treated as CPU. | None |
max_gpu_memory_gb | float | None | Explicit budget override in GB. Must be positive. | None |
cap_for_batching | bool | Pass True when the budget sizes batches — a measured budget is then capped at BATCH_WORKING_SET_CEILING_GB, because working sets beyond the saturation ceiling add allocation cost without throughput gain and starve unified-memory hosts. Never applied to an explicit max_gpu_memory_gb; capacity queries (the default) stay uncapped. | False |
Returns:
| Name | Type | Description |
|---|---|---|
float | float | Budget in GB. |
empty_device_cache¶
empty_device_cache() -> NoneRelease cached device memory. No-op without torch or a GPU.
gb_to_bytes¶
gb_to_bytes(gb: float) -> intConvert a GB budget to bytes — the package’s one GB↔bytes conversion.
is_oom_error¶
is_oom_error(exc: BaseException) -> boolTrue if exc is a device out-of-memory error (CUDA or MPS).
resolve_backend¶
resolve_backend(parallel)Coerce a backend specifier into a Backend instance.
Accepts the values callers typically thread through the algorithms
package (None/"cpu" → numpy, "gpu"/"torch" → torch,
"numpy"/"auto" → their direct Backend constructors).
Existing Backend instances are returned unchanged — this is
the main reason to prefer resolve_backend over constructing a new
Backend(...) at each call site: it avoids repeated device
detection/torch imports when a backend has already been chosen upstream.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
parallel | Backend specifier. One of: - None or "cpu": numpy backend. - "numpy", "torch", "auto": forwarded to Backend(...). - "gpu": alias for "torch" (auto-detects cuda/mps/cpu). - An existing Backend instance (returned as-is). | required |
Returns:
| Name | Type | Description |
|---|---|---|
Backend | Resolved backend instance. |