./PaxHeaders.16347/linear-algebra-2.2.30000644000000000000000000000013213563071136014211 xustar0030 mtime=1573679710.670089267 30 atime=1573679710.714089914 30 ctime=1573679710.714089914 linear-algebra-2.2.3/0000755000175000017500000000000013563071136014314 5ustar00olafolaf00000000000000linear-algebra-2.2.3/PaxHeaders.16347/INDEX0000644000000000000000000000013213563071136014723 xustar0030 mtime=1573679710.670089267 30 atime=1573679710.670089267 30 ctime=1573679710.714089914 linear-algebra-2.2.3/INDEX0000644000175000017500000000240513563071136015107 0ustar00olafolaf00000000000000matrix >> Linear Algebra Vector functions vec_projection Matrix functions cartprod cod funm lobpcg ndcovlt rotparams rotv smwsolve thfm Matrix factorization nmf_bpas nmf_pg sparse >> Sparse matrix support Block sparse matrices @blksparse/blksparse @blksparse/blksize @blksparse/ctranspose @blksparse/display @blksparse/full @blksparse/ismatrix @blksparse/isreal @blksparse/issparse @blksparse/minus @blksparse/mldivide @blksparse/mrdivide @blksparse/mtimes @blksparse/plus @blksparse/size @blksparse/sparse @blksparse/subsref @blksparse/transpose @blksparse/uminus @blksparse/uplus Kronecker Products @kronprod/kronprod @kronprod/columns @kronprod/ctranspose @kronprod/det @kronprod/disp @kronprod/display @kronprod/full @kronprod/inv @kronprod/iscomplex @kronprod/ismatrix @kronprod/isreal @kronprod/issparse @kronprod/issquare @kronprod/minus @kronprod/mldivide @kronprod/mpower @kronprod/mtimes @kronprod/numel @kronprod/plus @kronprod/rank @kronprod/rdivide @kronprod/rows @kronprod/size @kronprod/size_equal @kronprod/sparse @kronprod/times @kronprod/trace @kronprod/transpose @kronprod/uminus @kronprod/uplus Circulant matrices circulant_make_matrix circulant_matrix_vector_product circulant_eig circulant_inv linear-algebra-2.2.3/PaxHeaders.16347/inst0000644000000000000000000000013213563071136015031 xustar0030 mtime=1573679710.698089679 30 atime=1573679710.714089914 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/0000755000175000017500000000000013563071136015271 5ustar00olafolaf00000000000000linear-algebra-2.2.3/inst/PaxHeaders.16347/circulant_eig.m0000644000000000000000000000013213563071136020074 xustar0030 mtime=1573679710.690089562 30 atime=1573679710.690089562 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/circulant_eig.m0000644000175000017500000000474013563071136020264 0ustar00olafolaf00000000000000## Copyright (C) 2012 Nir Krakauer ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn{Function File} {@var{lambda} =} circulant_eig (@var{v}) ## @deftypefnx{Function File} {[@var{vs}, @var{lambda}] =} circulant_eig (@var{v}) ## ## Fast, compact calculation of eigenvalues and eigenvectors of a circulant matrix@* ## Given an @var{n}*1 vector @var{v}, return the eigenvalues @var{lambda} and optionally eigenvectors @var{vs} of the @var{n}*@var{n} circulant matrix @var{C} that has @var{v} as its first column ## ## Theoretically same as @code{eig(make_circulant_matrix(v))}, but many fewer computations; does not form @var{C} explicitly ## ## Reference: Robert M. Gray, Toeplitz and Circulant Matrices: A Review, Now Publishers, http://ee.stanford.edu/~gray/toeplitz.pdf, Chapter 3 ## ## @seealso{gallery, circulant_matrix_vector_product, circulant_inv} ## @end deftypefn function [a, b] = circulant_eig (v) ## FIXME when warning for broadcastin is turned off by default, this ## unwind_protect block could be removed ## we are using broadcasting on the code below so we turn off the ## warnings but will restore to previous state at the end bc_warn = warning ("query", "Octave:broadcast"); unwind_protect warning ("off", "Octave:broadcast"); #find the eigenvalues n = numel(v); lambda = ones(n, 1); s = (0:(n-1)); lambda = sum(v .* exp(-2*pi*i*s'*s/n))'; if nargout < 2 a = lambda; return endif #find the eigenvectors (which in fact do not depend on v) a = exp(-2*i*pi*s'*s/n) / sqrt(n); b = diag(lambda); unwind_protect_cleanup ## restore broadcats warning status warning (bc_warn.state, "Octave:broadcast"); end_unwind_protect endfunction %!shared v,C,vs,lambda %! v = [1 2 3]'; %! C = gallery("circul", v)'; %! [vs lambda] = circulant_eig(v); %!assert (vs*lambda, C*vs, 100*eps); linear-algebra-2.2.3/inst/PaxHeaders.16347/nmf_bpas.m0000644000000000000000000000013013563071136017047 xustar0029 mtime=1573679710.69408962 29 atime=1573679710.69408962 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/nmf_bpas.m0000644000175000017500000006321513563071136017243 0ustar00olafolaf00000000000000## Copyright (c) 2012 by Jingu Kim and Haesun Park ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{W}, @var{H}, @var{iter}, @var{HIS}] = } nmf_bpas (@var{A}, @var{k}) ## Nonnegative Matrix Factorization by Alternating Nonnegativity Constrained Least Squares ## using Block Principal Pivoting/Active Set method. ## ## This function solves one the following problems: given @var{A} and @var{k}, find @var{W} and @var{H} such that ## ## @group ## (1) minimize 1/2 * || @var{A}-@var{W}@var{H} ||_F^2 ## ## (2) minimize 1/2 * ( || @var{A}-@var{W}@var{H} ||_F^2 + alpha * || @var{W} ||_F^2 + beta * || @var{H} ||_F^2 ) ## ## (3) minimize 1/2 * ( || @var{A}-@var{W}@var{H} ||_F^2 + alpha * || @var{W} ||_F^2 + beta * (sum_(i=1)^n || @var{H}(:,i) ||_1^2 ) ) ## @end group ## ## where @var{W}>=0 and @var{H}>=0 elementwise. ## The input arguments are @var{A} : Input data matrix (m x n) and @var{k} : Target low-rank. ## ## ## @strong{Optional Inputs} ## @table @samp ## @item Type ## Default is 'regularized', which is recommended for quick application testing unless 'sparse' or 'plain' is explicitly needed. If sparsity is needed for 'W' factor, then apply this function for the transpose of 'A' with formulation (3). Then, exchange 'W' and 'H' and obtain the transpose of them. Imposing sparsity for both factors is not recommended and thus not included in this software. ## @table @asis ## @item 'plain' ## to use formulation (1) ## @item 'regularized' ## to use formulation (2) ## @item 'sparse' ## to use formulation (3) ## @end table ## ## @item NNLSSolver ## Default is 'bp', which is in general faster. ## @table @asis ## item 'bp' ## to use the algorithm in [1] ## item 'as' ## to use the algorithm in [2] ## @end table ## ## @item Alpha ## Parameter alpha in the formulation (2) or (3). Default is the average of all elements in A. No good justfication for this default value, and you might want to try other values. ## @item Beta ## Parameter beta in the formulation (2) or (3). ## Default is the average of all elements in A. No good justfication for this default value, and you might want to try other values. ## @item MaxIter ## Maximum number of iterations. Default is 100. ## @item MinIter ## Minimum number of iterations. Default is 20. ## @item MaxTime ## Maximum amount of time in seconds. Default is 100,000. ## @item Winit ## (m x k) initial value for W. ## @item Hinit ## (k x n) initial value for H. ## @item Tol ## Stopping tolerance. Default is 1e-3. If you want to obtain a more accurate solution, decrease TOL and increase MAX_ITER at the same time. ## @item Verbose ## If present the function will show information during the calculations. ## @end table ## ## @strong{Outputs} ## @table @samp ## @item W ## Obtained basis matrix (m x k) ## @item H ## Obtained coefficients matrix (k x n) ## @item iter ## Number of iterations ## @item HIS ## If present the history of computation is returned. ## @end table ## ## Usage Examples: ## @example ## nmf_bpas (A,10) ## nmf_bpas (A,20,'verbose') ## nmf_bpas (A,30,'verbose','nnlssolver','as') ## nmf_bpas (A,5,'verbose','type','sparse') ## nmf_bpas (A,60,'verbose','type','plain','Winit',rand(size(A,1),60)) ## nmf_bpas (A,70,'verbose','type','sparse','nnlssolver','bp','alpha',1.1,'beta',1.3) ## @end example ## ## References: ## [1] For using this software, please cite:@* ## Jingu Kim and Haesun Park, Toward Faster Nonnegative Matrix Factorization: A New Algorithm and Comparisons,@* ## In Proceedings of the 2008 Eighth IEEE International Conference on Data Mining (ICDM'08), 353-362, 2008@* ## [2] If you use 'nnls_solver'='as' (see below), please cite:@* ## Hyunsoo Kim and Haesun Park, Nonnegative Matrix Factorization Based @* ## on Alternating Nonnegativity Constrained Least Squares and Active Set Method, @* ## SIAM Journal on Matrix Analysis and Applications, 2008, 30, 713-730 ## ## Check original code at @url{http://www.cc.gatech.edu/~jingu} ## ## @seealso{nmf_pg} ## @end deftypefn ## 2015 - Modified and adapted to Octave 4.0 by ## Juan Pablo Carbajal # TODO # - Format code. # - Vectorize loops. function [W, H, iter, varargout] = nmf_bpas (A, k , varargin) page_screen_output (0, "local"); [m,n] = size(A); ST_RULE = 1; # --- Parse arguments --- # isnummatrix = @(x) ismatrix (x) & isnumeric (x); parser = inputParser (); parser.FunctionName = "nmf_bpas"; parser.addParamValue ('Winit', rand(m,k), isnummatrix); parser.addParamValue ('Hinit', rand(k,n), isnummatrix); parser.addParamValue ('Tol', 1e-3, @(x)x>0); parser.addParamValue ('Alpha', mean (A(:)), @(x)x>=0); parser.addParamValue ('Beta', mean (A(:)), @(x)x>=0); parser.addParamValue ('MaxIter', 100, @(x)x>0); parser.addParamValue ('MaxTime', 1e3, @(x)x>0); parser.addSwitch ('Verbose'); val_type = @(x,c) ischar (x) && any (strcmpi (x,c)); parser.addParamValue ('Type', 'regularized', ... @(x)val_type (x,{'regularized', 'sparse','plain'})); parser.addParamValue ('NNLSSolver', 'bp', @(x)val_type (x,{'bp', 'as'})); parser.parse(varargin{:}); % Default configuration par.m = m; par.n = n; par.type = parser.Results.Type; par.nnls_solver = parser.Results.NNLSSolver; par.alpha = parser.Results.Alpha; par.beta = parser.Results.Beta; par.max_iter = parser.Results.MaxIter; par.min_iter = 20; par.max_time = parser.Results.MaxTime; par.tol = parser.Results.Tol; par.verbose = parser.Results.Verbose; W = parser.Results.Winit; H = parser.Results.Hinit; # If the user asks for the 4th argument, it means they want the history # of the calculations. par.collectInfo = nargout > 3; clear parser val_type isnummatrix # ------------------- --- # ### PARSING TYPE # TODO add callbacks here to use during main loop. See [1] % for regularized/sparse case salphaI = sqrt (par.alpha) * eye (k); zerokm = zeros (k,m); if ( strcmpi (par.type, 'regularized') ) sbetaI = sqrt (par.beta) * eye (k); zerokn = zeros (k,n); elseif ( strcmpi (par.type, 'sparse') ) sbetaE = sqrt (par.beta) * ones (1,k); betaI = par.beta * ones (k,k); zero1n = zeros (1,n); endif ### if (par.collectInfo) % collect information for analysis/debugging [gradW, gradH] = getGradient (A,W,H,par.type,par.alpha,par.beta); initGrNormW = norm (gradW,'fro'); initGrNormH = norm (gradH,'fro'); initNorm = norm (A,'fro'); numSC = 3; initSCs = zeros (numSC,1); for j = 1:numSC initSCs(j) = ... getInitCriterion (j,A,W,H,par.type,par.alpha,par.beta,gradW,gradH); endfor ver.initGrNormW = initGrNormW; ver.initGrNormH = initGrNormH; ver.initNorm = initNorm; ver.SC1 = initSCs(1); ver.SC2 = initSCs(2); ver.SC3 = initSCs(3); ver.W_density = length (find (W>0)) / (m * k); ver.H_density = length (find (H>0)) / (n * k); tPrev = cputime; if (par.verbose) disp (ver); endif endif # Verbosity if (par.verbose) display (par); endif tStart = cputime; tTotal = 0; initSC = getInitCriterion (ST_RULE,A,W,H,par.type,par.alpha,par.beta); SCconv = 0; SC_COUNT = 3; #TODO: [1] Replace with callbacks avoid switching each time for iter = 1:par.max_iter switch par.type case 'plain' [H,gradHX,subIterH] = nnlsm (W,A,H,par.nnls_solver); [W,gradW,subIterW] = nnlsm (H',A',W',par.nnls_solver); extra_term = 0; case 'regularized' [H,gradHX,subIterH] = nnlsm ([W;sbetaI],[A;zerokn],H,par.nnls_solver); [W,gradW,subIterW] = nnlsm ([H';salphaI],[A';zerokm],W',par.nnls_solver); extra_term = par.beta * H; case 'sparse' [H,gradHX,subIterH] = nnlsm ([W;sbetaE],[A;zero1n],H,par.nnls_solver); [W,gradW,subIterW] = nnlsm ([H';salphaI],[A';zerokm],W',par.nnls_solver); extra_term = betaI * H; endswitch gradH = ( W * W' ) * H - W * A + extra_term; W = W'; gradW = gradW'; if (par.collectInfo) % collect information for analysis/debugging elapsed = cputime - tPrev; tTotal = tTotal + elapsed; idx = iter+1; ver.iter(idx) = iter; ver.elapsed(idx) = elapsed; ver.tTotal(idx) = tTotal; ver.subIterW(idx) = subIterW; ver.subIterH(idx) = subIterH; ver.relError(idx) = norm (A - W * H,'fro') / initNorm; ver.SC1(idx) = ... getStopCriterion (1,A,W,H,par.type,par.alpha,par.beta,gradW,gradH) / initSCs(1); ver.SC2(idx) = ... getStopCriterion (2,A,W,H,par.type,par.alpha,par.beta,gradW,gradH) / initSCs(2); ver.SC3(idx) = ... getStopCriterion (3,A,W,H,par.type,par.alpha,par.beta,gradW,gradH) / initSCs(3); ver.W_density(idx) = length (find (W>0)) / (m * k); ver.H_density(idx) = length (find (H>0)) / (n * k); if (par.verbose) toshow = structfun (@(x)x(end), ver, "UniformOutput", false); display (toshow); endif tPrev = cputime; endif if (iter > par.min_iter) SC = getStopCriterion (ST_RULE,A,W,H,par.type,par.alpha,par.beta,gradW,gradH); if ( ( par.collectInfo && tTotal > par.max_time) || ... (~par.collectInfo && cputime-tStart > par.max_time ) ) printf ("Stop: maximum total time reached.\n"); break; elseif ( SC / initSC <= par.tol ) SCconv = SCconv + 1; if (SCconv >= SC_COUNT) printf ("Stop: tolerance reached.\n"); break; endif else SCconv = 0; endif endif endfor [m,n] = size (A); norm2 = sqrt (sum (W.^2,1)); toNormalize = norm2 > eps; W(:,toNormalize) = W(:,toNormalize) ./ norm2(toNormalize); H(toNormalize,:) = H(toNormalize,:) .* norm2(toNormalize)'; final.iterations = iter; if (par.collectInfo) final.elapsed_total = tTotal; else final.elapsed_total = cputime - tStart; endif final.relative_error = norm (A - W * H,'fro') / norm(A,'fro'); final.W_density = length (find (W>0)) / (m * k); final.H_density = length(find (H>0)) / (n * k); if (par.verbose) display (final); endif if (par.collectInfo) varargout{1} = ver; endif endfunction ### Done till here Wed Mar 18 2015 %------------------- % Utility Functions %------------------- function retVal = getInitCriterion(stopRule,A,W,H,type,alpha,beta,gradW,gradH) % STOPPING_RULE : 1 - Normalized proj. gradient % 2 - Proj. gradient % 3 - Delta by H. Kim % 0 - None (want to stop by MAX_ITER or MAX_TIME) if nargin~=9 [gradW,gradH] = getGradient(A,W,H,type,alpha,beta); end [m,k]=size(W);, [k,n]=size(H);, numAll=(m*k)+(k*n); switch stopRule case 1 retVal = norm([gradW; gradH'],'fro')/numAll; case 2 retVal = norm([gradW; gradH'],'fro'); case 3 retVal = getStopCriterion(3,A,W,H,type,alpha,beta,gradW,gradH); case 0 retVal = 1; end endfunction function retVal = getStopCriterion(stopRule,A,W,H,type,alpha,beta,gradW,gradH) % STOPPING_RULE : 1 - Normalized proj. gradient % 2 - Proj. gradient % 3 - Delta by H. Kim % 0 - None (want to stop by MAX_ITER or MAX_TIME) if nargin~=9 [gradW,gradH] = getGradient(A,W,H,type,alpha,beta); end switch stopRule case 1 pGradW = gradW(gradW<0|W>0); pGradH = gradH(gradH<0|H>0); pGrad = [gradW(gradW<0|W>0); gradH(gradH<0|H>0)]; pGradNorm = norm(pGrad); retVal = pGradNorm/length(pGrad); case 2 pGradW = gradW(gradW<0|W>0); pGradH = gradH(gradH<0|H>0); pGrad = [gradW(gradW<0|W>0); gradH(gradH<0|H>0)]; retVal = norm(pGrad); case 3 resmat=min(H,gradH); resvec=resmat(:); resmat=min(W,gradW); resvec=[resvec; resmat(:)]; deltao=norm(resvec,1); %L1-norm num_notconv=length(find(abs(resvec)>0)); retVal=deltao/num_notconv; case 0 retVal = 1e100; end endfunction function [gradW,gradH] = getGradient(A,W,H,type,alpha,beta) switch type case 'plain' gradW = W*(H*H') - A*H'; gradH = (W'*W)*H - W'*A; case 'regularized' gradW = W*(H*H') - A*H' + alpha*W; gradH = (W'*W)*H - W'*A + beta*H; case 'sparse' k=size(W,2); betaI = beta*ones(k,k); gradW = W*(H*H') - A*H' + alpha*W; gradH = (W'*W)*H - W'*A + betaI*H; end endfunction function [X,grad,iter] = nnlsm(A,B,init,solver) switch solver case 'bp' [X,grad,iter] = nnlsm_blockpivot(A,B,0,init); case 'as' [X,grad,iter] = nnlsm_activeset(A,B,1,0,init); end endfunction function [ X,Y,iter,success ] = nnlsm_activeset( A, B, overwrite, isInputProd, init) % Nonnegativity Constrained Least Squares with Multiple Righthand Sides % using Active Set method % % This software solves the following problem: given A and B, find X such that % minimize || AX-B ||_F^2 where X>=0 elementwise. % % Reference: % Charles L. Lawson and Richard J. Hanson, Solving Least Squares Problems, % Society for Industrial and Applied Mathematics, 1995 % M. H. Van Benthem and M. R. Keenan, % Fast Algorithm for the Solution of Large-scale Non-negativity-constrained Least Squares Problems, % J. Chemometrics 2004; 18: 441-450 % % Written by Jingu Kim (jingu@cc.gatech.edu) % School of Computational Science and Engineering, % Georgia Institute of Technology % % Last updated Feb-20-2010 % % % A : input matrix (m x n) (by default), or A'*A (n x n) if isInputProd==1 % B : input matrix (m x k) (by default), or A'*B (n x k) if isInputProd==1 % overwrite : (optional, default:0) if turned on, unconstrained least squares solution is computed in the beginning % isInputProd : (optional, default:0) if turned on, use (A'*A,A'*B) as input instead of (A,B) % init : (optional) initial value for X % % X : the solution (n x k) % Y : A'*A*X - A'*B where X is the solution (n x k) % iter : number of iterations % success : 1 for success, 0 for failure. % Failure could only happen on a numericall very ill-conditioned problem. if nargin<3, overwrite=0;, end if nargin<4, isInputProd=0;, end if isInputProd AtA=A;,AtB=B; else AtA=A'*A;, AtB=A'*B; end [n,k]=size(AtB); MAX_ITER = n*5; % set initial feasible solution if overwrite [X,iter] = solveNormalEqComb(AtA,AtB); PassSet = (X > 0); NotOptSet = any(X<0); else if nargin<5 X = zeros(n,k); PassSet = false(n,k); NotOptSet = true(1,k); else X = init; PassSet = (X > 0); NotOptSet = any(X<0); end iter = 0; end Y = zeros(n,k); Y(:,~NotOptSet)=AtA*X(:,~NotOptSet) - AtB(:,~NotOptSet); NotOptCols = find(NotOptSet); bigIter = 0;, success=1; while(~isempty(NotOptCols)) bigIter = bigIter+1; if ((MAX_ITER >0) && (bigIter > MAX_ITER)) % set max_iter for ill-conditioned (numerically unstable) case success = 0;, bigIter, break end % find unconstrained LS solution for the passive set Z = zeros(n,length(NotOptCols)); [ Z,subiter ] = solveNormalEqComb(AtA,AtB(:,NotOptCols),PassSet(:,NotOptCols)); iter = iter + subiter; %Z(abs(Z)<1e-12) = 0; % One can uncomment this line for numerical stability. InfeaSubSet = Z < 0; InfeaSubCols = find(any(InfeaSubSet)); FeaSubCols = find(all(~InfeaSubSet)); if ~isempty(InfeaSubCols) % for infeasible cols ZInfea = Z(:,InfeaSubCols); InfeaCols = NotOptCols(InfeaSubCols); Alpha = zeros(n,length(InfeaSubCols));, Alpha(:,:) = Inf; InfeaSubSet(:,InfeaSubCols); [i,j] = find(InfeaSubSet(:,InfeaSubCols)); InfeaSubIx = sub2ind(size(Alpha),i,j); if length(InfeaCols) == 1 InfeaIx = sub2ind([n,k],i,InfeaCols * ones(length(j),1)); else InfeaIx = sub2ind([n,k],i,InfeaCols(j)'); end Alpha(InfeaSubIx) = X(InfeaIx)./(X(InfeaIx)-ZInfea(InfeaSubIx)); [minVal,minIx] = min(Alpha); Alpha(:,:) = repmat(minVal,n,1); X(:,InfeaCols) = X(:,InfeaCols)+Alpha.*(ZInfea-X(:,InfeaCols)); IxToActive = sub2ind([n,k],minIx,InfeaCols); X(IxToActive) = 0; PassSet(IxToActive) = false; end if ~isempty(FeaSubCols) % for feasible cols FeaCols = NotOptCols(FeaSubCols); X(:,FeaCols) = Z(:,FeaSubCols); Y(:,FeaCols) = AtA * X(:,FeaCols) - AtB(:,FeaCols); %Y( abs(Y)<1e-12 ) = 0; % One can uncomment this line for numerical stability. NotOptSubSet = (Y(:,FeaCols) < 0) & ~PassSet(:,FeaCols); NewOptCols = FeaCols(all(~NotOptSubSet)); UpdateNotOptCols = FeaCols(any(NotOptSubSet)); if ~isempty(UpdateNotOptCols) [minVal,minIx] = min(Y(:,UpdateNotOptCols).*~PassSet(:,UpdateNotOptCols)); PassSet(sub2ind([n,k],minIx,UpdateNotOptCols)) = true; end NotOptSet(NewOptCols) = false; NotOptCols = find(NotOptSet); end end endfunction function [ X,Y,iter,success ] = nnlsm_blockpivot( A, B, isInputProd, init ) % Nonnegativity Constrained Least Squares with Multiple Righthand Sides % using Block Principal Pivoting method % % This software solves the following problem: given A and B, find X such that % minimize || AX-B ||_F^2 where X>=0 elementwise. % % Reference: % Jingu Kim and Haesun Park, Toward Faster Nonnegative Matrix Factorization: A New Algorithm and Comparisons, % In Proceedings of the 2008 Eighth IEEE International Conference on Data Mining (ICDM'08), 353-362, 2008 % % Written by Jingu Kim (jingu@cc.gatech.edu) % Copyright 2008-2009 by Jingu Kim and Haesun Park, % School of Computational Science and Engineering, % Georgia Institute of Technology % % Check updated code at http://www.cc.gatech.edu/~jingu % Please send bug reports, comments, or questions to Jingu Kim. % This code comes with no guarantee or warranty of any kind. Note that this algorithm assumes that the % input matrix A has full column rank. % % Last modified Feb-20-2009 % % % A : input matrix (m x n) (by default), or A'*A (n x n) if isInputProd==1 % B : input matrix (m x k) (by default), or A'*B (n x k) if isInputProd==1 % isInputProd : (optional, default:0) if turned on, use (A'*A,A'*B) as input instead of (A,B) % init : (optional) initial value for X % % X : the solution (n x k) % Y : A'*A*X - A'*B where X is the solution (n x k) % iter : number of iterations % success : 1 for success, 0 for failure. % Failure could only happen on a numericall very ill-conditioned problem. if nargin<3, isInputProd=0;, end if isInputProd AtA = A;, AtB = B; else AtA = A'*A;, AtB = A'*B; end [n,k]=size(AtB); MAX_ITER = n*5; % set initial feasible solution X = zeros(n,k); if nargin<4 Y = - AtB; PassiveSet = false(n,k); iter = 0; else PassiveSet = (init > 0); [ X,iter ] = solveNormalEqComb(AtA,AtB,PassiveSet); Y = AtA * X - AtB; end % parameters pbar = 3; P = zeros(1,k);, P(:) = pbar; Ninf = zeros(1,k);, Ninf(:) = n+1; iter = 0; NonOptSet = (Y < 0) & ~PassiveSet; InfeaSet = (X < 0) & PassiveSet; NotGood = sum(NonOptSet)+sum(InfeaSet); NotOptCols = NotGood > 0; bigIter = 0;, success=1; while(~isempty(find(NotOptCols))) bigIter = bigIter+1; if ((MAX_ITER >0) && (bigIter > MAX_ITER)) % set max_iter for ill-conditioned (numerically unstable) case success = 0;, break end Cols1 = NotOptCols & (NotGood < Ninf); Cols2 = NotOptCols & (NotGood >= Ninf) & (P >= 1); Cols3Ix = find(NotOptCols & ~Cols1 & ~Cols2); if ~isempty(find(Cols1)) P(Cols1) = pbar;,Ninf(Cols1) = NotGood(Cols1); PassiveSet(NonOptSet & repmat(Cols1,n,1)) = true; PassiveSet(InfeaSet & repmat(Cols1,n,1)) = false; end if ~isempty(find(Cols2)) P(Cols2) = P(Cols2)-1; PassiveSet(NonOptSet & repmat(Cols2,n,1)) = true; PassiveSet(InfeaSet & repmat(Cols2,n,1)) = false; end if ~isempty(Cols3Ix) for i=1:length(Cols3Ix) Ix = Cols3Ix(i); toChange = max(find( NonOptSet(:,Ix)|InfeaSet(:,Ix) )); if PassiveSet(toChange,Ix) PassiveSet(toChange,Ix)=false; else PassiveSet(toChange,Ix)=true; end end end NotOptMask = repmat(NotOptCols,n,1); [ X(:,NotOptCols),subiter ] = solveNormalEqComb(AtA,AtB(:,NotOptCols),PassiveSet(:,NotOptCols)); iter = iter + subiter; X(abs(X)<1e-12) = 0; % for numerical stability Y(:,NotOptCols) = AtA * X(:,NotOptCols) - AtB(:,NotOptCols); Y(abs(Y)<1e-12) = 0; % for numerical stability % check optimality NonOptSet = NotOptMask & (Y < 0) & ~PassiveSet; InfeaSet = NotOptMask & (X < 0) & PassiveSet; NotGood = sum(NonOptSet)+sum(InfeaSet); NotOptCols = NotGood > 0; end endfunction function [ Z,iter ] = solveNormalEqComb( AtA,AtB,PassSet ) % Solve normal equations using combinatorial grouping. % Although this function was originally adopted from the code of % "M. H. Van Benthem and M. R. Keenan, J. Chemometrics 2004; 18: 441-450", % important modifications were made to fix bugs. % % Modified by Jingu Kim (jingu@cc.gatech.edu) % School of Computational Science and Engineering, % Georgia Institute of Technology % % Last updated Aug-12-2009 iter = 0; if (nargin ==2) || isempty(PassSet) || all(PassSet(:)) Z = AtA\AtB; iter = iter + 1; else Z = zeros(size(AtB)); [n,k1] = size(PassSet); ## Fixed on Aug-12-2009 if k1==1 Z(PassSet)=AtA(PassSet,PassSet)\AtB(PassSet); else ## Fixed on Aug-12-2009 % The following bug was identified by investigating a bug report by Hanseung Lee. [sortedPassSet,sortIx] = sortrows(PassSet'); breaks = any(diff(sortedPassSet)'); breakIx = [0 find(breaks) k1]; % codedPassSet = 2.^(n-1:-1:0)*PassSet; % [sortedPassSet,sortIx] = sort(codedPassSet); % breaks = diff(sortedPassSet); % breakIx = [0 find(breaks) k1]; for k=1:length(breakIx)-1 cols = sortIx(breakIx(k)+1:breakIx(k+1)); vars = PassSet(:,sortIx(breakIx(k)+1)); Z(vars,cols) = AtA(vars,vars)\AtB(vars,cols); iter = iter + 1; end end end endfunction %!shared m, n, k, A %! m = 30; %! n = 20; %! k = 10; %! A = rand(m,n); %!test %! [W,H,iter,HIS]=nmf_bpas(A,k); %!test %! [W,H,iter,HIS]=nmf_bpas(A,k,'verbose'); %!test %! [W,H,iter,HIS]=nmf_bpas(A,k,'verbose','nnlssolver','as'); %!test %! [W,H,iter,HIS]=nmf_bpas(A,k,'verbose','type','sparse'); %!test %! [W,H,iter,HIS]=nmf_bpas(A,k,'verbose','type','sparse','nnlssolver','bp','alpha',1.1,'beta',1.3); %!test %! [W,H,iter,HIS]=nmf_bpas(A,k,'verbose','type','plain','winit',rand(m,k)); %!demo %! m = 300; %! n = 200; %! k = 10; %! %! W_org = rand(m,k);, W_org(rand(m,k)>0.5)=0; %! H_org = rand(k,n);, H_org(rand(k,n)>0.5)=0; %! %! % normalize W, since 'nmf' normalizes W before return %! norm2=sqrt(sum(W_org.^2,1)); %! toNormalize = norm2 > eps; %! W_org(:,toNormalize) = W_org(:,toNormalize) ./ norm2(toNormalize); %! %! A = W_org * H_org; %! %! [W,H,iter,HIS]=nmf_bpas (A,k,'type','plain','tol',1e-4); %! %! % -------------------- column reordering before computing difference %! reorder = zeros(k,1); %! selected = zeros(k,1); %! for i=1:k %! for j=1:k %! if ~selected(j), break, end %! end %! minIx = j; %! %! for j=minIx+1:k %! if ~selected(j) %! d1 = norm(W(:,i)-W_org(:,minIx)); %! d2 = norm(W(:,i)-W_org(:,j)); %! if (d2. ## -*- texinfo -*- ## @deftypefn{Function File} {@var{y} =} ndcovlt (@var{x}, @var{t1}, @var{t2}, @dots{}) ## Computes an n-dimensional covariant linear transform of an n-d tensor, given a ## transformation matrix for each dimension. The number of columns of each transformation ## matrix must match the corresponding extent of @var{x}, and the number of rows determines ## the corresponding extent of @var{y}. For example: ## ## @example ## size (@var{x}, 2) == columns (@var{t2}) ## size (@var{y}, 2) == rows (@var{t2}) ## @end example ## ## The element @code{@var{y}(i1, i2, @dots{})} is defined as a sum of ## ## @example ## @var{x}(j1, j2, @dots{}) * @var{t1}(i1, j1) * @var{t2}(i2, j2) * @dots{} ## @end example ## ## over all j1, j2, @dots{}. For two dimensions, this reduces to ## @example ## @var{y} = @var{t1} * @var{x} * @var{t2}.' ## @end example ## ## [] passed as a transformation matrix is converted to identity matrix for ## the corresponding dimension. ## ## @end deftypefn ## Author: Jaroslav Hajek function y = ndcovlt (x, varargin) nd = max (ndims (x), nargin - 1); varargin = resize (varargin, 1, nd); # check dimensions for i = 1:nd ti = varargin{i}; if (isnumeric (ti) && ndims (ti) == 2) [r, c] = size (ti); if (r + c == 0) varargin{i} = eye (size (x, i)); elseif (c != size (x, i)) error ("ndcovt: dimension mismatch for x-th transformation matrix"); endif else error ("ndcovt: transformation matrices must be numeric 2d matrices"); endif endfor if (isempty (x)) szy = cellfun (@rows, varargin); y = zeros (szy); return endif ldp = [2:nd, 1]; ## First transformation. y = ldtrans (x, varargin{1}); ## Always shift one dimension. for i = 2:nd-1 y = ldtrans (permute (y, ldp), varargin{i}); endfor ## Permute to normal order now to save one permutation. if (nd > 2) y = ipermute (y, [nd-1:nd, 1:nd-2]); endif ## Now multiply from the right. szy = size (y); szy(end+1:nd-1) = 1; m = varargin{nd}; szy(nd) = rows (m); y = reshape (y, [], size (y, nd)); y = reshape (y * m.', szy); endfunction function y = ldtrans (x, m) sz = size (x); sz(1) = rows (m); y = reshape (m * x(:,:), sz); endfunction linear-algebra-2.2.3/inst/PaxHeaders.16347/rotv.m0000644000000000000000000000013013563071136016254 xustar0029 mtime=1573679710.69408962 29 atime=1573679710.69408962 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/rotv.m0000644000175000017500000000457613563071136016455 0ustar00olafolaf00000000000000## Copyright (C) 2002 Etienne Grossmann ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn{Function File} {@var{r} = } rotv ( v, ang ) ## @cindex ## The functionrotv calculates a Matrix of rotation about @var{v} w/ angle |v| ## r = rotv(v [,ang]) ## ## Returns the rotation matrix w/ axis v, and angle, in radians, norm(v) or ## ang (if present). ## ## rotv(v) == w'*w + cos(a) * (eye(3)-w'*w) - sin(a) * crossmat(w) ## ## where a = norm (v) and w = v/a. ## ## v and ang may be vertically stacked : If 'v' is 2x3, then ## rotv( v ) == [rotv(v(1,:)); rotv(v(2,:))] ## ## @example ## ## @end example ## @seealso{rotparams, rota, rot} ## @end deftypefn function r = rotv(v ,ang) if nargin > 1 v = v.*((ang(:)./sqrt(sum(v'.^2))')*ones(1,3)); end ## For checking only ## v00 = v ; ## static toto = floor(rand(1)*100) ; ## toto a = sqrt(sum(v'.^2))' ; oka = find(a!=0); if all(size(oka)), v(oka,:) = v(oka,:)./(a(oka)*ones(1,3)) ; end ## ca = cos(a); ## sa = sin(a); N = size(v,1) ; N3 = 3*N ; r = (reshape( v', N3,1 )*ones(1,3)).*kron(v,ones(3,1)) ; r += kron(cos(a),ones(3,3)) .* (kron(ones(N,1),eye(3))-r) ; ## kron(cos(a),ones(3,3)) .* (kron(ones(N,1),eye(3))-r0) ## cos(a) tmp = zeros(N3,3) ; tmp( 2:3:N3,1 ) = v(:,3) ; tmp( 1:3:N3,2 ) = -v(:,3) ; tmp( 3:3:N3,1 ) = -v(:,2) ; tmp( 1:3:N3,3 ) = v(:,2) ; tmp( 2:3:N3,3 ) = -v(:,1) ; tmp( 3:3:N3,2 ) = v(:,1) ; ## keyboard r -= kron(sin(a),ones(3)) .* tmp ; endfunction ## For checking only ## r2 = zeros(N3,3) ; ## for i=1:size(v,1), ## v0 = v00(i,:); ## t = norm(v0); ## if t, v0 = v0/t; end; ## r2(3*i-2:3*i,:) = v0'*v0 + cos(t)*(eye(3)-v0'*v0) + -sin(t)*[0, -v0(3), v0(2);v0(3), 0, -v0(1);-v0(2), v0(1), 0]; ## end ## max(abs(r2(:)-r(:))) linear-algebra-2.2.3/inst/PaxHeaders.16347/thfm.m0000644000000000000000000000013213563071136016222 xustar0030 mtime=1573679710.698089679 30 atime=1573679710.698089679 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/thfm.m0000644000175000017500000000773613563071136016422 0ustar00olafolaf00000000000000## Copyright (C) 2001 Rolf Fabian ## Copyright (C) 2001 Paul Kienzle ## Copyright (C) 2011 Philip Nienhuis ## Copyright (C) 2011 Carnë Draug ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn{Function File} {@var{y} =} thfm (@var{x}, @var{mode}) ## Trigonometric/hyperbolic functions of square matrix @var{x}. ## ## @var{mode} must be the name of a function. Valid functions are 'sin', 'cos', ## 'tan', 'sec', 'csc', 'cot' and all their inverses and/or hyperbolic variants, ## and 'sqrt', 'log' and 'exp'. ## ## The code @code{thfm (x, 'cos')} calculates matrix cosinus @emph{even if} input ## matrix @var{x} is @emph{not} diagonalizable. ## ## @emph{Important note}: ## This algorithm does @emph{not} use an eigensystem similarity transformation. It ## maps the @var{mode} functions to functions of @code{expm}, @code{logm} and ## @code{sqrtm}, which are known to be robust with respect to non-diagonalizable ## ('defective') @var{x}. ## ## @seealso{funm} ## @end deftypefn function y = thfm (x,M) ## minimal arg check only if ( nargin != 2 || !ischar (M) || ischar (x) ) print_usage; endif ## look for known functions of sqrt, log, exp I = eye (size (x)); switch (M) case {'cos'} if (isreal(x)) y = real( expm( i*x ) ); else y = ( expm( i*x ) + expm( -i*x ) ) / 2; endif case {'sin'} if (isreal(x)) y = imag( expm( i*x ) ); else y = ( expm( i*x ) - expm( -i*x ) ) / (2*i); endif case {'tan'} if (isreal(x)) t = expm( i*x ); y = imag(t)/real(t); else t = expm( -2*i*x ); y = -i*(I-t)/(I+t); endif case {'cot'} if (isreal(x)) t = expm( i*x ); y = real(t)/imag(t); else t = expm( -2*i*x ); y = i*(I+t)/(I-t); endif case {'sec'} if (isreal(x)) y = inv( real(expm(i*x)) ); else y = inv( expm(i*x)+expm(-i*x) )*2 ; endif case {'csc'} if (isreal(x)) y = inv( imag(expm(i*x)) ); else y = inv( expm(i*x)-expm(-i*x) )*2i; endif case {'log'} y = logm(x); case {'exp'} y = expm(x); case {'cosh'} y = ( expm(x)+expm(-x) )/2; case {'sinh'} y = ( expm(x)-expm(-x) )/2; case {'tanh'} t = expm( -2*x ); y = (I - t)/(I + t); case {'coth'} t = expm( -2*x ); y = (I + t)/(I - t); case {'sech'} y = 2 * inv( expm(x) + expm(-x) ); case {'csch'} y = 2 * inv( expm(x) - expm(-x) ); case {'asin'} y = -i * logm( i*x + sqrtm(I - x*x) ); case {'acos'} y = i * logm( x - i*sqrtm(I - x*x) ); case {'atan'} y = -i/2 * logm( (I + i*x)/(I - i*x) ); case {'acot'} y = i/2 * logm( (I + i*x)/(i*x - I) ); case {'asec'} y = i * logm( ( I - sqrtm(I - x*x) ) / x ); case {'acsc'} y = -i * logm( i*( I + sqrtm(I - x*x) ) / x ); case {'sqrt'} y = sqrtm(x); case {'asinh'} y = logm( x + sqrtm (x*x + I) ); case {'acosh'} y = logm( x + sqrtm (x*x - I) ); case {'atanh'} y = logm( (I + x)/(I - x) ) / 2; case {'acoth'} y = logm( (I + x)/(x - I) ) / 2; case {'asech'} y = logm( (I + sqrtm (I - x*x)) / x ); case {'acsch'} y = logm( (I + sqrtm (I + x*x)) / x ); otherwise error ("thfm doesn't support function %s - try to use funm instead.", M); endswitch endfunction linear-algebra-2.2.3/inst/PaxHeaders.16347/@blksparse0000644000000000000000000000013213563071136017117 xustar0030 mtime=1573679710.678089385 30 atime=1573679710.714089914 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@blksparse/0000755000175000017500000000000013563071136017357 5ustar00olafolaf00000000000000linear-algebra-2.2.3/inst/@blksparse/PaxHeaders.16347/isreal.m0000644000000000000000000000013213563071136020631 xustar0030 mtime=1573679710.674089326 30 atime=1573679710.674089326 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@blksparse/isreal.m0000644000175000017500000000160113563071136021012 0ustar00olafolaf00000000000000## Copyright (C) 2010 VZLU Prague ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} isreal (@var{s}) ## Returns true if the array is non-complex. ## @end deftypefn function is = isreal (s) is = isreal (s.sv); endfunction linear-algebra-2.2.3/inst/@blksparse/PaxHeaders.16347/mtimes.m0000644000000000000000000000013213563071136020650 xustar0030 mtime=1573679710.674089326 30 atime=1573679710.674089326 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@blksparse/mtimes.m0000644000175000017500000000627013563071136021040 0ustar00olafolaf00000000000000## Copyright (C) 2010 VZLU Prague ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} mtimes (@var{x}, @var{y}) ## Multiplies a block sparse matrix with a full matrix, or two block sparse ## matrices. Multiplication of block sparse * sparse is not implemented. ## If one of arguments is a scalar, it's a scalar multiply. ## @end deftypefn function c = mtimes (a, b) if (isa (a, "blksparse")) if (isa (b, "blksparse")) c = mtimes_ss (a, b); else c = mtimes_sm (a, b); endif elseif (isa (b, "blksparse")) c = mtimes_ms (a, b); else error ("blksparse: invalid arguments to mtimes"); endif endfunction function y = mtimes_sm (s, x) if (isscalar (x)) y = s; y.sv *= x; return; elseif (issparse (x)) error ("blksparse * sparse not implemented."); endif siz = s.siz; bsiz = s.bsiz; ## Check sizes. [xr, xc] = size (x); if (xr != siz(2)*bsiz(2)) gripe_nonconformant (siz.*bsiz, [xr, xc]); endif ## Form blocks. x = reshape (x, bsiz(2), siz(2), xc); x = permute (x, [1, 3, 2]); ## Scatter. xs = x(:,:,s.j); ## Multiply. ys = blkmm (s.sv, xs); ## Gather. y = accumdim (s.i, ys, 3, siz(1)); y = permute (y, [1, 3, 2]); ## Narrow blocks. y = reshape (y, bsiz(1)*siz(1), xc); endfunction function y = mtimes_ms (x, s) if (isscalar (x)) y = s; y.sv *= x; return; elseif (issparse (x)) error ("sparse * blksparse not implemented."); endif siz = s.siz; bsiz = s.bsiz; ## Check sizes. [xr, xc] = size (x); if (xc != siz(1)*bsiz(1)) gripe_nonconformant ([xr, xc], siz.*bsiz); endif ## Form blocks. x = reshape (x, xr, bsiz(2), siz(2)); ## Scatter. xs = x(:,:,s.i); ## Multiply. ys = blkmm (xs, s.sv); ## Gather. y = accumdim (s.j, ys, 3, siz(2)); ## Narrow blocks. y = reshape (y, xr, bsiz(2)*siz(2)); endfunction function s = mtimes_ss (s1, s2) ## Conformance check. siz1 = s1.siz; bsiz1 = s1.bsiz; siz2 = s2.siz; bsiz2 = s2.bsiz; if (bsiz1(2) != bsiz2(1)) gripe_nonconformant (bsiz1, bsiz2, "block sizes"); elseif (siz1(2) != siz2(1)) gripe_nonconformant (bsiz1.*siz1, bsiz2.*siz2); endif ## Hardcore hacks, man! ss = sparse (s1.i, s1.j, 1:length (s1.i), "unique"); ss = ss(:,s2.i); [i, j, k] = find (ss); sv = blkmm (s1.sv(:,:,k), s2.sv(:,:,j)); j = s2.j(j); s = blksparse (i, j, sv, siz1(1), siz2(2)); endfunction function gripe_nonconformant (s1, s2, what = "arguments") error ("Octave:nonconformant-args", ... "nonconformant %s (op1 is %dx%d, op2 is %dx%d)", what, s1, s2); endfunction linear-algebra-2.2.3/inst/@blksparse/PaxHeaders.16347/plus.m0000644000000000000000000000013213563071136020335 xustar0030 mtime=1573679710.674089326 30 atime=1573679710.674089326 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@blksparse/plus.m0000644000175000017500000000306113563071136020520 0ustar00olafolaf00000000000000## Copyright (C) 2010 VZLU Prague ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} plus (@var{s1}, @var{s2}) ## Add two blksparse objects. ## @end deftypefn function s = plus (s1, s2) if (isa (s1, "blksparse") && isa (s2, "blksparse")) ## Conformance check. siz1 = s1.siz; bsiz1 = s1.bsiz; siz2 = s2.siz; bsiz2 = s2.bsiz; if (bsiz1(2) != bsiz2(1)) gripe_nonconformant (bsiz1, bsiz2, "block sizes"); elseif (siz1(2) != siz2(1)) gripe_nonconformant (bsiz1.*siz1, bsiz2.*siz2); endif ## Stupid & simple. s = blksparse ([s1.i; s2.i], [s1.j; s2.j], cat (3, s1.sv, s2.sv), siz1(1), siz1(2)); else error ("blksparse: only blksparse + blksparse implemented"); endif endfunction function gripe_nonconformant (s1, s2, what = "arguments") error ("Octave:nonconformant-args", ... "nonconformant %s (op1 is %dx%d, op2 is %dx%d)", what, s1, s2); endfunction linear-algebra-2.2.3/inst/@blksparse/PaxHeaders.16347/blksize.m0000644000000000000000000000013213563071136021015 xustar0030 mtime=1573679710.670089267 30 atime=1573679710.670089267 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@blksparse/blksize.m0000644000175000017500000000157013563071136021203 0ustar00olafolaf00000000000000## Copyright (C) 2010 VZLU Prague ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} blksize (@var{x}) ## Returns the block size of the matrix. ## @end deftypefn function siz = blksize (s) siz = s.siz; endfunction linear-algebra-2.2.3/inst/@blksparse/PaxHeaders.16347/full.m0000644000000000000000000000013213563071136020314 xustar0030 mtime=1573679710.674089326 30 atime=1573679710.674089326 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@blksparse/full.m0000644000175000017500000000175213563071136020504 0ustar00olafolaf00000000000000## Copyright (C) 2010 VZLU Prague ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} full (@var{x}) ## Converts a block sparse matrix to full. ## @end deftypefn function f = full (s) f = zeros ([s.bsiz, s.siz]); f(:,:, sub2ind (s.siz, s.i, s.j)) = s.sv; f = reshape (permute (f, [1, 3, 2, 4]), s.bsiz .* s.siz); endfunction linear-algebra-2.2.3/inst/@blksparse/PaxHeaders.16347/ismatrix.m0000644000000000000000000000013213563071136021212 xustar0030 mtime=1573679710.674089326 30 atime=1573679710.674089326 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@blksparse/ismatrix.m0000644000175000017500000000160213563071136021374 0ustar00olafolaf00000000000000## Copyright (C) 2010 VZLU Prague ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} ismatrix (@var{s}) ## Returns true (a blksparse object is a matrix). ## @end deftypefn function yes = ismatrix (s) yes = true; endfunction linear-algebra-2.2.3/inst/@blksparse/PaxHeaders.16347/transpose.m0000644000000000000000000000013213563071136021370 xustar0030 mtime=1573679710.678089385 30 atime=1573679710.678089385 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@blksparse/transpose.m0000644000175000017500000000201013563071136021544 0ustar00olafolaf00000000000000## Copyright (C) 2010 VZLU Prague ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} transpose (@var{x}) ## Returns the transpose of a block sparse matrix @var{x}. ## @end deftypefn function y = transpose (x) y.siz = x.siz(2:-1:1); y.bsiz = x.bsiz(2:-1:1); [y.j,idx] = sort (x.i); y.i = x.j(idx); y.sv = permute (x.sv(:,:,idx), [2,1,3]); endfunction linear-algebra-2.2.3/inst/@blksparse/PaxHeaders.16347/blksparse.m0000644000000000000000000000013213563071136021340 xustar0030 mtime=1573679710.670089267 30 atime=1573679710.670089267 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@blksparse/blksparse.m0000644000175000017500000000647413563071136021536 0ustar00olafolaf00000000000000## Copyright (C) 2010 VZLU Prague ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn{Function File} {@var{s} =} blksparse (@var{i}, @var{j}, @var{sv}) ## @deftypefnx{Function File} {@var{s} =} blksparse (@var{i}, @var{j}, @var{sv}, @var{m}, @var{n}) ## @deftypefnx{Function File} {@var{s} =} blksparse (@dots{}, @var{mode}) ## ## Construct a block sparse matrix. The meaning of arguments is analogous to the ## built-in @code{sparse} function, except that @var{i}, @var{j} are indices of ## blocks rather than elements, and @var{sv} is a 3-dimensional array, the first two ## dimensions determining the block size. Optionally, @var{m} and @var{n} can be ## specified as the true block dimensions; if not, the maximum values of @var{i}, @var{j} ## are taken instead. The resulting sparse matrix has the size ## ## @example ## [@var{m}*@var{p}, @var{n}*@var{q}] ## @end example ## ## where ## ## @example ## @var{p} = size (@var{sv}, 1) ## @var{q} = size (@var{sv}, 2) ## @end example ## ## The blocks are located so that ## ## @example ## @var{s}(@var{i}(k):@var{i}(k)+@var{p}-1, @var{j}(k):@var{j}(K)+@var{q}-1) = @var{sv}(:,:,k) ## @end example ## ## Multiple blocks corresponding to the same pair of indices are summed, unless ## @var{mode} is "unique", in which case the last of them is used. ## @end deftypefn function s = blksparse (i, j, sv, m = 0, n = 0, mode) persistent chkver = check_version (); if (nargin == 0) i = j = zeros (0, 1); sv = zeros (1, 1, 0); s = class (struct ("i", i, "j", j, "sv", sv, "siz", [0, 0], "bsiz", [1, 1]), "blksparse"); return endif if (nargin < 3 || nargin > 6) print_usage (); endif if (! isvector (i) || ! isvector (j)) error ("blksparse: i, j must be vectors"); elseif (ndims (sv) != 3) error ("blksparse: sv must be a 3D array"); endif if (nargin == 4 && ischar (m)) mode = m; m = 0; elseif (nargin < 6) mode = "sum"; endif if (strcmp (mode, "unique")) summation = false; elseif (strcmp (mode, "sum") || strcmp (mode, "summation")) summation = true; else error ("blksparse: invalid mode: %s", mode); endif if (m == 0) m = max (i); endif if (n == 0) n = max (j); endif siz = [m, n]; ji = [j(:), i(:)]; [ji, fidx, ridx] = unique (ji, "rows"); j = ji(:,1); i = ji(:,2); if (summation) sv = accumdim (ridx, sv, 3, rows (ji)); else sv = sv(:,:,fidx); endif s = struct ("i", i, "j", j, "sv", sv, "siz", siz, "bsiz", size (sv)(1:2)); s = class (s, "blksparse"); endfunction function ok = check_version () ok = compare_versions (version, "3.3.51", ">="); if (! ok) error ("blksparse: can only be used with Octave 3.3.51+"); endif endfunction linear-algebra-2.2.3/inst/@blksparse/PaxHeaders.16347/issparse.m0000644000000000000000000000013213563071136021203 xustar0030 mtime=1573679710.674089326 30 atime=1573679710.674089326 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@blksparse/issparse.m0000644000175000017500000000161313563071136021367 0ustar00olafolaf00000000000000## Copyright (C) 2010 VZLU Prague ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} issparse (@var{s}) ## Returns true since a blksparse is sparse by definition. ## @end deftypefn function yes = issparse (s) yes = true; endfunction linear-algebra-2.2.3/inst/@blksparse/PaxHeaders.16347/sparse.m0000644000000000000000000000013213563071136020647 xustar0030 mtime=1573679710.674089326 30 atime=1573679710.674089326 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@blksparse/sparse.m0000644000175000017500000000233313563071136021033 0ustar00olafolaf00000000000000## Copyright (C) 2010 VZLU Prague ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} sparse (@var{x}) ## Converts a block sparse matrix to (built-in) sparse. ## @end deftypefn function sp = sparse (s) bsiz = s.bsiz; i = repmat (shiftdim (s.i, -2), bsiz); j = repmat (shiftdim (s.j, -2), bsiz); [iofs, jofs] = ndgrid (1:bsiz(1), 1:bsiz(2)); k = ones (1, size (s.sv, 3)); i = sub2ind ([bsiz(1), s.siz(1)], iofs(:,:,k), i); j = sub2ind ([bsiz(2), s.siz(2)], jofs(:,:,k), j); sp = sparse (i(:), j(:), s.sv(:), bsiz(1)*s.siz(1), bsiz(2)*s.siz(2)); endfunction linear-algebra-2.2.3/inst/@blksparse/PaxHeaders.16347/uplus.m0000644000000000000000000000013213563071136020522 xustar0030 mtime=1573679710.678089385 30 atime=1573679710.678089385 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@blksparse/uplus.m0000644000175000017500000000170713563071136020712 0ustar00olafolaf00000000000000## Copyright (C) 2010 VZLU Prague ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} uplus (@var{x}) ## Returns the unary plus of a block sparse matrix @var{x}. ## Effectively the matrix itself, except signs of zeros. ## @end deftypefn function y = uplus (x) y = x; y.sv = +x.sv; endfunction linear-algebra-2.2.3/inst/@blksparse/PaxHeaders.16347/mldivide.m0000644000000000000000000000013213563071136021147 xustar0030 mtime=1573679710.674089326 30 atime=1573679710.674089326 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@blksparse/mldivide.m0000644000175000017500000000636113563071136021340 0ustar00olafolaf00000000000000## Copyright (C) 2010 VZLU Prague ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} mldivide (@var{x}, @var{y}) ## Performs a left division with a block sparse matrix. ## If @var{x} is a block sparse matrix, it must be either diagonal ## or triangular, and @var{y} must be full. ## If @var{x} is built-in sparse or full, @var{y} is converted ## accordingly, then the built-in division is used. ## @end deftypefn function c = mldivide (a, b) if (isa (a, "blksparse")) if (issparse (b)) error ("blksparse: block sparse \\ sparse not implemented"); else c = mldivide_sm (a, b); endif elseif (issparse (a)) c = a \ sparse (b); else c = a \ full (b); endif endfunction function y = mldivide_sm (s, x) siz = s.siz; bsiz = s.bsiz; if (bsiz(1) != bsiz(2) || siz(1) != siz(2)) error ("blksparse: can only divide by square matrices with square blocks"); endif ## Check sizes. [xr, xc] = size (x); if (xr != siz(1)*bsiz(1)) gripe_nonconformant (siz.*bsiz, [xr, xc]); endif if (isempty (s) || isempty (x)) y = x; return; endif ## Form blocks. x = reshape (x, bsiz(1), siz(1), xc); x = permute (x, [1, 3, 2]); sv = s.sv; si = s.i; sj = s.j; ns = size (sv, 3); n = siz(1); nb = bsiz(1); d = find (si == sj); full_diag = length (d) == n; isdiag = full_diag && ns == n; # block diagonal islower = full_diag && all (si >= sj); # block upper triangular isupper = full_diag && all (si <= sj); # block lower triangular if (isdiag) xx = num2cell (x, [1, 2]); ss = num2cell (sv, [1, 2]); yy = cellfun (@mldivide, ss, xx, "uniformoutput", false); y = cat (3, yy{:}); clear xx ss yy; elseif (islower) y = x; ## this is the axpy version for j = 1:n-1 y(:,:,j) = sv(:,:,d(j)) \ y(:,:,j); k = d(j)+1:d(j+1)-1; xy = y(:,:,j*ones (1, length (k))); y(:,:,si(k)) -= blkmm (sv(:,:,k), xy); endfor y(:,:,n) = sv(:,:,ns) \ y(:,:,n); elseif (isupper) y = x; ## this is the axpy version for j = n:-1:2 y(:,:,j) = sv(:,:,d(j)) \ y(:,:,j); k = d(j-1)+1:d(j)-1; xy = y(:,:,j*ones (1, length (k))); y(:,:,si(k)) -= blkmm (sv(:,:,k), xy); endfor y(:,:,1) = sv(:,:,1) \ y(:,:,1); else error ("blksparse: mldivide: matrix must be block triangular or diagonal"); endif ## Narrow blocks. y = permute (y, [1, 3, 2]); y = reshape (y, bsiz(1)*siz(1), xc); endfunction function gripe_nonconformant (s1, s2, what = "arguments") error ("Octave:nonconformant-args", ... "nonconformant %s (op1 is %dx%d, op2 is %dx%d)", what, s1, s2); endfunction linear-algebra-2.2.3/inst/@blksparse/PaxHeaders.16347/mrdivide.m0000644000000000000000000000013213563071136021155 xustar0030 mtime=1573679710.674089326 30 atime=1573679710.674089326 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@blksparse/mrdivide.m0000644000175000017500000000623313563071136021344 0ustar00olafolaf00000000000000## Copyright (C) 2010 VZLU Prague ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} mrdivide (@var{x}, @var{y}) ## Performs a left division with a block sparse matrix. ## If @var{y} is a block sparse matrix, it must be either diagonal ## or triangular, and @var{x} must be full. ## If @var{y} is built-in sparse or full, @var{x} is converted ## accordingly, then the built-in division is used. ## @end deftypefn function c = mrdivide (a, b) if (isa (b, "blksparse")) if (issparse (a)) error ("blksparse: sparse / block sparse not implemented"); else c = mrdivide_ms (a, b); endif elseif (issparse (b)) c = sparse (a) / b; else c = full (a) / b; endif endfunction function y = mrdivide_ms (x, s) siz = s.siz; bsiz = s.bsiz; if (bsiz(1) != bsiz(2) || siz(1) != siz(2)) error ("blksparse: can only divide by square matrices with square blocks"); endif ## Check sizes. [xr, xc] = size (x); if (xc != siz(2)*bsiz(2)) gripe_nonconformant (siz.*bsiz, [xr, xc]); endif if (isempty (s) || isempty (x)) y = x; return; endif ## Form blocks. x = reshape (x, xr, bsiz(2), siz(2)); sv = s.sv; si = s.i; sj = s.j; ns = size (sv, 3); n = siz(2); nb = bsiz(2); d = find (si == sj); full_diag = length (d) == n; isdiag = full_diag && ns == n; # block diagonal islower = full_diag && all (si >= sj); # block upper triangular isupper = full_diag && all (si <= sj); # block lower triangular if (isdiag) xx = num2cell (x, [1, 2]); ss = num2cell (sv, [1, 2]); yy = cellfun (@mldivide, ss, xx, "uniformoutput", false); y = cat (3, yy{:}); clear xx ss yy; elseif (isupper) y = zeros (size (x)); ## this is the dot version y(:,:,1) = x(:,:,1) / sv(:,:,1); for j = 2:n k = d(j-1)+1:d(j)-1; xy = blkmm (y(:,:,si(k)), sv(:,:,k)); y(:,:,j) = (x(:,:,j) - sum (xy, 3)) / sv(:,:,d(j)); endfor elseif (islower) y = zeros (size (x)); ## this is the dot version y(:,:,n) = x(:,:,n) / sv(:,:,ns); for j = n-1:-1:1 k = d(j)+1:d(j+1)-1; xy = blkmm (y(:,:,si(k)), sv(:,:,k)); y(:,:,j) = (x(:,:,j) - sum (xy, 3)) / sv(:,:,d(j)); endfor else error ("blksparse: mldivide: matrix must be block triangular or diagonal"); endif ## Narrow blocks. y = reshape (y, xr, bsiz(2)*siz(2)); endfunction function gripe_nonconformant (s1, s2, what = "arguments") error ("Octave:nonconformant-args", ... "nonconformant %s (op1 is %dx%d, op2 is %dx%d)", what, s1, s2); endfunction linear-algebra-2.2.3/inst/@blksparse/PaxHeaders.16347/size.m0000644000000000000000000000013213563071136020324 xustar0030 mtime=1573679710.674089326 30 atime=1573679710.674089326 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@blksparse/size.m0000644000175000017500000000156513563071136020516 0ustar00olafolaf00000000000000## Copyright (C) 2010 VZLU Prague ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} size (@var{x}) ## Returns the size of the matrix. ## @end deftypefn function siz = size (s) siz = s.bsiz .* s.siz; endfunction linear-algebra-2.2.3/inst/@blksparse/PaxHeaders.16347/uminus.m0000644000000000000000000000013213563071136020672 xustar0030 mtime=1573679710.678089385 30 atime=1573679710.678089385 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@blksparse/uminus.m0000644000175000017500000000161613563071136021061 0ustar00olafolaf00000000000000## Copyright (C) 2010 VZLU Prague ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} uminus (@var{x}) ## Returns the negative of a block sparse matrix @var{x}. ## @end deftypefn function y = uminus (x) y = x; y.sv = -x.sv; endfunction linear-algebra-2.2.3/inst/@blksparse/PaxHeaders.16347/display.m0000644000000000000000000000013213563071136021017 xustar0030 mtime=1573679710.670089267 30 atime=1573679710.670089267 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@blksparse/display.m0000644000175000017500000000245013563071136021203 0ustar00olafolaf00000000000000## Copyright (C) 2010 VZLU Prague ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} display (@var{x}) ## Displays the block sparse matrix. ## @end deftypefn function display (s) printf ("%s = \n\n", argn); nbl = size (s.sv, 3); header = "Block Sparse Matrix (rows = %d, cols = %d, block = %dx%d, nblocks = %d)\n\n"; printf (header, s.siz .* s.bsiz, s.bsiz, nbl) if (nbl == 0) return; endif rng = [s.i, s.j] * diag (s.bsiz); rng = [rng(:,1) + 1-s.bsiz(1), rng(:,1), rng(:,2) + 1-s.bsiz(2), rng(:,2)]; for k = 1:nbl printf ("(%d:%d, %d:%d) ->\n\n", rng(k,:)); disp (s.sv(:,:,k)); puts ("\n"); endfor endfunction linear-algebra-2.2.3/inst/@blksparse/PaxHeaders.16347/ctranspose.m0000644000000000000000000000013213563071136021533 xustar0030 mtime=1573679710.670089267 30 atime=1573679710.670089267 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@blksparse/ctranspose.m0000644000175000017500000000225513563071136021722 0ustar00olafolaf00000000000000## Copyright (C) 2010 VZLU Prague ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} ctranspose (@var{x}) ## Returns the conjugate transpose of a block sparse matrix @var{x}. ## @end deftypefn function y = ctranspose (x) #siz = x.siz(2:-1:1); #bsiz = x.bsiz(2:-1:1); [j,idx] = sort (x.i); i = x.j(idx); sv = conj (permute (x.sv(:,:,idx), [2,1,3])); y = blksparse (i, j, sv); endfunction %!test %! r = blksparse ([1,2],[1,2],cat(3,eye(2),[1 2; -2 1])); %! rt = r'; %! assert (full(rt'),full(r)); linear-algebra-2.2.3/inst/@blksparse/PaxHeaders.16347/minus.m0000644000000000000000000000013213563071136020505 xustar0030 mtime=1573679710.674089326 30 atime=1573679710.674089326 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@blksparse/minus.m0000644000175000017500000000307113563071136020671 0ustar00olafolaf00000000000000## Copyright (C) 2010 VZLU Prague ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} minus (@var{s1}, @var{s2}) ## Subtract two blksparse objects. ## @end deftypefn function s = minus (s1, s2) if (isa (s1, "blksparse") && isa (s2, "blksparse")) ## Conformance check. siz1 = s1.siz; bsiz1 = s1.bsiz; siz2 = s2.siz; bsiz2 = s2.bsiz; if (bsiz1(2) != bsiz2(1)) gripe_nonconformant (bsiz1, bsiz2, "block sizes"); elseif (siz1(2) != siz2(1)) gripe_nonconformant (bsiz1.*siz1, bsiz2.*siz2); endif ## Stupid & simple. s = blksparse ([s1.i; s2.i], [s1.j; s2.j], cat (3, s1.sv, -s2.sv), siz1(1), siz1(2)); else error ("blksparse: only blksparse - blksparse implemented"); endif endfunction function gripe_nonconformant (s1, s2, what = "arguments") error ("Octave:nonconformant-args", ... "nonconformant %s (op1 is %dx%d, op2 is %dx%d)", what, s1, s2); endfunction linear-algebra-2.2.3/inst/@blksparse/PaxHeaders.16347/subsref.m0000644000000000000000000000013213563071136021023 xustar0030 mtime=1573679710.678089385 30 atime=1573679710.678089385 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@blksparse/subsref.m0000644000175000017500000000400113563071136021201 0ustar00olafolaf00000000000000## Copyright (C) 2010 VZLU Prague ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} subsref (@var{s}, @var{subs}) ## Index elements from a blksparse object. ## @end deftypefn function ss = subsref (s, subs) if (length (subs) != 1) error ("blksparse: invalid index chain"); endif if (strcmp (subs(1).type, "()")) ind = subs(1).subs; if (length (ind) == 2) idx = make_block_index (ind{1}, s.bsiz(1)); jdx = make_block_index (ind{2}, s.bsiz(2)); ## Use sparse indexing to solve it all. sn = sparse (s.i, s.j, 1:size (s.sv, 3), s.siz(1), s.siz (2)); sn = sn(idx, jdx); [i, j, k] = find (sn); ss = s; ss.i = i; ss.j = j; ss.sv = s.sv(:,:,k); ss.siz = size (sn); else error ("blksparse: linear indexing is not supported"); endif else error ("blksparse: only supports () indexing"); endif endfunction function bi = make_block_index (i, bs) if (strcmp (i, ':')) bi = i; else if (rem (numel (i), bs) == 0) ba = reshape (i, bs, []); bi = ba(1,:); if (any (rem (bi, bs) != 1) || any ((ba != bsxfun (@plus, bi, [0:bs-1].'))(:))) error ("blksparse: index must preserve block structure"); else bi = ceil (bi / bs); endif else error ("blksparse: index must preserve block structure"); endif endif endfunction linear-algebra-2.2.3/inst/PaxHeaders.16347/vec_projection.m0000644000000000000000000000013213563071136020275 xustar0030 mtime=1573679710.698089679 30 atime=1573679710.698089679 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/vec_projection.m0000644000175000017500000000551613563071136020467 0ustar00olafolaf00000000000000## Copyright (C) 2013 Her Majesty The Queen In Right of Canada ## Developed by Defence Research & Development Canada ## ## This file is part of Octave. ## ## Octave is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or (at ## your option) any later version. ## ## Octave is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{out} =} vec_projection (@var{x}, @var{y}) ## Compute the vector projection of a 3-vector onto another. ## @var{x} : size 1 x 3 and @var{y} : size 1 x 3 @var{tol} : size 1 x 1 ## ## @example ## vec_projection ([1,0,0], [0.5,0.5,0]) ## @result{} 0.70711 ## @end example ## ## Vector projection of @var{x} onto @var{y}, both are 3-vectors, ## returning the value of @var{x} along @var{y}. Function uses dot product, ## Euclidean norm, and angle between vectors to compute the proper length along ## @var{y}. ## @end deftypefn ## Author: DRE 2013 ## Created: 10 June 2013 function out = vec_projection (x, y, tol) %% Error handling if (size(x,1)!=1 && size(x,2)!=3) out = -1 warning ("vec_projection: first vector is not 1x3 3-vector"); endif if (size(y,1)!=1 && size(y,2)!=3) out = -1 warning ("vec_projection: second vector is not 1x3 3-vector"); endif %% Compute Dot Product Method: proj(x,y) = |x|*cos(theta) dp = dot (x,y); %% Compute Angle Between X and Y theta = dp / (norm (x,2) * norm (y,2)); theta = acos (theta); %%theta_d = 360/(2*pi) *(theta)%% for viewing %% Compute X Projected onto Y Unit Vector temp = norm (x,2) *(cos (theta)); %% validate with third argument if needed if (nargin == 3) %% Alternate Solution proj(x,y) = x * y/norm(y,2) %% Compute Y Unit Vector unit_y = y / (norm (y,2)); %% Euclidean 2-norm temp2 = dot (x,unit_y); if (temp2 - temp <= tol) out = temp; else out = -1; warning ("vec_projection: Warning, vector projection exceeded tolerance"); endif endif %% Final Stage output out = temp; endfunction %!test %! assert (vec_projection ([1,0,0], [0.5,0.5,0]), 0.70711,1e-5); %! assert (vec_projection ([1,2000,0], [0.5,15,0]), 1998.9, 1e-1); %! assert (vec_projection ([1,-2000,0], [0.5,15,0]), -1998.9, 1e-1); %! assert (vec_projection ([7,7,0], [15,0,0]), 7.000, 1e-10); %! assert (vec_projection ([1,1,0], [1.05,0.94,0]), 1.4121, 1e-4); %! assert (vec_projection ([1,1.1,0], [1.05,0.94,0]), 1.4788, 1e-4); linear-algebra-2.2.3/inst/PaxHeaders.16347/rotparams.m0000644000000000000000000000013013563071136017272 xustar0029 mtime=1573679710.69408962 29 atime=1573679710.69408962 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/rotparams.m0000644000175000017500000000407713563071136017467 0ustar00olafolaf00000000000000## Copyright (C) 2002 Etienne Grossmann ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn{Function File} {[@var{vstacked}, @var{astacked}] =} rotparams (@var{rstacked}) ## @cindex ## The function w = rotparams (r) - Inverse to rotv(). ## Using, @var{w} = rotparams(@var{r}) is such that ## rotv(w)*r' == eye(3). ## ## If used as, [v,a]=rotparams(r) , idem, with v (1 x 3) s.t. w == a*v. ## ## 0 <= norm(w)==a <= pi ## ## :-O !! Does not check if 'r' is a rotation matrix. ## ## Ignores matrices with zero rows or with NaNs. (returns 0 for them) ## ## @seealso{rotv} ## @end deftypefn function [vstacked, astacked] = rotparams (rstacked) N = size (rstacked,1) / 3; ## ang = 0 ; ## if length(varargin), ## if strcmp(varargin{1},'ang'), ang = 1; end ## end ok = all ( ! isnan (rstacked') ) & any ( rstacked' ); ok = min ( reshape (ok,3,N) ); ok = find (ok) ; ## keyboard vstacked = zeros (N,3); astacked = zeros (N,1); for j = ok, r = rstacked(3*j-2:3*j,:); [v,f] = eig (r); f = diag(f); [m,i] = min (abs (real (f)-1)); v = v(:,i); w = null (v'); u = w(:,1); a = u'*r*u; if a<1, a = real (acos (u'*r*u)); else a = 0; endif ## Check orientation x=r*u; if v'*[0 -u(3) u(2); u(3) 0 -u(1);-u(2) u(1) 0]*x < 0, v=-v; endif if nargout <= 1, v = v*a; endif vstacked(j,:) = -v'; astacked(j) = a; endfor endfunction linear-algebra-2.2.3/inst/PaxHeaders.16347/circulant_inv.m0000644000000000000000000000013213563071136020124 xustar0030 mtime=1573679710.690089562 30 atime=1573679710.690089562 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/circulant_inv.m0000644000175000017500000000371313563071136020313 0ustar00olafolaf00000000000000## Copyright (C) 2012 Nir Krakauer ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn{Function File} {@var{c} =} circulant_inv (@var{v}) ## ## Fast, compact calculation of inverse of a circulant matrix@* ## Given an @var{n}*1 vector @var{v}, return the inverse @var{c} of the @var{n}*@var{n} circulant matrix @var{C} that has @var{v} as its first column ## The returned @var{c} is the first column of the inverse, which is also circulant -- to get the full matrix, use `circulant_make_matrix(c)' ## ## Theoretically same as @code{inv(make_circulant_matrix(v))(:, 1)}, but requires many fewer computations and does not form matrices explicitly ## ## Roundoff may induce a small imaginary component in @var{c} even if @var{v} is real -- use @code{real(c)} to remedy this ## ## Reference: Robert M. Gray, Toeplitz and Circulant Matrices: A Review, Now Publishers, http://ee.stanford.edu/~gray/toeplitz.pdf, Chapter 3 ## ## @seealso{gallery, circulant_matrix_vector_product, circulant_eig} ## @end deftypefn function c = circulant_inv(v) ## Find the eigenvalues and eigenvectors [vs, lambda] = circulant_eig(v); ## Find the first column of the inverse c = vs * diag(1 ./ diag(lambda)) * conj(vs(:, 1)); endfunction %!shared v %! v = [1 2 3]'; %!assert (gallery ("circul", circulant_inv (v)), inv (gallery ("circul", v)), 10*eps); linear-algebra-2.2.3/inst/PaxHeaders.16347/smwsolve.m0000644000000000000000000000013013563071136017141 xustar0029 mtime=1573679710.69408962 29 atime=1573679710.69408962 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/smwsolve.m0000644000175000017500000000500013563071136017321 0ustar00olafolaf00000000000000## Copyright (C) 2009 VZLU Prague, a.s., Czech Republic ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn{Function File} {@var{x} =} smwsolve (@var{a}, @var{u}, @var{v}, @var{b}) ## @deftypefnx{Function File} {} smwsolve (@var{solver}, @var{u}, @var{v}, @var{b}) ## Solves the square system @code{(A + U*V')*X == B}, where @var{u} and @var{v} are ## matrices with several columns, using the Sherman-Morrison-Woodbury formula, ## so that a system with @var{a} as left-hand side is actually solved. This is ## especially advantageous if @var{a} is diagonal, sparse, triangular or ## positive definite. ## @var{a} can be sparse or full, the other matrices are expected to be full. ## Instead of a matrix @var{a}, a user may alternatively provide a function ## @var{solver} that performs the left division operation. ## @end deftypefn ## Author: Jaroslav Hajek function x = smwsolve (a, u, v, b) if (nargin != 4) print_usage (); endif n = columns (u); if (n != columns (v) || rows (a) != rows (u) || columns (a) != rows (v)) error ("smwsolve: dimension mismatch"); elseif (! issquare (a)) error ("smwsolve: need a square matrix"); endif nc = columns (b); n = columns (u); if (ismatrix (a)) xx = a \ [b, u]; elseif (isa (a, "function_handle")) xx = a ([b, u]); if (rows (xx) != rows (a) || columns (xx) != (nc + n)) error ("smwsolve: invalid result from a solver function"); endif else error ("smwsolve: a must be a matrix or function handle"); endif x = xx(:,1:nc); y = xx(:,nc+1:nc+n); vxx = v' * xx; vx = vxx(:,1:nc); vy = vxx(:,nc+1:nc+n); x = x - y * ((eye (n) + vy) \ vx); endfunction %!test %! A = 2.1*eye (10); %! u = rand (10, 2); u /= diag (norm (u, "cols")); %! v = rand (10, 2); v /= diag (norm (v, "cols")); %! b = rand (10, 2); %! x1 = (A + u*v') \ b; %! x2 = smwsolve (A, u, v, b); %! assert (x1, x2, 1e-13); linear-algebra-2.2.3/inst/PaxHeaders.16347/ndmult.m0000644000000000000000000000013013563071136016565 xustar0029 mtime=1573679710.69408962 29 atime=1573679710.69408962 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/ndmult.m0000644000175000017500000001055313563071136016756 0ustar00olafolaf00000000000000## Copyright (C) 2013 - Juan Pablo Carbajal ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . ## Author: Juan Pablo Carbajal ## -*- texinfo -*- ## @deftypefn {Function File} {@var{C} =} ndmult (@var{A},@var{B},@var{dim}) ## Multidimensional scalar product ## ## Given multidimensional arrays @var{A} and @var{B} with entries ## A(i1,12,@dots{},in) and B(j1,j2,@dots{},jm) and the 1-by-2 dimesion array @var{dim} ## with entries [N,K]. Assume that ## ## @example ## shape(@var{A},N) == shape(@var{B},K) ## @end example ## ## Then the function calculates the product ## ## @example ## @group ## ## C (i1,@dots{},iN-1,iN+1,@dots{},in,j1,@dots{},jK-1,jK+1,@dots{},jm) = ## = sum_over_s A(i1,@dots{},iN-1,s,iN+1,@dots{},in)*B(j1,@dots{},jK-1,s,jK+1,@dots{},jm) ## ## @end group ## @end example ## ## For example if @command{size(@var{A}) == [2,3,4]} and @command{size(@var{B}) == [5,3]} ## then the @command{@var{C} = ndmult(A,B,[2,2])} produces @command{size(@var{C}) == [2,4,5]}. ## ## This function is useful, for example, when calculating grammian matrices of a set of signals ## produced from different experiments. ## @example ## nT = 100; ## t = 2 * pi * linspace (0,1,nT).'; ## signals = zeros (nT,3,2); % 2 experiments measuring 3 signals at nT timestamps ## ## signals(:,:,1) = [sin(2*t) cos(2*t) sin(4*t).^2]; ## signals(:,:,2) = [sin(2*t+pi/4) cos(2*t+pi/4) sin(4*t+pi/6).^2]; ## ## sT(:,:,1) = signals(:,:,1).'; ## sT(:,:,2) = signals(:,:,2).'; ## G = ndmult (signals, sT, [1 2]); ## ## @end example ## In the example G contains the scalar product of all the signals against each other. ## This can be verified in the following way: ## @example ## s1 = 1 e1 = 1; % First signal in first experiment; ## s2 = 1 e2 = 2; % First signal in second experiment; ## [G(s1,e1,s2,e2) signals(:,s1,e1)'*signals(:,s2,e2)] ## @end example ## You may want to re-order the scalar products into a 2-by-2 arrangement (representing pairs of experiments) ## of gramian matrices. The following command @command{G = permute(G,[1 3 2 4])} does it. ## ## @end deftypefn function M = ndmult (A,B,dim) dA = dim(1); dB = dim(2); sA = size (A); nA = length (sA); perA = [1:(dA-1) (dA+1):(nA-1) nA dA](1:nA); Ap = permute (A, perA); Ap = reshape (Ap, prod (sA(perA(1:end-1))), sA(perA(end))); sB = size (B); nB = length (sB); perB = [dB 1:(dB-1) (dB+1):(nB-1) nB](1:nB); Bp = permute (B, perB); Bp = reshape (Bp, sB(perB(1)), prod (sB(perB(2:end)))); M = Ap * Bp; s = [sA(perA(1:end-1)) sB(perB(2:end))]; M = squeeze (reshape (M, s)); endfunction %!demo %! A =@(l)[1 l; 0 1]; %! N = 5; %! p = linspace (-1,1,N); %! T = zeros (2,2,N); %! # A book of x-shears, one transformation per page. %! for i=1:N %! T(:,:,i) = A(p(i)); %! endfor %! %! # The unit square %! P = [0 0; 1 0; 1 1; 0 1]; %! %! C = ndmult (T,P,[2 2]); %! # Re-order to get a book of polygons %! C = permute (C,[3 1 2]); %! %! try %! pkg load geometry %! do_plot = true; %! catch %! printf ("Geometry package needed to plot this demo\n."); %! do_plot = false; %! end %! if do_plot %! clf %! drawPolygon (P,"k","linewidth",2); %! hold on %! c = jet(N); %! for i=1:N %! drawPolygon (C(:,:,i),":","color",c(i,:),"linewidth",2); %! endfor %! axis equal %! set(gca,"visible","off"); %! hold off %! endif %! %! # ------------------------------------------------- %! # The handler A describes a parametrized planar geometrical %! # transformation (shear in the x-direction). %! # Choosing N values of the parameter we obtain a 2x2xN matrix. %! # We can apply all these transformations to the poligon defined %! # by matrix P in one operation. %! # The poligon resulting from the i-th parameter value is stored %! # in C(:,:,i). %! # You can plot them using the geometry package. linear-algebra-2.2.3/inst/PaxHeaders.16347/cod.m0000644000000000000000000000013213563071136016031 xustar0030 mtime=1573679710.690089562 30 atime=1573679710.690089562 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/cod.m0000644000175000017500000000622713563071136016223 0ustar00olafolaf00000000000000## Copyright (C) 2009 VZLU Prague, a.s., Czech Republic ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn{Function File} {[@var{q}, @var{r}, @var{z}] =} cod (@var{a}) ## @deftypefnx{Function File} {[@var{q}, @var{r}, @var{z}, @var{p}] =} cod (@var{a}) ## @deftypefnx{Function File} {[@dots{}] =} cod (@var{a}, '0') ## Computes the complete orthogonal decomposition (COD) of the matrix @var{a}: ## @example ## @var{a} = @var{q}*@var{r}*@var{z}' ## @end example ## Let @var{a} be an M-by-N matrix, and let @code{K = min(M, N)}. ## Then @var{q} is M-by-M orthogonal, @var{z} is N-by-N orthogonal, ## and @var{r} is M-by-N such that @code{@var{r}(:,1:K)} is upper ## trapezoidal and @code{@var{r}(:,K+1:N)} is zero. ## The additional @var{p} output argument specifies that pivoting should be used in ## the first step (QR decomposition). In this case, ## @example ## @var{a}*@var{p} = @var{q}*@var{r}*@var{z}' ## @end example ## If a second argument of '0' is given, an economy-sized factorization is returned ## so that @var{r} is K-by-K. ## ## @emph{NOTE}: This is currently implemented by double QR factorization plus some ## tricky manipulations, and is not as efficient as using xRZTZF from LAPACK. ## @seealso{qr} ## @end deftypefn ## Author: Jaroslav Hajek function [q, r, z, p] = cod (a, varargin) if (nargin < 1 || nargin > 2 || nargout > 4 || ! (ismatrix (a) && isnumeric (a))) print_usage (); endif [m, n] = size (a); k = min (m, n); economy = nargin == 2; pivoted = nargout == 4; ## Compute the initial QR decomposition if (pivoted) [q, r, p] = qr (a, varargin{:}); else [q, r] = qr (a, varargin{:}); endif if (m >= n) ## In this case, Z is identity, and we're finished. z = eye (n, class (a)); else ## Permutation inverts row order. pr = eye (m) (m:-1:1, :); ## Permutation inverts first m columns order. pc = eye (n) ([m:-1:1, m+1:n], :); ## Make n-by-m matrix, invert first m columns r = (pr * r * pc')'; ## QR factorize again. [z, r] = qr (r, varargin{:}); ## Recover final R and Z if (economy) r = pr * r' * pr'; z = pc * z * pr'; else r = pr * r' * pc'; z = pc * z * pc'; endif endif endfunction %!test %! a = rand (5, 10); %! [q, r, z] = cod (a); %! assert (norm (q*r*z' - a) / norm (a) < 1e-10); %!test %! a = rand (5, 10) + i * rand (5, 10); %! [q, r, z] = cod (a); %! assert (norm (q*r*z' - a) / norm (a) < 1e-10); %!test %! a = rand (5, 10); %! [q, r, z, p] = cod (a); %! assert (norm (q*r*z' - a*p) / norm (a) < 1e-10); linear-algebra-2.2.3/inst/PaxHeaders.16347/cartprod.m0000644000000000000000000000013213563071136017102 xustar0030 mtime=1573679710.690089562 30 atime=1573679710.690089562 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/cartprod.m0000644000175000017500000000346713563071136017277 0ustar00olafolaf00000000000000## Copyright (C) 2008 Muthiah Annamalai ## Copyright (C) 2010 VZLU Prague ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {} cartprod (@var{varargin}) ## ## Computes the cartesian product of given column vectors ( row vectors ). ## The vector elements are assumend to be numbers. ## ## Alternatively the vectors can be specified by as a matrix, by its columns. ## ## To calculate the cartesian product of vectors, ## P = A x B x C x D ... . Requires A, B, C, D be column vectors. ## The algorithm is iteratively calcualte the products, ## ( ( (A x B ) x C ) x D ) x etc. ## ## @example ## @group ## cartprod(1:2,3:4,0:1) ## ans = 1 3 0 ## 2 3 0 ## 1 4 0 ## 2 4 0 ## 1 3 1 ## 2 3 1 ## 1 4 1 ## 2 4 1 ## @end group ## @end example ## @end deftypefn ## @seealso{kron} function p = cartprod (varargin) if (nargin < 1) print_usage (); elseif (nargin == 1) p = varargin{1}; endif [p{1:nargin}] = ndgrid (varargin{:}); p = cat (nargin+1, p{:}); p = reshape (p, [], nargin); endfunction %!assert(cartprod(1:2,0:1),[1 0; 2 0; 1 1; 2 1]) linear-algebra-2.2.3/inst/PaxHeaders.16347/funm.m0000644000000000000000000000013213563071136016231 xustar0030 mtime=1573679710.690089562 30 atime=1573679710.690089562 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/funm.m0000644000175000017500000000734113563071136016421 0ustar00olafolaf00000000000000## Copyright (C) 2000-2019 P.R. Nienhuis ## Copyright (C) 2001 Paul Kienzle ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{B} =} funm (@var{A}, @var{F}) ## Compute matrix equivalent of function F; F can be a function name or ## a function handle and A must be a square matrix. ## ## For trigonometric and hyperbolic functions, @code{thfm} is automatically ## invoked as that is based on @code{expm} and diagonalization is avoided. ## For other functions diagonalization is invoked, which implies that ## -depending on the properties of input matrix @var{A}- the results ## can be very inaccurate @emph{without any warning}. For easy diagonizable and ## stable matrices results of funm will be sufficiently accurate. ## ## Note that you should not use funm for 'sqrt', 'log' or 'exp'; instead ## use sqrtm, logm and expm as these are more robust. ## ## Examples: ## ## @example ## B = funm (A, sin); ## (Compute matrix equivalent of sin() ) ## @end example ## ## @example ## function bk1 = besselk1 (x) ## bk1 = besselk(1, x); ## endfunction ## B = funm (A, besselk1); ## (Compute matrix equivalent of bessel function K1(); ## a helper function is needed here to convey extra ## arguments for besselk() ) ## @end example ## ## @seealso{thfm, expm, logm, sqrtm} ## @end deftypefn function B = funm (A, name) persistent thfuncs = {"cos", "sin", "tan", "sec", "csc", "cot", ... "cosh", "sinh", "tanh", "sech", "csch", "coth", ... "acos", "asin", "atan", "asec", "acsc", "acot", ... "acosh", "asinh", "atanh", "asech", "acsch", "acoth", ... } ## Function handle supplied? try ishndl = isstruct (functions (name)); fname = functions (name).function; name = '-'; catch ishndl = 0; fname = ' '; end_try_catch ## Check input if (nargin < 2 || (! (ischar (name) || ishndl)) || ischar (A)) print_usage (); elseif (! issquare (A)) error ("funm.m: square matrix expected for first argument\n"); endif if (! isempty (find (ismember ({fname, name}, thfuncs)))) ## Use more robust thfm () if (ishndl) name = fname; endif B = thfm (A, name); else ## Simply invoke eigenvalues. Note: risk for repeated eigenvalues!! ## Modeled after suggestion by N. Higham (based on R. Davis, 2007) ## FIXME Do we need automatic setting of TOL? tol = 1.e-15; [V, D] = eig (A + tol * randn (size(A))); D = diag (feval (name, diag(D))); B = V * D / V; ## The diagonalization generates complex values anyway, even for symmetric ## matrices, due to the tolerance trick after Higham/Davis applied above. ## Return real part if all abs(imaginary values) are < eps if (! any (abs (imag(B)(:)) > eps)) B = real (B); endif endif endfunction %!function b = fsin (a) %! b = sin (a); %!endfunction %% test helper function to avoid thfm; but use thfm results as reference %!test %! mtx = randn (100); %! assert (funm (mtx, "fsin"), thfm (mtx, "sin"), 1e-9) linear-algebra-2.2.3/inst/PaxHeaders.16347/circulant_make_matrix.m0000644000000000000000000000013213563071136021631 xustar0030 mtime=1573679710.690089562 30 atime=1573679710.690089562 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/circulant_make_matrix.m0000644000175000017500000000437113563071136022021 0ustar00olafolaf00000000000000## Copyright (C) 2012 Nir Krakauer ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn{Function File} {@var{C} =} circulant_make_matrix (@var{v}) ## Produce a full circulant matrix given the first column. ## ## @emph{Note:} this function has been deprecated and will be removed in the ## future. Instead, use @code{gallery} with the the @code{circul} option. ## To obtain the exactly same matrix, transpose the result, i.e., replace ## @code{circulant_make_matrix (@var{v})} with ## @code{gallery ("circul", @var{v})'}. ## ## Given an @var{n}*1 vector @var{v}, returns the @var{n}*@var{n} circulant ## matrix @var{C} where @var{v} is the left column and all other columns are ## downshifted versions of @var{v}. ## ## Note: If the first row @var{r} of a circulant matrix is given, the first ## column @var{v} can be obtained as @code{v = r([1 end:-1:2])}. ## ## Reference: Gene H. Golub and Charles F. Van Loan, Matrix Computations, 3rd Ed., Section 4.7.7 ## ## @seealso{gallery, circulant_matrix_vector_product, circulant_eig, circulant_inv} ## @end deftypefn function C = circulant_make_matrix(v) persistent warned = false; if (! warned) warned = true; warning ("Octave:deprecated-function", "`circulant_make_matrix (V)' has been deprecated in favor of `gallery (\"circul\", V)''. This function will be removed from future versions of the `linear-algebra' package"); endif n = numel(v); C = ones(n, n); for i = 1:n C(:, i) = v([(end-i+2):end 1:(end-i+1)]); #or circshift(v, i-1) endfor endfunction %!shared v,C %! v = [1 2 3]'; C = [1 3 2; 2 1 3; 3 2 1]; %!assert (circulant_make_matrix(v), C); linear-algebra-2.2.3/inst/PaxHeaders.16347/lobpcg.m0000644000000000000000000000013013563071136016530 xustar0029 mtime=1573679710.69408962 29 atime=1573679710.69408962 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/lobpcg.m0000644000175000017500000012052713563071136016724 0ustar00olafolaf00000000000000## Copyright (C) 2000-2011 A.V. Knyazev ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU Lesser General Public License as published by the Free ## Software Foundation; either version 3 of the License, or (at your option) any ## later version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License ## for more details. ## ## You should have received a copy of the GNU Lesser General Public License ## along with this program; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{blockVectorX}, @var{lambda}] =} lobpcg (@var{blockVectorX}, @var{operatorA}) ## @deftypefnx {Function File} {[@var{blockVectorX}, @var{lambda}, @var{failureFlag}] =} lobpcg (@var{blockVectorX}, @var{operatorA}) ## @deftypefnx {Function File} {[@var{blockVectorX}, @var{lambda}, @var{failureFlag}, @var{lambdaHistory}, @var{residualNormsHistory}] =} lobpcg (@var{blockVectorX}, @var{operatorA}, @var{operatorB}, @var{operatorT}, @var{blockVectorY}, @var{residualTolerance}, @var{maxIterations}, @var{verbosityLevel}) ## Solves Hermitian partial eigenproblems using preconditioning. ## ## The first form outputs the array of algebraic smallest eigenvalues @var{lambda} and ## corresponding matrix of orthonormalized eigenvectors @var{blockVectorX} of the ## Hermitian (full or sparse) operator @var{operatorA} using input matrix ## @var{blockVectorX} as an initial guess, without preconditioning, somewhat ## similar to: ## ## @example ## # for real symmetric operator operatorA ## opts.issym = 1; opts.isreal = 1; K = size (blockVectorX, 2); ## [blockVectorX, lambda] = eigs (operatorA, K, 'SR', opts); ## ## # for Hermitian operator operatorA ## K = size (blockVectorX, 2); ## [blockVectorX, lambda] = eigs (operatorA, K, 'SR'); ## @end example ## ## The second form returns a convergence flag. If @var{failureFlag} is 0 then ## all the eigenvalues converged; otherwise not all converged. ## ## The third form computes smallest eigenvalues @var{lambda} and corresponding eigenvectors ## @var{blockVectorX} of the generalized eigenproblem Ax=lambda Bx, where ## Hermitian operators @var{operatorA} and @var{operatorB} are given as functions, as ## well as a preconditioner, @var{operatorT}. The operators @var{operatorB} and ## @var{operatorT} must be in addition @emph{positive definite}. To compute the largest ## eigenpairs of @var{operatorA}, simply apply the code to @var{operatorA} multiplied by ## -1. The code does not involve @emph{any} matrix factorizations of @var{operatorA} and ## @var{operatorB}, thus, e.g., it preserves the sparsity and the structure of ## @var{operatorA} and @var{operatorB}. ## ## @var{residualTolerance} and @var{maxIterations} control tolerance and max number of ## steps, and @var{verbosityLevel} = 0, 1, or 2 controls the amount of printed ## info. @var{lambdaHistory} is a matrix with all iterative lambdas, and ## @var{residualNormsHistory} are matrices of the history of 2-norms of residuals ## ## Required input: ## @itemize @bullet ## @item ## @var{blockVectorX} (class numeric) - initial approximation to eigenvectors, ## full or sparse matrix n-by-blockSize. @var{blockVectorX} must be full rank. ## @item ## @var{operatorA} (class numeric, char, or function_handle) - the main operator ## of the eigenproblem, can be a matrix, a function name, or handle ## @end itemize ## ## Optional function input: ## @itemize @bullet ## @item ## @var{operatorB} (class numeric, char, or function_handle) - the second operator, ## if solving a generalized eigenproblem, can be a matrix, a function name, or ## handle; by default if empty, @code{operatorB = I}. ## @item ## @var{operatorT} (class char or function_handle) - the preconditioner, by ## default @code{operatorT(blockVectorX) = blockVectorX}. ## @end itemize ## ## Optional constraints input: ## @itemize @bullet ## @item ## @var{blockVectorY} (class numeric) - a full or sparse n-by-sizeY matrix of ## constraints, where sizeY < n. @var{blockVectorY} must be full rank. The ## iterations will be performed in the (operatorB-) orthogonal complement of the ## column-space of @var{blockVectorY}. ## @end itemize ## ## Optional scalar input parameters: ## @itemize @bullet ## @item ## @var{residualTolerance} (class numeric) - tolerance, by default, @code{residualTolerance = n * sqrt (eps)} ## @item ## @var{maxIterations} - max number of iterations, by default, @code{maxIterations = min (n, 20)} ## @item ## @var{verbosityLevel} - either 0 (no info), 1, or 2 (with pictures); by ## default, @code{verbosityLevel = 0}. ## @end itemize ## ## Required output: ## @itemize @bullet ## @item ## @var{blockVectorX} and @var{lambda} (class numeric) both are computed ## blockSize eigenpairs, where @code{blockSize = size (blockVectorX, 2)} ## for the initial guess @var{blockVectorX} if it is full rank. ## @end itemize ## ## Optional output: ## @itemize @bullet ## @item ## @var{failureFlag} (class integer) as described above. ## @item ## @var{lambdaHistory} (class numeric) as described above. ## @item ## @var{residualNormsHistory} (class numeric) as described above. ## @end itemize ## ## Functions @code{operatorA(blockVectorX)}, @code{operatorB(blockVectorX)} and ## @code{operatorT(blockVectorX)} must support @var{blockVectorX} being a matrix, not ## just a column vector. ## ## Every iteration involves one application of @var{operatorA} and @var{operatorB}, and ## one of @var{operatorT}. ## ## Main memory requirements: 6 (9 if @code{isempty(operatorB)=0}) matrices of the ## same size as @var{blockVectorX}, 2 matrices of the same size as @var{blockVectorY} ## (if present), and two square matrices of the size 3*blockSize. ## ## In all examples below, we use the Laplacian operator in a 20x20 square ## with the mesh size 1 which can be generated in MATLAB by running: ## @example ## A = delsq (numgrid ('S', 21)); ## n = size (A, 1); ## @end example ## ## or in MATLAB and Octave by: ## @example ## [~,~,A] = laplacian ([19, 19]); ## n = size (A, 1); ## @end example ## ## Note that @code{laplacian} is a function of the specfun octave-forge package. ## ## The following Example: ## @example ## [blockVectorX, lambda, failureFlag] = lobpcg (randn (n, 8), A, 1e-5, 50, 2); ## @end example ## ## attempts to compute 8 first eigenpairs without preconditioning, but not all ## eigenpairs converge after 50 steps, so failureFlag=1. ## ## The next Example: ## @example ## blockVectorY = []; ## lambda_all = []; ## for j = 1:4 ## [blockVectorX, lambda] = lobpcg (randn (n, 2), A, blockVectorY, 1e-5, 200, 2); ## blockVectorY = [blockVectorY, blockVectorX]; ## lambda_all = [lambda_all' lambda']'; ## pause; ## end ## @end example ## ## attemps to compute the same 8 eigenpairs by calling the code 4 times with ## blockSize=2 using orthogonalization to the previously founded eigenvectors. ## ## The following Example: ## @example ## R = ichol (A, struct('michol', 'on')); ## precfun = @@(x)R\(R'\x); ## [blockVectorX, lambda, failureFlag] = lobpcg (randn (n, 8), A, [], @@(x)precfun(x), 1e-5, 60, 2); ## @end example ## ## computes the same eigenpairs in less then 25 steps, so that failureFlag=0 ## using the preconditioner function @code{precfun}, defined inline. If @code{precfun} ## is defined as an octave function in a file, the function handle ## @code{@@(x)precfun(x)} can be equivalently replaced by the function name @code{precfun}. Running: ## ## @example ## [blockVectorX, lambda, failureFlag] = lobpcg (randn (n, 8), A, speye (n), @@(x)precfun(x), 1e-5, 50, 2); ## @end example ## ## produces similar answers, but is somewhat slower and needs more memory as ## technically a generalized eigenproblem with B=I is solved here. ## ## The following example for a mostly diagonally dominant sparse matrix A ## demonstrates different types of preconditioning, compared to the standard ## use of the main diagonal of A: ## ## @example ## clear all; close all; ## n = 1000; ## M = spdiags ([1:n]', 0, n, n); ## precfun = @@(x)M\x; ## A = M + sprandsym (n, .1); ## Xini = randn (n, 5); ## maxiter = 15; ## tol = 1e-5; ## [~,~,~,~,rnp] = lobpcg (Xini, A, tol, maxiter, 1); ## [~,~,~,~,r] = lobpcg (Xini, A, [], @@(x)precfun(x), tol, maxiter, 1); ## subplot (2,2,1), semilogy (r'); hold on; ## semilogy (rnp', ':>'); ## title ('No preconditioning (top)'); axis tight; ## M(1,2) = 2; ## precfun = @@(x)M\x; % M is no longer symmetric ## [~,~,~,~,rns] = lobpcg (Xini, A, [], @@(x)precfun(x), tol, maxiter, 1); ## subplot (2,2,2), semilogy (r'); hold on; ## semilogy (rns', '--s'); ## title ('Nonsymmetric preconditioning (square)'); axis tight; ## M(1,2) = 0; ## precfun = @@(x)M\(x+10*sin(x)); % nonlinear preconditioning ## [~,~,~,~,rnl] = lobpcg (Xini, A, [], @@(x)precfun(x), tol, maxiter, 1); ## subplot (2,2,3), semilogy (r'); hold on; ## semilogy (rnl', '-.*'); ## title ('Nonlinear preconditioning (star)'); axis tight; ## M = abs (M - 3.5 * speye (n, n)); ## precfun = @@(x)M\x; ## [~,~,~,~,rs] = lobpcg (Xini, A, [], @@(x)precfun(x), tol, maxiter, 1); ## subplot (2,2,4), semilogy (r'); hold on; ## semilogy (rs', '-d'); ## title ('Selective preconditioning (diamond)'); axis tight; ## @end example ## ## @heading References ## This main function @code{lobpcg} is a version of the preconditioned conjugate ## gradient method (Algorithm 5.1) described in A. V. Knyazev, Toward the Optimal ## Preconditioned Eigensolver: ## Locally Optimal Block Preconditioned Conjugate Gradient Method, ## SIAM Journal on Scientific Computing 23 (2001), no. 2, pp. 517-541. ## @uref{http://dx.doi.org/10.1137/S1064827500366124} ## ## @heading Known bugs/features ## @itemize @bullet ## @item ## an excessively small requested tolerance may result in often restarts and ## instability. The code is not written to produce an eps-level accuracy! Use ## common sense. ## @item ## the code may be very sensitive to the number of eigenpairs computed, ## if there is a cluster of eigenvalues not completely included, cf. ## @example ## operatorA = diag ([1 1.99 2:99]); ## [blockVectorX, lambda] = lobpcg (randn (100, 1),operatorA, 1e-10, 80, 2); ## [blockVectorX, lambda] = lobpcg (randn (100, 2),operatorA, 1e-10, 80, 2); ## [blockVectorX, lambda] = lobpcg (randn (100, 3),operatorA, 1e-10, 80, 2); ## @end example ## @end itemize ## ## @heading Distribution ## The main distribution site: @uref{http://math.ucdenver.edu/~aknyazev/} ## ## A C-version of this code is a part of the @uref{http://code.google.com/p/blopex/} ## package and is directly available, e.g., in PETSc and HYPRE. ## @end deftypefn function [blockVectorX,lambda,varargout] = lobpcg(blockVectorX,operatorA,varargin) %Begin % constants CONVENTIONAL_CONSTRAINTS = 1; SYMMETRIC_CONSTRAINTS = 2; %Initial settings failureFlag = 1; if nargin < 2 error('BLOPEX:lobpcg:NotEnoughInputs',... strcat('There must be at least 2 input agruments: ',... 'blockVectorX and operatorA')); end if nargin > 8 warning('BLOPEX:lobpcg:TooManyInputs',... strcat('There must be at most 8 input agruments ',... 'unless arguments are passed to a function')); end if ~isnumeric(blockVectorX) error('BLOPEX:lobpcg:FirstInputNotNumeric',... 'The first input argument blockVectorX must be numeric'); end [n,blockSize]=size(blockVectorX); if blockSize > n error('BLOPEX:lobpcg:FirstInputFat',... 'The first input argument blockVectorX must be tall, not fat'); end if n < 6 error('BLOPEX:lobpcg:MatrixTooSmall',... 'The code does not work for matrices of small sizes'); end if isa(operatorA,'numeric') nA = size(operatorA,1); if any(size(operatorA) ~= nA) error('BLOPEX:lobpcg:MatrixNotSquare',... 'operatorA must be a square matrix or a string'); end if size(operatorA) ~= n error('BLOPEX:lobpcg:MatrixWrongSize',... ['The size ' int2str(size(operatorA))... ' of operatorA is not the same as ' int2str(n)... ' - the number of rows of blockVectorX']); end end count_string = 0; operatorT = []; operatorB = []; residualTolerance = []; maxIterations = []; verbosityLevel = []; blockVectorY = []; sizeY = 0; for j = 1:nargin-2 if isequal(size(varargin{j}),[n,n]) if isempty(operatorB) operatorB = varargin{j}; else error('BLOPEX:lobpcg:TooManyMatrixInputs',... strcat('Too many matrix input arguments. ',... 'Preconditioner operatorT must be an M-function')); end elseif isequal(size(varargin{j},1),n) && size(varargin{j},2) < n if isempty(blockVectorY) blockVectorY = varargin{j}; sizeY=size(blockVectorY,2); else error('BLOPEX:lobpcg:WrongConstraintsFormat',... 'Something wrong with blockVectorY input argument'); end elseif ischar(varargin{j}) || isa(varargin{j},'function_handle') if count_string == 0 if isempty(operatorB) operatorB = varargin{j}; count_string = count_string + 1; else operatorT = varargin{j}; end elseif count_string == 1 operatorT = varargin{j}; else warning('BLOPEX:lobpcg:TooManyStringFunctionHandleInputs',... 'Too many string or FunctionHandle input arguments'); end elseif isequal(size(varargin{j}),[n,n]) error('BLOPEX:lobpcg:WrongPreconditionerFormat',... 'Preconditioner operatorT must be an M-function'); elseif max(size(varargin{j})) == 1 if isempty(residualTolerance) residualTolerance = varargin{j}; elseif isempty(maxIterations) maxIterations = varargin{j}; elseif isempty(verbosityLevel) verbosityLevel = varargin{j}; else warning('BLOPEX:lobpcg:TooManyScalarInputs',... 'Too many scalar parameters, need only three'); end elseif isempty(varargin{j}) if isempty(operatorB) count_string = count_string + 1; elseif ~isempty(operatorT) count_string = count_string + 1; elseif ~isempty(blockVectorY) error('BLOPEX:lobpcg:UnrecognizedEmptyInput',... ['Unrecognized empty input argument number ' int2str(j+2)]); end else error('BLOPEX:lobpcg:UnrecognizedInput',... ['Input argument number ' int2str(j+2) ' not recognized.']); end end if verbosityLevel if issparse(blockVectorX) fprintf(['The sparse initial guess with %i colunms '... 'and %i raws is detected \n'],n,blockSize); else fprintf(['The full initial guess with %i colunms '... 'and %i raws is detected \n'],n,blockSize); end if ischar(operatorA) fprintf('The main operator is detected as an M-function %s \n',... operatorA); elseif isa(operatorA,'function_handle') fprintf('The main operator is detected as an M-function %s \n',... func2str(operatorA)); elseif issparse(operatorA) fprintf('The main operator is detected as a sparse matrix \n'); else fprintf('The main operator is detected as a full matrix \n'); end if isempty(operatorB) fprintf('Solving standard eigenvalue problem, not generalized \n'); elseif ischar(operatorB) fprintf(['The second operator of the generalized eigenproblem \n'... 'is detected as an M-function %s \n'],operatorB); elseif isa(operatorB,'function_handle') fprintf(['The second operator of the generalized eigenproblem \n'... 'is detected as an M-function %s \n'],func2str(operatorB)); elseif issparse(operatorB) fprintf(strcat('The second operator of the generalized',... 'eigenproblem \n is detected as a sparse matrix \n')); else fprintf(strcat('The second operator of the generalized',... 'eigenproblem \n is detected as a full matrix \n')); end if isempty(operatorT) fprintf('No preconditioner is detected \n'); elseif ischar(operatorT) fprintf('The preconditioner is detected as an M-function %s \n',... operatorT); elseif isa(operatorT,'function_handle') fprintf('The preconditioner is detected as an M-function %s \n',... func2str(operatorT)); end if isempty(blockVectorY) fprintf('No matrix of constraints is detected \n') elseif issparse(blockVectorY) fprintf('The sparse matrix of %i constraints is detected \n',sizeY); else fprintf('The full matrix of %i constraints is detected \n',sizeY); end if issparse(blockVectorY) ~= issparse(blockVectorX) warning('BLOPEX:lobpcg:SparsityInconsistent',... strcat('The sparsity formats of the initial guess and ',... 'the constraints are inconsistent')); end end % Set defaults if isempty(residualTolerance) residualTolerance = sqrt(eps)*n; end if isempty(maxIterations) maxIterations = min(n,20); end if isempty(verbosityLevel) verbosityLevel = 0; end if verbosityLevel fprintf('Tolerance %e and maximum number of iterations %i \n',... residualTolerance,maxIterations) end %constraints preprocessing if isempty(blockVectorY) constraintStyle = 0; else % constraintStyle = SYMMETRIC_CONSTRAINTS; % more accurate? constraintStyle = CONVENTIONAL_CONSTRAINTS; end if constraintStyle == CONVENTIONAL_CONSTRAINTS if isempty(operatorB) gramY = blockVectorY'*blockVectorY; else if isnumeric(operatorB) blockVectorBY = operatorB*blockVectorY; else blockVectorBY = feval(operatorB,blockVectorY); end gramY=blockVectorY'*blockVectorBY; end gramY=(gramY'+gramY)*0.5; if isempty(operatorB) blockVectorX = blockVectorX - ... blockVectorY*(gramY\(blockVectorY'*blockVectorX)); else blockVectorX =blockVectorX - ... blockVectorY*(gramY\(blockVectorBY'*blockVectorX)); end elseif constraintStyle == SYMMETRIC_CONSTRAINTS if ~isempty(operatorB) if isnumeric(operatorB) blockVectorY = operatorB*blockVectorY; else blockVectorY = feval(operatorB,blockVectorY); end end if isempty(operatorT) gramY = blockVectorY'*blockVectorY; else blockVectorTY = feval(operatorT,blockVectorY); gramY = blockVectorY'*blockVectorTY; end gramY=(gramY'+gramY)*0.5; if isempty(operatorT) blockVectorX = blockVectorX - ... blockVectorY*(gramY\(blockVectorY'*blockVectorX)); else blockVectorX = blockVectorX - ... blockVectorTY*(gramY\(blockVectorY'*blockVectorX)); end end %Making the initial vectors (operatorB-) orthonormal if isempty(operatorB) %[blockVectorX,gramXBX] = qr(blockVectorX,0); gramXBX=blockVectorX'*blockVectorX; if ~isreal(gramXBX) gramXBX=(gramXBX+gramXBX')*0.5; end [gramXBX,cholFlag]=chol(gramXBX); if cholFlag ~= 0 error('BLOPEX:lobpcg:ConstraintsTooTight',... 'The initial approximation after constraints is not full rank'); end blockVectorX = blockVectorX/gramXBX; else %[blockVectorX,blockVectorBX] = orth(operatorB,blockVectorX); if isnumeric(operatorB) blockVectorBX = operatorB*blockVectorX; else blockVectorBX = feval(operatorB,blockVectorX); end gramXBX=blockVectorX'*blockVectorBX; if ~isreal(gramXBX) gramXBX=(gramXBX+gramXBX')*0.5; end [gramXBX,cholFlag]=chol(gramXBX); if cholFlag ~= 0 error('BLOPEX:lobpcg:InitialNotFullRank',... sprintf('%s\n%s', ... 'The initial approximation after constraints is not full rank',... 'or/and operatorB is not positive definite')); end blockVectorX = blockVectorX/gramXBX; blockVectorBX = blockVectorBX/gramXBX; end % Checking if the problem is big enough for the algorithm, % i.e. n-sizeY > 5*blockSize % Theoretically, the algorithm should be able to run if % n-sizeY > 3*blockSize, % but the extreme cases might be unstable, so we use 5 instead of 3 here. if n-sizeY < 5*blockSize error('BLOPEX:lobpcg:MatrixTooSmall','%s\n%s', ... 'The problem size is too small, relative to the block size.',... 'Try using eig() or eigs() instead.'); end % Preallocation residualNormsHistory=zeros(blockSize,maxIterations); lambdaHistory=zeros(blockSize,maxIterations+1); condestGhistory=zeros(1,maxIterations+1); blockVectorBR=zeros(n,blockSize); blockVectorAR=zeros(n,blockSize); blockVectorP=zeros(n,blockSize); blockVectorAP=zeros(n,blockSize); blockVectorBP=zeros(n,blockSize); %Initial settings for the loop if isnumeric(operatorA) blockVectorAX = operatorA*blockVectorX; else blockVectorAX = feval(operatorA,blockVectorX); end gramXAX = full(blockVectorX'*blockVectorAX); gramXAX = (gramXAX + gramXAX')*0.5; % eig(...,'chol') uses only the diagonal and upper triangle - % not true in MATLAB % Octave v3.2.3-4, eig() does not support inputting 'chol' [coordX,gramXAX]=eig(gramXAX,eye(blockSize)); lambda=diag(gramXAX); %eig returns non-ordered eigenvalues on the diagonal if issparse(blockVectorX) coordX=sparse(coordX); end blockVectorX = blockVectorX*coordX; blockVectorAX = blockVectorAX*coordX; if ~isempty(operatorB) blockVectorBX = blockVectorBX*coordX; end clear coordX condestGhistory(1)=-log10(eps)/2; %if too small cause unnecessary restarts lambdaHistory(1:blockSize,1)=lambda; activeMask = true(blockSize,1); % currentBlockSize = blockSize; %iterate all % % restart=1;%steepest descent %The main part of the method is the loop of the CG method: begin for iterationNumber=1:maxIterations % %Computing the active residuals % if isempty(operatorB) % if currentBlockSize > 1 % blockVectorR(:,activeMask)=blockVectorAX(:,activeMask) - ... % blockVectorX(:,activeMask)*spdiags(lambda(activeMask),0,currentBlockSize,currentBlockSize); % else % blockVectorR(:,activeMask)=blockVectorAX(:,activeMask) - ... % blockVectorX(:,activeMask)*lambda(activeMask); % %to make blockVectorR full when lambda is just a scalar % end % else % if currentBlockSize > 1 % blockVectorR(:,activeMask)=blockVectorAX(:,activeMask) - ... % blockVectorBX(:,activeMask)*spdiags(lambda(activeMask),0,currentBlockSize,currentBlockSize); % else % blockVectorR(:,activeMask)=blockVectorAX(:,activeMask) - ... % blockVectorBX(:,activeMask)*lambda(activeMask); % %to make blockVectorR full when lambda is just a scalar % end % end %Computing all residuals if isempty(operatorB) if blockSize > 1 blockVectorR = blockVectorAX - ... blockVectorX*spdiags(lambda,0,blockSize,blockSize); else blockVectorR = blockVectorAX - blockVectorX*lambda; %to make blockVectorR full when lambda is just a scalar end else if blockSize > 1 blockVectorR=blockVectorAX - ... blockVectorBX*spdiags(lambda,0,blockSize,blockSize); else blockVectorR = blockVectorAX - blockVectorBX*lambda; %to make blockVectorR full when lambda is just a scalar end end %Satisfying the constraints for the active residulas if constraintStyle == SYMMETRIC_CONSTRAINTS if isempty(operatorT) blockVectorR(:,activeMask) = blockVectorR(:,activeMask) - ... blockVectorY*(gramY\(blockVectorY'*... blockVectorR(:,activeMask))); else blockVectorR(:,activeMask) = blockVectorR(:,activeMask) - ... blockVectorY*(gramY\(blockVectorTY'*... blockVectorR(:,activeMask))); end end residualNorms=full(sqrt(sum(conj(blockVectorR).*blockVectorR)')); residualNormsHistory(1:blockSize,iterationNumber)=residualNorms; %index antifreeze activeMask = full(residualNorms > residualTolerance) & activeMask; %activeMask = full(residualNorms > residualTolerance); %above allows vectors back into active, which causes problems with frosen Ps %activeMask = full(residualNorms > 0); %iterate all, ignore freeze currentBlockSize = sum(activeMask); if currentBlockSize == 0 failureFlag=0; %all eigenpairs converged break end %Applying the preconditioner operatorT to the active residulas if ~isempty(operatorT) blockVectorR(:,activeMask) = ... feval(operatorT,blockVectorR(:,activeMask)); end if constraintStyle == CONVENTIONAL_CONSTRAINTS if isempty(operatorB) blockVectorR(:,activeMask) = blockVectorR(:,activeMask) - ... blockVectorY*(gramY\(blockVectorY'*... blockVectorR(:,activeMask))); else blockVectorR(:,activeMask) = blockVectorR(:,activeMask) - ... blockVectorY*(gramY\(blockVectorBY'*... blockVectorR(:,activeMask))); end end %Making active (preconditioned) residuals orthogonal to blockVectorX if isempty(operatorB) blockVectorR(:,activeMask) = blockVectorR(:,activeMask) - ... blockVectorX*(blockVectorX'*blockVectorR(:,activeMask)); else blockVectorR(:,activeMask) = blockVectorR(:,activeMask) - ... blockVectorX*(blockVectorBX'*blockVectorR(:,activeMask)); end %Making active residuals orthonormal if isempty(operatorB) %[blockVectorR(:,activeMask),gramRBR]=... %qr(blockVectorR(:,activeMask),0); %to increase stability gramRBR=blockVectorR(:,activeMask)'*blockVectorR(:,activeMask); if ~isreal(gramRBR) gramRBR=(gramRBR+gramRBR')*0.5; end [gramRBR,cholFlag]=chol(gramRBR); if cholFlag == 0 blockVectorR(:,activeMask) = blockVectorR(:,activeMask)/gramRBR; else warning('BLOPEX:lobpcg:ResidualNotFullRank',... 'The residual is not full rank.'); break end else if isnumeric(operatorB) blockVectorBR(:,activeMask) = ... operatorB*blockVectorR(:,activeMask); else blockVectorBR(:,activeMask) = ... feval(operatorB,blockVectorR(:,activeMask)); end gramRBR=blockVectorR(:,activeMask)'*blockVectorBR(:,activeMask); if ~isreal(gramRBR) gramRBR=(gramRBR+gramRBR')*0.5; end [gramRBR,cholFlag]=chol(gramRBR); if cholFlag == 0 blockVectorR(:,activeMask) = ... blockVectorR(:,activeMask)/gramRBR; blockVectorBR(:,activeMask) = ... blockVectorBR(:,activeMask)/gramRBR; else warning('BLOPEX:lobpcg:ResidualNotFullRankOrElse',... strcat('The residual is not full rank or/and operatorB ',... 'is not positive definite.')); break end end clear gramRBR; if isnumeric(operatorA) blockVectorAR(:,activeMask) = operatorA*blockVectorR(:,activeMask); else blockVectorAR(:,activeMask) = ... feval(operatorA,blockVectorR(:,activeMask)); end if iterationNumber > 1 %Making active conjugate directions orthonormal if isempty(operatorB) %[blockVectorP(:,activeMask),gramPBP] = qr(blockVectorP(:,activeMask),0); gramPBP=blockVectorP(:,activeMask)'*blockVectorP(:,activeMask); if ~isreal(gramPBP) gramPBP=(gramPBP+gramPBP')*0.5; end [gramPBP,cholFlag]=chol(gramPBP); if cholFlag == 0 blockVectorP(:,activeMask) = ... blockVectorP(:,activeMask)/gramPBP; blockVectorAP(:,activeMask) = ... blockVectorAP(:,activeMask)/gramPBP; else warning('BLOPEX:lobpcg:DirectionNotFullRank',... 'The direction matrix is not full rank.'); break end else gramPBP=blockVectorP(:,activeMask)'*blockVectorBP(:,activeMask); if ~isreal(gramPBP) gramPBP=(gramPBP+gramPBP')*0.5; end [gramPBP,cholFlag]=chol(gramPBP); if cholFlag == 0 blockVectorP(:,activeMask) = ... blockVectorP(:,activeMask)/gramPBP; blockVectorAP(:,activeMask) = ... blockVectorAP(:,activeMask)/gramPBP; blockVectorBP(:,activeMask) = ... blockVectorBP(:,activeMask)/gramPBP; else warning('BLOPEX:lobpcg:DirectionNotFullRank',... strcat('The direction matrix is not full rank ',... 'or/and operatorB is not positive definite.')); break end end clear gramPBP end condestGmean = mean(condestGhistory(max(1,iterationNumber-10-... round(log(currentBlockSize))):iterationNumber)); % restart=1; % The Raileight-Ritz method for [blockVectorX blockVectorR blockVectorP] if residualNorms > eps^0.6 explicitGramFlag = 0; else explicitGramFlag = 1; %suggested by Garrett Moran, private end activeRSize=size(blockVectorR(:,activeMask),2); if iterationNumber == 1 activePSize=0; restart=1; else activePSize=size(blockVectorP(:,activeMask),2); restart=0; end gramXAR=full(blockVectorAX'*blockVectorR(:,activeMask)); gramRAR=full(blockVectorAR(:,activeMask)'*blockVectorR(:,activeMask)); gramRAR=(gramRAR'+gramRAR)*0.5; if explicitGramFlag gramXAX=full(blockVectorAX'*blockVectorX); gramXAX=(gramXAX'+gramXAX)*0.5; if isempty(operatorB) gramXBX=full(blockVectorX'*blockVectorX); gramRBR=full(blockVectorR(:,activeMask)'*... blockVectorR(:,activeMask)); gramXBR=full(blockVectorX'*blockVectorR(:,activeMask)); else gramXBX=full(blockVectorBX'*blockVectorX); gramRBR=full(blockVectorBR(:,activeMask)'*... blockVectorR(:,activeMask)); gramXBR=full(blockVectorBX'*blockVectorR(:,activeMask)); end gramXBX=(gramXBX'+gramXBX)*0.5; gramRBR=(gramRBR'+gramRBR)*0.5; end for cond_try=1:2, %cond_try == 2 when restart if ~restart gramXAP=full(blockVectorAX'*blockVectorP(:,activeMask)); gramRAP=full(blockVectorAR(:,activeMask)'*... blockVectorP(:,activeMask)); gramPAP=full(blockVectorAP(:,activeMask)'*... blockVectorP(:,activeMask)); gramPAP=(gramPAP'+gramPAP)*0.5; if explicitGramFlag gramA = [ gramXAX gramXAR gramXAP gramXAR' gramRAR gramRAP gramXAP' gramRAP' gramPAP ]; else gramA = [ diag(lambda) gramXAR gramXAP gramXAR' gramRAR gramRAP gramXAP' gramRAP' gramPAP ]; end clear gramXAP gramRAP gramPAP if isempty(operatorB) gramXBP=full(blockVectorX'*blockVectorP(:,activeMask)); gramRBP=full(blockVectorR(:,activeMask)'*... blockVectorP(:,activeMask)); else gramXBP=full(blockVectorBX'*blockVectorP(:,activeMask)); gramRBP=full(blockVectorBR(:,activeMask)'*... blockVectorP(:,activeMask)); %or blockVectorR(:,activeMask)'*blockVectorBP(:,activeMask); end if explicitGramFlag if isempty(operatorB) gramPBP=full(blockVectorP(:,activeMask)'*... blockVectorP(:,activeMask)); else gramPBP=full(blockVectorBP(:,activeMask)'*... blockVectorP(:,activeMask)); end gramPBP=(gramPBP'+gramPBP)*0.5; gramB = [ gramXBX gramXBR gramXBP gramXBR' gramRBR gramRBP gramXBP' gramRBP' gramPBP ]; clear gramPBP else gramB=[eye(blockSize) zeros(blockSize,activeRSize) gramXBP zeros(blockSize,activeRSize)' eye(activeRSize) gramRBP gramXBP' gramRBP' eye(activePSize) ]; end clear gramXBP gramRBP; else if explicitGramFlag gramA = [ gramXAX gramXAR gramXAR' gramRAR ]; gramB = [ gramXBX gramXBR gramXBR' eye(activeRSize) ]; clear gramXAX gramXBX gramXBR else gramA = [ diag(lambda) gramXAR gramXAR' gramRAR ]; gramB = eye(blockSize+activeRSize); end clear gramXAR gramRAR; end condestG = log10(cond(gramB))+1; if (condestG/condestGmean > 2 && condestG > 2 )|| condestG > 8 %black magic - need to guess the restart if verbosityLevel fprintf('Restart on step %i as condestG %5.4e \n',... iterationNumber,condestG); end if cond_try == 1 && ~restart restart=1; %steepest descent restart for stability else warning('BLOPEX:lobpcg:IllConditioning',... 'Gramm matrix ill-conditioned: results unpredictable'); end else break end end [gramA,gramB]=eig(gramA,gramB); lambda=diag(gramB(1:blockSize,1:blockSize)); coordX=gramA(:,1:blockSize); clear gramA gramB if issparse(blockVectorX) coordX=sparse(coordX); end if ~restart blockVectorP = blockVectorR(:,activeMask)*... coordX(blockSize+1:blockSize+activeRSize,:) + ... blockVectorP(:,activeMask)*... coordX(blockSize+activeRSize+1:blockSize + ... activeRSize+activePSize,:); blockVectorAP = blockVectorAR(:,activeMask)*... coordX(blockSize+1:blockSize+activeRSize,:) + ... blockVectorAP(:,activeMask)*... coordX(blockSize+activeRSize+1:blockSize + ... activeRSize+activePSize,:); if ~isempty(operatorB) blockVectorBP = blockVectorBR(:,activeMask)*... coordX(blockSize+1:blockSize+activeRSize,:) + ... blockVectorBP(:,activeMask)*... coordX(blockSize+activeRSize+1:blockSize+activeRSize+activePSize,:); end else %use block steepest descent blockVectorP = blockVectorR(:,activeMask)*... coordX(blockSize+1:blockSize+activeRSize,:); blockVectorAP = blockVectorAR(:,activeMask)*... coordX(blockSize+1:blockSize+activeRSize,:); if ~isempty(operatorB) blockVectorBP = blockVectorBR(:,activeMask)*... coordX(blockSize+1:blockSize+activeRSize,:); end end blockVectorX = blockVectorX*coordX(1:blockSize,:) + blockVectorP; blockVectorAX=blockVectorAX*coordX(1:blockSize,:) + blockVectorAP; if ~isempty(operatorB) blockVectorBX=blockVectorBX*coordX(1:blockSize,:) + blockVectorBP; end clear coordX %%end RR lambdaHistory(1:blockSize,iterationNumber+1)=lambda; condestGhistory(iterationNumber+1)=condestG; if verbosityLevel fprintf('Iteration %i current block size %i \n',... iterationNumber,currentBlockSize); fprintf('Eigenvalues lambda %17.16e \n',lambda); fprintf('Residual Norms %e \n',residualNorms'); end end %The main step of the method was the CG cycle: end %Postprocessing %Making sure blockVectorX's "exactly" satisfy the blockVectorY constrains?? %Making sure blockVectorX's are "exactly" othonormalized by final "exact" RR if isempty(operatorB) gramXBX=full(blockVectorX'*blockVectorX); else if isnumeric(operatorB) blockVectorBX = operatorB*blockVectorX; else blockVectorBX = feval(operatorB,blockVectorX); end gramXBX=full(blockVectorX'*blockVectorBX); end gramXBX=(gramXBX'+gramXBX)*0.5; if isnumeric(operatorA) blockVectorAX = operatorA*blockVectorX; else blockVectorAX = feval(operatorA,blockVectorX); end gramXAX = full(blockVectorX'*blockVectorAX); gramXAX = (gramXAX + gramXAX')*0.5; %Raileigh-Ritz for blockVectorX, which is already operatorB-orthonormal [coordX,gramXBX] = eig(gramXAX,gramXBX); lambda=diag(gramXBX); if issparse(blockVectorX) coordX=sparse(coordX); end blockVectorX = blockVectorX*coordX; blockVectorAX = blockVectorAX*coordX; if ~isempty(operatorB) blockVectorBX = blockVectorBX*coordX; end %Computing all residuals if isempty(operatorB) if blockSize > 1 blockVectorR = blockVectorAX - ... blockVectorX*spdiags(lambda,0,blockSize,blockSize); else blockVectorR = blockVectorAX - blockVectorX*lambda; %to make blockVectorR full when lambda is just a scalar end else if blockSize > 1 blockVectorR=blockVectorAX - ... blockVectorBX*spdiags(lambda,0,blockSize,blockSize); else blockVectorR = blockVectorAX - blockVectorBX*lambda; %to make blockVectorR full when lambda is just a scalar end end residualNorms=full(sqrt(sum(conj(blockVectorR).*blockVectorR)')); residualNormsHistory(1:blockSize,iterationNumber)=residualNorms; if verbosityLevel fprintf('Final Eigenvalues lambda %17.16e \n',lambda); fprintf('Final Residual Norms %e \n',residualNorms'); end if verbosityLevel == 2 whos figure(491) semilogy((abs(residualNormsHistory(1:blockSize,1:iterationNumber-1)))'); title('Residuals for Different Eigenpairs','fontsize',16); ylabel('Eucledian norm of residuals','fontsize',16); xlabel('Iteration number','fontsize',16); %axis tight; %axis([0 maxIterations+1 1e-15 1e3]) set(gca,'FontSize',14); figure(492); semilogy(abs((lambdaHistory(1:blockSize,1:iterationNumber)-... repmat(lambda,1,iterationNumber)))'); title('Eigenvalue errors for Different Eigenpairs','fontsize',16); ylabel('Estimated eigenvalue errors','fontsize',16); xlabel('Iteration number','fontsize',16); %axis tight; %axis([0 maxIterations+1 1e-15 1e3]) set(gca,'FontSize',14); drawnow; end varargout(1)={failureFlag}; varargout(2)={lambdaHistory(1:blockSize,1:iterationNumber)}; varargout(3)={residualNormsHistory(1:blockSize,1:iterationNumber-1)}; end linear-algebra-2.2.3/inst/PaxHeaders.16347/circulant_matrix_vector_product.m0000644000000000000000000000013213563071136023756 xustar0030 mtime=1573679710.690089562 30 atime=1573679710.690089562 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/circulant_matrix_vector_product.m0000644000175000017500000000345013563071136024143 0ustar00olafolaf00000000000000## Copyright (C) 2012 Nir Krakauer ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn{Function File} {@var{y} =} circulant_matrix_vector_product (@var{v}, @var{x}) ## ## Fast, compact calculation of the product of a circulant matrix with a vector@* ## Given @var{n}*1 vectors @var{v} and @var{x}, return the matrix-vector product @var{y} = @var{C}@var{x}, where @var{C} is the @var{n}*@var{n} circulant matrix that has @var{v} as its first column ## ## Theoretically the same as @code{make_circulant_matrix(x) * v}, but does not form @var{C} explicitly; uses the discrete Fourier transform ## ## Because of roundoff, the returned @var{y} may have a small imaginary component even if @var{v} and @var{x} are real (use @code{real(y)} to remedy this) ## ## Reference: Gene H. Golub and Charles F. Van Loan, Matrix Computations, 3rd Ed., Section 4.7.7 ## ## @seealso{gallery, circulant_eig, circulant_inv} ## @end deftypefn function y = circulant_matrix_vector_product (v, x) xf = fft(x); vf = fft(v); z = vf .* xf; y = ifft(z); endfunction %!shared v,x %! v = [1 2 3]'; x = [2 5 6]'; %!assert (circulant_matrix_vector_product(v, x), circulant_make_matrix(v)*x, eps); linear-algebra-2.2.3/inst/PaxHeaders.16347/@kronprod0000644000000000000000000000013213563071136016767 xustar0030 mtime=1573679710.690089562 30 atime=1573679710.714089914 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/0000755000175000017500000000000013563071136017227 5ustar00olafolaf00000000000000linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/isreal.m0000644000000000000000000000013213563071136020501 xustar0030 mtime=1573679710.682089444 30 atime=1573679710.682089444 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/isreal.m0000644000175000017500000000216613563071136020671 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} isreal (@var{KP}) ## Return @t{true} if the Kronecker product @var{KP} is real, i.e. has no ## imaginary components. ## @seealso{isreal, @@kronprod/iscomplex} ## @end deftypefn function retval = isreal (KP) if (nargin != 1) print_usage (); endif if (!isa (KP, "kronprod")) error ("isreal: input argument must be of class 'kronprod'"); endif retval = (isreal (KP.A) & isreal (KP.B)); endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/rank.m0000644000000000000000000000013213563071136020155 xustar0030 mtime=1573679710.686089503 30 atime=1573679710.686089503 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/rank.m0000644000175000017500000000222313563071136020337 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} rank (@var{KP}) ## Return the rank of the Kronecker product @var{KP}. This is computed as the ## product of the ranks of the matrices forming the product. ## @seealso{rank, @@kronprod/det, @@kronprod/trace} ## @end deftypefn function retval = rank (KP) if (nargin != 1) print_usage (); endif if (!isa (KP, "kronprod")) error ("rank: input must be of class 'kronprod'"); endif retval = rank (KP.A) * rank (KP.B); endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/iscomplex.m0000644000000000000000000000013213563071136021225 xustar0030 mtime=1573679710.682089444 30 atime=1573679710.682089444 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/iscomplex.m0000644000175000017500000000216513563071136021414 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} iscomplex (@var{KP}) ## Return @t{true} if the Kronecker product @var{KP} contains any complex values. ## @seealso{iscomplex, @@kronprod/isreal} ## @end deftypefn function retval = iscomplex (KP) if (nargin != 1) print_usage (); endif if (!isa (KP, "kronprod")) error ("iscomplex: input argument must be of class 'kronprod'"); endif retval = (iscomplex (KP.A) || iscomplex (KP.B)); endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/mtimes.m0000644000000000000000000000013213563071136020520 xustar0030 mtime=1573679710.682089444 30 atime=1573679710.682089444 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/mtimes.m0000644000175000017500000000615613563071136020713 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} mtimes (@var{KP1}, @var{KP2}) ## Perform matrix multiplication operation. ## @end deftypefn function retval = mtimes (M1, M2) ## Check input if (nargin == 0) print_usage (); elseif (nargin == 1) ## This seems to be what happens for full and sparse matrices, so we copy this behaviour retval = M1; return; endif if (! (ismatrix (M1) && isnumeric (M1) && ismatrix (M2) && isnumeric (M2))) error ("mtimes: input arguments must be matrices"); endif if (columns (M1) != rows (M2)) error ("mtimes: nonconformant arguments (op1 is %dx%d, op2 is %dx%d)", rows (M1), columns (M1), rows (M2), columns (M2)); endif ## Take action depending on input types M1_is_KP = isa (M1, "kronprod"); M2_is_KP = isa (M2, "kronprod"); if (M1_is_KP && M2_is_KP) # Product of Kronecker Products ## Check if the size match such that the result is a Kronecker Product if (columns (M1.A) == rows (M2.A) && columns (M1.B) == rows (M2.B)) retval = kronprod (M1.A * M2.A, M1.B * M2.B); else ## Form the full matrix of the smallest matrix and use that to compute the ## final product ## XXX: Can we do something smarter here? numel1 = numel (M1); numel2 = numel (M2); if (numel1 < numel2) retval = full (M1) * M2; else retval = M1 * full (M2); endif endif elseif (M1_is_KP && isscalar (M2)) # Product of Kronecker Product and scalar if (numel (M1.A) < numel (M1.B)) retval = kronprod (M2 * M1.A, M1.B); else retval = kronprod (M1.A, M2 * M1.B); endif elseif (M1_is_KP && ismatrix (M2)) # Product of Kronecker Product and Matrix retval = zeros (rows (M1), columns (M2)); for n = 1:columns (M2) M = reshape (M2 (:, n), [columns(M1.B), columns(M1.A)]); retval (:, n) = vec (M1.B * M * M1.A'); endfor elseif (isscalar (M1) && M2_is_KP) # Product of scalar and Kronecker Product if (numel (M2.A) < numel (M2.B)) retval = kronprod (M1 * M2.A, M2.B); else retval = kronprod (M2.A, M1 * M2.B); endif elseif (ismatrix (M1) && M2_is_KP) # Product of Matrix and Kronecker Product retval = zeros (rows (M1), columns (M2)); for n = 1:rows (M1) M = reshape (M1 (n, :), [rows(M2.B), rows(M2.A)]); retval (n, :) = vec (M2.B' * M * M2.A); endfor else error ("mtimes: internal error for 'kronprod'"); endif endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/plus.m0000644000000000000000000000013213563071136020205 xustar0030 mtime=1573679710.686089503 30 atime=1573679710.686089503 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/plus.m0000644000175000017500000000333413563071136020373 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} plus (@var{a}, @var{a}) ## Return the sum of a Kronecker product and another matrix. This is performed ## by forming the full matrix of both inputs and is as such a potential expensive ## operation. ## @seealso{plus, @@kronprod/minus} ## @end deftypefn function retval = plus (M1, M2) if (nargin == 0 || nargin > 2) print_usage (); elseif (nargin == 1) ## This seems to be the behaviour for the built-in types so we copy that retval = M1; return; endif if (! (ismatrix (M1) && isnumeric (M1) && ismatrix (M2) && isnumeri (M2))) error ("plus: input arguments must be matrics"); endif if (!size_equal (M1, M2)) error ("plus: nonconformant arguments (op1 is %dx%d, op2 is %dx%d)", rows (M1), columns (M1), rows (M2), columns (M2)); endif ## XXX: Can we do something smarter here? if (issparse (M1)) M1 = sparse (M1); else M1 = full (M1); endif if (issparse (M2)) M2 = sparse (M2); else M2 = full (M2); endif retval = M1 + M2; endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/numel.m0000644000000000000000000000013213563071136020342 xustar0030 mtime=1573679710.686089503 30 atime=1573679710.686089503 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/numel.m0000644000175000017500000000215413563071136020527 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} numel (@var{KP}) ## Return the number of elements in the Kronecker product @var{KP}. ## @seealso{numel, @@kronprod/rows, @@kronprod/columns, @@kronprod/size} ## @end deftypefn function retval = numel (KP) if (nargin != 1) print_usage (); endif if (!isa (KP, "kronprod")) error ("numel: input must be of class 'kronprod'"); endif retval = prod (size (KP.A) .* size (KP.B)); endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/rdivide.m0000644000000000000000000000013213563071136020650 xustar0030 mtime=1573679710.686089503 30 atime=1573679710.686089503 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/rdivide.m0000644000175000017500000000350213563071136021033 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} rdivide (@var{a}, @var{b}) ## Perform element-by-element right division. ## @end deftypefn function retval = rdivide (a, b) ## Check input if (nargin < 2) print_usage (); endif if (! (ismatrix (a) && isnumeric (a) && ismatrix (b) && isnumeric (b))) error ("rdivide: input arguments must be scalars or matrices"); endif if (!size_equal (a, b) || !isscalar (b)) error ("times: nonconformant arguments (op1 is %dx%d, op2 is %dx%d)", rows (a), columns (a), rows (b), columns (b)); endif ## Take action depending on input if (isscalar (a) && isa (b, "kronprod")) retval = kronprod (a ./ b.A, 1 ./ b.B); elseif (isa (a, "kronprod") && isscalar (b)) if (numel (a.A) < numel (a.B)) retval = kronprod (a.A ./ b, a.B); else retval = kronprod (a.A, a.B ./ b); endif elseif (isa (a, "kronprod") && isa (b, "kronprod")) ## XXX: Can we do something smarter here? retval = full (a) ./ full (b); else ## XXX: We should probably handle sparse cases and all sorts of other ## situations better here retval = full (a) ./ full (b); endif endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/issquare.m0000644000000000000000000000013213563071136021056 xustar0030 mtime=1573679710.682089444 30 atime=1573679710.682089444 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/issquare.m0000644000175000017500000000212713563071136021243 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} issquare (@var{KP}) ## Return @t{true} if the Kronecker product @var{KP} is a square matrix. ## @seealso{@@kronprod/size} ## @end deftypefn function retval = issquare (KP) if (nargin != 1) print_usage (); endif if (!isa (KP, "kronprod")) error ("issquare: input argument must be of class 'kronprod'"); endif s = size (KP); retval = (s (1) == s (2)); endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/full.m0000644000000000000000000000013213563071136020164 xustar0030 mtime=1573679710.678089385 30 atime=1573679710.678089385 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/full.m0000644000175000017500000000272013563071136020350 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} full (@var{KP}) ## Return the full matrix representation of the Kronecker product @var{KP}. ## ## If @var{KP} is the Kronecker product of an @var{n}-by-@var{m} matrix and a ## @var{q}-by-@var{r} matrix, then the result is a @var{n}@var{q}-by-@var{m}@var{r} ## matrix. Thus, the result can require vast amount of memory, so this function ## should be avoided whenever possible. ## @seealso{full, @@kronprod/sparse} ## @end deftypefn function retval = full (KP) if (nargin != 1) print_usage (); endif if (!isa (KP, "kronprod")) error ("full: input argument must be of class 'kronprod'"); endif retval = full (kron (KP.A, KP.B)); if (!isempty (KP.P)) #retval = KP.P * retval * KP.P'; retval = retval (KP.P, KP.P); endif endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/kronprod.m0000644000000000000000000000013213563071136021060 xustar0030 mtime=1573679710.682089444 30 atime=1573679710.682089444 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/kronprod.m0000644000175000017500000000325713563071136021252 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} kronprod (@var{A}, @var{B}) ## @deftypefnx{Function File} kronprod (@var{A}, @var{B}, @var{P}) ## Construct a Kronecker product object. ## XXX: Write proper documentation ## ## With two input arguments, the following matrix is represented: kron (A, B); ## ## With three input arguments, the following matrix is represented: P * kron (A, B) * P' ## (P must be a permutation matrix) ## ## @end deftypefn function retval = kronprod (A, B, P) if (nargin == 0) KP.A = KP.B = KP.P = []; elseif (nargin == 2 && ismatrix (A) && isnumeric (A) && ismatrix (B) && isnumeric (B)) KP.A = A; KP.B = B; KP.P = []; elseif (nargin == 3 && ismatrix (A) && isnumeric (A) && ismatrix (B) && isnumeric (B)) # && strcmp (typeinfo (P), "permutation matrix")) # FIXME: why is above line commented-out? ## XXX: Check that the size of P is correct KP.A = A; KP.B = B; KP.P = P; else print_usage (); endif retval = class (KP, "kronprod"); endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/ismatrix.m0000644000000000000000000000013213563071136021062 xustar0030 mtime=1573679710.682089444 30 atime=1573679710.682089444 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/ismatrix.m0000644000175000017500000000162013563071136021244 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} ismatrix (@var{KP}) ## Return @t{true} to indicate that the Kronecker product @var{KP} always is a ## matrix. ## @end deftypefn function retval = ismatrix (KP) retval = true; endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/not_done0000644000000000000000000000013213563071136020574 xustar0030 mtime=1573679710.686089503 30 atime=1573679710.714089914 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/not_done/0000755000175000017500000000000013563071136021034 5ustar00olafolaf00000000000000linear-algebra-2.2.3/inst/@kronprod/not_done/PaxHeaders.16347/svd.m0000644000000000000000000000013213563071136021623 xustar0030 mtime=1573679710.686089503 30 atime=1573679710.686089503 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/not_done/svd.m0000644000175000017500000000321613563071136022010 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} svd (@var{KP}) ## XXX: Write documentation ## @end deftypefn function [U, S, V] = svd (KP) if (nargin < 1) print_usage (); endif if (!isa (KP, "kronprod")) error ("svd: input must be of class 'kronprod'"); endif ## XXX: I don't think this works properly for non-square A and B if (nargout <= 1) ## Only singular values were requested S_A = svd (KP.A); S_B = svd (KP.B); U = sort (kron (S_A, S_B), "descend"); elseif (nargout == 3) ## The full SVD was requested [U_A, S_A, V_A] = svd (KP.A); [U_B, S_B, V_B] = svd (KP.B); ## Compute and sort singular values [sv, idx] = sort (kron (diag (S_A), diag (S_B)), "descend"); ## Form matrices S = resize (diag (sv), [rows(KP), columns(KP)]); #Pu = eye (rows (KP)) (idx, :); U = kronprod (U_A, U_B, idx); #Pv = eye (columns (KP)) (idx, :); V = kronprod (V_A, V_B, idx); else print_usage (); endif endfunction linear-algebra-2.2.3/inst/@kronprod/not_done/PaxHeaders.16347/eig.m0000644000000000000000000000013213563071136021573 xustar0030 mtime=1573679710.682089444 30 atime=1573679710.682089444 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/not_done/eig.m0000644000175000017500000000454713563071136021770 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{lambda} =} eig (@var{KP}) ## @deftypefnx{Function File} {[var{V}, @var{lambda}] =} eig (@var{KP}) ## XXX: Write help text ## @seealso{eig, @kronprod/svd} ## @end deftypefn function [V, lambda] = eig (KP, A) ## XXX: This implementation provides a different permutation of eigenvalues and ## eigenvectors compared to 'eig (full (KP))' ## Check input if (nargin == 0 || nargin > 2) print_usage (); endif if (!isa (KP, "kronprod")) error ("eig: first input argument must be of class 'kronprod'"); endif if (!issquare (KP)) error ("eig: first input must be a square matrix"); endif ## Take action if (nargin == 1) if (nargout <= 1) ## Only eigenvalues were requested if (issquare (KP.A) && issquare (KP.B)) lambda_A = eig (KP.A); lambda_B = eig (KP.B); V = kronprod (lambda_A, lambda_B); else ## We should be able to do this using SVD error ("eig not implemented (yet) for Kronecker products of non-square matrices"); endif elseif (nargout == 2) ## Both eigenvectors and eigenvalues were requested if (issquare (KP.A) && issquare (KP.B)) [V_A, lambda_A] = eig (KP.A); [V_B, lambda_B] = eig (KP.B); V = kronprod (V_A, V_B); lambda = kronprod (lambda_A, lambda_B); else ## We should be able to do this using SVD error ("eig not implemented (yet) for Kronecker products of non-square matrices"); endif endif elseif (nargin == 2) ## Solve generalised eigenvalue problem ## XXX: Is there a fancy way of doing this? [V, lambda] = eig (full (KP), full (A)); endif endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/inv.m0000644000000000000000000000013213563071136020016 xustar0030 mtime=1573679710.678089385 30 atime=1573679710.678089385 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/inv.m0000644000175000017500000000337513563071136020211 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} inv (@var{KP}) ## Return the inverse of the Kronecker product @var{KP}. ## ## If @var{KP} is the Kronecker product of two square matrices @var{A} and @var{B}, ## the inverse will be computed as the Kronecker product of the inverse of ## @var{A} and @var{B}. ## ## If @var{KP} is square but not a Kronecker product of square matrices, the ## inverse will be computed using the SVD ## @seealso{@@kronprod/sparse} ## @end deftypefn function retval = inv (KP) ## Check input if (nargin != 1) print_usage (); endif if (!isa (KP, "kronprod")) error ("inv: input argument must be of class 'kronprod'"); endif ## Do the computations [n, m] = size (KP.A); [q, r] = size (KP.B); if (n == m && q == r) # A and B are both square retval = kronprod (inv (KP.A), inv (KP.B)); elseif (n*q == m*r) # kron (A, B) is square ## We use the SVD to compute the inverse. ## XXX: Should we use 'eig' instead? [U, S, V] = svd (KP); retval = U * (1./S) * V'; else error ("inv: argument must be a square matrix"); endif endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/trace.m0000644000000000000000000000013213563071136020320 xustar0030 mtime=1573679710.686089503 30 atime=1573679710.686089503 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/trace.m0000644000175000017500000000267213563071136020512 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} trace (@var{KP}) ## Returns the trace of the Kronecker product @var{KP}. ## ## If @var{KP} is a Kronecker product of two square matrices, the trace is ## computed as the product of the trace of these two matrices. Otherwise the ## trace is computed by forming the full matrix. ## @seealso{@@kronprod/det, @@kronprod/rank, @@kronprod/full} ## @end deftypefn function retval = trace (KP) if (nargin != 1) print_usage (); endif if (!isa (KP, "kronprod")) error ("trace: input must be of class 'kronprod'"); endif if (issquare (KP.A) && issquare (KP.B)) retval = trace (KP.A) * trace (KP.B); else ## XXX: Can we do something smarter here? Using 'eig' or 'svd'? retval = trace (full (KP)); endif endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/transpose.m0000644000000000000000000000013213563071136021240 xustar0030 mtime=1573679710.690089562 30 atime=1573679710.690089562 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/transpose.m0000644000175000017500000000225013563071136021422 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} transpose (@var{KP}) ## Returns the transpose of the Kronecker product @var{KP}. This is equivalent ## to ## ## @example ## @var{KP}.' ## @end example ## @seealso{transpose, @@kronprod/ctranspose} ## @end deftypefn function retval = transpose (KP) if (nargin != 1) print_usage (); endif if (!isa (KP, "kronprod")) error ("transpose: input must be of class 'kronprod'"); endif retval = kronprod (transpose (KP.A), transpose (KP.B)); endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/rows.m0000644000000000000000000000013213563071136020214 xustar0030 mtime=1573679710.686089503 30 atime=1573679710.686089503 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/rows.m0000644000175000017500000000213513563071136020400 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} rows (@var{KP}) ## Return the number of rows in the Kronecker product @var{KP}. ## @seealso{rows, @@kronprod/size, @@kronprod/columns, @@kronprod/numel} ## @end deftypefn function retval = rows (KP) if (nargin != 1) print_usage (); endif if (!isa (KP, "kronprod")) error ("rows: input must be of class 'kronprod'"); endif retval = rows (KP.A) * rows (KP.B); endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/times.m0000644000000000000000000000013213563071136020343 xustar0030 mtime=1573679710.686089503 30 atime=1573679710.686089503 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/times.m0000644000175000017500000000426313563071136020533 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} times (@var{KP}, @var{KP2}) ## Perform elemtn-by-element multiplication. ## @end deftypefn function retval = times (M1, M2) ## Check input if (nargin == 0) print_usage (); elseif (nargin == 1) ## This seems to be what happens for full and sparse matrices, so we copy this behaviour retval = M1; return; endif if (! (ismatrix (M1) && isnumeric (M1) && ismatrix (M2) && isnumeric (M2))) error ("times: input arguments must be matrices"); endif if (! size_equal (M1, M2)) error ("times: nonconformant arguments (op1 is %dx%d, op2 is %dx%d)", rows (M1), columns (M1), rows (M2), columns (M2)); endif ## Take action depending on input types M1_is_KP = isa (M1, "kronprod"); M2_is_KP = isa (M2, "kronprod"); ## Product of Kronecker Products ## Check if the size match such that the result is a Kronecker Product if (M1_is_KP && M2_is_KP && size_equal (M1.A, M2.A) && size_equal (M1.B, M2.B)) retval = kronprod (M1.A .* M2.A, M1.B .* M2.B); elseif (isscalar (M1) || isscalar (M2)) # Product of Kronecker Product and scalar retval = M1 * M2; ## Forward to mtimes. else # All other cases. ## Form the full matrix or sparse matrix of both matrices ## XXX: Can we do something smarter here? if (issparse (M1)) M1 = sparse (M1); else M1 = full (M1); endif if (issparse (M2)) M2 = sparse (M2); else M2 = full (M2); endif retval = M1 .* M2; endif endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/columns.m0000644000000000000000000000013213563071136020702 xustar0030 mtime=1573679710.678089385 30 atime=1573679710.678089385 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/columns.m0000644000175000017500000000215513563071136021070 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} columns (@var{KP}) ## Return the number of columns in the Kronecker product @var{KP}. ## @seealso{@@kronprod/rows, @@kronprod/size, @@kronprod/numel} ## @end deftypefn function retval = columns (KP) if (nargin != 1) print_usage (); endif if (!isa (KP, "kronprod")) error ("columns: input argument must be of class 'kronprod'"); endif retval = columns (KP.A) * columns (KP.B); endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/issparse.m0000644000000000000000000000013213563071136021053 xustar0030 mtime=1573679710.682089444 30 atime=1573679710.682089444 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/issparse.m0000644000175000017500000000215313563071136021237 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} issparse (@var{KP}) ## Return @t{true} if one of the matrices in the Kronecker product @var{KP} ## is sparse. ## @seealso{@@kronprod/sparse} ## @end deftypefn function retval = issparse (KP) if (nargin != 1) print_usage (); endif if (!isa (KP, "kronprod")) error ("issparse: input argument must be of class 'kronprod'"); endif retval = (issparse(KP.A) || issparse(KP.B)); endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/sparse.m0000644000000000000000000000013213563071136020517 xustar0030 mtime=1573679710.686089503 30 atime=1573679710.686089503 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/sparse.m0000644000175000017500000000225213563071136020703 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} sparse (@var{KP}) ## Return the Kronecker product @var{KP} represented as a sparse matrix. ## @seealso{sparse, @@kronprod/issparse, @@kronprod/full} ## @end deftypefn function retval = sparse (KP) if (nargin != 1) print_usage (); endif if (!isa (KP, "kronprod")) error ("sparse: input argument must be of class 'kronprod'"); endif ## XXX: Would this be better? kron (sparse (KP.A), sparse (KP.B))) retval = sparse (kron (KP.A, KP.B)); endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/uplus.m0000644000000000000000000000013213563071136020372 xustar0030 mtime=1573679710.690089562 30 atime=1573679710.690089562 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/uplus.m0000644000175000017500000000174713563071136020566 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} uplus (@var{KP}) ## Returns the unary plus operator working on the Kronecker product @var{KP}. ## This corresponds to @code{+@var{KP}} and simply returns the Kronecker ## product unchanged. ## @seealso{@@kronprod/uminus} ## @end deftypefn function KP = uplus (KP) endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/mldivide.m0000644000000000000000000000013213563071136021017 xustar0030 mtime=1573679710.682089444 30 atime=1573679710.682089444 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/mldivide.m0000644000175000017500000000412313563071136021202 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} mldivide (@var{M1}, @var{M2}) ## Perform matrix left division. ## @end deftypefn function retval = mldivide (M1, M2) ## Check input if (nargin != 2) print_usage (); endif if (! (ismatrix (M1) && isnumeric (M1) && ismatrix (M2) && isnumeric (M2))) error ("mldivide: both input arguments must be matrices"); endif if (rows (M1) != rows (M2)) error ("mldivide: nonconformant arguments (op1 is %dx%d, op2 is %dx%d)", rows (M1), columns (M1), rows (M2), columns (M2)); endif ## Take action depending on types M1_is_KP = isa (M1, "kronprod"); M2_is_KP = isa (M2, "kronprod"); if (M1_is_KP && M2_is_KP) # Left division of Kronecker Products error ("mldividide: this part not yet implemented as I'm lazy..."); elseif (M1_is_KP) # Left division of Kronecker Product and Matrix ## XXX: Does this give the same minimum-norm solution as when using ## XXX: full (M1) \ M2 ## XXX: ? It is the same when M1 is invertible. retval = zeros (columns (M1), columns (M2)); for n = 1:columns (M2) M = reshape (M2 (:, n), [rows(M1.B), rows(M1.A)]); retval (:, n) = vec ((M1.A \ (M1.B \ M)')'); endfor elseif (M2_is_KP) # Left division of Matrix and Kronecker Product error ("mldividide: this part not yet implemented as I'm lazy..."); else error ("mldivide: internal error for 'kronprod'"); endif endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/disp.m0000644000000000000000000000013213563071136020161 xustar0030 mtime=1573679710.678089385 30 atime=1573679710.678089385 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/disp.m0000644000175000017500000000221013563071136020337 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} disp (@var{KP}) ## Show the content of the Kronecker product @var{KP}. To avoid evaluating the ## Kronecker product, this function displays the two matrices defining the product. ## To display the actual values of @var{KP}, use @code{disp (full (@var{KP}))}. ## ## This function is equivalent to @code{@@kronprod/display}. ## @seealso{@@kronprod/display, @@kronprod/full} ## @end deftypefn function disp (KP) display (KP); endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/size.m0000644000000000000000000000013213563071136020174 xustar0030 mtime=1573679710.686089503 30 atime=1573679710.686089503 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/size.m0000644000175000017500000000255013563071136020361 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} size (@var{KP}) ## @deftypefnx{Function File} size (@var{KP}, @var{dim}) ## Return the size of the Kronecker product @var{KP} as a vector. ## @seealso{size, @@kronprod/rows, @@kronprod/columns, @@kronprod/numel} ## @end deftypefn function retval = size (KP, dim) if (nargin < 1) print_usage (); endif if (!isa (KP, "kronprod")) error ("size: input must be of class 'kronprod'"); endif if (nargin > 1 && !(isscalar (dim) && dim == round (dim) && dim > 0)) error ("size: optional second input must be a positive integer"); endif retval = size (KP.A) .* size (KP.B); if (nargin > 1) retval = retval (dim); endif endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/uminus.m0000644000000000000000000000013213563071136020542 xustar0030 mtime=1573679710.690089562 30 atime=1573679710.690089562 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/uminus.m0000644000175000017500000000240113563071136020722 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} uminus (@var{KP}) ## Returns the unary minus operator working on the Kronecker product @var{KP}. ## This corresponds to @code{-@var{KP}} and simply returns the Kronecker ## product with the sign of the smallest matrix in the product reversed. ## @seealso{@@kronprod/uminus} ## @end deftypefn function KP = uminus (KP) if (nargin != 1) print_usage (); endif if (!isa (KP, "kronprod")) error ("uplus: input must be of class 'kronprod'"); endif if (numel (KP.A) < numel (KP.B)) KP.A *= -1; else KP.B *= -1; endif endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/display.m0000644000000000000000000000013213563071136020667 xustar0030 mtime=1573679710.678089385 30 atime=1573679710.678089385 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/display.m0000644000175000017500000000307213563071136021054 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} display (@var{KP}) ## Show the content of the Kronecker product @var{KP}. To avoid evaluating the ## Kronecker product, this function displays the two matrices defining the product. ## To display the actual values of @var{KP}, use @code{display (full (@var{KP}))}. ## @seealso{@@kronprod/displ, @@kronprod/full} ## @end deftypefn function display (KP) if (nargin != 1) print_usage (); endif if (!isa (KP, "kronprod")) error ("display: input argument must be of class 'kronprod'"); endif if (isempty (KP.P)) disp ("Kronecker Product of A and B with"); disp ("A = "); disp (KP.A); disp ("B = "); disp (KP.B); else disp ("Permuted Kronecker Product of A and B (i.e. P * kron (A, B) * P') with"); disp ("A = "); disp (KP.A); disp ("B = "); disp (KP.B); disp ("P = "); disp (KP.P); endif endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/mpower.m0000644000000000000000000000013213563071136020533 xustar0030 mtime=1573679710.682089444 30 atime=1573679710.682089444 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/mpower.m0000644000175000017500000000257713563071136020731 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} mpower (@var{KP}, @var{k}) ## Perform matrix power operation. ## @end deftypefn function retval = mpower (KP, k) ## Check input if (nargin != 2) print_usage (); endif if (! (ismatrix (KP) && isnumeric (KP))) error ("mpower: first input argument must be a matrix"); endif if (! isscalar (k)) error ("mpower: second input argument must be a scalar"); endif ## Do the actual computation if (issquare (KP.A) && issquare (KP.B) && k == round (k)) retval = kronprod (KP.A^k, KP.B^k); elseif (issquare (KP)) ## XXX: Can we do something smarter here? retval = full (KP)^k; else error ("for A^b, A must be square"); endif endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/det.m0000644000000000000000000000013213563071136017776 xustar0030 mtime=1573679710.678089385 30 atime=1573679710.678089385 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/det.m0000644000175000017500000000354113563071136020164 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} det (@var{KP}) ## Compute the determinant of a Kronecker product. ## ## If @var{KP} is the Kronecker product of the @var{n}-by-@var{n} matrix @var{A} ## and the @var{q}-by-@var{q} matrix @var{B}, then the determinant is computed ## as ## ## @example ## det (@var{A})^q * det (@var{B})^n ## @end example ## ## If @var{KP} is not a Kronecker product of square matrices the determinant is ## computed by forming the full matrix and then computing the determinant. ## @seealso{det, @@kronprod/trace, @@kronprod/rank, @@kronprod/full} ## @end deftypefn function retval = det (KP) ## Check input if (nargin != 1) print_usage (); endif if (!isa (KP, "kronprod")) error ("det: input argument must be of class 'kronprod'"); endif if (!issquare (KP)) error ("det: argument must be a square matrix"); endif ## Take action [n, m] = size (KP.A); [q, r] = size (KP.B); if (n == m && q == r) # A and B are both square retval = (det (KP.A)^q) * (det (KP.B)^n); elseif (n*q == m*r) # kron (A, B) is square ## XXX: Can we do something smarter here? We should be able to use the SVD... retval = det (full (KP)); endif endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/ctranspose.m0000644000000000000000000000013213563071136021403 xustar0030 mtime=1573679710.678089385 30 atime=1573679710.678089385 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/ctranspose.m0000644000175000017500000000226213563071136021570 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} ctranspose (@var{KP}) ## The complex conjugate transpose of a Kronecker product. This is equivalent ## to ## ## @example ## @var{KP}' ## @end example ## @seealso{ctranspose, @@kronprod/transpose} ## @end deftypefn function retval = ctranspose (KP) if (nargin != 1) print_usage (); endif if (!isa (KP, "kronprod")) error ("ctranspose: input argument must be of class 'kronprod'"); endif retval = kronprod (ctranspose (KP.A), ctranspose (KP.B)); endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/minus.m0000644000000000000000000000013213563071136020355 xustar0030 mtime=1573679710.682089444 30 atime=1573679710.682089444 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/minus.m0000644000175000017500000000314013563071136020536 0ustar00olafolaf00000000000000## Copyright (C) 2010 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} minus (@var{a}, @var{a}) ## Return the difference between a Kronecker product and another matrix. This is performed ## by forming the full matrix of both inputs and is as such a potential expensive ## operation. ## @seealso{minus, @@kronprod/plus} ## @end deftypefn function retval = minus (M1, M2) if (nargin != 2) print_usage (); endif if (! (ismatrix (M1) && isnumeric (M1) && ismatrix (M2) && isnumeric (M2))) error ("minus: both input arguments must be matrices"); endif if (!size_equal (M1, M2)) error ("minus: nonconformant arguments (op1 is %dx%d, op2 is %dx%d)", rows (M1), columns (M1), rows (M2), columns (M2)); endif ## XXX: Can we do something smarter here? if (issparse (M1)) M1 = sparse (M1); else M1 = full (M1); endif if (issparse (M2)) M2 = sparse (M2); else M2 = full (M2); endif retval = M1 - M2; endfunction linear-algebra-2.2.3/inst/@kronprod/PaxHeaders.16347/size_equal.m0000644000000000000000000000013213563071136021363 xustar0030 mtime=1573679710.686089503 30 atime=1573679710.686089503 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/@kronprod/size_equal.m0000644000175000017500000000163613563071136021554 0ustar00olafolaf00000000000000## Copyright (C) 2010 VZLU Prague ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} size_equal (@dots{}) ## True if all input have same dimensions. ## @end deftypefn function iseq = size_equal (varargin) iseq = isequal (cellfun (@size, varargin, "UniformOutput", false){:}); endfunction linear-algebra-2.2.3/inst/PaxHeaders.16347/nmf_pg.m0000644000000000000000000000013013563071136016530 xustar0029 mtime=1573679710.69408962 29 atime=1573679710.69408962 30 ctime=1573679710.714089914 linear-algebra-2.2.3/inst/nmf_pg.m0000644000175000017500000002106513563071136016721 0ustar00olafolaf00000000000000## Copyright (C) 2005-2006 Chih-Jen Lin ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted provided that the following conditions are met: ## ## 1 Redistributions of source code must retain the above copyright notice, ## this list of conditions and the following disclaimer. ## 2 Redistributions in binary form must reproduce the above copyright ## notice, this list of conditions and the following disclaimer in the ## documentation and/or other materials provided with the distribution. ## ## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS'' ## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ## ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ## ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ## DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ## SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ## CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ## ## The views and conclusions contained in the software and documentation are ## those of the authors and should not be interpreted as representing official ## policies, either expressed or implied, of the copyright holders. ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{W}, @var{H}] =} nmf_pg (@var{V}, @var{Winit}, @ ## @var{Hinit}, @var{tol}, @var{timelimit}, @var{maxiter}) ## ## Non-negative matrix factorization by alternative non-negative least squares ## using projected gradients. ## ## The matrix @var{V} is factorized into two possitive matrices @var{W} and ## @var{H} such that @code{V = W*H + U}. Where @var{U} is a matrix of residuals ## that can be negative or positive. When the matrix @var{V} is positive the order ## of the elements in @var{U} is bounded by the optional named argument @var{tol} ## (default value @code{1e-9}). ## ## The factorization is not unique and depends on the inital guess for the matrices ## @var{W} and @var{H}. You can pass this initalizations using the optional ## named arguments @var{Winit} and @var{Hinit}. ## ## timelimit, maxiter: limit of time and iterations ## ## Examples: ## ## @example ## A = rand(10,5); ## [W H] = nmf_pg(A,tol=1e-3); ## U = W*H -A; ## disp(max(abs(U))); ## @end example ## ## @end deftypefn ## 2015 - Modified and adapted to Octave 4.0 by ## Juan Pablo Carbajal function [W, H] = nmf_pg (V, varargin) # JuanPi Fri 16 Mar 2012 10:49:11 AM CET # TODO: # - finish docstring # - avoid multiple transpositions # --- Parse arguments --- # isnummatrix = @(x) ismatrix (x) & isnumeric (x); parser = inputParser (); parser.FunctionName = "nmf_pg"; parser.addParamValue ('Winit', [], @ismatrix); parser.addParamValue ('Hinit', [], @ismatrix); parser.addParamValue ('Tol', 1e-6, @(x)x>0); parser.addParamValue ('TimeLimit', 10, @(x)x>0); parser.addParamValue ('MaxIter', 100, @(x)x>0); parser.addParamValue ('MaxSubIter', 1e3, @(x)x>0); parser.addParamValue ('Verbose', true); parser.parse(varargin{:}); Winit = parser.Results.Winit; Hinit = parser.Results.Hinit; tol = parser.Results.Tol; timelimit = parser.Results.TimeLimit; maxiter = parser.Results.MaxIter; maxsubiter = parser.Results.MaxSubIter; verbose = parser.Results.Verbose; # Check if text_waitbar is loaded __txtwb__ = true; if !exist ('text_waitbar') __txtwb__ = false; end clear parser # ------ # # --- Initialize matrices --- # [r c] = size (V); Hgiven = !isempty (Hinit); Wgiven = !isempty (Winit); if Wgiven && !Hgiven W = Winit; H = ones (size (W,2),c); elseif !Wgiven && Hgiven H = Hinit; W = ones (r, size(H,2)); elseif !Wgiven && !Hgiven if r == c W = ones (r) H = W else W = ones (r); H = ones (r,c); end else W = Winit; H = Hinit; end [Hr,Hc] = size(H); [Wr,Wc] = size(W); # start tracking time initt = cputime (); gradW = W*(H*H') - V*H'; gradH = (W'*W)*H - W'*V; initgrad = norm([gradW; gradH'],'fro'); # Tolerances for matrices tolW = max(0.001,tol)*initgrad; tolH = tolW; # ------ # # --- Main Loop --- # if verbose fprintf ('--- Factorizing %d-by-%d matrix into %d-by-%d times %d-by-%d\n',... r,c,Wr,Wc,Hr,Hc); fprintf ("Initial gradient norm = %f\n", initgrad); fflush (stdout); if __txtwb__ text_waitbar(0,'Please wait ...'); else printf ('Running main loop, this may take a while.\n'); fflush (stdout); end end for iter = 1:maxiter # stopping condition projnorm = norm ( [ gradW(gradW<0 | W>0); gradH(gradH<0 | H>0) ] ); stop_cond = [projnorm < tol*initgrad , cputime-initt > timelimit]; if any (stop_cond) if stop_cond(2) warning('mnf_pg:MaxIter',["Time limit exceeded.\n" ... "Could be solved increasing TimeLimit.\n"]); end break end # FIXME: avoid multiple transpositions [W, gradW, iterW] = nlssubprob(V', H', W', tolW, maxsubiter, verbose); W = W'; gradW = gradW'; if iterW == 1, tolW = 0.1 * tolW; end [H, gradH, iterH] = nlssubprob(V, W, H, tolH, maxsubiter, verbose); if iterH == 1, tolH = 0.1 * tolH; end if (iterW == 1 && iterH == 1 && tolH + tolW < tol*initgrad), warning ('nmf_pg:InvalidArgument','Failed to move'); break end if verbose && __txtwb__ text_waitbar (iter/maxiter); end end if iter == maxiter warning('mnf_pg:MaxIter',["Reached maximum iterations in main loop.\n" ... "Could be solved increasing MaxIter.\n"]); end if verbose fprintf ('\nIterations = %d\nFinal proj-grad norm = %f\n', iter, projnorm); fflush (stdout); end endfunction function [H, grad,iter] = nlssubprob(V,W,Hinit,tol,maxiter,verbose) % H, grad: output solution and gradient % iter: #iterations used % V, W: constant matrices % Hinit: initial solution % tol: stopping tolerance % maxiter: limit of iterations H = Hinit; WtV = W'*V; WtW = W'*W; alpha = 1; beta = 0.1; for iter=1:maxiter grad = WtW*H - WtV; projgrad = norm ( grad(grad < 0 | H >0) ); if projgrad < tol, break end % search step size Hn = max(H - alpha*grad, 0); d = Hn-H; gradd = sum ( sum (grad.*d) ); dQd = sum ( sum ((WtW*d).*d) ); if gradd + 0.5*dQd > 0.01*gradd, % decrease alpha while 1, alpha *= beta; Hn = max (H - alpha*grad, 0); d = Hn-H; gradd = sum (sum (grad.*d) ); dQd = sum (sum ((WtW*d).*d)); if gradd + 0.5*dQd <= 0.01*gradd || alpha < 1e-20 H = Hn; break end endwhile else % increase alpha while 1, Hp = Hn; alpha /= beta; Hn = max (H - alpha*grad, 0); d = Hn-H; gradd = sum ( sum (grad.*d) ); dQd = sum (sum ( (WtW*d).*d ) ); if gradd + 0.5*dQd > 0.01*gradd || Hn == Hp || alpha > 1e10 H = Hp; alpha *= beta; break end endwhile end endfor if iter == maxiter warning('mnf_pg:MaxIter',["Reached maximum iterations in nlssubprob\n" ... "Could be solved increasing MaxSubIter.\n"]); end endfunction %!demo %! t = linspace (0,1,100)'; %! %! ## --- Build hump functions of different frequency %! W_true = arrayfun ( @(f)sin(2*pi*f*t).^2, linspace (0.5,2,4), ... %! 'uniformoutput', false ); %! W_true = cell2mat (W_true); %! ## --- Build combinator vectors %! c = (1:4)'; %! H_true = arrayfun ( @(f)circshift(c,f), linspace (0,3,4), ... %! 'uniformoutput', false ); %! H_true = cell2mat (H_true); %! ## --- Mix them %! V = W_true*H_true; %! ## --- Give good inital guesses %! Winit = W_true + 0.4*randn(size(W_true)); %! Hinit = H_true + 0.2*randn(size(H_true)); %! ## --- Factorize %! [W H] = nmf_pg(V,'Winit',Winit,'Hinit',Hinit,'Tol',1e-6,'MaxIter',1e3); %! disp('True mixer') %! disp(H_true) %! disp('Rounded factorized mixer') %! disp(round(H)) %! ## --- Plot results %! plot(t,W,'o;factorized;') %! hold on %! plot(t,W_true,'-;True;') %! hold off %! axis tight linear-algebra-2.2.3/PaxHeaders.16347/DESCRIPTION0000644000000000000000000000013213563071136015637 xustar0030 mtime=1573679710.670089267 30 atime=1573679710.670089267 30 ctime=1573679710.714089914 linear-algebra-2.2.3/DESCRIPTION0000644000175000017500000000056213563071136016025 0ustar00olafolaf00000000000000Name: linear-algebra Version: 2.2.3 Date: 2019-11-08 Author: various authors Maintainer: Octave-Forge community Title: Linear algebra. Description: Additional linear algebra code, including matrix functions. Categories: Linear algebra Depends: octave (>= 4.0.0) Autoload: no License: GPLv3+, LGPLv3+, FreeBSD Url: http://octave.sf.net linear-algebra-2.2.3/PaxHeaders.16347/COPYING0000644000000000000000000000013213563071136015164 xustar0030 mtime=1573679710.670089267 30 atime=1573679710.670089267 30 ctime=1573679710.714089914 linear-algebra-2.2.3/COPYING0000644000175000017500000000004213563071136015343 0ustar00olafolaf00000000000000See individual files for licenses linear-algebra-2.2.3/PaxHeaders.16347/NEWS0000644000000000000000000000013213563071136014630 xustar0030 mtime=1573679710.670089267 30 atime=1573679710.670089267 30 ctime=1573679710.714089914 linear-algebra-2.2.3/NEWS0000644000175000017500000000614413563071136015020 0ustar00olafolaf00000000000000Summary of important user-visible changes for linear-algebra 2.2.3: ------------------------------------------------------------------- ** The following functions have been removed from the package. They have been in Octave core since version 4.4 or earlier: condeig gsvd pgmres (superseded by gmres in core Octave) Summary of important user-visible changes for linear-algebra 2.2.2: ------------------------------------------------------------------- ** Several functions have been adapted to the new core-Octave "ismatrix" behavior (the latter only checks for 2D size, not class). To this end all input matrices are checked against the "isnumeric" function. The linear-algebra package is expected to still work for older Octave versions than 4.0.0 as this "isnumeric" check is only additional. ** nmf_* functions use inputParser from Octave 4.0.0. They won't work with older versions. ** The interface of nmf_bpas has been simplified. The option 'verbose' is now a switch and it doesn't require a value. The history of the calculations is stored and returned only if the 4th output argument is requested. ** Package is no longer dependent on general (>= 1.3.0) Summary of important user-visible changes for linear-algebra 2.2.1: ------------------------------------------------------------------- ** The following functions is new in 2.2.1: vec_projection ** fixed bugs: nmf_pg doesn't use text_waitbar by default. The miscellaneous package is not required. nmf_bpas now respects the verbose option @blksparse/ctranspose returns a Block Sparse Matrix @kronprod/iscomplex.m, @kronprod/uminus.m:fixtypos src/CmplxGSVD.cc, src/dbleGSVD.cc: update Array constructor usage funm.m: fix texinfo, fix typo preventing thfm invocation where applicable, return real matrix when all |imaginary entries| < eps @kronprod and @blksparse subfunctions have been documented ** Makefile fixed to work with non-standard linker options e.g on Apple. ** The function circulant_make_matrix has been deprecated and will be removed from future versions of the linear-algebra package. Summary of important user-visible changes for linear-algebra 2.2.0: ------------------------------------------------------------------- ** The following functions are new in 2.2.0: circulant_eig circulant_inv circulant_make_matrix circulant_matrix_vector_product nmf_pg nmf_bpas ** Package is now dependent on general (>= 1.3.0) ** Package is no longer automatically loaded. Summary of important user-visible changes for linear-algebra 2.1.0: ------------------------------------------------------------------- ** The following functions are new in 2.1.0: lobpcg ndcovlt ** The following functions were removed since equivalents are now part of GNU octave core: bicg mgorth ** The following functions were deprecated since equivalents are now part of GNU octave core: pgmres ** The function `funm' now also accepts function handles. ** Help text of most functions has been improved.