# 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,9, 5, 1)    0.4249
    	(3,2, 1, 2)    0.3756
    	(4,7,10, 9)    0.1662
    	(4,8, 3,10)    0.8332
    	(5,3, 4, 8)    0.8386
    	(5,3, 6, 7)    0.4516
    	(6,7, 5, 1)    0.9566
    	(6,7, 6, 6)    0.1472
    	(7,8, 5, 6)    0.8699
    	(9,9, 1, 9)    0.7694

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, 49)	0.424889
    	(3,102)	0.375577
    	(4,897)	0.166154
    	(4,928)	0.833151
    	(5,733)	0.83864
    	(5,653)	0.451614
    	(6, 47)	0.956601
    	(6,557)	0.147153
    	(7,548)	0.869933
    	(9,809)	0.769436

    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)
    	(49, 1)	0.424889
    	( 2,13)	0.375577
    	(97,84)	0.166154
    	(28,94)	0.833151
    	(33,75)	0.83864
    	(53,65)	0.451614
    	(47, 6)	0.956601
    	(57,56)	0.147153
    	(48,57)	0.869933
    	( 9,89)	0.769436

    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)
    	( 1,49)	0.424889
    	(13, 2)	0.375577
    	(84,97)	0.166154
    	(94,28)	0.833151
    	(75,33)	0.83864
    	(65,53)	0.451614
    	( 6,47)	0.956601
    	(56,57)	0.147153
    	(57,48)	0.869933
    	(89, 9)	0.769436

    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)
    	( 481,1)	0.424889
    	(1013,1)	0.375577
    	(8964,1)	0.166154
    	(9274,1)	0.833151
    	(7325,1)	0.83864
    	(6525,1)	0.451614
    	( 466,1)	0.956601
    	(5566,1)	0.147153
    	(5477,1)	0.869933
    	(8089,1)	0.769436

    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)
    	(9, 41)	0.424889
    	(2,103)	0.375577
    	(7,894)	0.166154
    	(8,924)	0.833151
    	(3,735)	0.83864
    	(3,655)	0.451614
    	(7, 46)	0.956601
    	(7,556)	0.147153
    	(8,547)	0.869933
    	(9,809)	0.769436

    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)
    	(9,  5)	0.424889
    	(2,121)	0.375577
    	(7,840)	0.166154
    	(8,933)	0.833151
    	(3,744)	0.83864
    	(3,646)	0.451614
    	(7, 55)	0.956601
    	(7,556)	0.147153
    	(8,565)	0.869933
    	(9,881)	0.769436

    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)
    	(9,  5)	0.424889
    	(2,211)	0.375577
    	(7,390)	0.166154
    	(8,393)	0.833151
    	(3,474)	0.83864
    	(3,466)	0.451614
    	(7,505)	0.956601
    	(7,556)	0.147153
    	(8,655)	0.869933
    	(9,881)	0.769436

    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)
    	(9,401)	0.424889
    	(2, 13)	0.375577
    	(7,984)	0.166154
    	(8,294)	0.833151
    	(3,375)	0.83864
    	(3,565)	0.451614
    	(7,406)	0.956601
    	(7,556)	0.147153
    	(8,457)	0.869933
    	(9, 89)	0.769436

## Constituent parts of a sptenmat

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

    ans =

         9   401
         2    13
         7   984
         8   294
         3   375
         3   565
         7   406
         7   556
         8   457
         9    89

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

    ans =

        0.4249
        0.3756
        0.1662
        0.8332
        0.8386
        0.4516
        0.9566
        0.1472
        0.8699
        0.7694

    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, 13)	0.375577
    	(3,375)	0.83864
    	(3,565)	0.451614
    	(7,406)	0.956601
    	(7,556)	0.147153
    	(7,984)	0.166154
    	(8,294)	0.833151
    	(8,457)	0.869933
    	(9, 89)	0.769436
    	(9,401)	0.424889

    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)
    	(2, 13)	0.375577
    	(9, 89)	0.769436
    	(8,294)	0.833151
    	(3,375)	0.83864
    	(9,401)	0.424889
    	(7,406)	0.956601
    	(8,457)	0.869933
    	(7,556)	0.147153
    	(3,565)	0.451614
    	(7,984)	0.166154

## 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)
    	( 2,723)	0.783859
    	( 3, 32)	0.986158
    	( 4,647)	0.473343
    	( 5,775)	0.902819
    	( 5,236)	0.451059
    	( 5,256)	0.804517
    	( 5,357)	0.828864
    	( 7,191)	0.16627
    	( 7,447)	0.393906
    	(10,434)	0.520757

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

    B =

       (3,32)      0.9862
       (7,191)     0.1663
       (5,236)     0.4511
       (5,256)     0.8045
       (5,357)     0.8289
      (10,434)     0.5208
       (7,447)     0.3939
       (4,647)     0.4733
       (2,723)     0.7839
       (5,775)     0.9028

    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)
    	(2,1)	0.759479
    	(2,8)	0.949759
    	(3,5)	0.557939

    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
    		    0.7595         0         0         0         0         0         0
    		         0         0         0         0    0.5579         0         0
    		  Columns 8 through 9
    		         0         0
    		    0.9498         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
    	( 2,3, 3,8)    0.7839
    	( 3,2, 4,1)    0.9862
    	( 4,7, 5,7)    0.4733
    	( 5,5, 8,8)    0.9028
    	( 5,6, 4,3)    0.4511
    	( 5,6, 6,3)    0.8045
    	( 5,7, 6,4)    0.8289
    	( 7,1,10,2)    0.1663
    	( 7,7, 5,5)    0.3939
    	(10,4, 4,5)    0.5208

## 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
    	( 2,  1)	1
    	( 2,  2)	1
    	( 2,723)	0.783859
    	( 3, 32)	0.986158
    	( 4,647)	0.473343
    	( 5,236)	0.451059
    	( 5,256)	0.804517
    	( 5,357)	0.828864
    	( 5,775)	0.902819
    	( 7,191)	0.16627
    	( 7,447)	0.393906
    	(10,434)	0.520757

## Use end for the last index

End is not supported.

## Basic operations for sptenmat

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

    ans =

        2.9356

    +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
    	( 2,  1)	1
    	( 2,  2)	1
    	( 2,723)	0.783859
    	( 3, 32)	0.986158
    	( 4,647)	0.473343
    	( 5,236)	0.451059
    	( 5,256)	0.804517
    	( 5,357)	0.828864
    	( 5,775)	0.902819
    	( 7,191)	0.16627
    	( 7,447)	0.393906
    	(10,434)	0.520757

    -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
    	( 2,  1)	-1
    	( 2,  2)	-1
    	( 2,723)	-0.783859
    	( 3, 32)	-0.986158
    	( 4,647)	-0.473343
    	( 5,236)	-0.451059
    	( 5,256)	-0.804517
    	( 5,357)	-0.828864
    	( 5,775)	-0.902819
    	( 7,191)	-0.16627
    	( 7,447)	-0.393906
    	(10,434)	-0.520757

## 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.0000
        4.6144
        0.9725
        0.2241
        2.3528
             0
        0.1828
             0
             0
        0.2712

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

    ans =

        4.0000
        4.6144
        0.9725
        0.2241
        2.3528
             0
        0.1828
             0
             0
        0.2712

## 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
    	( 2,  1)	1
    	( 2,  2)	1
    	( 2,723)	0.783859
    	( 3, 32)	0.986158
    	( 4,647)	0.473343
    	( 5,236)	0.451059
    	( 5,256)	0.804517
    	( 5,357)	0.828864
    	( 5,775)	0.902819
    	( 7,191)	0.16627
    	( 7,447)	0.393906
    	(10,434)	0.520757