KerMor  0.9
Model order reduction for nonlinear dynamical systems and nonlinear approximation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
FileMatrix.m
Go to the documentation of this file.
1 namespace data{
2 
3 
4 /* (Autoinserted by mtoc++)
5  * This source code has been filtered by the mtoc++ executable,
6  * which generates code that can be processed by the doxygen documentation tool.
7  *
8  * On the other hand, it can neither be interpreted by MATLAB, nor can it be compiled with a C++ compiler.
9  * Except for the comments, the function bodies of your M-file functions are untouched.
10  * Consequently, the FILTER_SOURCE_FILES doxygen switch (default in our Doxyfile.template) will produce
11  * attached source files that are highly readable by humans.
12  *
13  * Additionally, links in the doxygen generated documentation to the source code of functions and class members refer to
14  * the correct locations in the source code browser.
15  * However, the line numbers most likely do not correspond to the line numbers in the original MATLAB source files.
16  */
17 
19  :public data.FileData,
20  public data.ABlockedData {
47  public: /* ( Constant ) */
48 
49  static const .integer BLOCK_SIZE = 512;
64  public:
65 
80  public:
81 
139  MinValue = Inf;
140 
141 
142  MaxValue = -Inf;
143 
144 
145  private:
146 
147  idx;
156  created;
164  blocksize;
172  private:
173 
174  cachedBlock = "[]";
182  cachedNr = 0;
183 
184  cacheDirty = false;
185 
186 
187  public:
188 
190 
191  if isempty(var)
192  error(" Cannot create a FileMatrix with empty first argument. Must either be a row number or a matrix. ");
193  end
194 
195 
196  matrixin = false;
197  if numel(var) > 1
198  A = var;
199  [n, m] = size(A); /* #ok<*PROP> */
200 
201  matrixin = true;
202 /* elseif isa(var,'data.FileMatrix')
203  * n = var.n;
204  * m = var.m;
205  * varargin = {'Dir', fileparts(var.DataDirectory),...
206  * 'BlockSize', var.blocksize}; */
207  else
208  n = var;
209  ip.addRequired('m');
210  end
211 
212  ip.addParamValue('Dir',KerMor.App.TempDirectory,...
213  @(v)isempty(v) || (ischar(v) && exist(v," dir ") == 7));
214  ip.addParamValue('BlockSize',KerMor.App.BlockSize,@(v)isposrealscalar(v));
215  ip.parse(varargin[:]);
216  /* Latest at here we have an m value */
217  if isfield(ip.Results," m ")
218  m = ip.Results.m;
219  end
220  /* Error checks */
221  if ~(round(n) == n && round(m) == m)
222  error(" Size arguments n, m must be integer values. ");
223  end
224  BYTEPERDOUBLE = 8;
225  bsize = min(ip.Results.BlockSize*1024^2,n*m*BYTEPERDOUBLE);
226  bcols = max(floor(bsize/(BYTEPERDOUBLE*n)),1);
227  nb = ceil(m / bcols);
228 
229  /* Determine the DataDirectory (store in each case, even if there is only one block.
230  * This is due to the fact that matrix operations can result in a filematrix with
231  * more than one block, thus needing to know where the previous matrix should have
232  * been located. */
233  ddir = ip.Results.Dir;
234  if isempty(ddir)
235  ddir = KerMor.App.TempDirectory;
236  end
237  this = this@data.FileData(fullfile(ddir,...
238  sprintf(" matrix_%s ",IDGenerator.generateID)));
239 
240  this.n= n;
241  this.m= m;
242  this.blocksize= bsize/1024^2;
243  this.bCols= bcols;
244  this.nBlocks= nb;
245  this.created= false(1,nb);
246  hlp = reshape(repmat(1:nb,bcols,1),[],1);
247  hlp2 = reshape(repmat(1:bcols,nb,1)^t,[],1);
248  this.idx= [hlp(1:m) hlp2(1:m)];
249 
250  if nb == 1
251  this.loadBlock(1);
252  end
253  /* Matrix case: Assign value directly */
254  if matrixin
255  this.subsasgn(struct(" type ",[" () "]," subs ",[[" : "," : "]]),A);
256  end
257  }
284  B = data.FileMatrix(A," Dir ",fileparts(this.DataDirectory)," Blocksize ",this.blocksize);
285  }
298  function [rowmin , rowmax ] = getColBoundingBox() {
299  rowmin = Inf*ones(this.n,1);
300  rowmax = -rowmin;
301  for i=1:this.nBlocks
302  A = this.loadBlock(i);
303  rowmin = min(rowmin, min(A,[],2));
304  rowmax = max(rowmax, max(A,[],2));
305  end
306  }
314  function pos = getBlockPos(nr) {
315  pos = (nr-1)*this.bCols + 1 : min(nr*this.bCols,this.m);
316  }
325  function copy = copyWithNewBlockSize(block_size) {
326  copy = data.FileMatrix(this.n,this.m,...
327  " Dir ",fileparts(this.DataDirectory)," BlockSize ",block_size);
328  for k=1:this.nBlocks
329  pos = this.getBlockPos(k);
330  copy.subsasgn(struct(" type ",[" () "]," subs ",[[" : ",pos]]),this.loadBlock(k));
331  end
332  }
333 
334 
335  function relocate(new_root) {
336 
337  /* Extract matrix_xxx folder name */
338  [~, mfolder] = fileparts(this.DataDirectory);
339  /* Concatenate with new path and call superclass relocate */
340  relocate@data.FileData(this, fullfile(new_root, mfolder));
341  }
365  function res = transposedTimes(B) {
366  if ~isa(B," data.FileMatrix ")
367  error(" Operation only applicable to other FileMatrix instances ");
368  end
369  res = data.FileMatrix(this.m,B.m," Dir ", fileparts(B.DataDirectory),...
370  " BlockSize ", B.blocksize);
371  key = struct(" type ",[" () "]," subs ",[]);
372  for j = 1:B.nBlocks
373  Bb = B.getBlock(j);
374  for i=1:this.nBlocks
375  key.subs= [this.getBlockPos(i),B.getBlockPos(j)];
376  res.subsasgn(key,this.getBlock(i)^t*Bb);
377  end
378  end
379  }
390  function s = sum(dim) {
391  if nargin < 2
392  dim = 1;
393  end
394  if dim == 1
395  s = zeros(1,this.m);
396  for k=1:this.nBlocks
397  s(this.getBlockPos(k)) = sum(this.loadBlock(k),1);
398  end
399  elseif dim == 2
400  s = zeros(this.n,1);
401  for k=1:this.nBlocks
402  s = s + sum(this.loadBlock(k),2);
403  end
404  else
405  error(" Invalid sum dimension: %d ",dim);
406  end
407  }
416  function value = power(expo) {
417  if ~isa(this," data.FileMatrix ") && ~isscalar(expo)
418  error(" FileMatrix power only defined for scalar values. ");
419  end
420  /* Special case for one block */
421  if this.nBlocks == 1
422  this.ensureCacheLoaded;
423  value = this.cachedBlock.^expo;
424  return;
425  end
426  value = data.FileMatrix(this.n,this.m," Dir ",fileparts(this.DataDirectory),...
427  " BlockSize ", this.blocksize);
428  for k=1:this.nBlocks
429  value.saveBlock(k,this.loadBlock(k).^expo);
430  end
431  }
432 
433 
434  function n = numel() {
435  n = 1;
436  }
437 
438 
439  function [n , m ] = size(dim) {
440  n = [this.n this.m];
441  if nargin == 2
442  if dim > 0 && dim < 3
443  n = n(dim);
444  else
445  n = 0;
446  end
447  elseif nargout == 2
448  n = this.n;
449  m = this.m;
450  end
451  }
460  function varargout = subsref(key) {
461  if strcmp(key(1).type," () ")
462  if this.nBlocks == 1
463  this.ensureCacheLoaded;
464  [varargout[1:nargout]] = builtin(" subsref ", this.cachedBlock, key);
465  return;
466  end
467  s = key.subs;
468  /* Default case: row & column adressing */
469  if length(s) == 2
470  /* "Select all" mode */
471  if strcmp(s[2]," : ")
472  s[2] = 1:this.m;
473  end
474  pos = this.idx(s[2],:);
475  blocks = unique(pos(:,1));
476  the_n = this.n;
477  if ~strcmp(s[1]," : ")
478  the_n = length(s[1]);
479  end
480  value = zeros(the_n,size(pos,1));
481  for bidx = 1:length(blocks)
482  b = blocks(bidx);
483  B = this.loadBlock(b);
484  value(:,pos(:,1) == b) = B(s[1],pos(pos(:,1)==b,2));
485  end
486  /* Linear addressing */
487  elseif length(key.subs) == 1
488  error(" Not yet implemented. ");
489  else
490  error(" ()-assignment must have one or two subscripts ");
491  end
492  varargout[1] = value;
493  else
494  [varargout[1:nargout]] = builtin(" subsref ", this, key);
495  end
496  }
509  function this = subsasgn(key,value) {
510  if strcmp(key(1).type," () ")
511  if this.nBlocks == 1
512  this.ensureCacheLoaded;
513  this.cachedBlock= builtin(" subsasgn ", this.cachedBlock, key, value);
514  this.cacheDirty= true;
515  return;
516  end
517  s = key.subs;
518  /* Default case: row & column adressing */
519  if length(s) == 2
520  /* "Select all" mode */
521  if strcmp(s[2]," : ")
522  s[2] = 1:this.m;
523  end
524  pos = this.idx(s[2],:);
525  blocks = unique(pos(:,1));
526  for bidx = 1:length(blocks)
527  b = blocks(bidx);
528  B = this.loadBlock(b);
529  B(s[1],pos(pos(:,1)==b,2)) = value(:,pos(:,1) == b);
530  this.saveBlock(b,B);
531  end
532  /* Linear addressing */
533  elseif length(key.subs) == 1
534  error(" Not yet implemented. ");
535  else
536  error(" ()-assignment must have one or two subscripts ");
537  end
538  else
539  builtin(" subsasgn ", this, key, value);
540  end
541  }
556  function diff = minus(B) {
557  if all(size(A) == size(B))
558  if isa(A," data.FileMatrix ")
559  if isa(B," data.FileMatrix ")
560  error(" Not yet implemented. ");
561  /* diff = data.FileMatrix(A.n, A.m, A);
562  * key = struct('type',{'()'},'subs',{{':'}});
563  * for i=1:A.nBlocks
564  * pos = A.getBlockPos(i);
565  * key.subs{2} = pos;
566  * diff.subsasgn(key,A.loadBlock(i) - B(:,pos));
567  * end */
568  else
569  /* Special case for one block */
570  if A.nBlocks == 1
571  A.ensureCacheLoaded;
572  diff = A.cachedBlock - B;
573  return;
574  end
576  diff = zeros(A.n, A.m);
577  for i=1:A.nBlocks
578  pos = A.getBlockPos(i);
579  diff(:,pos) = A.loadBlock(i) - B(:,pos);
580  end
581  end
582  else
583  diff = minus(B, A);
584  end
585  else
586  error(" Invalid matrix dimensions. ");
587  end
588  }
589 
590 
591  function a = mldivide(R) {
592  if isa(L," data.FileMatrix ")
593  if L.nBlocks == 1
594  L.ensureCacheLoaded;
595  a = L.cachedBlock\R;
596  else
597  error(" Not yet implemented ");
598  end
599  else
600  if R.nBlocks == 1
601  R.ensureCacheLoaded;
602  a = L\R.cachedBlock;
603  else
604  error(" Not yet implemented ");
605  end
606  end
607  }
608 
609 
610  function AB = mtimes(B) {
611  if isa(A," data.FileMatrix ")
612  /* FileMatrix * FileMatrix case */
613  if isa(B," data.FileMatrix ")
614  if A.nBlocks == 1 && B.nBlocks == 1
615  A.ensureCacheLoaded;
616  B.ensureCacheLoaded;
617  AB = data.FileMatrix(A.cachedBlock * B.cachedBlock);
618  return;
619  else
620  /* Set blocksize such that the result has the same number of columns per
621  * block as B has */
622  AB = data.FileMatrix(A.n,B.m," Dir ", fileparts(B.DataDirectory),...
623  " BlockSize ", A.blockSizeOf(A.n,B.bCols));
624  key = struct(" type ",[" () "]," subs ",[]);
625  for i=1:B.nBlocks
626  Bb = B.getBlock(i);
627  key.subs= [" : ",B.getBlockPos(i)];
628  for k = 1:A.nBlocks
629  Ab = A.getBlock(k);
630  sum = AB.subsref(key) + Ab*Bb(A.getBlockPos(k),:);
631  AB.subsasgn(key,sum);
632  end
633  end
634  end
635  else
636  /* Special case for one block */
637  if A.nBlocks == 1
638  A.ensureCacheLoaded;
639  AB = A.cachedBlock * B;
640  return;
641  end
642  if isscalar(B) /* Matrix*scalar case */
643 
644  AB = mtimes(B,A);
645  else
646  if A.m ~= size(B,1)
647  error(" Matrix dimensions must agree. ");
648  end
649  /* FileMatrix * vec case */
650  if size(B,2) == 1
651  AB = zeros(A.n,1);
652  for bidx = 1:A.nBlocks
653  /* Only multiply if nonzero */
654  if A.created(bidx)
655  ABlock = A.loadBlock(bidx);
656  AB = AB + ABlock*B(A.getBlockPos(bidx),:);
657  end
658  end
659  /* FileMatrix * matrix case */
660  else
661  AB = data.FileMatrix(A.n, size(B,2), " Dir ", fileparts(A.DataDirectory),...
662  " BlockSize ", A.blocksize);
663  ABcols = AB.bCols;
664  key = struct(" type ",[" () "]," subs ",[[" : "]]);
665  for i=1:A.nBlocks
666  if A.created(i)
667  b = A.loadBlock(i);
668  posm = A.getBlockPos(i);
669  /* Split up the additions into the block size of AB */
670  for j=1:ceil(size(B,2)/ABcols)
671  key.subs[2] = AB.getBlockPos(j);
672  /* This is reasonably fast as the same block in AB is loaded all
673  * the time. */
674  AB.subsasgn(key,AB.subsref(key) + b*B(posm,key.subs[2]));
675  end
676  end
677  end
678  end
679  end
680  end
681  /* [vec|mat] * FileMatrix case */
682  elseif isa(B," data.FileMatrix ")
683  /* Special case for one block */
684  if B.nBlocks == 1
685  B.ensureCacheLoaded;
686  AB = A*B.cachedBlock;
687  return;
688  end
689  if isscalar(A) /* scalar*Matrix */
690 
691  AB = data.FileMatrix(B.n, B.m, " Dir ", fileparts(B.DataDirectory),...
692  " BlockSize ", B.blocksize);
693  key = struct(" type ",[" () "]," subs ",[[" : "]]);
694  for bidx = 1:B.nBlocks
695  /* Only multiply if nonzero */
696  if B.created(bidx)
697  key.subs[2] = B.getBlockPos(bidx);
698  AB.subsasgn(key,A*B.loadBlock(bidx));
699  end
700  end
701  else
702  AB = data.FileMatrix(size(A,1), B.m, " Dir ", fileparts(B.DataDirectory),...
703  " BlockSize ", B.blocksize);
704  key = struct(" type ",[" () "]," subs ",[[" : "]]);
705  /* If AB has more blocks than B, the resulting matrix is larger than B.
706  * Thus, we need A*b to be as most as big as blocksize, which is why slices of B
707  * in the size of ABs blocks are taken. */
708  if AB.nBlocks > B.nBlocks
709  for i=1:AB.nBlocks
710  key.subs[2] = AB.getBlockPos(i);
711  b = B.subsref(key);
712  AB.subsasgn(key,A*b);
713  end
714  else
715  for i=1:B.nBlocks
716  if B.created(i)
717  key.subs[2] = B.getBlockPos(i);
718  AB.subsasgn(key,A*B.loadBlock(i));
719  end
720  end
721  /* Return a matrix if the A argument was a transposed vector */
722  if size(A,1) == 1
723  AB = AB.toMemoryMatrix;
724  end
725  end
726  end
727  end
728  }
739  function AB = times(B) {
740  if isa(A," data.FileMatrix ")
741  /* FileMatrix * FileMatrix case */
742  if isa(B," data.FileMatrix ")
743  error(" Not yet implemented. ");
744  else
745  /* Special case for one block */
746  if A.nBlocks == 1
747  A.ensureCacheLoaded;
748  AB = A.cachedBlock .* B;
749  return;
750  elseif isscalar(B)
751  /* Call matrix multiplication with scalar value */
752  AB = mtimes(B,A);
753  else
754  if A.n ~= size(B,1) || A.m ~= size(B,2)
755  error(" Matrix dimensions must agree. ");
756  end
757  AB = data.FileMatrix(A.n,A.m," Dir ", fileparts(A.DataDirectory),...
758  " BlockSize ", A.blocksize);
759 
760  for k=1:A.nBlocks
761  AB.saveBlock(k,A.loadBlock(k).*B(:,A.getBlockPos(k)));
762  end
763  end
764  end
765  else
766  /* Pointwise operation does not depend on which side it is done from. */
767  AB = times(B,A);
768  end
769  }
778  function trans = ctranspose() {
779  trans = data.FileMatrix(this.m, this.n, " BlockSize ", this.blocksize, ...
780  " Dir ", fileparts(this.DataDirectory));
781  /* Special case for only one block */
782  if this.nBlocks == 1
783  this.ensureCacheLoaded;
784  trans = this.cachedBlock^t;
785  return;
786  end
787  /* Else: multiple blocks */
788  if this.InPlaceTranspose
789  if this.nBlocks > 1
790  pi = ProcessIndicator(" Creating in-place transposed of %d-block matrix in %s " ,this.nBlocks,...
791  false,this.nBlocks,trans.DataDirectory);
792  end
793  key = struct(" type ",[" () "]," subs ",[[[]," : "]]);
794  for j=1:this.nBlocks
795  B = this.loadBlock(j);
796  key.subs[1] = this.getBlockPos(j);
797  trans.subsasgn(key,B^t);
798  if this.nBlocks > 1
799  pi.step;
800  end
801  end
802  else
803  if this.nBlocks > 1
804  pi = ProcessIndicator(" Creating transposed of %d-block matrix in %s ",2*this.nBlocks,...
805  false,this.nBlocks,trans.DataDirectory);
806  end
807  /* Write out blocks in small chunks */
808  for j=1:this.nBlocks
809  B = this.loadBlock(j);
810  for k=1:trans.nBlocks
811  pos = trans.getBlockPos(k);
812  chunk = B(pos,:); /* #ok */
813 
814  save(fullfile(trans.DataDirectory,sprintf(" tmp_%d_%d.mat ",j,k)), " chunk ");
815  end
816  if this.nBlocks > 1
817  pi.step;
818  end
819  end
820  /* Read in blocks from respective chunks */
821  for k=1:trans.nBlocks
822  B = trans.loadBlock(k);
823  for j=1:this.nBlocks
824  file = fullfile(trans.DataDirectory,sprintf(" tmp_%d_%d.mat ",j,k));
825  s = load(file);
826  pos = this.getBlockPos(j);
827  B(pos,:) = s.chunk^t;
828  /* remove temp file */
829  delete(file);
830  end
831  trans.saveBlock(k,B);
832  if this.nBlocks > 1
833  pi.step;
834  end
835  end
836  end
837  if this.nBlocks > 1
838  pi.stop;
839  end
840  }
841 
842 
843  function res = eq(B) {
844  res = false;
845  if isa(A," data.FileMatrix ") && all(size(A) == size(B))
846  if isa(B," data.FileMatrix ")
847  error(" not yet implemented ");
848  else
849  for i=1:A.nBlocks
850  pos = A.getBlockPos(i);
851  if A.created(i) || A.cachedNr == i
852  if ~isequal(A.loadBlock(i),B(:,pos)), return; end
853  else
854  if any(any(B(:,pos) ~= 0)), return; end
855  end
856  end
857  res = true;
858  end
859  elseif isa(B," data.FileMatrix ")
860  res = eq(B, A);
861  end
862  }
863 
864 
865  function res = ne(B) {
866  res = ~eq(A,B);
867  }
868 
869 
870  function horzcat(varargin) {
871  error(" not yet implemented ");
872  }
873 
874 
875  function vertcat(varargin) {
876  error(" not yet implemented ");
877  }
878 
879 
880  function delete() {
881  if ~isempty(this.created) && ~this.isSaved
882  /* Remove exactly the files for the matrix */
883  for k=1:this.nBlocks
884  if this.created(k)
885  f = fullfile(this.DataDirectory, sprintf(" block_%d.mat ",k));
886  if exist(f," file ")
887  delete(f);
888  end
889  end
890  end
891  end
892  /* Superclass delete removes the folder if empty. */
893  delete@data.FileData(this);
894  }
895 
896 
897  function n = getNumBlocks() {
898  n = this.nBlocks;
899  }
908  function B = getBlock(nr) {
909  B = this.loadBlock(nr);
910  }
919  protected:
920 
921 
922  function this = saveobj() {
923  this = saveobj@data.FileData(this);
924  if this.cacheDirty
925  A = this.cachedBlock;/* #ok */
926 
927  save([this.DataDirectory filesep sprintf(" block_%d.mat ",this.cachedNr)], " A ");
928  this.created(this.cachedNr) = true;
929  end
930  this.cachedBlock= [];
931  this.cachedNr= [];
932  this.cacheDirty= false;
933  }
934 
935 
936  private:
937 
938 
939  function ensureCacheLoaded() {
940  if this.nBlocks == 1 && isempty(this.cachedBlock)
941  this.loadBlock(1);
942  end
943  }
944 
945 
946  function saveBlock(nr,A) {
947  if nr == this.cachedNr
948  this.cachedBlock= A;
949  this.cacheDirty= true;
950  else
951  /* Save actual block that should be saved */
952  save([this.DataDirectory filesep sprintf(" block_%d.mat ",nr)], " A ");
953  end
954  this.updateMinMax(A);
955  this.created(nr) = true;
956  }
964  function A = loadBlock(nr) {
965  if nr == this.cachedNr
966  A = this.cachedBlock;
967  else
968  /* Before loading a new block, save the old one if the cache is dirty! */
969  if this.cacheDirty
970  A = this.cachedBlock;
971  save([this.DataDirectory filesep sprintf(" block_%d.mat ",this.cachedNr)], " A ");
972  this.updateMinMax(A);
973  this.created(this.cachedNr) = true;
974  /* cacheDirty is set "false" at end! */
975  end
976  if this.created(nr)
977  s = load([this.DataDirectory filesep sprintf(" block_%d.mat ",nr)]);
978  A = s.A;
979  else
980  /* Ensures correct size for block (even if only one with less than bCols
981  * columns) */
982  A = zeros(this.n, length(this.getBlockPos(nr)));
983  end
984  this.cachedNr= nr;
985  this.cachedBlock= A;
986  this.cacheDirty= false;
987  end
988  }
989 
990 
991  function updateMinMax(A) {
992  this.MinValue= min(this.MinValue,min(min(A)));
993  this.MaxValue= max(this.MaxValue,max(max(A)));
994  }
995 
996 
997  protected: /* ( Static ) */
998 
999  static function this = loadobj(this,initfrom) {
1000 
1001  created = false;
1002  if ~isa(this, " data.FileMatrix ")
1003  initfrom = this;
1004  this = data.FileMatrix(initfrom.n,initfrom.m," Dir ",...
1005  initfrom.DataDirectory," BlockSize ",initfrom.blocksize);
1006  created = true;
1007  end
1008  if nargin == 2 || created
1009  this.InPlaceTranspose= initfrom.InPlaceTranspose;
1010  this.bCols= initfrom.bCols;
1011  this.nBlocks= initfrom.nBlocks;
1012  this.n= initfrom.n;
1013  this.m= initfrom.m;
1014  this.MinValue= initfrom.MinValue;
1015  this.MaxValue= initfrom.MaxValue;
1016  this.idx= initfrom.idx;
1017  this.created= initfrom.created;
1018  this.blocksize= initfrom.blocksize;
1019  if this.nBlocks == 1
1020  field = " cachedBlock ";
1021  if isfield(initfrom," block1 ")
1022  field = " block1 ";
1023  end
1024  this.cachedBlock= initfrom.(field);
1025  end
1026  this = loadobj@data.FileData(this, initfrom);
1027  else
1028  this = loadobj@data.FileData(this);
1029  end
1030  }
1043  public: /* ( Static ) */
1044 
1045  static function data.FileMatrixfm = recoverFrom(char directory) {
1046  if nargin == 0
1047  directory = KerMor.getDir;
1048  if ~directory
1049  fm = [];
1050  return;
1051  end
1052  end
1053  d = dir(directory);
1054  nf = length(d)-2;
1055  if nf > 0
1056  nb = 0;
1057  for k=1:nf
1058  if ~exist(fullfile(directory,sprintf(" block_%d.mat ",k))," file ")
1059  break;
1060  end
1061  nb = nb + 1;
1062  end
1063  if nb > 0
1064  s = load(fullfile(directory," block_1.mat "));
1065  A1 = s.A;
1066  [N, nCols] = size(A1);
1067  if nb > 1
1068  s = load(fullfile(directory,sprintf(" block_%d.mat ",nb)));
1069  end
1070  M = (nb-1)*nCols + size(s.A,2);
1071  fm = data.FileMatrix(N,M," Dir ",fileparts(directory)," BlockSize ",8*nCols*N);
1072  fm.updateMinMax(A1); /* first block */
1073 
1074  if nb > 1
1075  fm.updateMinMax(s.A);
1076  for k=2:nb-1
1077  s2 = load(fullfile(directory,sprintf(" block_%d.mat ",k)));
1078  fm.updateMinMax(s2.A);
1079  end
1080  end
1081  /* Delete & reassign correct directory */
1082  rmdir(fm.DataDirectory);
1083  fm.DataDirectory= directory;
1084  fm.created(:) = true;
1085  fm.isSaved= true;
1086  else
1087  error(" No block_%%.mat files of a FileMatrix found. ");
1088  end
1089  else
1090  error(" No files found in %s ",directory);
1091  end
1092  }
1108  static function bs = blockSizeOf(arg1,integer arg2) {
1109  if nargin < 2
1110  n = numel(arg1);
1111  else
1112  n = arg1*arg2;
1113  end
1114  bs = n*8/1024^2;
1115  }
1130  static function res = test_FileMatrix() {
1131  res = true;
1132  B = rand(99,100);
1133  A = data.FileMatrix(99,100," BlockSize ",data.FileMatrix.blockSizeOf(B)/5);
1134  key = struct(" type ",[" () "]," subs ",[]);
1135  /* col-wise setting (fast) */
1136  for k=1:100
1137  key.subs= [" : ", k];
1138  A.subsasgn(key,B(:,k));
1139  end
1140  key.subs= [" : ", " : "];
1141  res = res && all(all(A.subsref(key) == B));
1142  /* Row-wise setting */
1143  for k=1:10
1144  key.subs= [k," : "];
1145  A.subsasgn(key,B(k,:));
1146  end
1147  key.subs= [" : ", " : "];
1148  res = res && all(all(A.toMemoryMatrix == B));
1149 
1150  /* Direct constructor test */
1151  A2 = data.FileMatrix(B);
1152  res = res && all(all(A2.subsref(key) == B));
1153 
1154  /* IsEqual test */
1155  res = res && A == B;
1156  B2 = B; B2(1,:) = -B2(1,:);
1157  res = res && A ~= B2;
1158 
1159  /* Transpose test */
1160  A.InPlaceTranspose= false;
1161  At = A^t;
1162  res = res && all(all(At.toMemoryMatrix == B^t));
1163  A.InPlaceTranspose= true;
1164  At = A^t;
1165  res = res && all(all(At.toMemoryMatrix == B^t));
1166 
1167  /* Bounding box test */
1168  [bm, bM] = Utils.getBoundingBox(B);
1169  [am, aM] = A.getColBoundingBox;
1170  res = res && isequal(bm,am) && isequal(bM,aM);
1171  }
1172 
1173 
1174  static function res = test_transposeTimes() {
1175  [A1,B1] = data.FileMatrix.getTestPair(80,100,5);
1176  [A2,B2] = data.FileMatrix.getTestPair(80,100,5);
1177  A3 = A1.transposedTimes(A2);
1178  res = norm(B1" *B2 - A3.toMemoryMatrix, "fro^t) < sqrt(eps);
1179  }
1180 
1181 
1182  static function res = test_SVD() {
1183  [A,B] = data.FileMatrix.getTestPair(99,100,5);
1184  /* SVD test */
1185  p = sqrt(eps);
1186  [u,s,v] = svd(B," econ ");
1187  [U,S,V] = A.getSVD;
1188  V = V.toMemoryMatrix;
1189  res = norm(U*S*V-B," fro ") < p;
1190  [U5,S5,V5] = A.getSVD(5);
1191  V5 = V5.toMemoryMatrix;
1192  res = res && norm(abs(V)-abs(v" ), "fro" ) < p && norm(abs(U)-abs(u), "fro^t) < p &&...
1193  norm(diag(S)-diag(s)) < p;
1194  res = res && norm(abs(V5)-abs(v(:,1:5)" ), "fro^t) < p ...
1195  && norm(abs(U5)-abs(u(:,1:5))," fro ") < p ...
1196  && norm(diag(S5)-diag(s(1:5,1:5))) < p;
1197 
1198  /* Exclude test */
1199  o = general.Orthonormalizer;
1200  exclu = o.orthonormalize(rand(size(B,1),5));
1201  [U,~,~] = A.getSVD(10,exclu);
1202  res = res && norm(exclu^t*U) < 1e-12;
1203  }
1204 
1205 
1206  static function res = test_SaveLoad() {
1207  [A,B] = data.FileMatrix.getTestPair(100,10000,1);
1208  /* Load/save */
1209  save Atmp A;
1210  clear A;
1211  load Atmp;
1212  res = A == B;
1213  rmdir(A.DataDirectory," s ");
1214  delete Atmp.mat;
1215 
1216  /* Multiblock save/load */
1217  [A,B] = data.FileMatrix.getTestPair(100,10000,10);
1218 
1219  /* Load/save */
1220  save Atmp A;
1221  clear A;
1222  load Atmp;
1223  res = res && A == B;
1224  rmdir(A.DataDirectory," s ");
1225  delete Atmp.mat;
1226  }
1227 
1228 
1229  static function res = test_SumPower() {
1230  [A,B] = data.FileMatrix.getTestPair(100,10000,40);
1231 
1232  /* Sum test */
1233  bs = sum(B,2);
1234  as = sum(A,2);
1235  res = isequal(sum(B,1),sum(A,1)) && all(abs((as-bs) ./ bs)) < sqrt(eps);
1236 
1237  /* Power test */
1238  res = res && A.^2 == B.^2;/* #ok */
1239 
1240  }
1241 
1242 
1243  static function res = test_ScalarMult() {
1244  res = true;
1245  [A,a] = data.FileMatrix.getTestPair(400,400);
1246  B = 4*A;
1247  res = res & isequal(4*a,B);
1248  C = A*1;
1249  res = res & isequal(a,C);
1250 
1251  B = 4.*A;
1252  res = res & isequal(4*a,B);
1253  C = A.*1;
1254  res = res & isequal(a,C);
1255 
1256  [A,a] = data.FileMatrix.getTestPair(400,400,4);
1257  B = 4*A;
1258  res = res & 4*a == B;
1259  C = A*1;
1260  res = res & a == C;
1261 
1262  B = 4.*A;
1263  res = res & 4*a == B;
1264  C = A.*1;
1265  res = res & a == C;
1266  }
1275  static function res = test_Times_MTimes() {
1276 
1277  /* No blocks */
1278  [A,B] = data.FileMatrix.getTestPair(100,1000);
1279  AB = A.*B;
1280  res = isequal(AB,B.*B);
1281  AB = B.*A;
1282  res = res & isequal(AB,B.*B);
1283 
1284  /* With blocks */
1285  [A,B] = data.FileMatrix.getTestPair(100,1000,4);
1286  AB = A.*B;
1287  res = res & AB == B.*B;
1288  AB = B.*A;
1289  res = res & AB == B.*B;
1290 
1291  /* Vector Multiplication test */
1292  v = rand(size(A,2),1);
1293  res = res && norm(A*v-B*v) < 1e-10;
1294  v = rand(size(A,2),100);
1295  res = res && all(Norm.L2(A*v-B*v) < 1e-10);
1296  v = rand(1,size(A,1));
1297  res = res && norm(v*A-v*B) < 1e-10;
1298  v = rand(100,size(A,1));
1299  res = res && all(Norm.L2(v*A-v*B) < 1e-10);
1300 
1301  /* Left / right multiplication test */
1302  R = rand(1000,200);
1303  L = rand(2000,50);
1304  /* With no blocks */
1305  [A, Amat] = data.FileMatrix.getTestPair(50,1000);
1306  LA = L*A;
1307  AR = A*R;
1308  res = res && isequal(LA,L*Amat);
1309  res = res && isequal(AR,Amat*R);
1310  /* With blocks */
1311  [A, Amat] = data.FileMatrix.getTestPair(50,1000,4);
1312  LA = L*A;
1313  AR = A*R;
1314  /* Left multiplication is exact as whole blocks can be used */
1315  res = res && LA == L*Amat;
1316  /* Right multiplication requires accumulation of values -> rounding errors */
1317  res = res && norm(AR - Amat*R) < 1e-12;
1318  }
1327  static function res = test_2FileMatrix_MTimes() {
1328  [A,B] = data.FileMatrix.getTestPair(100,1000);
1329  [C,D] = data.FileMatrix.getTestPair(1000,100);
1330  AC = A*C;
1331  res = AC == B*D;
1332  CA = C*A;
1333  res = res & CA == D*B;
1334 
1335  /* With blocks */
1336  [A,B] = data.FileMatrix.getTestPair(100,1000,4);
1337  [C,D] = data.FileMatrix.getTestPair(1000,100,5);
1338  AC = A*C;
1339  res = res & norm(B*D - AC.toMemoryMatrix," fro ") < 1e-10;
1340  CA = C*A;
1341  res = res & norm(D*A - CA.toMemoryMatrix," fro ") < 1e-10;
1342  }
1351  static function res = test_SpeedSVDTransp() {
1352  A = data.FileMatrix.getTestPair(100,1000,5);
1353  ti = tic;
1354  [u,s,v] = A.getSVD(5);
1355  t(1) = toc(ti);
1356 
1357  ti = tic;
1358  B = A^t;
1359  t(2) = toc(ti);
1360 
1361  ti = tic;
1362  [v2,s2,u2] = B.getSVD(5);
1363  t(3) = toc(ti);
1364  t(2) = t(2) + t(3);
1365 
1366  fprintf(" Direct SVD time: %g, Transposition time: %g, Transposed SVD time: %g\n ",t);
1367  res = true;
1368  }
1380  static function test_PartialSVD() {
1381  d = 100;
1382  A = data.FileMatrix.getTestPair(d,1000,3);
1383  B = data.FileMatrix.getTestPair(d,1000,1);
1384  idx = [1 d-1 floor(rand(1,10)*d)]+1;
1385  for k = 1:length(idx)
1386  [u,s] = B.getSVD(100,[],1:idx(k));
1387  fprintf(" u_nrows=%d, s_nrows=%d\n ",size(u,1),size(s,1));
1388  [u,s] = A.getSVD(100,[],1:idx(k));
1389  fprintf(" u_nrows=%d, s_nrows=%d\n ",size(u,1),size(s,1));
1390  end
1391  }
1398  private: /* ( Static ) */
1399 
1400  static function [A , B ] = getTestPair(n,m,nb) {
1401  if nargin < 3
1402  nb = 1;
1403  end
1404  B = rand(n,m);
1405  A = data.FileMatrix(n,m," BlockSize ",data.FileMatrix.blockSizeOf(B)/nb);
1406  /* Tedious formulation as use of direct operators inside the defining class of
1407  * overloads will not work.
1408  * See http://www.mathworks.com/help/matlab/matlab_oop/indexed-reference-and-assignment.html#br09nsm */
1409  A.subsasgn(struct(" type ",[" () "]," subs ",[[" : ", " : "]]),B);
1410  }
1411 
1412 
1413 };
1414 }
1415 
function vertcat(varargin)
Definition: FileMatrix.m:875
function value = power(expo)
Definition: FileMatrix.m:416
Collection of generally useful functions.
Definition: Utils.m:17
function this = saveobj()
Definition: FileMatrix.m:922
static function gen = generateID()
Generates a new unique ID.
Definition: IDGenerator.m:90
function s = sum(dim)
% Overloaded methods
Definition: FileMatrix.m:390
static function res = test_SaveLoad()
Definition: FileMatrix.m:1206
function res = transposedTimes(B)
Implements the operation A'*B for this matrix A and another FileMatrix B.
Definition: FileMatrix.m:365
function [ n , m ] = size(dim)
Implementation of ABlockedData.size.
Definition: FileMatrix.m:439
function pos = getBlockPos(nr)
Returns the column indices of the block "nr" within the full matrix.
Definition: FileMatrix.m:314
static function test_PartialSVD()
Tests the selective SVD/POD block-wise algorithm.
Definition: FileMatrix.m:1380
function varargout = subsref(key)
Implements subscripted value retrieval.
Definition: FileMatrix.m:460
static const .integer BLOCK_SIZE
The default block size to use for new FileMatrix instances. [MB].
Definition: FileMatrix.m:49
ABlockedData: General abstract class that allows computation of and SVD on a large matrix that is sep...
Definition: ABlockedData.m:18
function this = subsasgn(key, value)
Implements subscripted assignment.
Definition: FileMatrix.m:509
reshape
hanges the dimensions of the handle object array to the specified dimensions. See the MATLAB reshape ...
An integer value.
function B = getBlock(nr)
Implementation of ABlockedData.getBlock.
Definition: FileMatrix.m:908
static function res = test_SpeedSVDTransp()
Test results for 100000x100 matrix: BlockSVD: Computing truncated 50-SVD on 100x1000000 matrix (3 blo...
Definition: FileMatrix.m:1351
function a = mldivide(R)
Definition: FileMatrix.m:591
function relocate(new_root)
Relocates this FileMatrix instance to a new folder.
Definition: FileMatrix.m:335
A variable number of input arguments.
function diff = minus(B)
Definition: FileMatrix.m:556
InPlaceTranspose
Set this flag to true, if only so much space should be required as actually needed when transposing t...
Definition: FileMatrix.m:66
function horzcat(varargin)
Definition: FileMatrix.m:870
static function bs = blockSizeOf(arg1,integer arg2)
Computes the block size in Megabytes for a given matrix of matrix dimensions.
Definition: FileMatrix.m:1108
function B = spawnWithContent(matrix< double > A)
Creates a new FileMatrix containing the matrix A. The matrix is stored at the at the same location as...
Definition: FileMatrix.m:283
integer bCols
The number of columns for each block.
Definition: FileMatrix.m:82
FileData: Base class for access of files stored in a specific folder in the local file system...
Definition: FileData.m:18
function n = numel()
Definition: FileMatrix.m:434
function res = ne(B)
Definition: FileMatrix.m:865
Speed test * all(1:3)
char DataDirectory
The root folder where the FileData's files are saved.
Definition: FileData.m:56
static function res = test_ScalarMult()
Definition: FileMatrix.m:1243
integer m
The total number of columns.
Definition: FileMatrix.m:126
static function res = test_2FileMatrix_MTimes()
% Two FileMatrices No blocks
Definition: FileMatrix.m:1327
function trans = ctranspose()
Definition: FileMatrix.m:778
function prod = mtimes()
Need left-sided matrix multiplication if RHS singular vectors V should be returned.
Definition: ABlockedData.m:193
static function res = test_SVD()
Definition: FileMatrix.m:1182
static function res = test_SumPower()
Definition: FileMatrix.m:1229
integer nBlocks
The number of blocks into which this matrix is separated.
Definition: FileMatrix.m:95
static function this = loadobj(this, initfrom)
Loads a FileMatrix instance.
Definition: FileMatrix.m:999
FileMatrix(matrix< double > var, varargin)
Creates a new file matrix. Possible constructors:
Definition: FileMatrix.m:189
function n = getNumBlocks()
% data.ABlockedData implementations Implementation of ABlockedData.getNumBlocks
Definition: FileMatrix.m:897
integer n
The number of rows.
Definition: FileMatrix.m:113
static function rowvec< double > n = L2(matrix< double > x)
Returns the discrete norm for each column vector in x.
Definition: Norm.m:39
FileMatrix: File-based matrix which stores sets of columns in separate files.
Definition: FileMatrix.m:18
Global configuration class for all KerMor run-time settings.
Definition: KerMor.m:17
function AB = mtimes(B)
Override of ABlockedData.mtimes.
Definition: FileMatrix.m:610
Generates unique IDs.
Definition: IDGenerator.m:17
static function KerMor theinstance = App()
The singleton KerMor instance.
Definition: KerMor.m:910
Norm: Static class for commonly used norms on sets of vectors.
Definition: Norm.m:17
function res = eq(B)
Definition: FileMatrix.m:843
static function data.FileMatrix fm = recoverFrom(char directory)
Tries to recover a FileMatrix from a given directory, containing the old block data files...
Definition: FileMatrix.m:1045
function AB = times(B)
Override of ABlockedData.mtimes.
Definition: FileMatrix.m:739
static function res = test_Times_MTimes()
Definition: FileMatrix.m:1275
function res = isposrealscalar(value)
isposintscalar: Backwards-compatibility function for matlab versions greater than 2012a ...
static function res = test_transposeTimes()
Definition: FileMatrix.m:1174
function copy = copyWithNewBlockSize(block_size)
Definition: FileMatrix.m:325
function [ rowmin , rowmax ] = getColBoundingBox()
Computes the bounding box of the matrix with respect to columns.
Definition: FileMatrix.m:298
ProcessIndicator: A simple class that indicates process either via waitbar or text output...
static function [ double bmin , double bmax ] = getBoundingBox(double vectors)
Gets the bounding box for a matrix containing column vectors.
Definition: Utils.m:96
A variable number of output arguments.
static function res = test_FileMatrix()
Definition: FileMatrix.m:1130
static function d = getDir()
Returns a folder selected by a uigetdir command. Remembers the last selected folder (if successful & ...
Definition: KerMor.m:1114