# Tensors

>> Tensor Toolbox >> Tensor Types >> Tensors (dense)

Tensors are extensions of multidimensional arrays with additional operations defined on them. Here we explain the `tensor` class, for storing dense tensors, and the basics of creating and working with tensors. The `tensor` class is best described in the following reference:

- B. W. Bader and T. G. Kolda. Algorithm 862: MATLAB Tensor Classes for Fast Algorithm Prototyping, ACM Trans. Mathematical Software, 32:635-653, 2006. http://dx.doi.org/10.1145/1186785.1186794.

## Contents

- Creating a tensor from an array
- Creating a one-dimensional tensor
- Specifying trailing singleton dimensions in a tensor
- The constituent parts of a tensor
- Creating a tensor from its constituent parts
- Creating an empty tensor
- Use tenone to create a tensor of all ones
- Use tenzeros to create a tensor of all zeros
- Use tenrand to create a random tensor
- Use squeeze to remove singleton dimensions from a tensor
- Use double to convert a tensor to a (multidimensional) array
- Use ndims and size to get the size of a tensor
- Subscripted reference for a tensor
- Subscripted assignment for a tensor
- Using end for the last array index.
- Use find for subscripts of nonzero elements of a tensor
- Computing the Frobenius norm of a tensor
- Using reshape to rearrange elements in a tensor
- Using `unfold` and `vec` to convert a tensor to a matrix or vector
- Basic operations (plus, minus, and, or, etc.) on a tensor
- Using tenfun for elementwise operations on one or more tensors
- Use permute to reorder the modes of a tensor
- Symmetrizing and checking for symmetry in a tensor
- Displaying a tensor

    rng('default'); %<- Setting random seed for reproducibility of this script

## Creating a tensor from an array

The `tensor` command converts a (multidimensional) array to a tensor object.

    M = ones(4,3,2); %<-- A 4 x 3 x 2 array.
    X = tensor(M) %<-- Convert to a tensor object.

    X is a tensor of size 4 x 3 x 2
    	X(:,:,1) =
    	     1     1     1
    	     1     1     1
    	     1     1     1
    	     1     1     1
    	X(:,:,2) =
    	     1     1     1
    	     1     1     1
    	     1     1     1
    	     1     1     1

Optionally, you can specify a different shape for the tensor, so long as the input array has the right number of elements.

    X = tensor(M,[2 3 4]) %<-- M has 24 elements.

    X is a tensor of size 2 x 3 x 4
    	X(:,:,1) =
    	     1     1     1
    	     1     1     1
    	X(:,:,2) =
    	     1     1     1
    	     1     1     1
    	X(:,:,3) =
    	     1     1     1
    	     1     1     1
    	X(:,:,4) =
    	     1     1     1
    	     1     1     1

## Creating a one-dimensional tensor

The tensor class explicitly supports order-one tensors as well as trailing singleton dimensions, but the size must be explicit in the constructor. By default, a column array produces a 2-way tensor.

    X = tensor(rand(5,1)) %<-- Creates a 2-way tensor.

    X is a tensor of size 5 x 1
    	X(:,:) =
    	    0.8147
    	    0.9058
    	    0.1270
    	    0.9134
    	    0.6324

This is fixed by specifying the size explicitly.

    X = tensor(rand(5,1),5) %<-- Creates a 1-way tensor.

    X is a tensor of size 5
    	X(:) =
    	    0.0975
    	    0.2785
    	    0.5469
    	    0.9575
    	    0.9649

## Specifying trailing singleton dimensions in a tensor

Likewise, trailing singleton dimensions must be explictly specified.

    Y = tensor(rand(4,3,1)) %<-- Creates a 2-way tensor.

    Y is a tensor of size 4 x 3
    	Y(:,:) =
    	    0.1576    0.8003    0.7922
    	    0.9706    0.1419    0.9595
    	    0.9572    0.4218    0.6557
    	    0.4854    0.9157    0.0357

    Y = tensor(rand(4,3,1),[4 3 1]) %<-- Creates a 3-way tensor.

    Y is a tensor of size 4 x 3 x 1
    	Y(:,:,1) =
    	    0.8491    0.7431    0.7060
    	    0.9340    0.3922    0.0318
    	    0.6787    0.6555    0.2769
    	    0.7577    0.1712    0.0462

Unfortunately, the `whos` command does not report the size of 1D objects correctly (last checked for MATLAB 2006a).

    whos X Y %<-- Doesn't report the right size for X!

      Name      Size             Bytes  Class     Attributes

      X         1x1                384  tensor
      Y         4x3x1              456  tensor

## The constituent parts of a tensor

    X = tenrand([4 3 2]); %<-- Create data.
    X.data %<-- The array.

    ans(:,:,1) =

        0.0971    0.9502    0.7655
        0.8235    0.0344    0.7952
        0.6948    0.4387    0.1869
        0.3171    0.3816    0.4898

    ans(:,:,2) =

        0.4456    0.2760    0.1190
        0.6463    0.6797    0.4984
        0.7094    0.6551    0.9597
        0.7547    0.1626    0.3404

    X.size %<-- The size.

    ans =

         4     3     2

## Creating a tensor from its constituent parts

    Y = tensor(X.data,X.size) %<-- Copies X.

    Y is a tensor of size 4 x 3 x 2
    	Y(:,:,1) =
    	    0.0971    0.9502    0.7655
    	    0.8235    0.0344    0.7952
    	    0.6948    0.4387    0.1869
    	    0.3171    0.3816    0.4898
    	Y(:,:,2) =
    	    0.4456    0.2760    0.1190
    	    0.6463    0.6797    0.4984
    	    0.7094    0.6551    0.9597
    	    0.7547    0.1626    0.3404

## Creating an empty tensor

An empty constructor exists, primarily to support loading previously saved data in MAT-files.

    X = tensor %<-- Creates an empty tensor.

    X is a tensor of size [empty tensor]
    	X = []

## Use tenone to create a tensor of all ones

    X = tenones([3 4 2]) %<-- Creates a 3 x 4 x 2 tensor of ones.

    X is a tensor of size 3 x 4 x 2
    	X(:,:,1) =
    	     1     1     1     1
    	     1     1     1     1
    	     1     1     1     1
    	X(:,:,2) =
    	     1     1     1     1
    	     1     1     1     1
    	     1     1     1     1

## Use tenzeros to create a tensor of all zeros

    X = tenzeros([1 4 2]) %<-- Creates a 1 x 4 x 2 tensor of zeros.

    X is a tensor of size 1 x 4 x 2
    	X(:,:,1) =
    	     0     0     0     0
    	X(:,:,2) =
    	     0     0     0     0

## Use tenrand to create a random tensor

    X = tenrand([5 4 2]) %<-- Creates a random 5 x 4 x 2 tensor.

    X is a tensor of size 5 x 4 x 2
    	X(:,:,1) =
    	    0.5853    0.6991    0.1493    0.2435
    	    0.2238    0.8909    0.2575    0.9293
    	    0.7513    0.9593    0.8407    0.3500
    	    0.2551    0.5472    0.2543    0.1966
    	    0.5060    0.1386    0.8143    0.2511
    	X(:,:,2) =
    	    0.6160    0.5497    0.3804    0.7792
    	    0.4733    0.9172    0.5678    0.9340
    	    0.3517    0.2858    0.0759    0.1299
    	    0.8308    0.7572    0.0540    0.5688
    	    0.5853    0.7537    0.5308    0.4694

## Use squeeze to remove singleton dimensions from a tensor

    squeeze(Y) %<-- Removes singleton dimensions.

    ans is a tensor of size 4 x 3 x 2
    	ans(:,:,1) =
    	    0.0971    0.9502    0.7655
    	    0.8235    0.0344    0.7952
    	    0.6948    0.4387    0.1869
    	    0.3171    0.3816    0.4898
    	ans(:,:,2) =
    	    0.4456    0.2760    0.1190
    	    0.6463    0.6797    0.4984
    	    0.7094    0.6551    0.9597
    	    0.7547    0.1626    0.3404

## Use double to convert a tensor to a (multidimensional) array

    double(Y) %<-- Converts Y to a standard MATLAB array.

    ans(:,:,1) =

        0.0971    0.9502    0.7655
        0.8235    0.0344    0.7952
        0.6948    0.4387    0.1869
        0.3171    0.3816    0.4898

    ans(:,:,2) =

        0.4456    0.2760    0.1190
        0.6463    0.6797    0.4984
        0.7094    0.6551    0.9597
        0.7547    0.1626    0.3404

    Y.data %<-- Same thing.

    ans(:,:,1) =

        0.0971    0.9502    0.7655
        0.8235    0.0344    0.7952
        0.6948    0.4387    0.1869
        0.3171    0.3816    0.4898

    ans(:,:,2) =

        0.4456    0.2760    0.1190
        0.6463    0.6797    0.4984
        0.7094    0.6551    0.9597
        0.7547    0.1626    0.3404

## Use ndims and size to get the size of a tensor

    ndims(Y) %<-- Number of dimensions (or ways).

    ans =

         3

    size(Y) %<-- Row vector with the sizes of all dimension.

    ans =

         4     3     2

    size(Y,3) %<-- Size of a single dimension.

    ans =

         2

## Subscripted reference for a tensor

    X = tenrand([3 4 2 1]); %<-- Create a 3 x 4 x 2 x 1 random tensor.
    X(1,1,1,1) %<-- Extract a single element.

    ans =

        0.0119

It is possible to extract a subtensor that contains a single element. Observe that singleton dimensions are not dropped unless they are specifically specified, e.g., as above.

    X(1,1,1,:) %<-- Produces a tensor of order 1 and size 1.

    ans is a tensor of size 1
    	ans(:) =
    	    0.0119

In general, specified dimensions are dropped from the result. Here we specify the second and third dimension.

    X(:,1,1,:) %<-- Produces a tensor of size 3 x 1.

    ans is a tensor of size 3 x 1
    	ans(:,:) =
    	    0.0119
    	    0.3371
    	    0.1622

Moreover, the subtensor is automatically renumbered/resized in the same way that MATLAB works for arrays except that singleton dimensions are handled explicitly.

    X(1:2,[2 4],1,:) %<-- Produces a tensor of size 2 x 2 x 1.

    ans is a tensor of size 2 x 2 x 1
    	ans(:,:,1) =
    	    0.7943    0.6541
    	    0.3112    0.6892

It's also possible to extract a list of elements by passing in an array of subscripts or a column array of linear indices.

    subs = [1,1,1,1; 3,4,2,1]; X(subs) %<-- Extract 2 values by subscript.

    ans =

        0.0119
        0.9619

    inds = [1; 24]; X(inds) %<-- Same thing with linear indices.

    ans =

        0.0119
        0.9619

The difference between extracting a subtensor and a list of linear indices is ambiguous for 1-dimensional tensors. We can specify 'extract' as a second argument whenever we are using a list of subscripts.

    X = tenrand(10); %<-- Create a random tensor.
    X([1:6]') %<-- Extract a subtensor.

    ans is a tensor of size 6
    	ans(:) =
    	    0.0046
    	    0.7749
    	    0.8173
    	    0.8687
    	    0.0844
    	    0.3998

    X([1:6]','extract') %<-- Same thing *but* result is a vector.

    ans =

        0.0046
        0.7749
        0.8173
        0.8687
        0.0844
        0.3998

## Subscripted assignment for a tensor

We can assign a single element, an entire subtensor, or a list of values for a tensor.

    X = tenrand([3,4,2]); %<-- Create some data.
    X(1,1,1) = 0 %<-- Replaces the (1,1,1) element.

    X is a tensor of size 3 x 4 x 2
    	X(:,:,1) =
    	         0    0.1361    0.5499    0.6221
    	    0.2638    0.8693    0.1450    0.3510
    	    0.1455    0.5797    0.8530    0.5132
    	X(:,:,2) =
    	    0.4018    0.1233    0.4173    0.9448
    	    0.0760    0.1839    0.0497    0.4909
    	    0.2399    0.2400    0.9027    0.4893

    X(1:2,1:2,1) = ones(2,2) %<-- Replaces a 2 x 2 subtensor.

    X is a tensor of size 3 x 4 x 2
    	X(:,:,1) =
    	    1.0000    1.0000    0.5499    0.6221
    	    1.0000    1.0000    0.1450    0.3510
    	    0.1455    0.5797    0.8530    0.5132
    	X(:,:,2) =
    	    0.4018    0.1233    0.4173    0.9448
    	    0.0760    0.1839    0.0497    0.4909
    	    0.2399    0.2400    0.9027    0.4893

    X([1 1 1;1 1 2]) = [5;7] %<-- Replaces the (1,1,1) and (1,1,2)
    			 %elements.

    X is a tensor of size 3 x 4 x 2
    	X(:,:,1) =
    	    5.0000    1.0000    0.5499    0.6221
    	    1.0000    1.0000    0.1450    0.3510
    	    0.1455    0.5797    0.8530    0.5132
    	X(:,:,2) =
    	    7.0000    0.1233    0.4173    0.9448
    	    0.0760    0.1839    0.0497    0.4909
    	    0.2399    0.2400    0.9027    0.4893

    X([1;13]) = [5;7] %<-- Same as above using linear indices.

    X is a tensor of size 3 x 4 x 2
    	X(:,:,1) =
    	    5.0000    1.0000    0.5499    0.6221
    	    1.0000    1.0000    0.1450    0.3510
    	    0.1455    0.5797    0.8530    0.5132
    	X(:,:,2) =
    	    7.0000    0.1233    0.4173    0.9448
    	    0.0760    0.1839    0.0497    0.4909
    	    0.2399    0.2400    0.9027    0.4893

It is possible to grow the tensor automatically by assigning elements outside the original range of the tensor.

    X(1,1,3) = 1 %<-- Grows the size of the tensor.

    X is a tensor of size 3 x 4 x 3
    	X(:,:,1) =
    	    5.0000    1.0000    0.5499    0.6221
    	    1.0000    1.0000    0.1450    0.3510
    	    0.1455    0.5797    0.8530    0.5132
    	X(:,:,2) =
    	    7.0000    0.1233    0.4173    0.9448
    	    0.0760    0.1839    0.0497    0.4909
    	    0.2399    0.2400    0.9027    0.4893
    	X(:,:,3) =
    	     1     0     0     0
    	     0     0     0     0
    	     0     0     0     0

## Using end for the last array index.

    X(end,end,end)  %<-- Same as X(3,4,3).

    ans =

         0

    X(1,1,1:end-1)  %<-- Same as X(1,1,1:2).

    ans is a tensor of size 2
    	ans(:) =
    	     5
    	     7

It is also possible to use `end` to index past the end of an array.

    X(1,1,end+1) = 5 %<-- Same as X(1,1,4).

    X is a tensor of size 3 x 4 x 4
    	X(:,:,1) =
    	    5.0000    1.0000    0.5499    0.6221
    	    1.0000    1.0000    0.1450    0.3510
    	    0.1455    0.5797    0.8530    0.5132
    	X(:,:,2) =
    	    7.0000    0.1233    0.4173    0.9448
    	    0.0760    0.1839    0.0497    0.4909
    	    0.2399    0.2400    0.9027    0.4893
    	X(:,:,3) =
    	     1     0     0     0
    	     0     0     0     0
    	     0     0     0     0
    	X(:,:,4) =
    	     5     0     0     0
    	     0     0     0     0
    	     0     0     0     0

## Use find for subscripts of nonzero elements of a tensor

The `find` function returns a list of nonzero subscripts for a tensor. Note that differs from the standard version, which returns linear indices.

    X = tensor(floor(3*rand(2,2,2))) %<-- Generate some data.

    X is a tensor of size 2 x 2 x 2
    	X(:,:,1) =
    	     1     1
    	     2     0
    	X(:,:,2) =
    	     2     0
    	     1     1

    [S,V] = find(X) %<-- Find all the nonzero subscripts and values.

    S =

         1     1     1
         2     1     1
         1     2     1
         1     1     2
         2     1     2
         2     2     2

    V =

         1
         2
         1
         2
         1
         1

    S = find(X >= 2) %<-- Find subscripts of values >= 2.

    S =

         2     1     1
         1     1     2

    V = X(S) %<-- Extract the corresponding values from X.

    V =

         2
         2

## Computing the Frobenius norm of a tensor

`norm` computes the Frobenius norm of a tensor. This corresponds to the Euclidean norm of the vectorized tensor.

    T = tensor(randn(2,3,3));
    norm(T)

    ans =

        4.9219

## Using reshape to rearrange elements in a tensor

`reshape` reshapes a tensor into a given size array. The total number of elements in the tensor cannot change.

    X = tensor(randi(10,3,2,3));
    Y = reshape(X,[3,3,2])

    Y is a tensor of size 3 x 3 x 2
    	Y(:,:,1) =
    	     8     2     8
    	     2     4     1
    	     7     7    10
    	Y(:,:,2) =
    	     8     5     6
    	     5     4     9
    	     5     6     8

## Using `unfold` and `vec` to convert a tensor to a matrix or vector

    X = tenrand([2 3 2])
    X1 = unfold(X,1) % mode-1 unfolding
    X2 = unfold(X,2) % mode-2 unfolding
    X3 = unfold(X,3) % mode-3 unfolding
    xvec = vec(X)

    X is a tensor of size 2 x 3 x 2
    	X(:,:,1) =
    	    0.6443    0.8116    0.3507
    	    0.3786    0.5328    0.9390
    	X(:,:,2) =
    	    0.8759    0.6225    0.2077
    	    0.5502    0.5870    0.3012

    X1 =

        0.6443    0.8116    0.3507    0.8759    0.6225    0.2077
        0.3786    0.5328    0.9390    0.5502    0.5870    0.3012

    X2 =

        0.6443    0.3786    0.8759    0.5502
        0.8116    0.5328    0.6225    0.5870
        0.3507    0.9390    0.2077    0.3012

    X3 =

        0.6443    0.3786    0.8116    0.5328    0.3507    0.9390
        0.8759    0.5502    0.6225    0.5870    0.2077    0.3012

    xvec =

        0.6443
        0.3786
        0.8116
        0.5328
        0.3507
        0.9390
        0.8759
        0.5502
        0.6225
        0.5870
        0.2077
        0.3012

## Basic operations (plus, minus, and, or, etc.) on a tensor

The tensor object supports many basic operations, illustrated here.

    A = tensor(floor(3*rand(2,3,2)))
    B = tensor(floor(3*rand(2,3,2)))

    A is a tensor of size 2 x 3 x 2
    	A(:,:,1) =
    	     1     2     0
    	     0     0     0
    	A(:,:,2) =
    	     0     0     1
    	     1     2     0
    B is a tensor of size 2 x 3 x 2
    	B(:,:,1) =
    	     2     1     0
    	     2     0     1
    	B(:,:,2) =
    	     1     1     0
    	     0     2     0

    A & B %<-- Calls and.

    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	   1   1   0
    	   0   0   0
    	ans(:,:,2) =
    	   0   0   0
    	   0   1   0

    A | B %<-- Calls or.

    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	   1   1   0
    	   1   0   1
    	ans(:,:,2) =
    	   1   1   1
    	   1   1   0

    xor(A,B) %<-- Calls xor.

    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	   0   0   0
    	   1   0   1
    	ans(:,:,2) =
    	   1   1   1
    	   1   0   0

    A==B %<-- Calls eq.

    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	   0   0   1
    	   0   1   0
    	ans(:,:,2) =
    	   0   0   0
    	   0   1   1

    A~=B %<-- Calls neq.

    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	   1   1   0
    	   1   0   1
    	ans(:,:,2) =
    	   1   1   1
    	   1   0   0

    A>B %<-- Calls gt.

    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	   0   1   0
    	   0   0   0
    	ans(:,:,2) =
    	   0   0   1
    	   1   0   0

    A>=B %<-- Calls ge.

    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	   0   1   1
    	   0   1   0
    	ans(:,:,2) =
    	   0   0   1
    	   1   1   1

    A<B %<-- Calls lt.

    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	   1   0   0
    	   1   0   1
    	ans(:,:,2) =
    	   1   1   0
    	   0   0   0

    A<=B %<-- Calls le.

    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	   1   0   1
    	   1   1   1
    	ans(:,:,2) =
    	   1   1   0
    	   0   1   1

    ~A %<-- Calls not.

    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	   0   0   1
    	   1   1   1
    	ans(:,:,2) =
    	   1   1   0
    	   0   0   1

    +A %<-- Calls uplus.

    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	     1     2     0
    	     0     0     0
    	ans(:,:,2) =
    	     0     0     1
    	     1     2     0

    -A %<-- Calls uminus.

    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	    -1    -2     0
    	     0     0     0
    	ans(:,:,2) =
    	     0     0    -1
    	    -1    -2     0

    A+B %<-- Calls plus.

    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	     3     3     0
    	     2     0     1
    	ans(:,:,2) =
    	     1     1     1
    	     1     4     0

    A-B %<-- Calls minus.

    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	    -1     1     0
    	    -2     0    -1
    	ans(:,:,2) =
    	    -1    -1     1
    	     1     0     0

    A.*B %<-- Calls times.

    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	     2     2     0
    	     0     0     0
    	ans(:,:,2) =
    	     0     0     0
    	     0     4     0

    5*A %<-- Calls mtimes.

    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	     5    10     0
    	     0     0     0
    	ans(:,:,2) =
    	     0     0     5
    	     5    10     0

    A.^B %<-- Calls power.

    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	     1     2     1
    	     0     1     0
    	ans(:,:,2) =
    	     0     0     1
    	     1     4     1

    A.^2 %<-- Calls power.

    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	     1     4     0
    	     0     0     0
    	ans(:,:,2) =
    	     0     0     1
    	     1     4     0

    A.\B %<-- Calls ldivide.

    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	    2.0000    0.5000       NaN
    	       Inf       NaN       Inf
    	ans(:,:,2) =
    	   Inf   Inf     0
    	     0     1   NaN

    A./2 %<-- Calls rdivide.

    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	    0.5000    1.0000         0
    	         0         0         0
    	ans(:,:,2) =
    	         0         0    0.5000
    	    0.5000    1.0000         0

    A./B %<-- Calls rdivide (but beware divides by zero!)

    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	    0.5000    2.0000       NaN
    	         0       NaN         0
    	ans(:,:,2) =
    	     0     0   Inf
    	   Inf     1   NaN

## Using tenfun for elementwise operations on one or more tensors

The function `tenfun` applies a specified function to a number of tensors. This can be used for any function that is not predefined for tensors.

    tenfun(@(x)(x+1),A) %<-- Increment every element of A by one.

    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	     2     3     1
    	     1     1     1
    	ans(:,:,2) =
    	     1     1     2
    	     2     3     1

    tenfun(@max,A,B) %<-- Max of A and B, elementwise.

    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	     2     2     0
    	     2     0     1
    	ans(:,:,2) =
    	     1     1     1
    	     1     2     0

    C = tensor(floor(5*rand(2,3,2))) %<-- Create another tensor.
    tenfun(@median,A,B,C) %<-- Elementwise means for A, B, and C.

    C is a tensor of size 2 x 3 x 2
    	C(:,:,1) =
    	     1     2     0
    	     1     2     1
    	C(:,:,2) =
    	     4     4     2
    	     0     3     2
    ans is a tensor of size 2 x 3 x 2
    	ans(:,:,1) =
    	     1     2     0
    	     1     0     1
    	ans(:,:,2) =
    	     1     1     1
    	     0     2     0

## Use permute to reorder the modes of a tensor

    X = tensor(1:24,[3 4 2]) %<-- Create a tensor.

    X is a tensor of size 3 x 4 x 2
    	X(:,:,1) =
    	     1     4     7    10
    	     2     5     8    11
    	     3     6     9    12
    	X(:,:,2) =
    	    13    16    19    22
    	    14    17    20    23
    	    15    18    21    24

    permute(X,[3 2 1]) %<-- Reverse the modes.

    ans is a tensor of size 2 x 4 x 3
    	ans(:,:,1) =
    	     1     4     7    10
    	    13    16    19    22
    	ans(:,:,2) =
    	     2     5     8    11
    	    14    17    20    23
    	ans(:,:,3) =
    	     3     6     9    12
    	    15    18    21    24

Permuting a 1-dimensional tensor works correctly.

    X = tensor(1:4,4); %<-- Create a 1-way tensor.
    permute(X,1) %<-- Call permute with *only* one dimension.

    ans is a tensor of size 4
    	ans(:) =
    	     1
    	     2
    	     3
    	     4

## Symmetrizing and checking for symmetry in a tensor

A tensor can be symmetrized in a collection of modes with the command `symmetrize`. The new, symmetric tensor is formed by averaging over all elements in the tensor which are required to be equal.

    W = tensor(rand(4,4,4));
    Y=symmetrize(X);

A second argument can also be passed to `symmetrize` which specifies an array of modes with respect to which the tensor should be symmetrized.

    X = tensor(rand(3,2,3));
    Z = symmetrize(X,[1,3]);

Additionally, one can check for symmetry in tensors with the `issymmetric` function. Similar to `symmetrize`, a collection of modes can be passed as a second argument.

    issymmetric(Y)
    issymmetric(Z,[1,3])

    ans =

      logical

       1

    ans =

      logical

       1

## Displaying a tensor

The function `disp` can be used to display a tensor and correctly displays very small and large elements.

    X = tensor(1:24,[3 4 2]); %<-- Create a 3 x 4 x 2 tensor.
    X(:,:,1) = X(:,:,1) * 1e15; %<-- Make the first slice very large.
    X(:,:,2) = X(:,:,2) * 1e-15; %<-- Make the second slice very small.
    disp(X)

    ans is a tensor of size 3 x 4 x 2
    	ans(:,:,1) =
    	   1.0e+16 *
    	    0.1000    0.4000    0.7000    1.0000
    	    0.2000    0.5000    0.8000    1.1000
    	    0.3000    0.6000    0.9000    1.2000
    	ans(:,:,2) =
    	   1.0e-13 *
    	    0.1300    0.1600    0.1900    0.2200
    	    0.1400    0.1700    0.2000    0.2300
    	    0.1500    0.1800    0.2100    0.2400