argamak/tensor
Types
A Tensor
is a generic container for n-dimensional data structures.
pub opaque type Tensor(a, dn, axis)
When a tensor operation cannot succeed.
pub type TensorError {
EmptyTensor
IncompatibleAxes
IncompatibleShape
InvalidData
SpaceErrors(space.SpaceErrors)
}
Constructors
-
EmptyTensor
-
IncompatibleAxes
-
IncompatibleShape
-
InvalidData
-
SpaceErrors(space.SpaceErrors)
Functions
pub fn as_format(for tensor: Tensor(a, b, c), apply format: fn() ->
Format(d)) -> Tensor(d, b, c)
Changes the Format
of a Tensor
.
Converting from float formats to integer formats truncates the data. For
consistency, consider using round
, floor
, or ceil
before casting from
float formats to integer formats.
Lowering precision may lead to an overflow or underflow, the outcome of which depends on platform and compiler.
Examples
> import argamak/format
> as_format(for: from_int(0), apply: format.float32)
from_float(0.)
> import argamak/space
> type Axis { X }
> assert Ok(space) = space.d1(#(X, -1))
> try tensor = from_floats(of: [1., 2., 3.], into: space)
> Ok(as_format(for: tensor, apply: format.int32))
from_ints(of: [1, 2, 3], into: space)
pub fn axes(tensor: Tensor(a, b, c)) -> List(c)
Returns the axes of a given Tensor
.
Examples
> axes(from_int(3))
[]
> import argamak/space
> type Axis { X }
> assert Ok(space) = space.d1(#(X, -1))
> try tensor = from_floats(of: [1., 2., 3.], into: space)
> Ok(axes(tensor))
Ok([X])
> type OtherAxis { Alpha Omega }
> assert Ok(space) = space.d2(#(Alpha, 1), #(Omega, 3))
> try tensor = from_ints(of: [1, 2, 3], into: space)
> Ok(axes(tensor))
Ok([Alpha, Omega])
pub fn broadcast(from tensor: Tensor(a, b, c), into new_space: Space(
d,
e,
)) -> Result(Tensor(a, d, e), TensorError)
Results in a Tensor
broadcast into a given n-dimensional Space
on
success, or a TensorError
on failure.
The new Space
cannot be of lower dimensionality than the Tensor
’s
current Space
.
The new Tensor
’s current Space
must have dimension sizes compatible with
the right-most dimensions of the new Space
; that is, every current
dimension size must be 1
or equal to its counterpart in the new Space
.
Examples
> import argamak/space
> type Axis { X Y Z }
> let tensor = from_int(0)
> assert Ok(space) = space.d1(#(X, 3))
> try tensor = broadcast(from: tensor, into: space)
> Ok(print(from: tensor, wrap_at: -1, meta: True))
// Tensor
// format: Int32
// space: D1 #(X, 3)
// data:
// [0, 0, 0]
Ok(Nil)
> assert Ok(space) = space.d1(#(X, -1))
> let tensor = from_ints(of: [-1], into: space)
> assert Ok(space) = space.d1(#(Y, 5))
> try tensor = broadcast(from: tensor, into: space)
> Ok(print(from: tensor, wrap_at: -1, meta: True))
// Tensor
// format: Int32
// space: D1 #(Y, 5)
// data:
// [-1, -1, -1, -1, -1]
Ok(Nil)
> assert Ok(space) = space.d1(#(X, -1))
> try tensor = from_floats(of: [1., 2., 3.], into: space)
> assert Ok(space) = space.d2(#(X, 2), #(Y, 3))
> try tensor = broadcast(from: tensor, into: space)
> Ok(print(from: tensor, wrap_at: -1, meta: True))
// Tensor
// format: Float32
// space: D2 #(X, 2), #(Y, 3)
// data:
// [[1.0, 2.0, 3.0],
// [1.0, 2.0, 3.0]]
Ok(Nil)
pub fn broadcast_over(from tensor: Tensor(a, b, c), into new_space: Space(
d,
e,
), with axes: fn(#(c, Int)) -> e) -> Result(
Tensor(a, d, e),
TensorError,
)
Results in a Tensor
broadcast into a given n-dimensional Space
on
success, or a TensorError
on failure.
The new Space
cannot be of lower dimensionality than the Tensor
’s
current Space
.
The given function will be used to map from the elements of the Tensor
’s
current Space
to axes of the new Space
, allowing broadcasting into a
Space
that would be incompatible for a standard broadcast
operation.
The function must uniquely map the current Space
’s axes to the new
Space
’s axes; that is, duplicate axes will result in a TensorError
.
Furthermore, the current Space
’s axes must maintain the same relative
order when mapped to the new Space
.
The new Tensor
’s current Space
must have dimension sizes compatible with
the matching dimensions of the new Space
; that is, every current dimension
size must be 1
or equal to its counterpart in the new Space
.
Examples
> import argamak/space
> type Axis { X Y Z }
> assert Ok(space) = space.d1(#(X, -1))
> try tensor = from_floats(of: [1., 2., 3.], into: space)
> assert Ok(space) = space.d2(#(X, 3), #(Y, 2))
> try new_tensor = broadcast_over(
from: tensor,
into: space,
with: fn(_) { X },
)
> Ok(print(from: new_tensor, wrap_at: -1, meta: True))
// Tensor
// format: Float32
// space: D2 #(X, 3), #(Y, 2)
// data:
// [[1.0, 1.0],
// [2.0, 2.0],
// [3.0, 3.0]]
Ok(Nil)
> try tensor = from_ints(of: [1, 2, 3, 4, 5, 6], into: space)
> assert Ok(space) = space.d3(#(X, 3), #(Y, 2), #(Z, 2))
> try new_tensor = broadcast_over(
from: tensor,
into: space,
with: fn(element) {
let #(axis, _size) = element
case axis {
X -> X
Y -> Z
}
},
)
> Ok(print(from: new_tensor, wrap_at: -1, meta: True))
// Tensor
// format: Int32
// space: D3 #(X, 3), #(Y, 2), #(Z, 2)
// data:
// [[[1, 2],
// [1, 2]],
// [[3, 4],
// [3, 4]],
// [[5, 6],
// [5, 6]]]
Ok(Nil)
> import gleam/pair
> try new_tensor = broadcast_over(
from: tensor,
into: space,
with: pair.first,
)
> Ok(print(from: new_tensor, wrap_at: -1, meta: True))
// Tensor
// format: Int32
// space: D3 #(X, 3), #(Y, 2), #(Z, 2)
// data:
// [[[1, 1],
// [2, 2]],
// [[3, 3],
// [4, 4]],
// [[5, 5],
// [6, 6]]]
Ok(Nil)
pub fn format(tensor: Tensor(a, b, c)) -> Format(a)
Returns the Format
of a given Tensor
.
See argamak/format
for more information.
Examples
import argamak/format
> format(from_float(0.))
format.float32()
> import argamak/space
> type Axis { X }
> assert Ok(space) = space.d1(#(X, -1))
> try tensor = from_ints(of: [1, 2, 3], into: space)
> Ok(format(tensor))
Ok(format.int32())
pub fn from_float(float: Float) -> Tensor(Float, D0, Nil)
Converts a Float
into a Tensor
.
Examples
> let tensor = from_float(1.)
> print(from: tensor, wrap_at: -1, meta: False)
// 1.0
Nil
pub fn from_floats(of list: List(Float), into space: Space(a, b)) -> Result(
Tensor(Float, a, b),
TensorError,
)
Results in a Tensor
created from a list of floats and placed into a given
n-dimensional Space
on success, or a TensorError
on failure.
The Space
’s Shape
may have a single dimension given as -1
, in which
case that dimension’s size will be inferred from the given list. This is
useful when working with lists of unknown length.
Examples
> import argamak/space
> type Axis { X Y Z }
> assert Ok(space) = space.d1(#(X, -1))
> try tensor = from_floats(of: [1.], into: space)
> Ok(print(from: tensor, wrap_at: -1, meta: True))
// Tensor
// format: Float32
// space: D1 #(X, 1)
// data:
// [1.0]
Ok(Nil)
> assert Ok(space) = space.d2(#(X, 2), #(Y, 2))
> try tensor = from_floats(of: [1., 2., 3., 4.], into: space)
> Ok(print(from: tensor, wrap_at: -1, meta: True))
// Tensor
// format: Float32
// space: D2 #(X, 2), #(Y, 2)
// data:
// [[1.0, 2.0],
// [3.0, 4.0]]
Ok(Nil)
> assert Ok(space) = space.d3(#(X, -1), #(Y, 2), #(Z, 2))
> let list = [1., 2., 3., 4., 5., 6., 7., 8.]
> try tensor = from_floats(of: list, into: space)
> Ok(print(from: tensor, wrap_at: -1, meta: True))
// Tensor
// format: Float32
// space: D3 #(X, 2), #(Y, 2), #(Z, 2)
// data:
// [[[1.0, 2.0],
// [3.0, 4.0]],
// [[5.0, 6.0],
// [7.0, 8.0]]]
Ok(Nil)
pub fn from_int(int: Int) -> Tensor(Int, D0, Nil)
Converts an Int
into a Tensor
.
Examples
> let tensor = from_int(1)
> print(from: tensor, wrap_at: -1, meta: False)
// 1
Nil
pub fn from_ints(of list: List(Int), into space: Space(a, b)) -> Result(
Tensor(Int, a, b),
TensorError,
)
Results in a Tensor
created from a list of integers and placed into a
given n-dimensional Space
on success, or a TensorError
on failure.
The Space
’s Shape
may have a single dimension given as -1
, in which
case that dimension’s size will be inferred from the given list. This is
useful when working with lists of unknown length.
Examples
> import argamak/space
> type Axis { X Y Z }
> assert Ok(space) = space.d1(#(X, -1))
> try tensor = from_ints(of: [1], into: space)
> Ok(print(from: tensor, wrap_at: -1, meta: True))
// Tensor
// format: Int32
// space: D1 #(X, 1)
// data:
// [1]
Ok(Nil)
> assert Ok(space) = space.d2(#(X, 2), #(Y, 2))
> try tensor = from_ints(of: [1, 2, 3, 4], into: space)
> Ok(print(from: tensor, wrap_at: -1, meta: True))
// Tensor
// format: Int32
// space: D2 #(X, 2), #(Y, 2)
// data:
// [[1, 2],
// [3, 4]]
Ok(Nil)
> assert Ok(space) = space.d3(#(X, -1), #(Y, 2), #(Z, 2))
> let list = [1, 2, 3, 4, 5, 6, 7, 8]
> try tensor = from_ints(of: list, into: space)
> Ok(print(from: tensor, wrap_at: -1, meta: True))
// Tensor
// format: Int32
// space: D3 #(X, 2), #(Y, 2), #(Z, 2)
// data:
// [[[1, 2],
// [3, 4]],
// [[5, 6],
// [7, 8]]]
Ok(Nil)
pub fn from_native(of native: Native, into space: Space(a, b), with format: fn() ->
Format(c)) -> Result(Tensor(c, a, b), TensorError)
Results in a Tensor
created from a Native
representation on success, or
a TensorError
on failure.
Examples
> import argamak/format
> import argamak/space
> import gleam/dynamic.{Dynamic}
> external fn erlang_tensor(Dynamic) -> Native =
> "Elixir.Nx" "tensor"
> let native = erlang_tensor(dynamic.from([[1, 2], [3, 4]]))
> assert Ok(space) = space.d2(#(X, 2), #(Y, -1))
> try tensor = from_native(of: native, into: space, with: format.int32)
> Ok(print(from: tensor, wrap_at: -1, meta: True))
// Tensor
// format: Int32
// space: D2 #(X, 2), #(Y, 2)
// data:
// [[1, 2],
// [3, 4]]
Ok(Nil)
pub fn print(from tensor: Tensor(a, b, c), wrap_at max_width: Int, meta meta: Bool) -> Nil
Prints a Tensor
’s underlying data to standard out.
Takes a max_width
(in columns) argument for which the special values -1
and 0
represent default and no wrapping, respectively.
If the meta
argument is True
, various Tensor
details will be printed
with the data.
Examples
> import argamak/space
> type Axis { X Y Z }
> assert Ok(space) = space.d2(#(X, 2), #(Y, 2))
> try tensor = from_ints(of: [1, 2, 3, 4], into: space)
> Ok(print(from: tensor, wrap_at: -1, meta: False))
// [[1, 2],
// [3, 4]]
Ok(Nil)
> assert Ok(space) = space.d3(#(X, 2), #(Y, 1), #(Z, 4))
> let list = [1, 2, 3, 4, 5, 6, 7, 8]
> try tensor = from_ints(of: list, into: space)
> Ok(print(from: tensor, wrap_at: 10, meta: True))
// Tensor
// format: Int64
// space: D3 #(X, 2), #(Y, 1), #(Z, 4)
// data:
// [[[1, 2,
// 3, 4]],
// [[5, 6,
// 7, 8]]]
Ok(Nil)
pub fn rank(tensor: Tensor(a, b, c)) -> Int
Returns the rank of a given Tensor
as an Int
representing the number of
dimensions.
Examples
> rank(from_float(0.))
0
> import argamak/space
> type Axis { X Y Z }
> assert Ok(space) = space.d1(#(X, -1))
> try tensor = from_ints(of: [1, 2, 3], into: space)
> Ok(rank(tensor))
Ok(1)
> assert Ok(space) = space.d3(#(X, 2), #(Y, 2), #(Z, 2))
> try tensor = from_ints(of: [1, 2, 3, 4, 5, 6, 7, 8], into: space)
> Ok(rank(tensor))
Ok(3)
pub fn reshape(put tensor: Tensor(a, b, c), into new_space: Space(
d,
e,
)) -> Result(Tensor(a, d, e), TensorError)
Results in a Tensor
placed into a given n-dimensional Space
on success,
or a TensorError
on failure.
The Space
’s Shape
may have a single dimension given as -1
, in which
case that dimension’s size will be inferred from the given list. This is
useful when working with lists of unknown length.
Examples
> import argamak/space
> type Axis { X Y Z }
> let tensor = from_float(1.)
> assert Ok(space) = space.d1(#(X, -1))
> try tensor = reshape(put: tensor, into: space)
> Ok(print(from: tensor, wrap_at: -1, meta: True))
// Tensor
// format: Float32
// space: D1 #(X, 1)
// data:
// [1.0]
Ok(Nil)
> assert Ok(space) = space.d1(#(X, -1))
> try tensor = from_floats(of: [1., 2., 3., 4.], into: space)
> assert Ok(space) = space.d2(#(X, 2), #(Y, 2))
> try tensor = reshape(put: tensor, into: space)
> Ok(print(from: tensor, wrap_at: -1, meta: True))
// Tensor
// format: Float32
// space: D2 #(X, 2), #(Y, 2)
// data:
// [[1.0, 2.0],
// [3.0, 4.0]]
Ok(Nil)
> assert Ok(space) = space.d2(#(X, 2), #(Y, -1))
> let list = [1., 2., 3., 4., 5., 6., 7., 8.]
> try tensor = from_floats(of: list, into: space)
> assert Ok(space) = space.d3(#(X, -1), #(Y, 2), #(Z, 2))
> try tensor = reshape(put: tensor, into: space)
> Ok(print(from: tensor, wrap_at: -1, meta: True))
// Tensor
// format: Float32
// space: D3 #(X, 2), #(Y, 2), #(Z, 2)
// data:
// [[[1.0, 2.0],
// [3.0, 4.0]],
// [[5.0, 6.0],
// [7.0, 8.0]]]
Ok(Nil)
> assert Ok(space) = space.d3(#(X, 1), #(Y, 1), #(Z, 1))
> try tensor = from_floats(of: [1.], into: space)
> assert Ok(space) = space.d0()
> try tensor = reshape(put: tensor, into: space)
> Ok(print(from: tensor, wrap_at: -1, meta: False))
// 1.0
Ok(Nil)
pub fn shape(tensor: Tensor(a, b, c)) -> List(Int)
Returns the shape of a given Tensor
.
Examples
> shape(from_float(0.))
[]
> import argamak/space
> type Axis { X Y Z }
> assert Ok(space) = space.d1(#(X, -1))
> try tensor = from_ints(of: [1, 2, 3], into: space)
> Ok(shape(tensor))
Ok([3])
> assert Ok(space) = space.d3(#(X, 2), #(Y, 2), #(Z, 2))
> try tensor = from_ints(of: [1, 2, 3, 4, 5, 6, 7, 8], into: space)
> Ok(shape(tensor))
Ok([2, 2, 2])
pub fn space(tensor: Tensor(a, b, c)) -> Space(b, c)
Returns the Space
a given Tensor
is currently in.
Examples
> import argamak/space
> assert Ok(space) = space.d0()
> space(from_float(0.))
space
> type Axis { X Y Z }
> assert Ok(space) = space.d1(#(X, -1))
> try tensor = from_ints(of: [1, 2, 3], into: space)
> Ok(space(tensor))
Ok(space)
> assert Ok(space) = space.d3(#(X, 2), #(Y, 2), #(Z, 2))
> try tensor = from_ints(of: [1, 2, 3, 4, 5, 6, 7, 8], into: space)
> Ok(space(tensor))
Ok(space)
pub fn to_float(tensor: Tensor(Float, D0, a)) -> Float
Converts a Tensor
without dimensions into a Float
.
Examples
> let tensor = from_float(0.)
> to_float(tensor)
0.
> import argamak/format
> let tensor = from_int(0)
> let tensor = as_format(for: tensor, apply: format.float32)
> to_float(tensor)
0.
pub fn to_int(tensor: Tensor(Int, D0, a)) -> Int
Converts a Tensor
without dimensions into an Int
.
Examples
> let tensor = from_int(0)
> to_int(tensor)
0
> import argamak/format
> let tensor = from_float(0.)
> let tensor = as_format(for: tensor, apply: format.int32)
> to_int(tensor)
0
pub fn to_list(tensor: Tensor(a, b, c)) -> List(a)
Converts a Tensor
into a flat list of numbers.
Examples
> to_list(from_int(0))
[0]
> import argamak/space
> type Axis { X Y }
> assert Ok(space) = space.d2(#(X, 3), #(Y, 1))
> try tensor = from_floats(of: [1., 2., 3.], into: space)
> Ok(to_list(tensor))
Ok([1., 2., 3.])