Data.Tensor
Dense multi-dimensional tensors over a flat FloatBuf.
A Tensor is a flat buffer of f64 words plus three lists, one entry per axis: the axis shape (its extent), its strides (the flat-offset step for a unit step along that axis), and its axes (a name). Reading t[i, j] is a strided lookup: offset = sum_k idx[k] * strides[k], then a single tbuf_get. Because the layout lives entirely in the stride list, transposing by name is a permutation of the three lists with no data movement, and the underlying buffer is shared until a write forces a copy (the buffer’s own rc==1 in-place / shared-copy discipline).
The surface covers construction, indexing, transpose-by-name, a contiguity-checked reshape, elementwise math (map_tensor, zip_with_tensor, add/sub/mul/div, scale), full reductions (sum_all, prod_all, mean), and matmul. Every reduction and contraction sums in row-major source-loop order, so results are bit-identical across backends. Broadcasting is deliberately absent, and the math functions require contiguous operands (a transposed view must be materialised first).
t[i, j] and t[i, j] := v are surface sugar for at_tensor / tensor_set.
Types
Tensor
type Tensor = MkTensor(FloatBuf, List(Int), List(Int), List(String))
A dense tensor: flat storage plus per-axis shape, strides, and names.
Functions and Values
buf
buf : (Data.Tensor.Tensor) -> FloatBuf
The flat backing buffer.
shape
shape : (Data.Tensor.Tensor) -> List(Int)
The extent of each axis, outermost first.
shape(new([2, 3], 0.0))
[2, 3]
strides
strides : (Data.Tensor.Tensor) -> List(Int)
The flat-offset stride of each axis.
strides(new([2, 3], 0.0))
[3, 1]
axes
axes : (Data.Tensor.Tensor) -> List(String)
The name of each axis.
axes(new([2, 3], 0.0))
[0, 1]
rank
rank : (Data.Tensor.Tensor) -> Int
The number of axes.
rank(new([2, 3], 0.0))
2
size
size : (Data.Tensor.Tensor) -> Int
The total number of elements: the product of the shape.
size(new([2, 3], 0.0))
6
new
new : (List(Int), Float) -> Data.Tensor.Tensor
A tensor of the given shape with every element set to fill, row-major.
let t = new([2, 2], 7.0)
t[1, 1]
7
from_list
from_list : (List(Int), List(Float)) -> Data.Tensor.Tensor
A row-major tensor of the given shape filled from a flat list of values. Extra list elements past the shape’s size are ignored; missing ones stay 0.
let t = from_list([2, 2], [1.0, 2.0, 3.0, 4.0])
t[1, 0]
3
at_tensor
at_tensor : (Data.Tensor.Tensor, List(Int)) -> Float ! {Fail}
The element at a multi-index, or fail() if the offset is out of range. Backs t[i, j].
at_tensor(from_list([2, 2], [1.0, 2.0, 3.0, 4.0]), [0, 1])
2
tensor_set
tensor_set : (Data.Tensor.Tensor, List(Int), Float) -> Data.Tensor.Tensor ! {Fail}
A tensor equal to t but with the element at a multi-index set to v, or fail() if out of range. Backs t[i, j] := v.
let t = tensor_set(new([2, 2], 0.0), [0, 1], 5.0)
t[0, 1]
5
transpose
transpose : (Data.Tensor.Tensor, String, String) -> Data.Tensor.Tensor ! {Fail}
Transpose two named axes: a permutation of the shape, strides, and names with no data movement (the buffer is shared). Reading a transposed tensor walks the same buffer in the permuted stride order.
let t = transpose(from_list([2, 2], [1.0, 2.0, 3.0, 4.0]), "0", "1")
t[0, 1]
3
reshape
reshape : (Data.Tensor.Tensor, List(Int)) -> Data.Tensor.Tensor ! {Fail}
Reinterpret the elements under a new shape of the same size. Requires the tensor to be contiguous (row-major strides); a transposed view must be copied first, so reshaping one is a fail(). The new axes get default names.
shape(reshape(from_list([2, 2], [1.0, 2.0, 3.0, 4.0]), [4]))
[4]
map_tensor
map_tensor : forall e0. ((Float) -> Float ! {Fail, e0}, Data.Tensor.Tensor) -> Data.Tensor.Tensor ! {Fail, e0}
A tensor of the same shape with f applied to every element. Requires a contiguous input; the result is contiguous.
sum_all(map_tensor(\(x) -> x + 1.0, from_list([2], [10.0, 20.0])))
32
zip_with_tensor
zip_with_tensor : forall e0. ((Float, Float) -> Float ! {Fail, e0}, Data.Tensor.Tensor, Data.Tensor.Tensor) -> Data.Tensor.Tensor ! {Fail, e0}
Combine two identically-shaped contiguous tensors elementwise with f, or fail() if the shapes differ or either is not contiguous. No broadcasting.
sum_all(zip_with_tensor(\(x, y) -> x + y, from_list([2], [1.0, 2.0]), from_list([2], [3.0, 4.0])))
10
add
add : (Data.Tensor.Tensor, Data.Tensor.Tensor) -> Data.Tensor.Tensor ! {Fail}
Elementwise sum of two identically-shaped tensors.
sum_all(add(from_list([2], [1.0, 2.0]), from_list([2], [3.0, 4.0])))
10
sub
sub : (Data.Tensor.Tensor, Data.Tensor.Tensor) -> Data.Tensor.Tensor ! {Fail}
Elementwise difference.
mul
mul : (Data.Tensor.Tensor, Data.Tensor.Tensor) -> Data.Tensor.Tensor ! {Fail}
Elementwise (Hadamard) product, not matrix multiplication.
sum_all(mul(from_list([2], [2.0, 3.0]), from_list([2], [4.0, 5.0])))
23
div
div : (Data.Tensor.Tensor, Data.Tensor.Tensor) -> Data.Tensor.Tensor ! {Fail}
Elementwise quotient.
scale
scale : (Float, Data.Tensor.Tensor) -> Data.Tensor.Tensor ! {Fail}
Every element multiplied by a scalar.
sum_all(scale(2.0, from_list([2], [1.0, 2.0])))
6
sum_all
sum_all : (Data.Tensor.Tensor) -> Float ! {Fail}
The sum of every element, added in row-major order. Requires a contiguous tensor (so the summation order is well defined).
sum_all(from_list([2, 2], [1.0, 2.0, 3.0, 4.0]))
10
prod_all
prod_all : (Data.Tensor.Tensor) -> Float ! {Fail}
The product of every element, in row-major order.
prod_all(from_list([2], [3.0, 4.0]))
12
mean
mean : (Data.Tensor.Tensor) -> Float ! {Fail}
The arithmetic mean of every element.
mean(from_list([2, 2], [1.0, 2.0, 3.0, 4.0]))
2.5
sum_axis
sum_axis : (Data.Tensor.Tensor, String) -> Data.Tensor.Tensor ! {Fail}
Reduce over one named axis by summing, removing that axis (rank r becomes r - 1); the remaining axes keep their names. The contracted axis is summed in index order 0..extent (source loop order), so the result is bit-identical across backends. fail() on a missing axis or a non-contiguous input.
let s = sum_axis(from_list([2, 2], [1.0, 2.0, 3.0, 4.0]), "0")
(at_tensor(s, [0]), at_tensor(s, [1]))
(4, 6)
mean_axis
mean_axis : (Data.Tensor.Tensor, String) -> Data.Tensor.Tensor ! {Fail}
Reduce over one named axis by averaging: the sum over that axis divided by its extent, removing the axis. Same source-loop order and contiguity requirement as sum_axis.
let m = mean_axis(from_list([2, 2], [1.0, 2.0, 3.0, 4.0]), "1")
(at_tensor(m, [0]), at_tensor(m, [1]))
(1.5, 3.5)
matmul
matmul : (Data.Tensor.Tensor, Data.Tensor.Tensor) -> Data.Tensor.Tensor ! {Fail}
Matrix product of a rank-2 [m, k] tensor with a rank-2 [k, n] tensor, giving [m, n]. The contraction sums in source loop order, so the result is bit-identical across backends. fail() unless both operands are contiguous, rank 2, with matching inner extents.
let c = matmul(from_list([2, 2], [1.0, 2.0, 3.0, 4.0]), from_list([2, 2], [1.0, 0.0, 0.0, 1.0]))
(c[0, 0], c[1, 1])
(1, 4)