Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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)