tensor_basics.rst
Tensor basics
=============
Creating a tensor
-----------------
A tensor is nothing more than a multi-dimensional array.
Let's take for this example the tensor :math:`\tilde X` defined by its frontal slices:
.. math::
X_1 =
\left[
\begin{matrix}
0 & 2 & 4 & 6\\
8 & 10 & 12 & 14\\
16 & 18 & 20 & 22
\end{matrix}
\right]
\text{and}
X_2 =
\left[
\begin{matrix}
1 & 3 & 5 & 7\\
9 & 11 & 13 & 15\\
17 & 19 & 21 & 23
\end{matrix}
\right]
In Python, this array can be expressed as a numpy array::
>>> import numpy as np
>>> X = np.arange(24).reshape((3, 4, 2))
You can view the frontal slices by fixing the last axis::
>>> X[..., 0]
array([[ 0, 2, 4, 6],
[ 8, 10, 12, 14],
[16, 18, 20, 22]])
>>> X[..., 1]
array([[ 1, 3, 5, 7],
[ 9, 11, 13, 15],
[17, 19, 21, 23]])
Unfolding
---------
Also called **matrization**, **unfolding** a tensor is done by reading the element in a given way as to obtain a matrix instead of a tensor.
For a tensor of size :math:`(I_1, I_2, \cdots, I_n)`, the k-mode unfolding of this tensor will be of size :math:`(I_k, I_1 \times \cdots \times I_{k-1} \times I_{k+1} \cdots \times I_n)`.
.. important::
In tensorly we use an unfolding different from the classical one as defined in [1]_ for better performance.
Given a tensor :math:`\tilde X \in \mathbb{R}^{I_1 \times I_2 \times \cdots \times I_N}`, the
mode-n unfolding of :math:`\tilde X` is a matrix :math:`\mathbf{X}_{[n]} \in \mathbb{R}^{I_n, I_M}`,
with :math:`M = \prod_{\substack{k=1,\\k \neq n}}^N I_k` and is defined by
the mapping from element :math:`(i_1, i_2, \cdots, i_N)` to :math:`(i_n, j)`, with
.. math::
j = \sum_{\substack{k=1,\\k \neq n}}^N i_k \times \prod_{m=k+1}^N I_m.
.. warning::
Traditionally, mode-1 unfolding denotes the unfolding along the first dimension.
However, to be consistent with the Python indexing that always starts at zero,
in tensorly, unfolding also starts at zero!
Therefore ``unfold(tensor, 0)`` will unfold said tensor along its first dimension!
For instance, using the :math:`\tilde X` previously defined, the 0-mode unfolding of :math:`\tilde X`:
.. math::
\tilde X_{[0]} =
\left[ \begin{matrix}
0 & 1 & 2 & 3 & 4 & 5 & 6 & 7\\
8 & 9 & 10 & 11 & 12 & 13 & 14 & 15\\
16 & 17 & 18 & 19 & 20 & 21 & 22 & 23\\
\end{matrix} \right]
The 1-mode unfolding is given by:
.. math::
\tilde X_{[1]} =
\left[ \begin{matrix}
0 & 1 & 8 & 9 & 16 & 17\\
2 & 3 & 10 & 11 & 18 & 19\\
4 & 5 & 12 & 13 & 20 & 21\\
6 & 7 & 14 & 15 & 22 & 23\\
\end{matrix} \right]
Finally, the 2-mode unfolding is the unfolding along the last axis:
.. math::
\tilde X_{[2]} =
\left[ \begin{matrix}
0 & 2 & 4 & 6 & 8 & 10 & 12 & 14 & 16 & 18 & 20 & 22\\
1 & 3 & 5 & 7 & 9 & 11 & 13 & 15 & 17 & 19 & 21 & 23\\
\end{matrix} \right]
In tensorly:
.. code-block:: python
>>> unfold(X, 0) # mode-1 unfolding
array([[ 0, 1, 2, 3, 4, 5, 6, 7],
[ 8, 9, 10, 11, 12, 13, 14, 15],
[16, 17, 18, 19, 20, 21, 22, 23]])
>>> unfold(X, 1) # mode-2 unfolding
array([[ 0, 1, 8, 9, 16, 17],
[ 2, 3, 10, 11, 18, 19],
[ 4, 5, 12, 13, 20, 21],
[ 6, 7, 14, 15, 22, 23]])
>>> unfold(X, 2) # mode-3 unfolding
array([[ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22],
[ 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23]])
Folding
-------
You can **fold** an unfolded tensor back from matrix to full tensor using the :func:`tensorly.base.fold` function.
.. code-block:: python
>>> from tensorly import fold
>>> unfolding = unfold(X, 1)
>>> original_shape = X.shape
>>> fold(unfolding, 1, original_shape)
array([[[ 0, 1],
[ 2, 3],
[ 4, 5],
[ 6, 7]],
[[ 8, 9],
[10, 11],
[12, 13],
[14, 15]],
[[16, 17],
[18, 19],
[20, 21],
[22, 23]]])
References
----------
.. [1] T.G.Kolda and B.W.Bader, "Tensor Decompositions and Applications",
SIAM REVIEW, vol. 51, n. 3, pp. 455-500, 2009.