Python API

silt has two primary types: shape and tensor. Shape can have between 1 and 4 dimensions, while the tensor type supports multiple strict data-types and can live on the CPU or the GPU:

s = silt.shape(512, 512)                    # 2D Tensor Shape
t = silt.tensor(silt.float32, s, silt.gpu)  # Strict-Typed GPU Tensor
silt.set_(t, 0.0)                           # Set Data to Zeros (In-Place)

silt converts data to and from pytorch and numpy, and provides a simple device upload / download interface. Note that these conversions currently copy the data:

t_numpy = silt.tensor.from_numpy(np.full((512, 512), 0.0, dtype=np.float32))                          # CPU Tensor
t_torch = silt.tensor.from_torch(torch.full((512, 512), 0.0, dtype=torch.float32, device="cuda"))  # GPU Tensor

t_numpy = t_numpy.to_gpu() # Move data to GPU
t_torch = t_torch.to_cpu() # Move data to CPU

t_numpy = t_numpy.torch() # Convert to pytorch
t_torch = t_torch.numpy() # Convert to numpy

API Reference

Generated from the built extension module (docstrings come from nanobind’s .def(...) bindings, or its own auto-generated signature when none is given). :imported-members: is needed because python/silt/__init__.py re-exports the extension’s contents via from .silt import * – without it, autodoc treats everything as “imported” rather than defined here and skips it. Requires silt to be importable in whatever Python environment runs sphinx-build (i.e. installed via pip install -e . first) – unlike the C++ reference, this reads the real module, not source text.

silt – simple immediate lightweight tensors.

The compiled extension module (silt.silt) provides the core types: shape, slice, tensor, view, and the operation free-functions. This package re-exports them and is the intended home for the pure-Python convenience layer.

silt.add(lhs, rhs)
silt.arange(n, dtype=dtype.float32, host=host.cpu)

A 1D tensor of n consecutive values starting at 0, analogous to numpy.arange. Requires numpy.

silt.clamp(lhs, min, max)
silt.divide(lhs, rhs)
class silt.dtype(*values)

Bases: Enum

float32 = 2
float64 = 3
int = 1
int64 = 5
rng = 4
silt.empty(shape, dtype=dtype.float32, host=host.cpu)

Allocate without initializing – contents are whatever the allocator handed back.

silt.full(shape, value, dtype=dtype.float32, host=host.cpu)

A new tensor filled with value.

class silt.host(*values)

Bases: Enum

cpu = 0
gpu = 1
silt.like(t, fill=None)

A new tensor with the same shape, dtype and host as t, optionally filled with a scalar value (left uninitialized if fill is omitted).

silt.linspace(a, b, n, dtype=dtype.float32, host=host.cpu)

A 1D tensor of n evenly spaced values from a to b inclusive, analogous to numpy.linspace. Requires numpy.

silt.maximum(lhs, rhs)
silt.minimum(lhs, rhs)
silt.mix(lhs, rhs, w)
silt.multiply(lhs, rhs)
silt.ones(shape, dtype=dtype.float32, host=host.cpu)

A new tensor filled with 1.

silt.rand(shape, seed_value=0)

Allocate a GPU RNG-state tensor and seed it in one step – previously two easy-to-forget calls: tensor(silt.rng, shape, silt.gpu) then silt.seed(t, seed_value, 0).

Named rand rather than rng: silt.rng is already the RNG dtype constant (exported to module level like the other dtypes), and reusing the name here would shadow it and break existing code such as silt.tensor(silt.rng, shape, silt.gpu).

class silt.shape(*args, **kwargs)

Bases: object

property dim

(self) -> int

property elem

(self) -> int

property ext

(self) -> collections.abc.List[int]

reshape(self, d0: int = 1, d1: int = 1, d2: int = 1, d3: int = 1) → silt.silt.shape
class silt.slice(*args, **kwargs)

Bases: object

property dim

(self) -> int

property elem

(self) -> int

property extent

(self) -> collections.abc.List[int]

index(self, arg0: int, arg1: int, arg2: int, arg3: int, /) → None
property maxelem

(self) -> int

property offset

(self) -> collections.abc.List[int]

reset(self) → None
property shape

(self) -> silt.silt.shape

property stride

(self) -> collections.abc.List[int]

transform(self, arg: int, /) → int
class silt.tensor(*args, **kwargs)

Bases: object

copy_to(self, host: silt.silt.host | None = None) → silt.silt.tensor
property dtype

(self) -> silt::dtype

property elem

(self) -> int

flatten(self) → silt.silt.tensor
from_numpy = <nanobind.nb_func object>
from_torch = <nanobind.nb_func object>
property host

(self) -> silt::host_t

item(self) → object
property nbytes

(self) -> int

property ndim

(self) -> int

numpy(self) → object
reshape(self, d0: int = 1, d1: int = 1, d2: int = 1, d3: int = 1) → silt.silt.tensor
property shape

(self) -> silt.silt.shape

property size

(self) -> int

slice(self, arg: tuple, /) → silt.silt.view
to(self, arg: silt.silt.host, /) → silt.silt.tensor
to_cpu(self) → silt.silt.tensor
to_gpu(self) → silt.silt.tensor
torch(self) → object
property type

(self) -> silt::dtype

class silt.view

Bases: object

property dtype

(self) -> silt::dtype

property elem

(self) -> int

property host

(self) -> silt::host_t

property slice

(self) -> silt.silt.slice

property type

(self) -> silt::dtype

silt.zeros(shape, dtype=dtype.float32, host=host.cpu)

A new tensor filled with 0.