# Tensors

*Tensors* are mathematical objects that give generalizations of vectors and matrices. In the Wolfram System, a tensor is represented as a set of lists, nested to a certain number of levels. The nesting level is the *rank* of the tensor.

Interpretations of nested lists.

A tensor of rank k is essentially a k‐dimensional table of values. To be a true rank k tensor, it must be possible to arrange the elements in the table in a k‐dimensional cuboidal array. There can be no holes or protrusions in the cuboid.

The *indices* that specify a particular element in the tensor correspond to the coordinates in the cuboid. The *dimensions* of the tensor correspond to the side lengths of the cuboid.

One simple way that a rank k tensor can arise is in giving a table of values for a function of k variables. In physics, the tensors that occur typically have indices which run over the possible directions in space or spacetime. Notice, however, that there is no built‐in notion of covariant and contravariant tensor indices in the Wolfram System: you have to set these up explicitly using metric tensors.

Table[f,{i_{1},n_{1}},{i_{2},n_{2}},…,{i_{k},n_{k}}] | |

create an n_{1}×n_{2}×…×n_{k} tensor whose elements are the values of f | |

Array[a,{n_{1},n_{2},…,n_{k}}] | create an n_{1}×n_{2}×…×n_{k} tensor with elements given by applying a to each set of indices |

ArrayQ[t,n] | test whether t is a tensor of rank n |

Dimensions[t] | give a list of the dimensions of a tensor |

ArrayDepth[t] | find the rank of a tensor |

MatrixForm[t] | print with the elements of t arranged in a two‐dimensional array |

Functions for creating and testing the structure of tensors.

The rank of a tensor is equal to the number of indices needed to specify each element. You can pick out subtensors by using a smaller number of indices.

Transpose[t] | transpose the first two indices in a tensor |

Transpose[t,{p_{1},p_{2},…}] | transpose the indices in a tensor so that the k becomes the p_{k} |

Tr[t,f] | form the generalized trace of the tensor t |

Outer[f,t_{1},t_{2}] | form the generalized outer product of the tensors t_{1} and t_{2} with "multiplication operator" f |

t_{1}.t_{2} | form the dot product of t_{1} and t_{2} (last index of t_{1} contracted with first index of t_{2}) |

Inner[f,t_{1},t_{2},g] | form the generalized inner product, with "multiplication operator" f and "addition operator" g |

Tensor manipulation operations.

You can think of a rank k tensor as having k "slots" into which you insert indices. Applying Transpose is effectively a way of reordering these slots. If you think of the elements of a tensor as forming a k‐dimensional cuboid, you can view Transpose as effectively rotating (and possibly reflecting) the cuboid.

In the most general case, Transpose allows you to specify an arbitrary reordering to apply to the indices of a tensor. The function Transpose[T,{p_{1},p_{2},…,p_{k}}] gives you a new tensor T^{′} such that the value of T^{′}_{i1 i2 … ik} is given by T_{ip1 ip2 … ipk}.

If you originally had an n_{p1}×n_{p2}×…×n_{pk} tensor, then by applying Transpose, you will get an n_{1}×n_{2}×…×n_{k} tensor.

If you have a tensor that contains lists of the same length at different levels, then you can use Transpose to effectively collapse different levels.

You can also use Tr to extract diagonal elements of a tensor.

Outer products, and their generalizations, are a way of building higher‐rank tensors from lower‐rank ones. Outer products are also sometimes known as direct, tensor, or Kronecker products.

From a structural point of view, the tensor you get from Outer[f,t,u] has a copy of the structure of u inserted at the "position" of each element in t. The elements in the resulting structure are obtained by combining elements of t and u using the function f.

If you take the generalized outer product of an m_{1}×m_{2}×…×m_{r} tensor and an n_{1}×n_{2}×…×n_{s} tensor, you get an m_{1}×…×m_{r}×n_{1}×…×n_{s} tensor. If the original tensors have ranks r and s, your result will be a rank r+s tensor.

In terms of indices, the result of applying Outer to two tensors T_{i1 i2 … ir} and U_{j1 j2 … js} is the tensor V_{i1 i2 … irj1 j2 … js} with elements f[T_{i1 i2 … ir},U_{j1 j2 … js}].

In doing standard tensor calculations, the most common function f to use in Outer is Times, corresponding to the standard outer product.

Particularly in doing combinatorial calculations, however, it is often convenient to take f to be List. Using Outer, you can then get combinations of all possible elements in one tensor, with all possible elements in the other.

In constructing Outer[f,t,u] you effectively insert a copy of u at every point in t. To form Inner[f,t,u], you effectively combine and collapse the last dimension of t and the first dimension of u. The idea is to take an m_{1}×m_{2}×…×m_{r} tensor and an n_{1}×n_{2}×…×n_{s} tensor, with m_{r}=n_{1}, and get an m_{1}×m_{2}×…×m_{r-1}×n_{2}×…×n_{s} tensor as the result.

The simplest examples are with vectors. If you apply Inner to two vectors of equal length, you get a scalar. Inner[f,v_{1},v_{2},g] gives a generalization of the usual scalar product, with f playing the role of multiplication, and g playing the role of addition.

You can think of Inner as performing a "contraction" of the last index of one tensor with the first index of another. If you want to perform contractions across other pairs of indices, you can do so by first transposing the appropriate indices into the first or last position, then applying Inner, and then transposing the result back.

In many applications of tensors, you need to insert signs to implement antisymmetry. The function Signature[{i_{1},i_{2},…}], which gives the signature of a permutation, is often useful for this purpose.

Outer[f,t_{1},t_{2},…] | form a generalized outer product by combining the lowest‐level elements of t_{1},t_{2},… |

Outer[f,t_{1},t_{2},…,n] | treat only sublists at level n as separate elements |

Outer[f,t_{1},t_{2},…,n_{1},n_{2},…] | treat only sublists at level n_{i} in t_{i} as separate elements |

Inner[f,t_{1},t_{2},g] | form a generalized inner product using the lowest‐level elements of t_{1} |

Inner[f,t_{1},t_{2},g,n] | contract index n of the first tensor with the first index of the second tensor |

Treating only certain sublists in tensors as separate elements.

ArrayFlatten[t,r] | create a flat rank r tensor from a rank r tensor of rank r tensors |

ArrayFlatten[t] | flatten a matrix of matrices (equivalent to ArrayFlatten[t,2]) |