# Converting sparse tensors to matrices and vice versa

We show how to convert a sptensor to a matrix stored in coordinate format and with extra information so that it can be converted back to a sptensor.

## Contents

- Creating a sptenmat (sparse tensor as sparse matrix) object
- Constituent parts of a sptenmat
- Creating a sptenmat from its constituent parts
- Creating a sptenmat with no nonzeros
- Creating an emtpy sptenmat
- Use double to convert a sptenmat to a MATLAB sparse matrix
- Use full to convert a sptenmat to a tenmat
- Use sptensor to convert a sptenmat to a sptensor
- Use size and tsize for the dimensions of a sptenmat
- Subscripted reference for a sptenmat
- Subscripted assignment for a sptenmat
- Use end for the last index
- Basic operations for sptenmat
- Use aatx to efficiently compute A * A' * x for a sptenmat
- Displaying a tenmat

## Creating a sptenmat (sparse tensor as sparse matrix) object

A sparse tensor can be converted to a sparse matrix. The matrix, however, is not stored as a MATLAB sparse matrix because that format is sometimes inefficient for converted sparse tensors. Instead, the row and column indices are stored explicitly.

First, we create a sparse tensor to be converted.

    X = sptenrand([10 10 10 10],10) %<-- Generate some data.

    X is a sparse tensor of size 10 x 10 x 10 x 10 with 10 nonzeros
    	( 1, 5, 2, 3)    0.4712
    	( 1,10, 2,10)    0.1493
    	( 3, 5, 1, 4)    0.1359
    	( 3, 9,10, 8)    0.5325
    	( 4, 6,10, 6)    0.7258
    	( 5, 2, 1, 9)    0.3987
    	( 5, 7, 7, 2)    0.3584
    	( 9, 4, 6, 2)    0.2853
    	( 9, 7, 6, 5)    0.8686
    	(10, 6, 9,10)    0.6264

All the same options for tenmat are available as for tenmat.

    A = sptenmat(X,1) %<-- Mode-1 matricization.

    A is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 10 nonzeros
    	A.rindices = [ 1 ] (modes of tensor corresponding to rows)
    	A.cindices = [ 2  3  4 ] (modes of tensor corresponding to columns)
    	( 1,215)	0.471156
    	( 1,920)	0.14931
    	( 3,305)	0.135864
    	( 3,799)	0.532498
    	( 4,596)	0.725789
    	( 5,802)	0.398703
    	( 5,167)	0.358419
    	( 9,154)	0.285279
    	( 9,457)	0.868635
    	(10,986)	0.626413

    A = sptenmat(X,[2 3]) %<-- More than one mode is mapped to the columns.

    A is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 10 nonzeros
    	A.rindices = [ 2  3 ] (modes of tensor corresponding to rows)
    	A.cindices = [ 1  4 ] (modes of tensor corresponding to columns)
    	(15, 21)	0.471156
    	(20, 91)	0.14931
    	( 5, 33)	0.135864
    	(99, 73)	0.532498
    	(96, 54)	0.725789
    	( 2, 85)	0.398703
    	(67, 15)	0.358419
    	(54, 19)	0.285279
    	(57, 49)	0.868635
    	(86,100)	0.626413

    A = sptenmat(X,[2 3],'t') %<-- Specify column dimensions (transpose).

    A is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 10 nonzeros
    	A.rindices = [ 1  4 ] (modes of tensor corresponding to rows)
    	A.cindices = [ 2  3 ] (modes of tensor corresponding to columns)
    	( 21,15)	0.471156
    	( 91,20)	0.14931
    	( 33, 5)	0.135864
    	( 73,99)	0.532498
    	( 54,96)	0.725789
    	( 85, 2)	0.398703
    	( 15,67)	0.358419
    	( 19,54)	0.285279
    	( 49,57)	0.868635
    	(100,86)	0.626413

    A = sptenmat(X,1:4) %<-- All modes mapped to rows, i.e., vectorize.

    A is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 10 nonzeros
    	A.rindices = [ 1  2  3  4 ] (modes of tensor corresponding to rows)
    	A.cindices = [  ] (modes of tensor corresponding to columns)
    	(2141,1)	0.471156
    	(9191,1)	0.14931
    	(3043,1)	0.135864
    	(7983,1)	0.532498
    	(5954,1)	0.725789
    	(8015,1)	0.398703
    	(1665,1)	0.358419
    	(1539,1)	0.285279
    	(4569,1)	0.868635
    	(9860,1)	0.626413

    A = sptenmat(X,2) %<-- By default, columns are ordered as [1 3 4].

    A is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 10 nonzeros
    	A.rindices = [ 2 ] (modes of tensor corresponding to rows)
    	A.cindices = [ 1  3  4 ] (modes of tensor corresponding to columns)
    	( 5,211)	0.471156
    	(10,911)	0.14931
    	( 5,303)	0.135864
    	( 9,793)	0.532498
    	( 6,594)	0.725789
    	( 2,805)	0.398703
    	( 7,165)	0.358419
    	( 4,159)	0.285279
    	( 7,459)	0.868635
    	( 6,990)	0.626413

    A = sptenmat(X,2,[3 1 4]) %<-- Explicit column ordering.

    A is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 10 nonzeros
    	A.rindices = [ 2 ] (modes of tensor corresponding to rows)
    	A.cindices = [ 3  1  4 ] (modes of tensor corresponding to columns)
    	( 5,202)	0.471156
    	(10,902)	0.14931
    	( 5,321)	0.135864
    	( 9,730)	0.532498
    	( 6,540)	0.725789
    	( 2,841)	0.398703
    	( 7,147)	0.358419
    	( 4,186)	0.285279
    	( 7,486)	0.868635
    	( 6,999)	0.626413

    A = sptenmat(X,2,'fc') %<-- Foward cyclic.

    A is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 10 nonzeros
    	A.rindices = [ 2 ] (modes of tensor corresponding to rows)
    	A.cindices = [ 3  4  1 ] (modes of tensor corresponding to columns)
    	( 5, 22)	0.471156
    	(10, 92)	0.14931
    	( 5,231)	0.135864
    	( 9,280)	0.532498
    	( 6,360)	0.725789
    	( 2,481)	0.398703
    	( 7,417)	0.358419
    	( 4,816)	0.285279
    	( 7,846)	0.868635
    	( 6,999)	0.626413

    A = sptenmat(X,2,'bc') %<-- Backward cyclic.

    A is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 10 nonzeros
    	A.rindices = [ 2 ] (modes of tensor corresponding to rows)
    	A.cindices = [ 1  4  3 ] (modes of tensor corresponding to columns)
    	( 5,121)	0.471156
    	(10,191)	0.14931
    	( 5, 33)	0.135864
    	( 9,973)	0.532498
    	( 6,954)	0.725789
    	( 2, 85)	0.398703
    	( 7,615)	0.358419
    	( 4,519)	0.285279
    	( 7,549)	0.868635
    	( 6,900)	0.626413

## Constituent parts of a sptenmat

    A.subs %<-- Subscripts of the nonzeros.

    ans =

         5   121
        10   191
         5    33
         9   973
         6   954
         2    85
         7   615
         4   519
         7   549
         6   900

    A.vals %<-- The corresponding nonzero values.

    ans =

        0.4712
        0.1493
        0.1359
        0.5325
        0.7258
        0.3987
        0.3584
        0.2853
        0.8686
        0.6264

    A.tsize %<-- Size of the original tensor.

    ans =

        10    10    10    10

    A.rdims %<-- Dimensions that were mapped to the rows.

    ans =

         2

    A.cdims %<-- Dimensions that were mapped to the columns.

    ans =

         1     4     3

## Creating a sptenmat from its constituent parts

    B = sptenmat(A.subs,A.vals,A.rdims,A.cdims,A.tsize) %<-- Copies A

    B is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 10 nonzeros
    	B.rindices = [ 2 ] (modes of tensor corresponding to rows)
    	B.cindices = [ 1  4  3 ] (modes of tensor corresponding to columns)
    	( 2, 85)	0.398703
    	( 4,519)	0.285279
    	( 5, 33)	0.135864
    	( 5,121)	0.471156
    	( 6,900)	0.626413
    	( 6,954)	0.725789
    	( 7,549)	0.868635
    	( 7,615)	0.358419
    	( 9,973)	0.532498
    	(10,191)	0.14931

    B = sptenmat(double(A),A.rdims,A.cdims,A.tsize) %<-- More efficient to pass a matrix.

    B is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 10 nonzeros
    	B.rindices = [ 2 ] (modes of tensor corresponding to rows)
    	B.cindices = [ 1  4  3 ] (modes of tensor corresponding to columns)
    	( 5, 33)	0.135864
    	( 2, 85)	0.398703
    	( 5,121)	0.471156
    	(10,191)	0.14931
    	( 4,519)	0.285279
    	( 7,549)	0.868635
    	( 7,615)	0.358419
    	( 6,900)	0.626413
    	( 6,954)	0.725789
    	( 9,973)	0.532498

## Creating a sptenmat with no nonzeros

    A = sptenmat([],[],A.rdims,A.cdims,A.tsize) %<-- An empty sptenmat.

    A is an all-zero sptenmat from an sptensor of size 10 x 10 x 10 x 10
    	A.rindices = [ 2 ] (modes of tensor corresponding to rows)
    	A.cindices = [ 1  4  3 ] (modes of tensor corresponding to columns)

## Creating an emtpy sptenmat

    A = sptenmat %<-- A really empty sptenmat.

    A is an all-zero sptenmat from an sptensor of size [empty tensor]
    	A.rindices = [  ] (modes of tensor corresponding to rows)
    	A.cindices = [  ] (modes of tensor corresponding to columns)

## Use double to convert a sptenmat to a MATLAB sparse matrix

    X = sptenrand([10 10 10 10],10); %<-- Create a tensor.
    A = sptenmat(X,1) %<-- Convert it to a sptenmat

    A is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 10 nonzeros
    	A.rindices = [ 1 ] (modes of tensor corresponding to rows)
    	A.cindices = [ 2  3  4 ] (modes of tensor corresponding to columns)
    	( 1,384)	0.608106
    	( 2,763)	0.175996
    	( 2,499)	0.00202556
    	( 3,111)	0.790224
    	( 3,451)	0.513609
    	( 3,781)	0.213229
    	( 7,852)	0.10345
    	( 7,636)	0.157337
    	( 7,658)	0.407515
    	(10,129)	0.407757

    B = double(A) %<-- Convert it to a MATLAB sparse matrix

    B =

       (3,111)     0.7902
      (10,129)     0.4078
       (1,384)     0.6081
       (3,451)     0.5136
       (2,499)     0.0020
       (7,636)     0.1573
       (7,658)     0.4075
       (2,763)     0.1760
       (3,781)     0.2132
       (7,852)     0.1034

    whos A B %<-- The storage for B (the sparse matrix) is larger than for A.

      Name       Size              Bytes  Class       Attributes

      A         10x1000             1184  sptenmat
      B         10x1000             8168  double      sparse

    C = B'; %<-- Transposing the result fixes the problem.
    whos C

      Name         Size            Bytes  Class     Attributes

      C         1000x10              248  double    sparse

## Use full to convert a sptenmat to a tenmat

    B = sptenmat(sptenrand([3 3 3], 3), 1) %<-- Create a sptenmat

    B is a sptenmat from an sptensor of size 3 x 3 x 3 with 3 nonzeros
    	B.rindices = [ 1 ] (modes of tensor corresponding to rows)
    	B.cindices = [ 2  3 ] (modes of tensor corresponding to columns)
    	(1,7)	0.410904
    	(1,8)	0.399794
    	(3,1)	0.505522

    C = full(B) %<-- Convert to a tenmat

    C is a matrix corresponding to a tensor of size 3 x 3 x 3
    	C.rindices = [ 1 ] (modes of tensor corresponding to rows)
    	C.cindices = [ 2  3 ] (modes of tensor corresponding to columns)
    	C.data =
    		  Columns 1 through 7
    		         0         0         0         0         0         0    0.4109
    		         0         0         0         0         0         0         0
    		    0.5055         0         0         0         0         0         0
    		  Columns 8 through 9
    		    0.3998         0
    		         0         0
    		         0         0

## Use sptensor to convert a sptenmat to a sptensor

    Y = sptensor(A) %<-- Convert a sptenmat to a sptensor

    Y is a sparse tensor of size 10 x 10 x 10 x 10 with 10 nonzeros
    	( 1,4, 9,4)    0.6081
    	( 2,3, 7,8)    0.1760
    	( 2,9,10,5)    0.0020
    	( 3,1, 2,2)    0.7902
    	( 3,1, 6,5)    0.5136
    	( 3,1, 9,8)    0.2132
    	( 7,2, 6,9)    0.1034
    	( 7,6, 4,7)    0.1573
    	( 7,8, 6,7)    0.4075
    	(10,9, 3,2)    0.4078

## Use size and tsize for the dimensions of a sptenmat

    size(A) %<-- Matrix size
    tsize(A) %<-- Corresponding tensor size

    ans =

              10        1000

    ans =

        10    10    10    10

## Subscripted reference for a sptenmat

This is not supported beyond getting the constituent parts.

## Subscripted assignment for a sptenmat

    A(1:2,1:2) = ones(2) %<-- Replace part of the matrix.

    A is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 14 nonzeros
    	A.rindices = [ 1 ] (modes of tensor corresponding to rows)
    	A.cindices = [ 2  3  4 ] (modes of tensor corresponding to columns)
    	( 1,  1)	1
    	( 1,  2)	1
    	( 1,384)	0.608106
    	( 2,  1)	1
    	( 2,  2)	1
    	( 2,499)	0.00202556
    	( 2,763)	0.175996
    	( 3,111)	0.790224
    	( 3,451)	0.513609
    	( 3,781)	0.213229
    	( 7,636)	0.157337
    	( 7,658)	0.407515
    	( 7,852)	0.10345
    	(10,129)	0.407757

## Use end for the last index

End is not supported.

## Basic operations for sptenmat

    norm(A) %<-- Norm of the matrix.

    ans =

        2.3879

    +A %<-- Calls uplus.

    ans is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 14 nonzeros
    	ans.rindices = [ 1 ] (modes of tensor corresponding to rows)
    	ans.cindices = [ 2  3  4 ] (modes of tensor corresponding to columns)
    	( 1,  1)	1
    	( 1,  2)	1
    	( 1,384)	0.608106
    	( 2,  1)	1
    	( 2,  2)	1
    	( 2,499)	0.00202556
    	( 2,763)	0.175996
    	( 3,111)	0.790224
    	( 3,451)	0.513609
    	( 3,781)	0.213229
    	( 7,636)	0.157337
    	( 7,658)	0.407515
    	( 7,852)	0.10345
    	(10,129)	0.407757

    -A %<-- Calls uminus.

    ans is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 14 nonzeros
    	ans.rindices = [ 1 ] (modes of tensor corresponding to rows)
    	ans.cindices = [ 2  3  4 ] (modes of tensor corresponding to columns)
    	( 1,  1)	-1
    	( 1,  2)	-1
    	( 1,384)	-0.608106
    	( 2,  1)	-1
    	( 2,  2)	-1
    	( 2,499)	-0.00202556
    	( 2,763)	-0.175996
    	( 3,111)	-0.790224
    	( 3,451)	-0.513609
    	( 3,781)	-0.213229
    	( 7,636)	-0.157337
    	( 7,658)	-0.407515
    	( 7,852)	-0.10345
    	(10,129)	-0.407757

## Use aatx to efficiently compute A * A' * x for a sptenmat

    x = ones(10,1); %<-- Create vector
    aatx(A,x) %<-- Compute A * A' * x

    ans =

        4.3698
        4.0310
        0.9337
             0
             0
             0
        0.2015
             0
             0
        0.1663

    double(A) * double(A)' * x %<-- Same as above but less efficient

    ans =

        4.3698
        4.0310
        0.9337
             0
             0
             0
        0.2015
             0
             0
        0.1663

## Displaying a tenmat

Shows the original tensor dimensions, the modes mapped to rows, the modes mapped to columns, and the matrix.

    disp(A)

    ans is a sptenmat from an sptensor of size 10 x 10 x 10 x 10 with 14 nonzeros
    	ans.rindices = [ 1 ] (modes of tensor corresponding to rows)
    	ans.cindices = [ 2  3  4 ] (modes of tensor corresponding to columns)
    	( 1,  1)	1
    	( 1,  2)	1
    	( 1,384)	0.608106
    	( 2,  1)	1
    	( 2,  2)	1
    	( 2,499)	0.00202556
    	( 2,763)	0.175996
    	( 3,111)	0.790224
    	( 3,451)	0.513609
    	( 3,781)	0.213229
    	( 7,636)	0.157337
    	( 7,658)	0.407515
    	( 7,852)	0.10345
    	(10,129)	0.407757