Tensorex (tensorex v0.3.0) View Source

Functions to operate basic commands with tensors.

Link to this section Summary

Types

t()

Represents a tensor.

Functions

Checks if the given tensor is diagonal or not.

Returns a tensor or a number stored at the index.

Returns a tensor where all of elements are the given value.

Creates a new tensor from a list (of lists (of lists of ...)).

Returns a tensor or a number stored at the index and update it at the same time.

Returns a 2-rank tensor with all diagonal elements of 1.

Returns a tensor where each element is the result of invoking mapper on each corresponding element of the given tensor.

Pops the tensor or the number stored at the index out of the tensor.

Checks if the given tensor is upper triangular or not.

Returns a tensor with all of zero elements.

Link to this section Types

Specs

t() :: %Tensorex{
  data: %{optional([non_neg_integer(), ...]) => number()},
  shape: [pos_integer(), ...]
}

Represents a tensor.

The data structure is a map with list of indices keys and numeric values. Zero values are omitted. The shape is a list of each dimension at the order.

This module implements the Access behaviour. So that you can access elements of the tensor via tensor[indices] syntax, where indices must be a list of integer/0s or Range.t/0s. See fetch/2 for concrete examples.

Link to this section Functions

Specs

diagonal?(t()) :: boolean()

Checks if the given tensor is diagonal or not.

iex> Tensorex.diagonal?(Tensorex.from_list([[2, 0,  0],
...>                                        [0, 3,  0],
...>                                        [0, 0, -9]]))
true

iex> Tensorex.diagonal?(Tensorex.from_list([[ 2  , 0,  0],
...>                                        [ 0  , 3,  0],
...>                                        [-5.3, 0, -9]]))
false
Link to this function

fetch(tensorex, indices)

View Source

Specs

fetch(t(), [integer() | Range.t(), ...]) :: {:ok, t() | number()} | :error

Returns a tensor or a number stored at the index.

The key can be a list of indices or ranges. If integer indices are given, it returns a tensor or a numeric value specified by the index. If ranges are given, it returns a tensor consisting partial elements.

Negative indices are counted from the end.

iex> Tensorex.from_list([[[ 1   ,   -3.1,   2  ],
...>                      [ 4   ,    5  ,  -6.1],
...>                      [ 0.9 ,  -91.2,  11  ]],
...>                     [[10   ,  -30.1,  20  ],
...>                      [40   ,   50  , -60.1],
...>                      [ 0.09, -910.2, 110  ]]])[[0, 0, 0]]
1

iex> Tensorex.from_list([[[ 1   ,   -3.1,   2  ],
...>                      [ 4   ,    5  ,  -6.1],
...>                      [ 0.9 ,  -91.2,  11  ]],
...>                     [[10   ,  -30.1,  20  ],
...>                      [40   ,   50  , -60.1],
...>                      [ 0.09, -910.2, 110  ]]])[[0, 0]]
%Tensorex{data: %{[0] => 1, [1] => -3.1, [2] => 2}, shape: [3]}

iex> Tensorex.from_list([[[ 1   ,   -3.1,   2  ],
...>                      [ 4   ,    5  ,  -6.1],
...>                      [ 0.9 ,  -91.2,  11  ]],
...>                     [[10   ,  -30.1,  20  ],
...>                      [40   ,   50  , -60.1],
...>                      [ 0.09, -910.2, 110  ]]])[[0]]
%Tensorex{data: %{[0, 0] => 1  , [0, 1] =>  -3.1, [0, 2] =>  2  ,
                  [1, 0] => 4  , [1, 1] =>   5  , [1, 2] => -6.1,
                  [2, 0] => 0.9, [2, 1] => -91.2, [2, 2] => 11  }, shape: [3, 3]}

iex> Tensorex.from_list([[[ 1   ,   -3.1,   2  ],
...>                      [ 4   ,    5  ,  -6.1],
...>                      [ 0.9 ,  -91.2,  11  ]],
...>                     [[10   ,  -30.1,  20  ],
...>                      [40   ,   50  , -60.1],
...>                      [ 0.09, -910.2, 110  ]]])[[2]]
nil

iex> Tensorex.from_list([[ 1,  2,  3],
...>                     [ 4,  5,  6],
...>                     [ 7,  8,  9],
...>                     [10, 11, 12]])[[1..2]]
%Tensorex{data: %{[0, 0] => 4, [0, 1] => 5, [0, 2] => 6,
                  [1, 0] => 7, [1, 1] => 8, [1, 2] => 9}, shape: [2, 3]}

iex> Tensorex.from_list([[ 1,  2,  3],
...>                     [ 4,  5,  6],
...>                     [ 7,  8,  9],
...>                     [10, 11, 12]])[[-2..-1]]
%Tensorex{data: %{[0, 0] =>  7, [0, 1] =>  8, [0, 2] =>  9,
                  [1, 0] => 10, [1, 1] => 11, [1, 2] => 12}, shape: [2, 3]}

iex> Tensorex.from_list([[ 1,  2,  3],
...>                     [ 4,  5,  6],
...>                     [ 7,  8,  9],
...>                     [10, 11, 12]])[[1..2, 1..-1]]
%Tensorex{data: %{[0, 0] => 5, [0, 1] => 6,
                  [1, 0] => 8, [1, 1] => 9}, shape: [2, 2]}

iex> Tensorex.from_list([[ 1,  2,  3],
...>                     [ 4,  0,  6],
...>                     [ 7,  8,  9],
...>                     [10, 11, 12]])[[1, 1]]
0.0

Specs

fill([pos_integer(), ...], number()) :: t()

Returns a tensor where all of elements are the given value.

iex> Tensorex.fill([3, 4, 2], 2)
%Tensorex{data: %{[0, 0, 0] => 2, [0, 0, 1] => 2,
                  [0, 1, 0] => 2, [0, 1, 1] => 2,
                  [0, 2, 0] => 2, [0, 2, 1] => 2,
                  [0, 3, 0] => 2, [0, 3, 1] => 2,
                  [1, 0, 0] => 2, [1, 0, 1] => 2,
                  [1, 1, 0] => 2, [1, 1, 1] => 2,
                  [1, 2, 0] => 2, [1, 2, 1] => 2,
                  [1, 3, 0] => 2, [1, 3, 1] => 2,
                  [2, 0, 0] => 2, [2, 0, 1] => 2,
                  [2, 1, 0] => 2, [2, 1, 1] => 2,
                  [2, 2, 0] => 2, [2, 2, 1] => 2,
                  [2, 3, 0] => 2, [2, 3, 1] => 2}, shape: [3, 4, 2]}

iex> Tensorex.fill([2, 2, 5], 0.0)
%Tensorex{data: %{}, shape: [2, 2, 5]}

Specs

from_list(Enum.t()) :: t()

Creates a new tensor from a list (of lists (of lists of ...)).

iex> Tensorex.from_list([1.1, 2.1, -5.3, 4])
%Tensorex{data: %{[0] => 1.1, [1] => 2.1, [2] => -5.3, [3] => 4}, shape: [4]}

iex> Tensorex.from_list([[1.1,  2.1, -5.3, 4  ],
...>                     [0.8, -8,   21.4, 3.3]])
%Tensorex{data: %{[0, 0] => 1.1, [0, 1] =>  2.1, [0, 2] => -5.3, [0, 3] => 4  ,
                  [1, 0] => 0.8, [1, 1] => -8,   [1, 2] => 21.4, [1, 3] => 3.3}, shape: [2, 4]}

iex> Tensorex.from_list([[[0.0, 0.0, 0.0],
...>                      [0.0, 0.0, 0.0]],
...>                     [[0.0, 0.0, 0.0],
...>                      [0.0, 0.0, 0.0]]])
%Tensorex{data: %{}, shape: [2, 2, 3]}
Link to this function

get_and_update(tensor, indices, fun)

View Source

Specs

get_and_update(
  t(),
  [integer() | Range.t(), ...],
  (t() -> :pop | {any(), t()}) | (number() -> :pop | {any(), number()})
) :: {any(), t()}

Returns a tensor or a number stored at the index and update it at the same time.

iex> get_and_update_in(
...>   Tensorex.from_list([[[ 1   ,   -3.1,   2  ],
...>                        [ 4   ,    5  ,  -6.1],
...>                        [ 0.9 ,  -91.2,  11  ]],
...>                       [[10   ,  -30.1,  20  ],
...>                        [40   ,   50  , -60.1],
...>                        [ 0.09, -910.2, 110  ]]])[[0, 1, 0]], &{&1, &1 * 3.5})
{4, %Tensorex{data: %{[0, 0, 0] =>  1   , [0, 0, 1] =>   -3.1, [0, 0, 2] =>   2  ,
                      [0, 1, 0] => 14.0 , [0, 1, 1] =>    5  , [0, 1, 2] =>  -6.1,
                      [0, 2, 0] =>  0.9 , [0, 2, 1] =>  -91.2, [0, 2, 2] =>  11  ,
                      [1, 0, 0] => 10   , [1, 0, 1] =>  -30.1, [1, 0, 2] =>  20  ,
                      [1, 1, 0] => 40   , [1, 1, 1] =>   50  , [1, 1, 2] => -60.1,
                      [1, 2, 0] =>  0.09, [1, 2, 1] => -910.2, [1, 2, 2] => 110  }, shape: [2, 3, 3]}}

iex> get_and_update_in(
...>   Tensorex.from_list([[ 1,  2,  3],
...>                       [ 4,  5,  6],
...>                       [ 7,  8,  9],
...>                       [10, 11, 12]])[[1..2, 1..2]],
...>   &{&1, Tensorex.from_list([[13, 14],
...>                             [15, 16]])})
{%Tensorex{data: %{[0, 0] => 5, [0, 1] => 6,
                   [1, 0] => 8, [1, 1] => 9}, shape: [2, 2]},
 %Tensorex{data: %{[0, 0] =>  1, [0, 1] =>  2, [0, 2] =>  3,
                   [1, 0] =>  4, [1, 1] => 13, [1, 2] => 14,
                   [2, 0] =>  7, [2, 1] => 15, [2, 2] => 16,
                   [3, 0] => 10, [3, 1] => 11, [3, 2] => 12}, shape: [4, 3]}}

iex> get_and_update_in(
...>   Tensorex.from_list([[ 1,  2,  3],
...>                       [ 4,  5,  6],
...>                       [ 7,  8,  9],
...>                       [10, 11, 12]])[[2]],
...>   &{&1, Tensorex.from_list([0, 0, 16])})
{%Tensorex{data: %{[0] => 7, [1] => 8, [2] => 9}, shape: [3]},
 %Tensorex{data: %{[0, 0] =>  1, [0, 1] =>  2, [0, 2] =>  3,
                   [1, 0] =>  4, [1, 1] =>  5, [1, 2] =>  6,
                                               [2, 2] => 16,
                   [3, 0] => 10, [3, 1] => 11, [3, 2] => 12}, shape: [4, 3]}}

iex> get_and_update_in(
...>   Tensorex.from_list([[ 1,  2],
...>                       [ 3,  4]])[[0..-1, 0..-1]],
...>   &{&1, Tensorex.from_list([[-2,  0],
...>                             [ 0, -3]])})
{%Tensorex{data: %{[0, 0] =>  1, [0, 1] =>  2,
                   [1, 0] =>  3, [1, 1] =>  4}, shape: [2, 2]},
 %Tensorex{data: %{[0, 0] => -2,
                                 [1, 1] => -3}, shape: [2, 2]}}

iex> get_and_update_in(
...>   Tensorex.zero([3, 2])[[1..-1, 1..-1]],
...>   &{&1, Tensorex.from_list([[ 1],
...>                             [-1]])})
{%Tensorex{data: %{}, shape: [2, 1]},
 %Tensorex{data: %{[1, 1] =>  1,
                   [2, 1] => -1}, shape: [3, 2]}}
Link to this function

kronecker_delta(dimension)

View Source

Specs

kronecker_delta(pos_integer()) :: t()

Returns a 2-rank tensor with all diagonal elements of 1.

iex> Tensorex.kronecker_delta(3)
%Tensorex{data: %{[0, 0] => 1,
                               [1, 1] => 1,
                                            [2, 2] => 1}, shape: [3, 3]}

Specs

map(t(), ([pos_integer(), ...], number() -> number()) | (number() -> number())) ::
  t()

Returns a tensor where each element is the result of invoking mapper on each corresponding element of the given tensor.

iex> Tensorex.map(Tensorex.from_list([[[ 0,  1, 2], [-3, -1,  1]],
...>                                  [[-4, -2, 0], [ 1,  0, -1]]]), &(&1 * &1))
%Tensorex{data: %{                 [0, 0, 1] => 1, [0, 0, 2] => 4, [0, 1, 0] => 9, [0, 1, 1] => 1, [0, 1, 2] => 1,
                  [1, 0, 0] => 16, [1, 0, 1] => 4,                 [1, 1, 0] => 1,                 [1, 1, 2] => 1}, shape: [2, 2, 3]}

iex> Tensorex.map(Tensorex.from_list([[[ 0,  1, 2], [-3, -1,  1]],
...>                                  [[-4, -2, 0], [ 1,  0, -1]]]), &(&1 + 3))
%Tensorex{data: %{[0, 0, 0] =>  3.0, [0, 0, 1] => 4, [0, 0, 2] => 5  ,                 [0, 1, 1] => 2  , [0, 1, 2] => 4,
                  [1, 0, 0] => -1  , [1, 0, 1] => 1, [1, 0, 2] => 3.0, [1, 1, 0] => 4, [1, 1, 1] => 3.0, [1, 1, 2] => 2}, shape: [2, 2, 3]}

iex> Tensorex.map(Tensorex.from_list([[-3, -1,  1],
...>                                  [-4, -2,  0],
...>                                  [ 1,  0, -1]]),
...>              fn
...>                value, [index, index] -> value * value
...>                value, _ -> value
...>              end)
%Tensorex{data: %{[0, 0] =>  9, [0, 1] => -1, [0, 2] => 1,
                  [1, 0] => -4, [1, 1] =>  4,
                  [2, 0] =>  1,               [2, 2] => 1}, shape: [3, 3]}

Specs

pop(t(), [integer() | Range.t(), ...]) :: {t() | number(), t()}

Pops the tensor or the number stored at the index out of the tensor.

iex> pop_in(
...>   Tensorex.from_list([[[ 1   ,   -3.1,   2  ],
...>                        [ 4   ,    5  ,  -6.1],
...>                        [ 0.9 ,  -91.2,  11  ]],
...>                       [[10   ,  -30.1,  20  ],
...>                        [40   ,   50  , -60.1],
...>                        [ 0.09, -910.2, 110  ]]])[[0]])
{%Tensorex{data: %{[0, 0] => 1,   [0, 1] => -3.1 , [0, 2] =>  2  ,
                   [1, 0] => 4,   [1, 1] =>  5   , [1, 2] => -6.1,
                   [2, 0] => 0.9, [2, 1] => -91.2, [2, 2] => 11  }, shape: [3, 3]},
 %Tensorex{data: %{[1, 0, 0] => 10   , [1, 0, 1] =>  -30.1, [1, 0, 2] =>  20  ,
                   [1, 1, 0] => 40   , [1, 1, 1] =>   50  , [1, 1, 2] => -60.1,
                   [1, 2, 0] =>  0.09, [1, 2, 1] => -910.2, [1, 2, 2] => 110  }, shape: [2, 3, 3]}}

iex> pop_in(
...>   Tensorex.from_list([[[ 1   ,   -3.1,   2  ],
...>                        [ 4   ,    5  ,  -6.1],
...>                        [ 0.9 ,  -91.2,  11  ]],
...>                       [[10   ,  -30.1,  20  ],
...>                        [40   ,   50  , -60.1],
...>                        [ 0.09, -910.2, 110  ]]])[[0, 1, 2]])
{-6.1, %Tensorex{data: %{[0, 0, 0] =>  1   , [0, 0, 1] =>   -3.1, [0, 0, 2] =>   2  ,
                         [0, 1, 0] =>  4   , [0, 1, 1] =>    5  ,
                         [0, 2, 0] =>  0.9 , [0, 2, 1] =>  -91.2, [0, 2, 2] =>  11  ,
                         [1, 0, 0] => 10   , [1, 0, 1] =>  -30.1, [1, 0, 2] =>  20  ,
                         [1, 1, 0] => 40   , [1, 1, 1] =>   50  , [1, 1, 2] => -60.1,
                         [1, 2, 0] =>  0.09, [1, 2, 1] => -910.2, [1, 2, 2] => 110  }, shape: [2, 3, 3]}}

Specs

triangular?(t()) :: boolean()

Checks if the given tensor is upper triangular or not.

iex> Tensorex.triangular?(Tensorex.from_list([[2, 1,  3],
...>                                          [0, 3,  6],
...>                                          [0, 0, -9]]))
true

iex> Tensorex.triangular?(Tensorex.from_list([[2, 0,  0],
...>                                          [0, 3,  0],
...>                                          [3, 0, -9]]))
false

iex> Tensorex.triangular?(Tensorex.from_list([[[2,  5], [0,  1]],
...>                                          [[0,  0], [0, -2]],
...>                                          [[0,  0], [0,  0]]]))
true

iex> Tensorex.triangular?(Tensorex.from_list([[[2,  5], [0,  1]],
...>                                          [[6,  0], [0, -2]],
...>                                          [[0,  0], [0,  0]]]))
false

Specs

zero([pos_integer(), ...]) :: t()

Returns a tensor with all of zero elements.

iex> Tensorex.zero([4, 4, 2])
%Tensorex{data: %{}, shape: [4, 4, 2]}

iex> Tensorex.zero([-5])
** (ArgumentError) expected a list of positive integers, got: [-5]