3. Basics

TensCalc computations and optimizations are defined using symbolic expressions supported by the class Tcalculus, named after tensor calculus.

3.1. What are Tensors?

In TensCalc, tensors are multi-dimensional real-valued arrays over which one performs numerical operations. The size() of a tensor is a vector that specifies how many entries the tensor has in each dimension. The following table shows common tensors and their sizes:

Common tensor types

name

number of dimensions

TensCalc’s size

mathematical set

scalar

0

[]

\(\mathbb{R}\)

\(n\)-vector

1

[n]

\(\mathbb{R^n}\)

\(n\)-by-\(m\) matrix

2

[n,m]

\(\mathbb{R^{n\times m}}\)

tensor with \(d\) of dimensions

d

[n1,n2,...,nd]

\(\mathbb{R^{n_1\times n_2\times \cdots\times n_d}}\)

Warning

It is common (at least within MATLAB©) to make no distinction between a scalar, a 1-vector, and a 1-by-1 matrix. In MATLAB© it is also common not to distinguish between an \(n\)-vector and an \(n\)-by-1 matrix. However, TensCalc does make a distinction between all these and does not allow, e.g., adding a 2-vector with a 2-by-1 matrix, without an explicit reshape() operation.

TensCalc is slightly more permissive with operations between scalars and tensors of larger sizes in that it does allow summations between a scalar and a tensor of any size, with the understanding that the scalar is added to every entry of the tensor, which is consistent with MATLAB©’s syntax.

See Using MATLAB© matrices in TensCalc symbolic expressions regarding the rules for automatic conversion of sizes between MATLAB© matrices and TensCalc tensors.

3.2. Building Tcalculus symbolic expressions

TensCalc symbolic expressions are supported by the class

class Tcalculus

but you never really need to call this class directly. Instead, symbolic expressions are built like regular MATLAB© expressions using many of the usual MATLAB© operators and functions, which have been overloaded to operate on TensCalc symbolic expressions.

Warning

To speed up operations, the class Tcalculus keeps some information in a few auxiliary global variables. Before defining a new computation or optimization it is a good idea to clear these variables with

clear all

If this is not possible, one can use the following method to just clear Tcalculus’s auxiliary global variables

Tcalculus.clear()

However, after using this method, any instances of the Tcalculus class that remains in memory becomes invalid and will lead to errors if used in a subsequent computations or optimizations without necessarily resulting in a syntax error. It is thus strongly advised to use clear all rather than Tcalculus.clear.

3.2.1. Symbolic variables

Most symbolic expressions start with symbolic variables that represent tensors that will only be assigned numeric values at code-execution time. Symbolic variables are created using

Tvariable name size
Parameters
  • name (character string) – Name of the variable to be created

  • size (vector of integers) – Size of the tensor as a vector of integers. When omitted, the empty size [] is assumed, which corresponds to a scalar.

The variable is created in the caller’s workspace:

>> clear all
>> Tvariable a [3,4];
>> whos
   Name      Size            Bytes  Class        Attributes
   a         3x4                39  Tcalculus
   ans       3x4                39  Tcalculus

Tvariable() can also be used as a regular MATLAB© function using the syntax:

Tvariable(name, size)
Returns

Tcalculus symbolic expression holding the symbolic variable

In this case, Tvariable() returns a symbolic expression that contains the variable. Note that the name of the symbolic variable is still given by name regardless of the name of the variable that you use to store it in:

>> clear all
>> y=Tvariable('a',[3,4]);
>> whos
   Name      Size            Bytes  Class        Attributes
   y         3x4                39  Tcalculus
>> disp(y)
variable1   = variable('a',) : [3,4]

3.2.2. Using MATLAB© matrices in TensCalc symbolic expressions

Often symbolic expressions involve regular MATLAB© matrices, as in adding a symbolic variable created with Tvariable() with a regular MATLAB© matrix:

>> Tvariable a [2,2]
>> b=a+[2,1;3,4]

The following rules are used to convert MATLAB© matrices to TensCalc symbolic expressions. In essence, the conversion is completely transparent unless the matrix is 1-by-1 or n-by-1.

Rules for automatic convertion between MATLAB© matrices and TensCalc tensors

MATLAB© variable

MATLAB©’s size

TensCalc variable

TensCalc’s size

1-by-1 matrix

[1,1]

scalar

[]

n-by-1 column matrix

[n,1]

n-vector

[n]

1-by-n row matrix

[1,n]

1-by-n tensor

[1,n]

m-by-n matrix

[m,n]

m-by-n tensor

[m,n]

n1-by-n2- … -by-nd matrix

[n1,n2,...,nd]

n1-by-n2- … -by-nd tensor

[n1,n2,...,nd]

TensCalc also provides a few functions that can be used to directly create symbolic tensors that can be useful when either the rules above do not have the desired effect (e.g., in the somewhat unlikely case wants to create a 1-by-1 tensor, rather than a scalar) or when it is more efficient to directly create the symbolic tensor.

Functions to create (constant) tensors

Usage

Description

Notes

Tzeros([n1, ..., nd])
Tzeros(n1, ..., nd)

Returns a tensor with all entries equal to 0. The tensor size can be provided as a single vector with the number of entries in all directions, or as multiple input parameters, one per dimension.

This function can be used interchangeably with the regular MATLAB© function zeros, as long as the the size conversion rules in Rules for automatic convertion between MATLAB© matrices and TensCalc tensors are appropriate.

Tones([n1, ..., nd])
Tones(n1, ..., nd)

Returns a tensor with all entries equal to 1. The tensor size is specified as in Tzeros().

This function can be used interchangeably with the regular MATLAB© function ones, as long as the the size conversion rules in Rules for automatic convertion between MATLAB© matrices and TensCalc tensors are appropriate.

Teye([n1, ..., nk, n1, ..., nk])
Teye(n1, ..., nk, n1, ..., nk)

Returns an “identity” tensor with all entries equal to zero, except for the entries with the indice 1 equal to the indice k+1, the indice 2 equal to the indice k+2, …, as in

(i1,i2,...,ik,i1,i2,...,ik)

These entries are all equal to 1.

For k=1, this function can be used interchangeably with the regular MATLAB© function eye, but is convenient to generate “identity” tensors with a larger number of dimensions.

Tconstant(mat, size)

Returns a tensor with entries given by the matrix mat and size specified by size as in Tzeros().

This function is typically used to override the size conversion rules in Rules for automatic convertion between MATLAB© matrices and TensCalc tensors.

Warning

When called with a single argument Tzeros(), Tones(), and Teye() differ from their MATLAB© counterparts: Tzeros() and Tones() return vectors (i.e., tensors with 1 dimension), rather than square matrices, and Teye() generates an error since it has no counter-part for vectors.

3.3. Accessing information about the size of symbolic variables

Functions to access information about symbolic expressions

Usage

Description

Notes

size(X)
[n1,n2,...,nd]=size(X)
size(X, dim)

Size of a tensor

Similar syntax to MATLAB©

ndims(X)

Number of dimensions in a tensor

Similar syntax to MATLAB©. Note that a scalar (which has empty size = []) always has 0 dimensions.

numel(X)

Number of elements in a tensor

Similar syntax to MATLAB©. Note that a scalar (which has empty size = []) always has 1 elements.

length(X)

Length of a tensor

Similar syntax to MATLAB©. Note that a scalar (which has empty size = []) always has 1 elements.

isempty(X)

True for an empty tensor

Similar syntax to MATLAB©. Note that a scalar (which has empty size = []) always has 1 elements so it is never empty.

3.4. Indexing and resizing symbolic variables

TensCalc uses the same syntax as MATLAB© to index tensors:

  • X(i,j,k,...) returns a subtensor formed by the elements of X with subscripts vectors i,j,k,...

    The resulting tensor has the same number of dimensions as X, with lengths along each dimension given by length(i), length(j), length(k),...

  • A colon : can be used as a subscript to indicate all subscripts on that particular dimension.

  • The keyword end can be used within an indexing expression to denote the last index. Specifically, end = size(X,k) when used as part of the kth index.

  • subsref(X,S) with a subscript reference structure S behaves as in regular MATLAB©, with he caveat that entries of the tensor must always be indexed using subscripts the type (). However, this does not preclude the construction of cells of Tcalculus objects.

Functions reshape and resize symbolic variables

Usage

Description

Notes

reshape(X, size)
reshape(X, n1, ..., nd)

Reshape array

Similar syntax to MATLAB©, except that it does not support using [] as one of the dimensions.

repmat(X, size)
repmat(X, n1, ..., nd)

Replicate and tile tensor

Similar syntax to MATLAB©, with the understanding that the number of dimensions of X must be strictly preserved. Often repmat() needs to be combined with reshape() to obtain the desired effect. For example to replicate twice a 3-vector X to create a 3-by-2 matrix by placing the copies of X side by side, one needs:

Y=repmat(reshape(X,3,1),1,2);

or, to create a 2-by-3 matrix by placing the copies of X one on top of the other, one needs:

Y=repmat(reshape(X,1,3),2,1);
cat(dim, A, B, ...)

Concatenate tensors along the dimension dim

Similar syntax to MATLAB©, with the understanding that the number of dimensions of the input tensors A,B,... must match for all but dimensions but dim. TensCalc will try to add singleton dimensions to make cat() succeed as best as it can. For example in the following code, the scalar variable a with size [] is augmented to the size [1,1] so that concatenation to a 2-by-3 matrix is possible:

>> Tvariable a [];
>> b=[a,a,a;a,a,a];
>> size(b)
ans =
    2     3

and in the following code, the vector variable b with size [3] is augmented to the size [3,1] so that concatenation to a 3-by-2 matrix is possible:

>> Tvariable b [3];
>> c=[b,b];
>> size(c)
ans =
    3     2
vertcat(A, B, ...)

Concatenate tensors along the 1st dimension, which is equivalent to cat(1,A,B,...)` and also to ``[A;B;...]

Similar syntax to MATLAB©, with the same caveats as cat().

horzcat(dim, A, B, ...)

Concatenate tensors along the 2nd dimension, which is equivalent to cat(2,A,B,...) and also to [A,B,...]

Similar syntax to MATLAB©, with the same caveats as cat().

vec2tensor(X, sz, subs)
vec2tensor(X, sz, subs, dim)

Expands a vector to a sparse tensor

In the 1st form
param X

Tcalculus n-vector (tensor with size [n])

param sz

vector with d integers

param subs

n-by-d matrix of subscripts

and returns a Tcalculus tensor Y with size sz, with the nonzero entries taken from X, with Y(subs(i,:))=X(i) for i=1:n

In the 2nd form
param X

Tcalculus tensor X with size(X,dim)=n

param sz

vector with d integers

param subs

n-by-d matrix subscripts

and returns a Tcalculus tensor Y with size similar to that of X, but the dim dimension expanded to the sizes in sz, and the nonzero entries taken from X, with Y(...,subs(i,:),...)=X(...,i,...) for i=1:n, where the ... denote indices of the dimensions before and after dim

This function is typically used to create sparse tensors from the entries of a (typically full) vector. See Creating structured matrices

Warning

Unlike MATLAB©, TensCalc does not allow for subscripted assignments, such as

A(1,2)=5

This functionality needs to be achieved with the concatenation operations cat(), vertcat(), horzcat().

3.4.1. Creating structured matrices

The function vec2tensor() is very useful to create structured matrices from vectors, to be used as optimization variables

  • Diagonal matrix:

    % Creates an NxN diagonal matrix
    Tvariable v [N];
    A=vec2tensor(v,[N,N],[1:N;1:N]');
    
  • Lower triangular matrix:

    % Creates an NxN lower triangular matrix
    [i,j]=find(ones(N));
    k=find(i>=j);
    Tvariable v length(k);
    A=vec2tensor(v,[N,N],[i(k),j(k)]);
    
  • Symmetric matrix:

    % Creates an NxN symmetric matrix
    [i,j]=find(ones(N));
    kl=find(i>j);
    k0=find(i==j);
    Tvariable v length(k0)+length(kl);
    A=vec2tensor([v;v(1:length(kl))],[N,N],[i(kl),j(kl);i(k0),j(k0);j(kl),i(kl)]);
    
  • Matrix with the same sparsity structure as a known matrix:

    % Creates a matrix with the sparsity structure of S
    [i,j]=find(S);
    Tvariable v length(i);
    A=vec2tensor(v,size(S),[i,j]);
    

In all these examples, one would set v to be an optimization variable, that implicitly represents the structured matrix.