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.
rng('default'); %<- Setting random seed for reproducibility of this script 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, 2, 8, 9) 0.4387 ( 2,10, 9, 3) 0.3816 ( 3, 5, 8, 7) 0.7655 ( 6,10, 4, 4) 0.7952 ( 7, 9, 7, 1) 0.1869 ( 9, 2, 7, 8) 0.4898 (10, 5,10, 1) 0.4456 (10, 8, 7,10) 0.6463 (10,10, 1, 1) 0.7094 (10,10, 2, 1) 0.7547
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,872) 0.438744 ( 2,290) 0.381558 ( 3,675) 0.765517 ( 6,340) 0.7952 ( 7, 69) 0.186873 ( 9,762) 0.489764 (10, 95) 0.445586 (10,968) 0.646313 (10, 10) 0.709365 (10, 20) 0.754687
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) (72, 81) 0.438744 (90, 22) 0.381558 (75, 63) 0.765517 (40, 36) 0.7952 (69, 7) 0.186873 (62, 79) 0.489764 (95, 10) 0.445586 (68,100) 0.646313 (10, 10) 0.709365 (20, 10) 0.754687
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) ( 81,72) 0.438744 ( 22,90) 0.381558 ( 63,75) 0.765517 ( 36,40) 0.7952 ( 7,69) 0.186873 ( 79,62) 0.489764 ( 10,95) 0.445586 (100,68) 0.646313 ( 10,10) 0.709365 ( 10,20) 0.754687
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) (8711,1) 0.438744 (2892,1) 0.381558 (6743,1) 0.765517 (3396,1) 0.7952 ( 687,1) 0.186873 (7619,1) 0.489764 ( 950,1) 0.445586 (9680,1) 0.646313 ( 100,1) 0.709365 ( 200,1) 0.754687
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) ( 2,871) 0.438744 (10,282) 0.381558 ( 5,673) 0.765517 (10,336) 0.7952 ( 9, 67) 0.186873 ( 2,769) 0.489764 ( 5,100) 0.445586 ( 8,970) 0.646313 (10, 10) 0.709365 (10, 20) 0.754687
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) ( 2,808) 0.438744 (10,219) 0.381558 ( 5,628) 0.765517 (10,354) 0.7952 ( 9, 67) 0.186873 ( 2,787) 0.489764 ( 5,100) 0.445586 ( 8,997) 0.646313 (10, 91) 0.709365 (10, 92) 0.754687
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) ( 2, 88) 0.438744 (10,129) 0.381558 ( 5,268) 0.765517 (10,534) 0.7952 ( 9,607) 0.186873 ( 2,877) 0.489764 ( 5,910) 0.445586 ( 8,997) 0.646313 (10,901) 0.709365 (10,902) 0.754687
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) ( 2,781) 0.438744 (10,822) 0.381558 ( 5,763) 0.765517 (10,336) 0.7952 ( 9,607) 0.186873 ( 2,679) 0.489764 ( 5,910) 0.445586 ( 8,700) 0.646313 (10, 10) 0.709365 (10,110) 0.754687
Constituent parts of a sptenmat
A.subs %<-- Subscripts of the nonzeros.
ans = 2 781 10 822 5 763 10 336 9 607 2 679 5 910 8 700 10 10 10 110
A.vals %<-- The corresponding nonzero values.
ans = 0.4387 0.3816 0.7655 0.7952 0.1869 0.4898 0.4456 0.6463 0.7094 0.7547
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,679) 0.489764 ( 2,781) 0.438744 ( 5,763) 0.765517 ( 5,910) 0.445586 ( 8,700) 0.646313 ( 9,607) 0.186873 (10, 10) 0.709365 (10,110) 0.754687 (10,336) 0.7952 (10,822) 0.381558
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) (10, 10) 0.709365 (10,110) 0.754687 (10,336) 0.7952 ( 9,607) 0.186873 ( 2,679) 0.489764 ( 8,700) 0.646313 ( 5,763) 0.765517 ( 2,781) 0.438744 (10,822) 0.381558 ( 5,910) 0.445586
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,527) 0.0758543 ( 2,999) 0.0539501 ( 3,543) 0.530798 ( 3,388) 0.779167 ( 4,722) 0.934011 ( 5,240) 0.129906 ( 6,362) 0.568824 ( 7,823) 0.469391 ( 7,586) 0.0119021 (10,716) 0.337123
B = double(A) %<-- Convert it to a MATLAB sparse matrix
B = (5,240) 0.1299 (6,362) 0.5688 (3,388) 0.7792 (2,527) 0.0759 (3,543) 0.5308 (7,586) 0.0119 (10,716) 0.3371 (4,722) 0.9340 (7,823) 0.4694 (2,999) 0.0540
whos A B %<-- The storage for B (the sparse matrix) is larger than for A.
Name Size Bytes Class Attributes A 10x1000 1144 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,2) 0.748152 (1,8) 0.450542 (3,4) 0.0838214
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.7482 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0838 0 0 0 Columns 8 through 9 0.4505 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 ( 2, 7, 3, 6) 0.0759 ( 2, 9,10,10) 0.0540 ( 3, 3, 5, 6) 0.5308 ( 3, 8, 9, 4) 0.7792 ( 4, 2, 3, 8) 0.9340 ( 5,10, 4, 3) 0.1299 ( 6, 2, 7, 4) 0.5688 ( 7, 3, 3, 9) 0.4694 ( 7, 6, 9, 6) 0.0119 (10, 6, 2, 8) 0.3371
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,527) 0.0758543 ( 2,999) 0.0539501 ( 3,388) 0.779167 ( 3,543) 0.530798 ( 4,722) 0.934011 ( 5,240) 0.129906 ( 6,362) 0.568824 ( 7,586) 0.0119021 ( 7,823) 0.469391 (10,716) 0.337123
Use end for the last index
End is not supported.
Basic operations for sptenmat
norm(A) %<-- Norm of the matrix.
ans = 2.5386
+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,527) 0.0758543 ( 2,999) 0.0539501 ( 3,388) 0.779167 ( 3,543) 0.530798 ( 4,722) 0.934011 ( 5,240) 0.129906 ( 6,362) 0.568824 ( 7,586) 0.0119021 ( 7,823) 0.469391 (10,716) 0.337123
-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,527) -0.0758543 ( 2,999) -0.0539501 ( 3,388) -0.779167 ( 3,543) -0.530798 ( 4,722) -0.934011 ( 5,240) -0.129906 ( 6,362) -0.568824 ( 7,586) -0.0119021 ( 7,823) -0.469391 (10,716) -0.337123
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.0087 0.8888 0.8724 0.0169 0.3236 0.2205 0 0 0.1137
double(A) * double(A)' * x %<-- Same as above but less efficient
ans = 4.0000 4.0087 0.8888 0.8724 0.0169 0.3236 0.2205 0 0 0.1137
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,527) 0.0758543 ( 2,999) 0.0539501 ( 3,388) 0.779167 ( 3,543) 0.530798 ( 4,722) 0.934011 ( 5,240) 0.129906 ( 6,362) 0.568824 ( 7,586) 0.0119021 ( 7,823) 0.469391 (10,716) 0.337123