Function Repository Resource:

CPDecomposition

Source Notebook

Compute the canonical polyadic (CP) decomposition of a tensor

Contributed by: Nikolay Murzin

ResourceFunction["CPDecomposition"][tensor]

returns a list of matrix factors decomposing tensor.

ResourceFunction["CPDecomposition"][tensor,rank]

provides a positive integer rank for decomposing tensor.

ResourceFunction["CPDecomposition"][,property]

returns a property or a list of properties of the decomposition.

ResourceFunction["CPDecomposition"][,All]

returns an association with all the properties.

Details and Options

The CP (canonical polyadic) decomposition is also known as the CANDECOMP/PARAFAC decomposition.
The CP decomposition expresses a tensor as the sum of rank-1 tensors, which can be useful for dimensionality reduction, compression, and revealing latent structure in data.
Given an input tensor and a desired tensor rank, ResourceFunction["CPDecomposition"] returns a list of factor matrices representing the decomposed tensor.
In ResourceFunction["CPDecomposition"][tensor,rank], if rank, the second dimension of each factor, is set to Automatic, the default rank is heuristically determined as Min[16,Total[dims]-Max[dims]], where dims represents the dimensions of the input tensor.
ResourceFunction["CPDecomposition"] uses the alternating least squares (ALS) algorithm to compute the decomposition.
The ALS algorithm is a randomized algorithm. Due to this, ResourceFunction["CPDecomposition"] may return different results on different evaluations. Use SeedRandom or provide "InitialFactors" for reproducibility.
The argument property can be any of the following:
"Factors"list of matrix factors decomposing an input tensor
"ReconstructedTensor"reconstructed tensor
"Error"total squared error between input and reconstructed tensors
"Iterations"number of iterations performed
"Rank"rank of the decompostion
ResourceFunction["CPDecomposition"] takes the following options:
MaxIterations100maximum number of iterations for the ALS algorithm
Tolerance10-6tolerance threshold for convergence
"InitialFactors"Automaticinitial list of factors for the ALS algorithm
In the setting of the "InitialFactors" option, the ith factor should have dimensions equal to {di,rank} with di being the tensor’s ith dimension.

Examples

Basic Examples (1) 

Compute the CP decomposition of a random rank-3 tensor:

In[1]:=
ResourceFunction["CPDecomposition"][RandomReal[{-1, 1}, {3, 4, 5}]]
Out[1]=

Scope (4) 

Return all the properties of the CP decomposition:

In[2]:=
tensor = RandomReal[{-1, 1}, {3, 4, 5}];
ResourceFunction["CPDecomposition"][
 RandomReal[{-1, 1}, {3, 4, 5}], All]
Out[3]=

Return a single property:

In[4]:=
ResourceFunction["CPDecomposition"][tensor, "ReconstructedTensor"]
Out[4]=

Specify a different decomposition rank:

In[5]:=
tensor = RandomReal[{-1, 1}, {2, 3, 4, 5}];
ResourceFunction["CPDecomposition"][tensor, {"Rank", "Error"}]
Out[6]=

Increasing the rank reduces the error:

In[7]:=
ResourceFunction["CPDecomposition"][tensor, 10, {"Rank", "Error"}]
Out[7]=

Scalars (rank-0 tensors) and vectors (rank-1 tensors) are returned as their own decomposition:

In[8]:=
ResourceFunction["CPDecomposition"][42, All]
Out[8]=
In[9]:=
ResourceFunction["CPDecomposition"][{123}, All]
Out[9]=

CP decomposition of a sparse tensor:

In[10]:=
st = LeviCivitaTensor[4, SparseArray]
Out[10]=
In[11]:=
ResourceFunction["CPDecomposition"][st]
Out[11]=

Options (4) 

InitialFactors (1) 

Providing explicit initial factors for the ALS algorithm will make the decomposition deterministic:

In[12]:=
tensor = RandomReal[{-1, 1}, {3, 4, 5}];
In[13]:=
initFactors = RandomReal[1, {#, 7}] & /@ {3, 4, 5};
In[14]:=
ResourceFunction["CPDecomposition"][tensor, 7, All, "InitialFactors" -> initFactors]
Out[14]=

MaxIterations (1) 

Increasing MaxIterations can further reduce the error, at the cost of longer evaluation times:

In[15]:=
tensor = RandomReal[{-1, 1}, {3, 4, 5}];
In[16]:=
SeedRandom[1234];
ResourceFunction["CPDecomposition"][tensor, {"Error", "Iterations"}]
Out[7]=
In[17]:=
SeedRandom[1234];
ResourceFunction["CPDecomposition"][tensor, {"Error", "Iterations"}, MaxIterations -> 1000]
Out[18]=

Tolerance (2) 

Increasing the error tolerance will result in faster convergence:

In[19]:=
tensor = RandomReal[{-1, 1}, {3, 4, 5}];
In[20]:=
SeedRandom[1234];
ResourceFunction["CPDecomposition"][tensor, {"Error", "Iterations"}, Tolerance -> 10^(-3)]
Out[7]=

Decreasing the error tolerance may reduce error:

In[21]:=
SeedRandom[1234];
ResourceFunction["CPDecomposition"][tensor, {"Error", "Iterations"}, Tolerance -> 10^(-6)]
Out[22]=

Applications (4) 

A 3D test image:

In[23]:=
image = ExampleData[{"TestImage3D", "CTengine"}]
Out[23]=

Compute the CP decomposition of the image (this might take a long time to evaluate):

In[24]:=
AbsoluteTiming[
 decomp = ResourceFunction["CPDecomposition"][ImageData@image, 8, All];]
Out[24]=

The CP decomposition is able to compress the data in the image:

In[25]:=
ByteCount[decomp["Factors"]]
Out[25]=
In[26]:=
ByteCount[image]
Out[26]=

Show the reconstructed tensor as an image:

In[27]:=
Image3D@decomp["ReconstructedTensor"]
Out[27]=

Properties and Relations (2) 

Given the CP decomposition factors:

In[28]:=
dimensions = {2, 3, 4};
tensor = RandomReal[{-1, 1}, dimensions];
{factors, rt, error} = ResourceFunction["CPDecomposition"][
  tensor, {"Factors", "ReconstructedTensor", "Error"}]
Out[29]=

One can reconstruct a tensor using the ResourceFunction KhatriRaoProduct along with Total and ArrayReshape with initial tensor dimensions:

In[30]:=
ArrayReshape[
  Total[ResourceFunction["KhatriRaoProduct"] @@ factors, {2}], dimensions] == rt
Out[30]=

The error can be computed using SquaredEuclideanDistance with the flattened original and reconstructed tensors:

In[31]:=
SquaredEuclideanDistance[Flatten[tensor], Flatten[rt]] == error
Out[31]=

For a matrix, CPDecomposition returns two factor matrices a and b, with the original matrix reconstructed as a.Transpose[b]:

In[32]:=
matrix = RandomComplex[{-1 - I, 1 + I}, {10, 20}];
In[33]:=
{a, b} = ResourceFunction["CPDecomposition"][matrix];
In[34]:=
a . Transpose[b] - matrix // Chop
Out[34]=

Version History

  • 1.0.0 – 05 April 2023

Source Metadata

Related Resources

License Information