XuPy
XuPy is a comprehensive Python package that provides GPU-accelerated masked arrays and NumPy-compatible functionality using CuPy. It automatically handles GPU/CPU fallback and offers an intuitive interface for scientific computing with masked data.
Features
- GPU Acceleration: Automatic GPU detection with CuPy fallback to NumPy
- Masked Arrays: GPU masked arrays with the full
numpy.maAPI (every name ofnumpy.ma.__all__for numeric and bool dtypes) andnumpy.masemantics - Statistical Functions: Comprehensive statistical operations (mean, std, var, min, max, etc.)
- Array Manipulation: Reshape, transpose, squeeze, expand_dims, and more
- Mathematical Functions: Trigonometric, exponential, logarithmic, and rounding functions
- Random Generation: Various random number generators (normal, uniform, etc.)
- Universal Functions: Support for applying any CuPy/NumPy ufunc with mask preservation
- Performance: Optimized for large-scale data processing on GPU
What's new in 2.0
- NumPy 2 namespace.
xpis a NumPy >= 2.0 namespace resolved per backend (CuPy on GPU, NumPy on CPU). Names removed in NumPy 2 raiseAttributeErrorwith a hint;xp.floatandxp.cfloatare gone (usexp.float64/xp.complex128). xupy.mabehaves likenumpy.maon NumPy and CuPy data: same masks, fill values, hard masks,numpy.madomain rules (results outside a function domain are masked; no other NaN/Inf auto-masking), return kinds (numpy scalars ormasked) and all the public functions, includingmedian,unique/set operations,cov,polyfit,clump_*,masked_where& co. Structured/record/object dtypes are not supported (NotImplementedError).- Device rule.
masked_array/MaskedArray/array/*_likemove host input (NumPy,numpy.ma, lists) to the active backend; CuPy data and existing XuPy masked arrays never move implicitly, and operations follow the device of their operands. - No host synchronisation in element-wise operations, ufuncs,
@, axis reductions,sort,clip,where,concatenate,average, ... (seetest/test_gpu_no_sync.py). Only scalar results,repr, boolean-mask assignment and data-dependent output sizes (unique,compressed,nonzero, ...) synchronise. MemoryContextfixes (MiB units, device restore, safe and fast cleanup) and a typed package (py.typed,xupy/__init__.pyi).
Installation
pip install xupy # CPU only (NumPy >= 2.0)
pip install "xupy[cuda12]" # with CuPy for CUDA 12.x
pip install "xupy[cuda13]" # with CuPy for CUDA 13.x
Pick the extra matching the "CUDA Version" reported by nvidia-smi.
Alternatively, install XuPy and then let the helper detect your CUDA version and install CuPy:
pip install xupy
python -m xupy.install_cupy # or: xupy-install-cupy
Options: --dry-run (show the command without running it), -y/--yes (do not ask for confirmation), --package PKG (install a specific CuPy package, e.g. cupy-cuda12x).
import xupy never prompts. If an NVIDIA GPU is present but CuPy is unusable, XuPy falls back to NumPy and emits a single warning; set XUPY_NO_GPU_WARNING=1 to silence it.
Quick Start
import xupy as xp
# Create arrays with automatic GPU detection
a = xp.random.normal(0, 1, (1000, 1000))
b = xp.random.normal(0, 1, (1000, 1000))
# Create masks
mask = xp.random.random((1000, 1000)) > 0.1
# Create masked arrays
am = xp.ma.masked_array(a, mask)
bm = xp.ma.masked_array(b, mask)
# Perform operations (masks are automatically handled)
result = am + bm
mean_val = am.mean()
std_val = am.std()
Backends and Devices
xp is a NumPy 2.x namespace backed by CuPy (GPU) when it is usable, NumPy (CPU) otherwise. The namespace is resolved at every access, so it always reflects the active backend.
import xupy as xp
xp.use_cpu() # global default: NumPy (thread-safe, idempotent)
xp.use_gpu() # global default: CuPy (RuntimeError if CuPy is unusable)
with xp.backend("cpu"): # scoped, thread- and asyncio-local ("cpu"/"numpy"/"gpu"/"cupy")
a = xp.zeros(3) # NumPy array; other threads are unaffected
xp.on_gpu # live: reflects the active backend
xp.mafollows the backend: XuPy's GPU masked arrays on GPU,numpy.maon CPU.xp.npandxp.npmaare alwaysnumpyandnumpy.ma.from xupy import on_gpu(andfrom xupy import *) is a snapshot taken at import time; usexp.on_gpufor the live value.use_cpu()/use_gpu()change the default for all threads. A switch from another thread while a computation is running can split it across backends; for concurrent code preferwith xp.backend(...), which only affects the current thread/task.xupy.mamasked arrays follow their data: creating one from host data (NumPy arrays,numpy.maarrays, lists) places it on the active backend (the GPU in GPU mode); an existing masked array never moves implicitly, and operations run on the device of their operands (a GPU masked array stays on the GPU even insidewith xp.backend("cpu")). Usea.to_device("cpu")/"gpu"to move one explicitly.- Because
xupy.mafollows the backend,import xupy.ma.core as mcyieldsnumpy.ma.coreon CPU; usefrom xupy.ma import coreorsys.modules["xupy.ma"]to always reach XuPy's module. - Names removed in NumPy 2 (
NaN,float_,in1d,trapz, ...) raiseAttributeErrorwith a hint on both backends, e.g.xupy has no attribute 'NaN': removed in NumPy 2.0, use 'nan'. - NumPy 2 names CuPy lacks are shimmed on GPU (
vecdot,unstack,sort(stable=, descending=),unique(sorted=),errstate,linalg.vector_norm, ...). Host-only names with no CuPy equivalent (emath,strings,char,rec, ...) raise anAttributeErrorthat points toxp.backend("cpu")/xp.asnumpy(). xp.on_device(i)is always a context manager. On GPU,iin0 .. n_gpus-1selects that CUDA device (also with a single GPU) and-1runs the block on the CPU; out-of-range values raiseValueError. On CPU it is a no-op for anyi.xp.set_device(i)sets the current CUDA device (setting the current one is a silent no-op, an invalid id raisesValueError); it is a no-op on CPU.- The GPU banner (on import) and switch messages (when
use_cpu()/use_gpu()actually change the backend) are printed to stdout and also emitted on thexupylogger at INFO level;xp.backend(...)scopes are silent.
Performance Benefits
XuPy automatically detects GPU availability and provides significant speedup for large arrays:
- Small arrays (< 1000 elements): CPU (NumPy) may be faster due to GPU overhead
- Medium arrays (1000-10000 elements): GPU provides 2-5x speedup
- Large arrays (> 10000 elements): GPU provides 5-20x speedup depending on operation complexity
Benchmarks
python benchmarks/bench_ma.py compares xupy.ma (GPU), raw CuPy and numpy.ma on a few array sizes (--sizes 500,2000,4000, --repeat N, --no-numpy); it is a standalone script and is not run in CI.
GPU Requirements
- A GPU supported by CuPy >= 14 (see the CuPy documentation)
- CuPy >= 14 (optional) installed, e.g.
pip install "xupy[cuda12]"orpip install "xupy[cuda13]" - Automatic fallback to NumPy if GPU is unavailable
Requirements
- Python >= 3.10
- NumPy >= 2.0
- CuPy >= 14 (optional, for GPU support)
API Compatibility
XuPy maintains high compatibility with NumPy's masked array interface while leveraging CuPy's optimized operations:
- All standard properties (
shape,dtype,size,ndim,T) - Comprehensive arithmetic operations with mask propagation
- Memory-optimized statistical methods (
mean,std,var,min,max) using CuPy's native operations - Array manipulation methods (
reshape,transpose,squeeze) - Universal function support through
apply_ufunc - Conversion to NumPy masked arrays via
asmarray() - GPU memory management through
MemoryContext
GPU Memory Management
XuPy includes an advanced MemoryContext class for efficient GPU memory management:
import xupy as xp
# Basic usage with automatic cleanup
with xp.MemoryContext() as ctx:
# GPU operations
data = xp.random.normal(0, 1, (10000, 10000))
result = data.mean()
# Memory automatically cleaned up on exit
# Advanced features
with xp.MemoryContext(memory_threshold=0.8, auto_cleanup=True) as ctx:
# Monitor memory usage
mem_info = ctx.get_memory_info()
# 'total', 'free' and 'used' are in MiB (1024**2 bytes)
print(f"GPU Memory: {mem_info['used']:.2f} MiB")
# Aggressive cleanup when needed
if ctx.check_memory_pressure():
ctx.aggressive_cleanup()
# Emergency cleanup for critical situations
ctx.emergency_cleanup()
MemoryContext Features
- Automatic Cleanup: Memory freed automatically when exiting context
- Memory Monitoring: Real-time tracking of GPU memory usage
- Pressure Detection: Automatic cleanup when memory usage is high
- Aggressive Cleanup: Force garbage collection and cache clearing
- Emergency Cleanup: Nuclear option for out-of-memory situations
- Safe Cleanup: Only garbage collection and memory-pool freeing; user objects are never modified
- Memory History: Keep history of memory usage over time
All memory figures are binary: MB / MiB = 10242 bytes and GB / GiB = 10243 bytes
(this also holds for xp.array_size(shape, dtype, out_unit='MB'), which accepts 'B', 'KB', 'MB', 'GB').
The previous device is always restored when the context exits.
Documentation
For detailed documentation, including comprehensive API reference and advanced usage examples, see docs/source/index.md.
License
See LICENSE.
Metadata
Release files for XuPy 2.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| xupy-2.0.0.tar.gz | 211.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| xupy-2.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 307.6 kB
Release files / xupy-2.0.0.tar.gz
| Download URL | xupy-2.0.0.tar.gz |
|---|---|
| Size | 211.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8d0dd62152cc37dd90385423df750fc1700dedb6225b873f35760e7a5e182b87
|
|
BLAKE2b-256 checksum How to use checksums |
0b979b1ed6e9e0c9fee048e1c09768f81d51c82c7d1ba9ee0e557e0778298226
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.15
|
Release files / xupy-2.0.0-py3-none-any.whl
| Download URL | xupy-2.0.0-py3-none-any.whl |
|---|---|
| Size | 96.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
16d735e0c58f3b2971a892ccf290c81b61534ed7104c70da9df6a298b1a2d5c6
|
|
BLAKE2b-256 checksum How to use checksums |
89421a020446b8d84eded58239978280077206397d07abb5011ab83012ad134a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.15
|