192 error(
" Cannot create a FileMatrix with empty first argument. Must either be a row number or a matrix. ");
212 ip.addParamValue(
'Dir',
KerMor.
App.TempDirectory,...
213 @(v)isempty(v) || (ischar(v) && exist(v,
" dir ") == 7));
215 ip.parse(varargin[:]);
217 if isfield(ip.Results,
" m ")
221 if ~(round(
n) ==
n && round(
m) ==
m)
222 error(
" Size arguments n, m must be integer values. ");
225 bsize = min(ip.Results.BlockSize*1024^2,
n*
m*BYTEPERDOUBLE);
226 bcols = max(floor(bsize/(BYTEPERDOUBLE*
n)),1);
227 nb = ceil(
m / bcols);
233 ddir = ip.Results.Dir;
237 this =
this@data.FileData(fullfile(ddir,...
242 this.blocksize= bsize/1024^2;
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)];
255 this.
subsasgn(
struct(
" type ",[
" () "],
" subs ",[[
" : ",
" : "]]),A);
284 B = data.FileMatrix(A,
" Dir ",fileparts(this.
DataDirectory),
" Blocksize ",this.blocksize);
299 rowmin = Inf*ones(this.
n,1);
302 A = this.loadBlock(i);
303 rowmin = min(rowmin, min(A,[],2));
304 rowmax = max(rowmax, max(A,[],2));
315 pos = (nr-1)*this.
bCols + 1 : min(nr*this.
bCols,this.
m);
326 copy = data.FileMatrix(this.
n,this.
m,...
327 " Dir ",fileparts(this.
DataDirectory),
" BlockSize ",block_size);
330 copy.subsasgn(
struct(
" type ",[
" () "],
" subs ",[[
" : ",pos]]),this.loadBlock(
k));
340 relocate@data.FileData(
this, fullfile(new_root, mfolder));
366 if ~isa(B,
" data.FileMatrix ")
367 error(
" Operation only applicable to other FileMatrix instances ");
369 res = data.FileMatrix(this.
m,B.m,
" Dir ", fileparts(B.DataDirectory),...
370 " BlockSize ", B.blocksize);
371 key =
struct(
" type ",[
" () "],
" subs ",[]);
402 s = s +
sum(this.loadBlock(
k),2);
405 error(
" Invalid sum dimension: %d ",dim);
417 if ~isa(
this,
" data.FileMatrix ") && ~isscalar(expo)
418 error(
" FileMatrix power only defined for scalar values. ");
422 this.ensureCacheLoaded;
423 value = this.cachedBlock.^expo;
426 value = data.FileMatrix(this.
n,this.
m,
" Dir ",fileparts(this.
DataDirectory),...
427 " BlockSize ", this.blocksize);
429 value.saveBlock(
k,this.loadBlock(
k).^expo);
439 function [n , m ] =
size(dim) {
442 if dim > 0 && dim < 3
461 if strcmp(key(1).type,
" () ")
463 this.ensureCacheLoaded;
464 [
varargout[1:nargout]] = builtin(
" subsref ", this.cachedBlock, key);
471 if strcmp(s[2],
" : ")
474 pos = this.idx(s[2],:);
475 blocks = unique(pos(:,1));
477 if ~strcmp(s[1],
" : ")
478 the_n = length(s[1]);
480 value = zeros(the_n,
size(pos,1));
481 for bidx = 1:length(blocks)
483 B = this.loadBlock(b);
484 value(:,pos(:,1) == b) = B(s[1],pos(pos(:,1)==b,2));
487 elseif length(key.subs) == 1
488 error(
" Not yet implemented. ");
490 error(
" ()-assignment must have one or two subscripts ");
494 [varargout[1:nargout]] = builtin(
" subsref ",
this, key);
510 if strcmp(key(1).type,
" () ")
512 this.ensureCacheLoaded;
513 this.cachedBlock= builtin(
" subsasgn ", this.cachedBlock, key, value);
514 this.cacheDirty=
true;
521 if strcmp(s[2],
" : ")
524 pos = this.idx(s[2],:);
525 blocks = unique(pos(:,1));
526 for bidx = 1:length(blocks)
528 B = this.loadBlock(b);
529 B(s[1],pos(pos(:,1)==b,2)) = value(:,pos(:,1) == b);
533 elseif length(key.subs) == 1
534 error(
" Not yet implemented. ");
536 error(
" ()-assignment must have one or two subscripts ");
539 builtin(
" subsasgn ",
this, key, value);
558 if isa(A,
" data.FileMatrix ")
559 if isa(B,
" data.FileMatrix ")
560 error(
" Not yet implemented. ");
572 diff = A.cachedBlock - B;
576 diff = zeros(A.n, A.m);
578 pos = A.getBlockPos(i);
579 diff(:,pos) = A.loadBlock(i) - B(:,pos);
586 error(
" Invalid matrix dimensions. ");
592 if isa(L,
" data.FileMatrix ")
597 error(
" Not yet implemented ");
604 error(
" Not yet implemented ");
611 if isa(A,
" data.FileMatrix ")
613 if isa(B,
" data.FileMatrix ")
614 if A.nBlocks == 1 && B.nBlocks == 1
617 AB = data.FileMatrix(A.cachedBlock * B.cachedBlock);
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 ",[]);
627 key.subs= [
" : ",B.getBlockPos(i)];
630 sum = AB.subsref(key) + Ab*Bb(A.getBlockPos(
k),:);
631 AB.subsasgn(key,
sum);
639 AB = A.cachedBlock * B;
647 error(
" Matrix dimensions must agree. ");
652 for bidx = 1:A.nBlocks
655 ABlock = A.loadBlock(bidx);
656 AB = AB + ABlock*B(A.getBlockPos(bidx),:);
661 AB = data.FileMatrix(A.n,
size(B,2),
" Dir ", fileparts(A.DataDirectory),...
662 " BlockSize ", A.blocksize);
664 key =
struct(
" type ",[
" () "],
" subs ",[[
" : "]]);
668 posm = A.getBlockPos(i);
670 for j=1:ceil(
size(B,2)/ABcols)
671 key.subs[2] = AB.getBlockPos(j);
674 AB.subsasgn(key,AB.subsref(key) + b*B(posm,key.subs[2]));
682 elseif isa(B,
" data.FileMatrix ")
686 AB = A*B.cachedBlock;
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
697 key.subs[2] = B.getBlockPos(bidx);
698 AB.subsasgn(key,A*B.loadBlock(bidx));
702 AB = data.FileMatrix(
size(A,1), B.m,
" Dir ", fileparts(B.DataDirectory),...
703 " BlockSize ", B.blocksize);
704 key =
struct(
" type ",[
" () "],
" subs ",[[
" : "]]);
708 if AB.nBlocks > B.nBlocks
710 key.subs[2] = AB.getBlockPos(i);
712 AB.subsasgn(key,A*b);
717 key.subs[2] = B.getBlockPos(i);
718 AB.subsasgn(key,A*B.loadBlock(i));
723 AB = AB.toMemoryMatrix;
740 if isa(A,
" data.FileMatrix ")
742 if isa(B,
" data.FileMatrix ")
743 error(
" Not yet implemented. ");
748 AB = A.cachedBlock .* B;
754 if A.n ~=
size(B,1) || A.m ~=
size(B,2)
755 error(
" Matrix dimensions must agree. ");
757 AB = data.FileMatrix(A.n,A.m,
" Dir ", fileparts(A.DataDirectory),...
758 " BlockSize ", A.blocksize);
761 AB.saveBlock(
k,A.loadBlock(
k).*B(:,A.getBlockPos(
k)));
779 trans = data.FileMatrix(this.
m, this.
n,
" BlockSize ", this.blocksize, ...
783 this.ensureCacheLoaded;
784 trans = this.cachedBlock^
t;
791 false,this.
nBlocks,trans.DataDirectory);
793 key =
struct(
" type ",[
" () "],
" subs ",[[[],
" : "]]);
795 B = this.loadBlock(j);
797 trans.subsasgn(key,B^t);
805 false,this.
nBlocks,trans.DataDirectory);
809 B = this.loadBlock(j);
810 for k=1:trans.nBlocks
811 pos = trans.getBlockPos(
k);
814 save(fullfile(trans.DataDirectory,sprintf(
" tmp_%d_%d.mat ",j,
k)),
" chunk ");
821 for k=1:trans.nBlocks
822 B = trans.loadBlock(k);
824 file = fullfile(trans.DataDirectory,sprintf(
" tmp_%d_%d.mat ",j,k));
827 B(pos,:) = s.chunk^
t;
831 trans.saveBlock(k,B);
843 function res =
eq(B) {
845 if isa(A,
" data.FileMatrix ") &&
all(
size(A) ==
size(B))
846 if isa(B,
" data.FileMatrix ")
847 error(
" not yet implemented ");
850 pos = A.getBlockPos(i);
851 if A.created(i) || A.cachedNr == i
852 if ~isequal(A.loadBlock(i),B(:,pos)),
return; end
854 if any(any(B(:,pos) ~= 0)),
return; end
859 elseif isa(B,
" data.FileMatrix ")
865 function res =
ne(B) {
871 error(
" not yet implemented ");
876 error(
" not yet implemented ");
881 if ~isempty(this.created) && ~this.isSaved
893 delete@data.FileData(
this);
909 B = this.loadBlock(nr);
923 this =
saveobj@data.FileData(
this);
925 A = this.cachedBlock;
927 save([this.
DataDirectory filesep sprintf(
" block_%d.mat ",this.cachedNr)],
" A ");
928 this.created(this.cachedNr) =
true;
930 this.cachedBlock= [];
932 this.cacheDirty=
false;
939 function ensureCacheLoaded() {
940 if this.
nBlocks == 1 && isempty(this.cachedBlock)
946 function saveBlock(nr,A) {
947 if nr == this.cachedNr
949 this.cacheDirty=
true;
952 save([this.
DataDirectory filesep sprintf(
" block_%d.mat ",nr)],
" A ");
954 this.updateMinMax(A);
955 this.created(nr) =
true;
964 function A = loadBlock(nr) {
965 if nr == this.cachedNr
966 A = this.cachedBlock;
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;
977 s = load([this.
DataDirectory filesep sprintf(" block_%d.mat ",nr)]);
986 this.cacheDirty= false;
991 function updateMinMax(A) {
999 static function this =
loadobj(
this,initfrom) {
1002 if ~isa(
this,
" data.FileMatrix ")
1004 this = data.FileMatrix(initfrom.n,initfrom.m,
" Dir ",...
1005 initfrom.DataDirectory,
" BlockSize ",initfrom.blocksize);
1008 if nargin == 2 || created
1010 this.
bCols= initfrom.bCols;
1011 this.
nBlocks= initfrom.nBlocks;
1016 this.idx= initfrom.idx;
1017 this.created= initfrom.created;
1018 this.blocksize= initfrom.blocksize;
1020 field =
" cachedBlock ";
1021 if isfield(initfrom,
" block1 ")
1024 this.cachedBlock= initfrom.(field);
1026 this =
loadobj@data.FileData(
this, initfrom);
1028 this =
loadobj@data.FileData(
this);
1058 if ~exist(fullfile(directory,sprintf(
" block_%d.mat ",
k)),
" file ")
1064 s = load(fullfile(directory,
" block_1.mat "));
1066 [N, nCols] =
size(A1);
1068 s = load(fullfile(directory,sprintf(
" block_%d.mat ",nb)));
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);
1075 fm.updateMinMax(s.A);
1077 s2 = load(fullfile(directory,sprintf(
" block_%d.mat ",
k)));
1078 fm.updateMinMax(s2.A);
1082 rmdir(fm.DataDirectory);
1083 fm.DataDirectory= directory;
1084 fm.created(:) =
true;
1087 error(
" No block_%%.mat files of a FileMatrix found. ");
1090 error(
" No files found in %s ",directory);
1133 A = data.FileMatrix(99,100,
" BlockSize ",data.FileMatrix.blockSizeOf(B)/5);
1134 key =
struct(
" type ",[
" () "],
" subs ",[]);
1137 key.subs= [
" : ",
k];
1138 A.subsasgn(key,B(:,
k));
1140 key.subs= [
" : ",
" : "];
1141 res = res &&
all(
all(A.subsref(key) == B));
1144 key.subs= [
k,
" : "];
1145 A.subsasgn(key,B(
k,:));
1147 key.subs= [
" : ",
" : "];
1148 res = res &&
all(
all(A.toMemoryMatrix == B));
1151 A2 = data.FileMatrix(B);
1152 res = res &&
all(
all(A2.subsref(key) == B));
1155 res = res && A == B;
1156 B2 = B; B2(1,:) = -B2(1,:);
1157 res = res && A ~= B2;
1160 A.InPlaceTranspose=
false;
1162 res = res &&
all(
all(At.toMemoryMatrix == B^t));
1163 A.InPlaceTranspose=
true;
1165 res = res &&
all(
all(At.toMemoryMatrix == B^t));
1169 [am, aM] = A.getColBoundingBox;
1170 res = res && isequal(bm,am) && isequal(bM,aM);
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);
1183 [A,B] = data.FileMatrix.getTestPair(99,100,5);
1186 [u,s,v] = svd(B,
" econ ");
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;
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;
1207 [A,B] = data.FileMatrix.getTestPair(100,10000,1);
1213 rmdir(A.DataDirectory,
" s ");
1217 [A,B] = data.FileMatrix.getTestPair(100,10000,10);
1223 res = res && A == B;
1224 rmdir(A.DataDirectory,
" s ");
1230 [A,B] = data.FileMatrix.getTestPair(100,10000,40);
1235 res = isequal(
sum(B,1),
sum(A,1)) &&
all(abs((as-bs) ./ bs)) < sqrt(eps);
1238 res = res && A.^2 == B.^2;
1245 [A,a] = data.FileMatrix.getTestPair(400,400);
1247 res = res & isequal(4*a,B);
1249 res = res & isequal(a,C);
1252 res = res & isequal(4*a,B);
1254 res = res & isequal(a,C);
1256 [A,a] = data.FileMatrix.getTestPair(400,400,4);
1258 res = res & 4*a == B;
1263 res = res & 4*a == B;
1278 [A,B] = data.FileMatrix.getTestPair(100,1000);
1280 res = isequal(AB,B.*B);
1282 res = res & isequal(AB,B.*B);
1285 [A,B] = data.FileMatrix.getTestPair(100,1000,4);
1287 res = res & AB == B.*B;
1289 res = res & AB == B.*B;
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);
1305 [A, Amat] = data.FileMatrix.getTestPair(50,1000);
1308 res = res && isequal(LA,L*Amat);
1309 res = res && isequal(AR,Amat*R);
1311 [A, Amat] = data.FileMatrix.getTestPair(50,1000,4);
1315 res = res && LA == L*Amat;
1317 res = res && norm(AR - Amat*R) < 1e-12;
1328 [A,B] = data.FileMatrix.getTestPair(100,1000);
1329 [C,D] = data.FileMatrix.getTestPair(1000,100);
1333 res = res & CA == D*B;
1336 [A,B] = data.FileMatrix.getTestPair(100,1000,4);
1337 [C,D] = data.FileMatrix.getTestPair(1000,100,5);
1339 res = res & norm(B*D - AC.toMemoryMatrix,
" fro ") < 1e-10;
1341 res = res & norm(D*A - CA.toMemoryMatrix,
" fro ") < 1e-10;
1352 A = data.FileMatrix.getTestPair(100,1000,5);
1354 [u,s,v] = A.getSVD(5);
1362 [v2,s2,u2] = B.getSVD(5);
1366 fprintf(
" Direct SVD time: %g, Transposition time: %g, Transposed SVD time: %g\n ",t);
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));
1400 static function [A , B ] = getTestPair(n,
m,nb) {
1405 A = data.FileMatrix(n,m,
" BlockSize ",data.FileMatrix.blockSizeOf(B)/nb);
1409 A.subsasgn(
struct(
" type ",[
" () "],
" subs ",[[
" : ",
" : "]]),B);
function vertcat(varargin)
function value = power(expo)
Collection of generally useful functions.
function this = saveobj()
static function gen = generateID()
Generates a new unique ID.
function s = sum(dim)
% Overloaded methods
static function res = test_SaveLoad()
function res = transposedTimes(B)
Implements the operation A'*B for this matrix A and another FileMatrix B.
function [ n , m ] = size(dim)
Implementation of ABlockedData.size.
function pos = getBlockPos(nr)
Returns the column indices of the block "nr" within the full matrix.
static function test_PartialSVD()
Tests the selective SVD/POD block-wise algorithm.
function varargout = subsref(key)
Implements subscripted value retrieval.
static const .integer BLOCK_SIZE
The default block size to use for new FileMatrix instances. [MB].
ABlockedData: General abstract class that allows computation of and SVD on a large matrix that is sep...
function this = subsasgn(key, value)
Implements subscripted assignment.
reshape
hanges the dimensions of the handle object array to the specified dimensions. See the MATLAB reshape ...
function B = getBlock(nr)
Implementation of ABlockedData.getBlock.
static function res = test_SpeedSVDTransp()
Test results for 100000x100 matrix: BlockSVD: Computing truncated 50-SVD on 100x1000000 matrix (3 blo...
function relocate(new_root)
Relocates this FileMatrix instance to a new folder.
A variable number of input arguments.
InPlaceTranspose
Set this flag to true, if only so much space should be required as actually needed when transposing t...
function horzcat(varargin)
static function bs = blockSizeOf(arg1,integer arg2)
Computes the block size in Megabytes for a given matrix of matrix dimensions.
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...
integer bCols
The number of columns for each block.
FileData: Base class for access of files stored in a specific folder in the local file system...
char DataDirectory
The root folder where the FileData's files are saved.
static function res = test_ScalarMult()
integer m
The total number of columns.
static function res = test_2FileMatrix_MTimes()
% Two FileMatrices No blocks
function trans = ctranspose()
function prod = mtimes()
Need left-sided matrix multiplication if RHS singular vectors V should be returned.
static function res = test_SVD()
static function res = test_SumPower()
integer nBlocks
The number of blocks into which this matrix is separated.
static function this = loadobj(this, initfrom)
Loads a FileMatrix instance.
FileMatrix(matrix< double > var, varargin)
Creates a new file matrix. Possible constructors:
function n = getNumBlocks()
% data.ABlockedData implementations Implementation of ABlockedData.getNumBlocks
integer n
The number of rows.
static function rowvec< double > n = L2(matrix< double > x)
Returns the discrete norm for each column vector in x.
FileMatrix: File-based matrix which stores sets of columns in separate files.
Global configuration class for all KerMor run-time settings.
function AB = mtimes(B)
Override of ABlockedData.mtimes.
static function KerMor theinstance = App()
The singleton KerMor instance.
Norm: Static class for commonly used norms on sets of vectors.
static function data.FileMatrix fm = recoverFrom(char directory)
Tries to recover a FileMatrix from a given directory, containing the old block data files...
function AB = times(B)
Override of ABlockedData.mtimes.
static function res = test_Times_MTimes()
function res = isposrealscalar(value)
isposintscalar: Backwards-compatibility function for matlab versions greater than 2012a ...
static function res = test_transposeTimes()
function copy = copyWithNewBlockSize(block_size)
function [ rowmin , rowmax ] = getColBoundingBox()
Computes the bounding box of the matrix with respect to columns.
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.
A variable number of output arguments.
static function res = test_FileMatrix()
static function d = getDir()
Returns a folder selected by a uigetdir command. Remembers the last selected folder (if successful & ...