svod-tensor
High-level tensor API with lazy evaluation.
Basic Example
use Tensor;
use array;
let a = from_ndarray;
let b = from_ndarray;
let mut c = &a + &b;
c.realize?;
let view = c.?;
assert_eq!;
ndarray Interop
use Tensor;
use array;
// Zero-copy from ndarray (fast path for C-contiguous arrays)
let input = array!;
let t = from_ndarray;
// Compute and extract back as ndarray
let result = .?;
assert_eq!;
Zero-Copy View
For realized tensors on CPU, array_view returns a borrowed ndarray view
without copying data:
let mut t = from_slice;
t.realize?;
let view = t.?; // no copy, lifetime tied to tensor
assert_eq!;
Prepare/Execute Infrastructure
For repeated kernel executions (e.g., benchmarks, inference loops), separate preparation from execution:
use Tensor;
let a = from_slice;
let b = from_slice;
let mut result = a.matmul?;
// One-time preparation (compiles kernels, allocates buffers)
let plan = result.prepare?; // prepare() takes &mut self
// Fast repeated execution
for _ in 0..1000
Batch Execution
Realize multiple tensors together — shares compilation and avoids redundant work.
Tested in tensor/src/test/unit/batch.rs:
// test_batch_shared_input
let x = from_slice;
let ten = full?;
let two = full?;
let mut a = &x + &ten;
let mut b = &x * &two;
realize_batch?;
// a = [11, 12, 13], b = [2, 4, 6]
Prepare once, execute many times (test_prepare_batch_execute):
let mut a = &from_slice + &from_slice;
let mut b = &from_slice * &from_slice;
let plan = prepare_batch?;
plan.execute?;
assert_eq!;
// a = [4, 6], b = [20, 60]
Features
Supported:
- Lazy tensor construction
- Arithmetic: add, sub, mul, div, pow
- Math: sqrt, exp, log, sin, cos
- Reduction: sum, mean, max, min, argmax, argmin
- Shape: reshape, transpose, permute, expand, squeeze
- Activation: relu, sigmoid, tanh, softmax, gelu
- Matrix: matmul, dot, linear
Dynamic Shapes (Variable API)
Create tensors with symbolic dimensions for dynamic batching.
Tested in tensor/src/test/unit/variable.rs:
// test_variable_create, test_full_dynamic_symbolic_shape
let batch = new;
let bound = batch.bind?;
let t = full_dynamic?;
Compile once, execute with different variable values (test_prepare_execute_loop):
let batch = new;
let input = empty_dynamic;
// Assign initial data (lazy — no allocation yet)
input.assign;
// Compile plan (resolves assigns, allocates buffers)
let mut sum = input.sum?;
let mut plan = prepare_batch?;
plan.execute?; // first run
// Fast loop: write new data via array_view_mut, rebind N
input.?.copy_from_slice;
let bound = batch.bind?;
plan.execute_with_vars?;
Testing