Expand description
A lazy, graph-based tensor engine for the CPU, with f32/f64 element
types and a pluggable backend (pure-Rust by default, Intel MKL behind the
mkl feature).
Operations on a Tensor don’t compute anything - they build a computation
graph and return a TensorPromise. Calling .materialize() plans the
whole graph (ordering, buffer reuse, scalar-op fusion) and runs it in one
pass, handing back a finished Tensor.
use candela::{arange, Tensor};
// Building the expression allocates nothing; only `.materialize()` runs it.
let x: Tensor<f64> = arange!(4); // [0, 1, 2, 3]
let y = (x * 2.0 + 1.0).materialize(); // 2x + 1, fused into one pass
assert_eq!(y.data(), &[1.0, 3.0, 5.0, 7.0]);§The types
Tensor- a materialized buffer with a shape and stride.TensorPromise- an unevaluated computation graph;.materialize()runs it.CachedTensorPromise- a promise that keeps its result alive for reuse across separate materializations.Skeleton- a graph compiled once overSkeletonSlotplaceholders and run many times against new data, skipping per-call planning. See theskeletonmodule for the dynamic-shape and caching variants.
§Building a graph
A promise is built up op by op and stays inert until you materialize it.
Fallible ops (anything shape-dependent, like matmul)
return a Result at construction time, so a graph that could never run is
rejected before any compute happens.
use candela::{srange, Dimension, OpError, Tensor};
let a: Tensor<f32> = srange![2 * 3, &[2, 3]]; // 2x3, values 0..6
let b: Tensor<f32> = srange![3 * 2, &[3, 2]]; // 3x2, values 0..6
let c = a.matmul(&b)?.materialize(); // shape mismatch would fail here
assert_eq!(c.shape(), &[2, 2]);§Reusing intermediate results
.materialize() consumes the graph and frees
every intermediate buffer. When you want to keep a mid-graph value alive -
to inspect it, or to branch off it more than once - call
.cache() to turn the promise into a
CachedTensorPromise. It computes at most once and hands the stored result
to everyone downstream.
use candela::Tensor;
let a = Tensor::from_scalar(1.0_f64, &[3, 3]);
let b = (a + 2.0).cache(); // will hold onto its result
let peek = b.snapshot(); // computes b once, fills the cache
assert_eq!(peek.data(), &[3.0; 9]);
let c = (b * 10.0).materialize(); // reuses the cached b, no recompute
assert_eq!(c.data(), &[30.0; 9]);§Errors
Candela splits failures by how likely they are to be a bug:
- The inline arithmetic operators (
+,-,*,/) panic on a shape mismatch. A mismatch there is almost always a programming error, and making them fallible would force an.unwrap()onto every expression. - Everything else that can fail returns
Result<_,OpError>- and, because the graph is built eagerly, it fails at construction time rather than deep inside.materialize().
§Feature flags
mkl- swap the default pure-Rust backend for Intel MKL. Links against MKL (handled byintel-mkl-src), so the libraries must be available on the build host. See thebackendsdocs.tracing- emittracingspans through the planner and execution for profiling and debugging.
§Concepts
The docs module shows in detail how the processing pipeline actually works,
from expression to computed tensor. Start with the overview for
the general behaviour; it links each subsystem from there.
Modules§
Macros§
- arange
- Build a 1D tensor of evenly spaced values, NumPy-
arangestyle. - branch_
duo_ fast_ iter - branch_
fast_ iter - ones
- Build a tensor of the given shape filled with ones.
- s
- Build the
SliceRangelist forslice, one entry per axis. - srange
- Build a tensor of evenly spaced values and reshape it in one step.
- zeros
- Build a tensor of the given shape filled with zeros.
Structs§
- Cached
Tensor Promise - A lazy computation whose result is kept alive after the first evaluation.
- Informed
Iter - Structural walk over a tensor, yielding a
StepInfoper element and per dimension boundary. - Iter
- Iterator over a tensor’s elements in logical (row-major) order.
- Layout
- How a tensor’s logical shape maps onto its flat backing buffer.
- Slice
Range - A per-axis range for
slice, one entry per axis. - Tensor
- Allocated tensor data exposed through the public API.
- Tensor
Promise - A lazy computation that runs when you call
.materialize().
Enums§
- OpError
- The error returned by fallible tensor operations.
- Step
Info - A single event in a structural walk of a tensor, produced by
Tensor::informed_iter.
Traits§
- Composable
- A subset of all tensor types that can be materialized
- Dimension
- Shape, stride, and layout queries shared by every tensor-like value.
- Float
Like Tensor Element - Sealed marker for floating-point tensor element types:
f32andf64.