tensor/tensor.nu — an n-dimensional array over gpukit.
The reusable ndarray the ML packages want: onnx keeps its tensors welded to the graph runtime, and gpukit is a marshalling floor nobody wants to program against. Tensor is the shared layer — shape, broadcasting, matmul and reductions — that onnx, anomaly and a future training package can all sit on.
Storage is row-major contiguous f64 (NURL's native float). dtype records the logical type: an F64 tensor is exact f64; an F32 tensor keeps its values on the f32 grid (results are rounded to f32 after each op), so it behaves like float32 for interop while computing in f64. Bytes in/out (from_f32 / to_f32) bridge to onnx weights and files.
: i TE_F64 0: i TE_F32 1: Tensor: Tensor {
i dtype
( Vec i ) shape
( Vec f ) data
}
@ tensor_of i dtype ( Vec i ) shape ( Vec f ) data → TensorAdopt a data vector (moved in) under a shape. nelem must equal prod(shape).
@ tensor_free Tensor t → v@ tensor_full i dtype ( Vec i ) shape f v → Tensor@ tensor_zeros i dtype ( Vec i ) shape → Tensor@ tensor_ones i dtype ( Vec i ) shape → Tensor@ tensor_from_data i dtype ( Vec i ) shape ( Vec f ) data → TensorFrom an explicit row-major f64 buffer (data is copied and rounded to the dtype grid; shape is adopted — the tensor takes ownership of it).
@ tensor_arange i dtype i n → Tensor1-D [0, 1, …, n-1].
@ tensor_ndim Tensor t → i@ tensor_size Tensor t → i@ tensor_dtype Tensor t → i@ tensor_dim Tensor t i ax → i@ tensor_shape Tensor t → ( Vec i )@ tensor_data Tensor t → ( Vec f )@ tensor_flat Tensor t i k → fFlat element read/write.
@ tensor_set_flat Tensor t i k f v → v@ tensor_reshape Tensor t ( Vec i ) shape → ?TensorThe same data under a new shape (must have equal nelem). Data is copied so the result is independent; shape is adopted (or freed on a size mismatch).
@ tensor_clone Tensor t → TensorClone a tensor (independent copy).
@ tensor_astype Tensor t i dtype → Tensortensor/dev.nu — DEVICE-RESIDENT tensors (M3).
A DTensor is a Tensor whose data lives in GPU memory (a gpukit GkBuf): ops chain on the device with no host roundtrips, which is what a NN forward pass needs (upload the weights once, stream activations through). Residency is EXPLICIT — tensor_to_device / dtensor_to_host move data, ops never sync behind your back.
Numerics: a TE_F32 DTensor computes IN float32 on the device — true float32 semantics (accumulation included), matching numpy float32 and onnxruntime. That differs from the HOST TE_F32 Tensor, which computes in f64 and rounds each result to the f32 grid: elementwise results agree exactly, but reductions/matmul accumulate differently (f32 vs f64 sums). TE_F64 DTensors are bit-identical to host ops wherever the kernel accumulates sequentially (elementwise, matmul).
: DTensor: DTensor {
i dtype
( Vec i ) shape
GkBuf buf
}
@ dtensor_ok DTensor d → b@ dtensor_free DTensor d → v@ dtensor_ndim DTensor d → i@ dtensor_size DTensor d → i@ dtensor_dtype DTensor d → i@ dtensor_dim DTensor d i ax → i@ tensor_to_device * GpuKit kit Tensor t → DTensor@ dtensor_to_host * GpuKit kit DTensor d → Tensor@ dtensor_add * GpuKit kit DTensor a DTensor b → ?DTensor@ dtensor_sub * GpuKit kit DTensor a DTensor b → ?DTensor@ dtensor_mul * GpuKit kit DTensor a DTensor b → ?DTensor@ dtensor_div * GpuKit kit DTensor a DTensor b → ?DTensor@ dtensor_adds * GpuKit kit DTensor a f v → ?DTensor@ dtensor_subs * GpuKit kit DTensor a f v → ?DTensor@ dtensor_muls * GpuKit kit DTensor a f v → ?DTensor@ dtensor_divs * GpuKit kit DTensor a f v → ?DTensor@ dtensor_relu * GpuKit kit DTensor a → ?DTensor@ dtensor_sigmoid * GpuKit kit DTensor a → ?DTensor@ dtensor_exp * GpuKit kit DTensor a → ?DTensor@ dtensor_tanh * GpuKit kit DTensor a → ?DTensor@ dtensor_sqrt * GpuKit kit DTensor a → ?DTensor@ dtensor_log * GpuKit kit DTensor a → ?DTensor@ dtensor_matmul * GpuKit kit DTensor a DTensor b → ?DTensor@ dtensor_softmax * GpuKit kit DTensor a → ?DTensor@ dtensor_sum * GpuKit kit DTensor a → ?fSum of every element (downloads one scalar; accumulates in the buffer's element type — true float32 for TE_F32).
tensor/ops.nu — broadcasting elementwise, unary maps, matmul and reductions.
Elementwise binary ops broadcast with numpy rules (align trailing dims, size-1 stretches). matmul runs on the GPU via gpukit for large f64 problems and on a plain triple loop otherwise — identical results either way. F32 tensors keep their outputs on the f32 grid.
: ~ i g_t_gpu 0 // 0 unprobed, 1 ready, -1 unavailable── GPU singleton (probed lazily; matmul only) ────────────────────────
: ~ i g_t_kit 0 // *GpuKit as an int@ tensor_gpu_close → vRelease the tensor GPU singleton (tests call this so leak checkers are happy).
@ tensor_add Tensor a Tensor b → ?Tensor@ tensor_sub Tensor a Tensor b → ?Tensor@ tensor_mul Tensor a Tensor b → ?Tensor@ tensor_div Tensor a Tensor b → ?Tensor@ tensor_maximum Tensor a Tensor b → ?Tensor@ tensor_minimum Tensor a Tensor b → ?Tensor@ tensor_pow Tensor a Tensor b → ?Tensor@ tensor_adds Tensor t f s → Tensor@ tensor_muls Tensor t f s → Tensor@ tensor_subs Tensor t f s → Tensor@ tensor_divs Tensor t f s → Tensor@ tensor_neg Tensor t → Tensor@ tensor_abs Tensor t → Tensor@ tensor_exp Tensor t → Tensor@ tensor_log Tensor t → Tensor@ tensor_sqrt Tensor t → Tensor@ tensor_relu Tensor t → Tensor@ tensor_sigmoid Tensor t → Tensor@ tensor_tanh Tensor t → Tensor@ tensor_matmul Tensor a Tensor b → ?Tensor@ tensor_transpose Tensor t → ?Tensor@ tensor_permute Tensor t ( Vec i ) perm → ?TensorGeneral axis permutation. perm is a length-ndim ordering of the axes.
@ tensor_sum Tensor t i axis b keepdim → Tensoraxis < 0 → reduce over everything (scalar result).
@ tensor_max Tensor t i axis b keepdim → Tensor@ tensor_min Tensor t i axis b keepdim → Tensor@ tensor_prod Tensor t i axis b keepdim → Tensor@ tensor_mean Tensor t i axis b keepdim → Tensor@ tensor_bmm Tensor a Tensor b → ?TensorBatched matmul: [..,M,K] · [..,K,N] → [..,M,N], batch dims broadcast.
@ tensor_softmax Tensor t i axis → TensorNumerically-stable softmax along one axis.
@ tensor_slice Tensor t ( Vec i ) starts ( Vec i ) stops → ?TensorSlice: out[d] spans [starts[d], stops[d]) of each dim.
@ tensor_concat2 Tensor a Tensor b i axis → ?TensorConcatenate two tensors along axis (shapes equal except along axis).
@ tensor_argmax Tensor t i axis b keepdim → Tensor@ tensor_argmin Tensor t i axis b keepdim → Tensor