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