Code covered by the BSD License  

Highlights from
Efficient Object-Oriented Kronecker Product Manipulation

5.0

5.0 | 5 ratings Rate this file 37 Downloads (last 30 days) File Size: 55.3 KB File ID: #25969

Efficient Object-Oriented Kronecker Product Manipulation

by

 

28 Nov 2009 (Updated )

A class for efficient manipulation of N-fold Kronecker products in terms of their operands only.

| Watch this File

File Information
Description

This is a class for efficiently representing and manipulating N-fold Kronecker products of matrices (or of objects that behave like matrices) in terms of their operands only.
 
Given matrices {A,B,C,D,...} and a scalar s, an object M of this class can be used to represent
 
    Matrix = s * A kron B kron C kron D kron ... (Eq. 1)
 
where "A kron B" denotes kron(A,B), the Kronecker product of A and B. Internally, however, M stores the operands {s,A,B,C,D,...} separately, which is typically far more byte-compact than numerically expanding out the RHS of Eq. 1.
 
Furthermore, many mathematical manipulations of Kronecker products are more efficient when done in terms of {s,A,B,C,D,...} separately than when done with the explicit numerical form of M as a matrix. The class overloads a number of methods and math operators in a way that exploits the Kronecker product structure accordingly.
 
Among these methods/operators are: mtimes (*), times (.*) , tranpose (.') , ctranpose (') , rdivide (./), ldivide (.\), mldivide (\), mrdivide (/), inv, pinv, power, mpower, norm, sum, cond, eig, svd, abs, nnz, orth, chol, lu, qr, full, sparse, ...
 
Some restrictions apply to these overloads. In particular, bi-operand math operations involving two KronProd objects, e.g. M1*M2, typically require the operands of each KronProd to be of compatible sizes. However, I find these restrictions to be satisfied often in applications.

Consult "help KronProd/methodname" for more info on each method. Optionally also, read krontest.m for demonstrations of their use.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 EXAMPLE #1:
 
 A primary application of this class is to efficiently perform separable tensorial operations, i.e., where a linear transform is applied to all columns of an array, then all rows, and so on.
 
The following example is of a separable transformation of a 3D array X that transforms all of its columns via multiplication with a non-square matrix A, then transforms all rows by multiplication with B, then finally transforms all 3rd-dimensional axes by multiplication with C. Two approaches to this are compared. The first approach uses kron(). The second uses the KronProd class. Other operations are also shown for illustration purposes.
 
Notice the orders of magnitude reduction both in CPU time and in memory consumption, using the KronProd object.
 
  
      %DATA
      m=25; n=15; p=40;
      mm=16; nn=n; pp=10;
      A=rand(mm,m); B=pi*eye(n); C=rand(pp,p);
      s=4; % a scalar
      X=rand(m,n,p);
  
  
  
  
      %METHOD I: based on kron()
      tic;
  
         Matrix = s*kron(C,kron(B,A));
  
         y1 = Matrix*X(:); %The tensorial transformation
             y1=reshape(y1,[mm,nn,pp]);
  
         z1 = Matrix.'*y1(:);
  
         w1 = Matrix.'\z1;
 
      toc;
      %Elapsed time is 78.729007 seconds.
  
  
  
  
  
      %METHOD II: based on KronProd object
      tic;
  
         Object = KronProd({A,pi,C},[1 2 3],[m,n,p],s); %equivalent to Matrix above
  
           y2 = Object*X;
                  % This operation could also have been implemented
                  % as y2=reshape( Object*X(:) , [mm,nn,pp]);
                    
           z2 = Object.'*y1;
  
           w2 = Object.'\z1;
  
      toc
      % Elapsed time is 0.003958 seconds.
  
  
 
  
      %%%ERROR ANALYSIS
      PercentError=@(x,y) norm(x(:)-y(:),2)/norm(x(:),'inf')*100;
  
          PercentError(y1,y2), % = 3.0393e-012
  
          PercentError(size(y1),size(y2)), % = 0
  
          PercentError(z1,z2), % = 1.3017e-012
          PercentError(w1,w2), % = 4.3409e-011
  
  
 
      %%%MEMORY FOOTPRINT
  
     >> whos Matrix Object
  
  
             Name Size Bytes Class Attributes
       
             Matrix 2400x15000 288000000 double
             Object 2400x15000 8102 KronProd
  

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
EXAMPLE #2: As a more practical example, the KronProd class is very useful in conjunction with the following tool for signal interpolation/reconstruction:

http://www.mathworks.com/matlabcentral/fileexchange/26292-regular-control-point-interpolation-matrix-with-boundary-conditions

An example involving 2D signal reconstruction using cubic B-splines is provided in the file Example2D.m at the above link.

MATLAB release MATLAB 7.9 (R2009b)
Tags for This File   Please login to tag files.
Please login to add a comment or rating.
Comments and Ratings (8)
18 Dec 2013 WALEEM

Thanks for sharing this code, Matt. With the help of your code, I have been able to resolve an estimation issue I have had (for the past 13 months) with a model. In the process of estimating the model, I had to deal with a 4^10-by-4^10 (8796Gb) matrix in a several thousands loop. This almost meant the end of the project.

But I stumbled upon your code, and was able to complete the construction of the model.

I can't thank you enough for this. I will be sharing my code when it is all done, and I will duely reference your code.

Thank you.

07 Sep 2012 Matt J

Hi Roemer,

Thanks for you feedback. Regarding concatenating KronProd objects: The concatenation operation that you've described isn't possible precisely as you've requested it, because the concatenation of 2 Kronecker products is not, in general, mathematically equivalent to a 3rd Kronecker product. Because it's not possible mathematically, it is equally not possible in software.

However, I did create the following FEX package to allow one to combine simpler operators into more complicated operators, which might be equivalent to what you're asking for

http://www.mathworks.com/matlabcentral/fileexchange/26611-on-the-fly-definition-of-custom-matrix-objects

Here's a simplified example where I concatenate kron(eye(3),eye(3)) with itself

>> A=eye(3); B=eye(3); K=KronProd({A,B});
>> Kcat=MatrixObj; Kcat.Ops.mtimes=@(A,x)[K*x;K*x];
>> Kcat*(1:9)'

ans =

1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9

The mixture of the MatrixObj class with other classes has had some problems in past MATLAB versions, unfortunately, so how well it works for you could depends on what version you have.

30 Aug 2012 Roemer van der Meij

This is a fantastic piece of work. The amount of speed-up and memory efficiency has been a tremendous help already. There are calculations I have to do on often enormous arrays resulting from Kronecker products, easily needing up to 400GB of RAM/memory-mapped space. Using your OOP implementation is of huge help to me and my (PhD) project, and it's a nice way to learn how to do some OOP myself. Thanks!

I have one question/request, I assume you might not have the time, but maybe you could give me some pointers on how to do it. Maybe it's very easy, and I'm just missing it.
I would like to be able to do:

KronProdC = cat(1,KronProdA,KronProdB)

I.e., concatenating KronProd objects along dimension 1 (or 2). Concatenation would occur over 1st/2nd dimension of the kronecker product. Maybe it's not necessary to expand the class, but use a trick to modify existing KronProd objects, but my intuition for this is not very trained.
Being able to do this, I could extend your work into a Kathri-Rao product, which would speed up a large set of problems and algorithms using the PARAFAC/TuckerX models. These multi-dimensional decomposition models are used a lot in chemometrics, and are gaining a lot of popularity in neuroscience the past years (my field). Both usually use Matlab for these calculations, and this would speedup results for a lot of people, many could benefit. So, I got very excited when I saw and tested your work :).
Any help is greatly appreciated,
Roemer

12 Jun 2012 Danielle

Wow! No more out of memory errors and so fast!

15 Feb 2012 Omar

This is what I need :-)

23 Feb 2010 Matt J

Oleg, I fixed some of the ragged text justification and uncommented some of the text. Not sure if those were the unreadabilities that you were talking about, though. The Description editor is a little unwieldy and gives me very limited control of spacing.

22 Feb 2010 Oleg Komarov

You may consider to edit the description since it's really unreadable. No way I'm gonna get past all those blocks of comments and those funny spaced examples.

12 Jan 2010 Sean  
Updates
30 Nov 2009

Minor typo fixes in description of package

15 Dec 2009

*New class methods: times, rdivide ldivide, rank, orth, svd, pinv, qr, lu, chol, loadobj.

*Expansions of old methods: eig, mldivide, mtimes, mrdivide

*See UpdateNotes.txt in package for more

23 Dec 2009

Bug fix in qr() method (see UpdateNotes.txt). Also added relevant test of the fix to krontest.m

08 Jan 2010

Added additional example to Description section with link to a related FEX submission.

11 Jan 2010

*Overloaded cellfun() for the KronProd class

*Added simpler options for the domainsize parameter in the constructor syntax KronProd(opset,opdims,domainsizes,...)

*See UpdateNotes for details

22 Feb 2010

*Overloaded kron() for the KronProd class.
*Reimplemented the class definition using classdef file.
*loadobj now always does a construct-on-load.
*See UpdateNotes for more details.

23 Feb 2010

At the suggestion of a user, neatened up the Description section

05 Aug 2010

In constructor KronProd(opset,opinds, ...) introduced default value for opinds of 1:length(opset).

This allows simple 1-argument contructor calls such as
KronProd({C,B,A}), which is equivalent to kron(A,kron(B,C))

Contact us