hurray-python: Dtype, Device, and Tensor
This entry covers three foundational Python types:
hurray.Dtype— element type descriptor class +hurray.dtypesubmodulehurray.Device— device descriptor class +hurray.devicesubmodulehurray.Tensor— tensor constructor and core properties
Dtype system
Tier 1 vs Tier 2
The Hurray element type system is split into two tiers, matching the spec:
| Tier | Criterion | Python location |
|---|---|---|
| 1 | Array API-compatible | hurray.<name> and hurray.dtype.<name> |
| 2 | Extended / sub-byte | hurray.dtype.<name> only |
Tier 1 types (accessible at the top level):
| Name | Bit width | Kind |
|---|---|---|
bool | 1 | boolean |
int8, uint8 | 8 | integer |
int16, uint16 | 16 | integer |
int32, uint32 | 32 | integer |
int64, uint64 | 64 | integer |
float16, bfloat16 | 16 | float |
float32 | 32 | float |
float64 | 64 | float |
Tier 2 types (only on hurray.dtype.*):
| Name | Bit width | Kind |
|---|---|---|
int4, uint4 | 4 | integer |
int2, uint2 | 2 | integer |
float8_e4m3, float8_e5m2, float8_e8m0 | 8 | float |
float4_e2m1 | 4 | float |
float6_e2m3, float6_e3m2 | 6 | float |
float128 | 128 | float |
complex64, complex128 | 64 / 128 | complex |
Singleton identity
Tier 1 dtype constants are the same Python object on the top-level module
and on hurray.dtype:
import hurray
assert hurray.float32 is hurray.dtype.float32 # same object, not just ==
assert hurray.int8 is hurray.dtype.int8
This ensures that set membership and dict key lookups work correctly regardless of which path is used to import the constant.
Using Dtype as a dict key
Dtype is frozen (immutable) and implements __hash__ via the wire tag byte:
import hurray
lookup = {hurray.float32: "fp32 weights", hurray.dtype.int4: "quantized"}
assert lookup[hurray.float32] == "fp32 weights"
assert lookup[hurray.dtype.int4] == "quantized"
from_name round-trip
import hurray
d = hurray.Dtype.from_name("float32")
assert d == hurray.float32
assert d.name == "float32"
assert d.bit_width == 32
assert d.is_float
assert d.is_array_api
# Unknown name raises hurray.InvalidDescriptorError
try:
hurray.Dtype.from_name("not_a_type")
except hurray.InvalidDescriptorError as e:
print(f"rejected: {e}")
Submodule import
The hurray.dtype submodule is registered in sys.modules, so the following
import forms all work:
import hurray.dtype
from hurray.dtype import int4, float8_e4m3
Device system
A Device is a (kind, device_id, memory_class) triple. It is frozen and
hashable.
Well-known constants
hurray.device exposes a constant for each supported device kind, all at
device_id=0 and memory_class="standard":
import hurray
hurray.device.cpu # CPU host memory
hurray.device.cuda # CUDA device 0
hurray.device.rocm # ROCm device 0
hurray.device.metal # Metal (Apple Silicon)
hurray.device.vulkan
hurray.device.webgpu
hurray.device.hexagon
hurray.device.level_zero
hurray.device.opencl
Constructor
import hurray
# Default: device_id=0, memory_class="standard"
cpu = hurray.Device("cpu")
# Specific GPU
gpu1 = hurray.Device("cuda", 1)
# Unified memory (hardware-coherent CPU+GPU access)
gpu_um = hurray.Device("cuda", 0, "unified")
# Pinned host memory (CPU-accessible, device-mapped)
pinned = hurray.Device("cuda", 0, "host_pinned")
Equality and hashing
import hurray
assert hurray.Device("cpu") == hurray.device.cpu # same triple
assert hurray.Device("cuda", 0) != hurray.Device("cuda", 1) # different id
# Usable as dict key
device_names = {hurray.device.cpu: "host", hurray.device.cuda: "gpu0"}
assert device_names[hurray.Device("cpu")] == "host"
Submodule import
import hurray.device
from hurray.device import cpu, cuda
Constructing a Tensor
import struct
import hurray
# Pack six float32 values as raw bytes (little-endian)
buf = struct.pack("6f", 1.0, 2.0, 3.0, 4.0, 5.0, 6.0)
# Construct a 2×3 float32 tensor on the CPU
t = hurray.Tensor(buf, hurray.float32, [2, 3])
assert t.shape == (2, 3) # tuple[int | None, ...]
assert t.ndim == 2
assert t.size == 6 # total element count (None if any dim is dynamic)
assert t.dtype == hurray.float32
assert t.device == hurray.device.cpu
Explicit device
import hurray, struct
buf = struct.pack("4f", 1.0, 2.0, 3.0, 4.0)
t_gpu = hurray.Tensor(buf, hurray.float32, [4], hurray.Device("cuda", 0))
assert t_gpu.device.kind == "cuda"
Sub-byte types
Buffer sizes for sub-byte types are computed with ceiling division over the bit
width. For int4, two elements pack into one byte:
import hurray
buf = bytes([0xAB, 0xCD]) # 2 bytes = 4 nibbles = 4 int4 elements
t = hurray.Tensor(buf, hurray.dtype.int4, [4])
assert t.size == 4
assert t.dtype.is_sub_byte
Dynamic dimensions
If the tensor shape contains a DYNAMIC dimension (wire value u64::MAX), that
dimension maps to None in the Python shape tuple and size returns None:
# shape tuple with a dynamic dim: (1, None, 768)
# t.size == None
Running the examples
Build the wheel with maturin, then run:
cd hurray-python
maturin develop # build + install in-place (requires a venv)
python examples/dtype.py
python examples/device.py
python examples/tensor.py
All three examples print a confirmation line and exit with code 0 on success.
Spec references
docs/spec/element-types.md— Tier 1 / Tier 2 partition and type propertiesdocs/spec/buffer-protocol.md—DeviceTagandMemoryClasswire tablesdocs/spec/data-model.md—DYNAMICdimension sentinel (u64::MAX)docs/impl/python-bindings.md— Python binding implementation guide