├── @ktensor ├── convn.m ├── full.m ├── innerprod.m ├── mean.m ├── std.m └── var.m ├── @sptensor ├── innerprod.m ├── nvecs.m └── ttm2.m ├── @tensor ├── convn.m ├── innerprod.m ├── nvecs.m ├── ttm.m └── ttv.m ├── @ttensor ├── convn.m └── innerprod.m ├── BestRank1 ├── bestrank1_222.m ├── bestrank1_2222.m ├── bestrank1tensorapprox.m ├── cp_r1LM.m ├── cp_r1lm_optmu.m ├── cp_roro.m ├── lmrank1_update.m └── seqproj_trunc.m ├── Deconvolution ├── convolutive_to_bcd.m ├── demo_mnist_ts_deconvolution.m ├── demo_rank1_ts_deconv.m ├── gen_ts_conv.m ├── tedia2P.m ├── tedia4R.m ├── toeplitz_factor.m ├── ts_deconv_init.m └── ts_deconv_rank1_als.m ├── Denoising ├── function_LumChrom2rgb.m ├── function_rgb2LumChrom.m ├── tt_block_denoise.m ├── tt_block_denoise_localregion.m ├── tt_block_denoise_neighbour.m ├── tt_block_denoise_neighbour_level2.m ├── tt_image_denoising_neighbour_.m └── tt_tensor_denoise.m ├── LICENSE ├── README.md ├── btd ├── b2d_rR.m ├── bcdLoR_als.m ├── bcdLp1_asu3.m ├── bdiagtimematrix.m ├── btd3.m ├── btd_ajd.m ├── btd_ajd2.m ├── btd_rLM.m ├── btd_rR.m ├── cp_asu.m ├── crb_bcdLp1.m └── cribBCDLoR.m ├── cpd ├── comparefoldings.m ├── cost_als.m ├── cp_ajd.m ├── cp_ajdv2.m ├── cp_anc.m ├── cp_boundlda_als.m ├── cp_boundlda_ipm.m ├── cp_boundlda_itp.m ├── cp_boundlda_sqp.m ├── cp_congruence.m ├── cp_fLMa.m ├── cp_fLMb_v2.m ├── cp_fastals.m ├── cp_fcp.m ├── cp_gradient.m ├── cp_gradient2.m ├── cp_gradients.m ├── cp_gram.m ├── cp_hessian.m ├── cp_init.m ├── cp_nc_itp.m ├── cp_nc_sqp.m ├── cp_papals.m ├── cp_paro.m ├── cp_paro_v2.m ├── cp_rankdetermination.m ├── cp_to_tt.m ├── cp_tt_anc.m ├── cp_ttconv.m ├── cpc_ttconv.m ├── cpc_ttconv_fLM.m ├── cpo_als1.m ├── cpo_als2.m ├── cpostruct_als.m ├── cpostruct_als2.m ├── cprintf.m ├── cpstruct_als.m ├── cpstruct_lroat.m ├── cpx_fLMa.m └── cribCP.m ├── cross └── crossindexes.m ├── data ├── amino.mat └── lena_std.tiff ├── linreg ├── linreg_bound.m ├── linreg_lrmx.m ├── linreg_lrmx_als.m └── linreg_lrmx_bals.m └── readme.m /@ktensor/convn.m: -------------------------------------------------------------------------------- 1 | function Z = convn(X,Y) 2 | % Convolution between two K-tensors or a K-tensor and a tensor X and Y 3 | % 4 | % Phan Anh Huy, 2016 5 | % 6 | 7 | if (isa(X,'double')||isa(X,'tensor')) 8 | Z = convn(Y,tensor(X)); 9 | 10 | elseif (isa(Y,'double')||isa(Y,'tensor')) 11 | 12 | Nx = ndims(X);Ny = ndims(Y); 13 | SzX = size(X); 14 | SzY = size(Y); 15 | 16 | R = size(X.u{1},2); 17 | 18 | Z = X.u; 19 | for n = 1:min(Nx,Ny) 20 | u1 = Z{n}; 21 | u2 = eye(SzY(n)); 22 | 23 | u2 = [zeros(SzX(n),SzY(n)); u2]; 24 | u1 = [zeros(SzY(n),R); u1]; 25 | 26 | u3 = ifft((khatrirao(fft(u1,[],1).', fft(u2,[],1).').'),[],1); 27 | u3 = u3(1:end-1,:); 28 | Z{n} = u3; 29 | end 30 | 31 | % 32 | if Nx 1 47 | y = tnt*tnt'; 48 | [u,d] = eigs(y, r, 'LM', eigsopts); 49 | u = tnt*u; 50 | else 51 | u = tnt; 52 | end 53 | u = bsxfun(@rdivide,u,sqrt(sum(u.^2))); 54 | end 55 | 56 | %tn = sptenmat(t,n); 57 | %[u,d] = eigs(@(x)aatx(tn,x), size(t,n), r, 'LM', eigsopts); 58 | 59 | if isfield(opts,'flipsign') 60 | flipsign = opts.flipsign; 61 | else 62 | flipsign = true; 63 | end 64 | 65 | if flipsign 66 | % Make the largest magnitude element be positive 67 | [val,loc] = max(abs(u)); 68 | for i = 1:r 69 | if u(loc(i),i) < 0 70 | u(:,i) = u(:,i) * -1; 71 | end 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /@sptensor/ttm2.m: -------------------------------------------------------------------------------- 1 | function Y = ttm(X,V,varargin) 2 | %TTM Sparse tensor times matrix. 3 | % 4 | % Y = TTM(X,A,N) computes the n-mode product of the sptensor X with 5 | % a dense matrix A; i.e., X x_N A. The integer N specifies the 6 | % dimension (or mode) of X along which A should be multiplied. If 7 | % size(A) = [J,I], then X must have size(X,N) = I. The result will 8 | % will be a (dense) tensor or sptensor of the same order and size as X 9 | % except that size(Y,N) = J. 10 | % 11 | % Y = TTM(X,{A,B,C,...}) computes the n-mode product of the sptensor 12 | % X with a sequence of matrices in the cell array. The n-mode 13 | % products are computed sequentially along all dimensions (or modes) 14 | % of X. The cell array contains ndims(X) matrices. 15 | % 16 | % Y = TTM(X,{A,B,C,...},DIMS) computes the sequence tensor-matrix 17 | % products along the dimensions specified by DIMS. 18 | % 19 | % Y = TTM(...,'t') performs the same computations as above except 20 | % the matrices are transposed. 21 | % 22 | % Examples 23 | % X = sptenrand([5 3 4 2], 10); 24 | % A = rand(4,5); B = rand(4,3); C = rand(3,4); D = rand(3,2); 25 | % Y = ttm(X, A, 1) %<-- computes X times A in mode-1 26 | % Y = ttm(X, {A,B,C,D}, 1) %<-- same as above 27 | % Y = ttm(X, A', 1, 't') %<-- same as above 28 | % Y = ttm(X, {A,B,C,D}, [1 2 3 4]) %<-- 4-way multiply 29 | % Y = ttm(X, {D,C,B,A}, [4 3 2 1]) %<-- same as above 30 | % Y = ttm(X, {A,B,C,D}) %<-- same as above 31 | % Y = ttm(X, {A',B',C',D'}, 't') %<-- same as above 32 | % Y = ttm(X, {C,D}, [3 4]) %<-- X times C in mode-3 & D in mode-4 33 | % Y = ttm(X, {A,B,C,D}, [3 4]) %<-- same as above 34 | % Y = ttm(X, {A,B,D}, [1 2 4]) %<-- 3-way multiply 35 | % Y = ttm(X, {A,B,C,D}, [1 2 4]) %<-- same as above 36 | % Y = ttm(X, {A,B,D}, -3) %<-- same as above 37 | % Y = ttm(X, {A,B,C,D}, -3) %<-- same as above 38 | % 39 | % See also SPTENSOR, TENSOR/TTM. 40 | % 41 | %MATLAB Tensor Toolbox. 42 | %Copyright 2010, Sandia Corporation. 43 | 44 | % This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. 45 | % http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. 46 | % Copyright (2010) Sandia Corporation. Under the terms of Contract 47 | % DE-AC04-94AL85000, there is a non-exclusive license for use of this 48 | % work by or on behalf of the U.S. Government. Export of this data may 49 | % require a license from the United States Government. 50 | % The full license terms can be found in tensor_toolbox/LICENSE.txt 51 | % $Id: ttm.m,v 1.19 2010/03/19 23:46:30 tgkolda Exp $ 52 | 53 | %% Check the number of arguments 54 | if (nargin < 2) 55 | error('TTM requires at least two arguments.'); 56 | end 57 | 58 | %% Create 'n' and 'tflag' arguments from varargin 59 | n = 1:ndims(X); 60 | tflag = ''; 61 | if numel(varargin) == 1 62 | if ischar(varargin{1}) 63 | tflag = varargin{1}; 64 | else 65 | n = varargin{1}; 66 | end 67 | elseif numel(varargin) == 2 68 | n = varargin{1}; 69 | tflag = varargin{2}; 70 | end 71 | 72 | %% Handle cell array 73 | if iscell(V) 74 | % Copy n into dims 75 | dims = n; 76 | % Check that the dimensions are valid 77 | [dims,vidx] = tt_dimscheck(dims,ndims(X),numel(V)); 78 | % Calculate individual products 79 | Y = ttm(X, V{vidx(1)}, dims(1), tflag); 80 | for i = 2 : numel(dims) 81 | Y = ttm(Y, V{vidx(i)}, dims(i), tflag); 82 | end 83 | % All done 84 | return; 85 | end 86 | 87 | %% Check the second argument 88 | if ndims(V) ~= 2 89 | error('tensor/ttm: 2nd argument must be a matrix.'); 90 | end 91 | 92 | %% Flip V is transposed 93 | if tflag == 't' 94 | V = V'; 95 | end 96 | 97 | %% Check n 98 | if numel(n) ~= 1 || (n < 0) || (n > ndims(X)) 99 | error('Dimension N must be between 1 and NDIMS(X).'); 100 | end 101 | 102 | %% Compute the product 103 | 104 | % Check that sizes match! 105 | if size(X,n) ~= size(V,2) 106 | error('Size mismatch on V'); 107 | end 108 | 109 | 110 | 111 | % Compute Xn' 112 | % Xnt = sptenmat(X,n,'t'); 113 | N = ndims(X); 114 | X = permute(X,[1:n-1 n+1:N n]); 115 | siz = size(X); 116 | X = reshape(X,[prod(siz(1:end-1)) siz(end)]); 117 | X = spmatrix(X); 118 | 119 | % Compute the new size 120 | siz(end) = size(V,1); 121 | 122 | % Extract the dimensions 123 | % rdims = Xnt.rdims; 124 | % cdims = Xnt.cdims; 125 | 126 | % Convert to sparse matrix and do the multiplication; result is generally a 127 | % dense matrix 128 | Y = X * V'; % modified on April 7, 2013 129 | 130 | % modified on April 7, 2013 131 | if nnz(Y) <= 0.5 * prod(siz) 132 | % Final result is a *sparse* tensor 133 | %Ynt = sptenmat(Z, rdims, cdims, siz); 134 | %Y = sptensor(Ynt); 135 | Y = sparse(Y); 136 | [ir,ic,val] = find(Y); 137 | Y = sptensor([ir,ic],val,size(Y)); 138 | Y = reshape(Y,siz); 139 | else 140 | % Final result is a *dense* tensor 141 | %Ynt = tenmat(Z, rdims, cdims, siz); 142 | %Y = tensor(Ynt); 143 | Y = tensor(Y,siz); 144 | end 145 | Y = permute(Y,[1:n-1 N n:N-1]); 146 | 147 | end 148 | -------------------------------------------------------------------------------- /@tensor/convn.m: -------------------------------------------------------------------------------- 1 | function Z = convn(X,Y) 2 | % Convolution between a Ktensor X and a tensor Y 3 | % 4 | % Phan Anh Huy, 2016 5 | % 6 | 7 | Nx = ndims(X);Ny = ndims(Y); 8 | SzX = size(X); 9 | SzY = size(Y); 10 | 11 | if isa(Y,'ktensor') 12 | Z = convn(Y,X); 13 | else 14 | Z = convn(double(X),double(Y)); 15 | end -------------------------------------------------------------------------------- /@tensor/innerprod.m: -------------------------------------------------------------------------------- 1 | function res = innerprod(X,Y) 2 | %INNERPROD Efficient inner product with a tensor. 3 | % 4 | % R = INNERPROD(X,Y) efficiently computes the inner product between 5 | % two tensors X and Y. If Y is a tensor, then inner product is 6 | % computed directly. Otherwise, the inner product method for 7 | % that type of tensor is called. 8 | % 9 | % See also TENSOR, SPTENSOR/INNERPROD, KTENSOR/INNERPROD, TTENSOR/INNERPROD 10 | % 11 | %MATLAB Tensor Toolbox. 12 | %Copyright 2010, Sandia Corporation. 13 | 14 | % This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. 15 | % http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. 16 | % Copyright (2010) Sandia Corporation. Under the terms of Contract 17 | % DE-AC04-94AL85000, there is a non-exclusive license for use of this 18 | % work by or on behalf of the U.S. Government. Export of this data may 19 | % require a license from the United States Government. 20 | % The full license terms can be found in tensor_toolbox/LICENSE.txt 21 | % $Id: innerprod.m,v 1.10 2010/03/19 23:46:30 tgkolda Exp $ 22 | 23 | % X is a tensor 24 | switch class(Y) 25 | 26 | case {'tensor'} 27 | % No need for same size check because it is implicit in the inner 28 | % product below. 29 | x = reshape(X.data, 1, numel(X.data)); 30 | y = reshape(Y.data, numel(Y.data), 1); 31 | res = x*conj(y); % fixed for complex-valued tensor 32 | 33 | case {'sptensor','ktensor','ttensor'} 34 | % Reverse arguments to call specialized code 35 | res = conj(innerprod(Y,X)); % Fixed for complex-valued tensor 36 | 37 | otherwise 38 | disp(['Inner product not available for class ' class(Y)]); 39 | 40 | end 41 | 42 | return; 43 | -------------------------------------------------------------------------------- /@tensor/nvecs.m: -------------------------------------------------------------------------------- 1 | function u = nvecs(X,n,r,opts) 2 | %NVECS Compute the leading mode-n vectors for a tensor. 3 | % 4 | % U = NVECS(X,n,r) computes the r leading eigenvalues of Xn*Xn' 5 | % (where Xn is the mode-n matricization of X), which provides 6 | % information about the mode-n fibers. In two-dimensions, the r 7 | % leading mode-1 vectors are the same as the r left singular vectors 8 | % and the r leading mode-2 vectors are the same as the r right 9 | % singular vectors. 10 | % 11 | % U = NVECS(X,n,r,OPTS) specifies options: 12 | % OPTS.eigsopts: options passed to the EIGS routine [struct('disp',0)] 13 | % OPTS.flipsign: make each column's largest element positive [true] 14 | % 15 | % See also TENSOR, TENMAT, EIGS. 16 | % 17 | %MATLAB Tensor Toolbox. 18 | %Copyright 2010, Sandia Corporation. 19 | 20 | % This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. 21 | % http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. 22 | % Copyright (2010) Sandia Corporation. Under the terms of Contract 23 | % DE-AC04-94AL85000, there is a non-exclusive license for use of this 24 | % work by or on behalf of the U.S. Government. Export of this data may 25 | % require a license from the United States Government. 26 | % The full license terms can be found in tensor_toolbox/LICENSE.txt 27 | % $Id: nvecs.m,v 1.6 2010/03/19 23:46:31 tgkolda Exp $ 28 | 29 | if ~exist('opts','var') 30 | opts = struct; 31 | end 32 | 33 | if isfield(opts,'eigsopts') 34 | eigsopts = opts.eigsopts; 35 | else 36 | eigsopts.disp = 0; 37 | end 38 | 39 | Xn = double(tenmat(X,n)); 40 | % Phan Anh Huy, 06/2012 41 | if size(Xn,1) < size(Xn,2) || (size(Xn,1) < 1e6) 42 | Y = Xn*Xn'; 43 | [u,d] = eigs(Y, r, 'LM', eigsopts); 44 | else 45 | if size(Xn,2) > 1 % modified on April 24, 2012 46 | Y = Xn'*Xn; 47 | [u,d] = eigs(Y, r, 'LM', eigsopts); 48 | u = Xn*u; 49 | else 50 | u = Xn; 51 | end 52 | u = bsxfun(@rdivide,u,sqrt(sum(u.^2))); 53 | end 54 | 55 | if isfield(opts,'flipsign') 56 | flipsign = opts.flipsign; 57 | else 58 | flipsign = true; 59 | end 60 | 61 | if flipsign 62 | % Make the largest magnitude element be positive 63 | [val,loc] = max(abs(u)); 64 | for i = 1:r 65 | if u(loc(i),i) < 0 66 | u(:,i) = u(:,i) * -1; 67 | end 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /@tensor/ttm.m: -------------------------------------------------------------------------------- 1 | function Y = ttm(X,V,varargin) 2 | %TTM Tensor times matrix. 3 | % 4 | % Y = TTM(X,A,N) computes the n-mode product of tensor X with a 5 | % matrix A; i.e., X x_N A. The integer N specifies the dimension 6 | % (or mode) of X along which A should be multiplied. If size(A) = 7 | % [J,I], then X must have size(X,N) = I. The result will be the 8 | % same order and size as X except that size(Y,N) = J. 9 | % 10 | % Y = TTM(X,{A,B,C,...}) computes the n-mode product of tensor X 11 | % with a sequence of matrices in the cell array. The n-mode 12 | % products are computed sequentially along all dimensions (or modes) 13 | % of X. The cell array contains ndims(X) matrices. 14 | % 15 | % Y = TTM(X,{A,B,C,...},DIMS) computes the sequence tensor-matrix 16 | % products along the dimensions specified by DIMS. 17 | % 18 | % Y = TTM(...,'t') performs the same computations as above except 19 | % the matrices are transposed. 20 | % 21 | % Examples 22 | % X = tensor(rand(5,3,4,2)); 23 | % A = rand(4,5); B = rand(4,3); C = rand(3,4); D = rand(3,2); 24 | % Y = ttm(X, A, 1) %<-- computes X times A in mode-1 25 | % Y = ttm(X, {A,B,C,D}, 1) %<-- same as above 26 | % Y = ttm(X, A', 1, 't') %<-- same as above 27 | % Y = ttm(X, {A,B,C,D}, [1 2 3 4]) %<-- 4-way multiply 28 | % Y = ttm(X, {D,C,B,A}, [4 3 2 1]) %<-- same as above 29 | % Y = ttm(X, {A,B,C,D}) %<-- same as above 30 | % Y = ttm(X, {A',B',C',D'}, 't') %<-- same as above 31 | % Y = ttm(X, {C,D}, [3 4]) %<-- X times C in mode-3 & D in mode-4 32 | % Y = ttm(X, {A,B,C,D}, [3 4]) %<-- same as above 33 | % Y = ttm(X, {A,B,D}, [1 2 4]) %<-- 3-way multiply 34 | % Y = ttm(X, {A,B,C,D}, [1 2 4]) %<-- same as above 35 | % Y = ttm(X, {A,B,D}, -3) %<-- same as above 36 | % Y = ttm(X, {A,B,C,D}, -3) %<-- same as above 37 | % 38 | % See also TENSOR, TENSOR/TTT, TENSOR/TTV. 39 | % 40 | %MATLAB Tensor Toolbox. 41 | %Copyright 2010, Sandia Corporation. 42 | 43 | % This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. 44 | % http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. 45 | % Copyright (2010) Sandia Corporation. Under the terms of Contract 46 | % DE-AC04-94AL85000, there is a non-exclusive license for use of this 47 | % work by or on behalf of the U.S. Government. Export of this data may 48 | % require a license from the United States Government. 49 | % The full license terms can be found in tensor_toolbox/LICENSE.txt 50 | % $Id: ttm.m,v 1.18 2010/03/19 23:46:31 tgkolda Exp $ 51 | 52 | % Fast ttm, 2012/07/17, Phan Anh Huy 53 | 54 | %% Check the number of arguments 55 | if (nargin < 2) 56 | error('TTM requires at least two arguments.'); 57 | end 58 | 59 | %% Create 'n' and 'tflag' arguments from varargin 60 | n = 1:ndims(X); 61 | tflag = ''; 62 | if numel(varargin) == 1 63 | if ischar(varargin{1}) 64 | tflag = varargin{1}; 65 | else 66 | n = varargin{1}; 67 | end 68 | elseif numel(varargin) == 2 69 | n = varargin{1}; 70 | tflag = varargin{2}; 71 | end 72 | 73 | %% Handle cell array 74 | if iscell(V) 75 | % Copy n into dims 76 | dims = n; 77 | % Check that the dimensions are valid 78 | [dims,vidx] = tt_dimscheck(dims,ndims(X),numel(V)); 79 | % Calculate individual products 80 | Y = ttm(X, V{vidx(1)}, dims(1), tflag); 81 | for i = 2 : numel(dims) 82 | Y = ttm(Y, V{vidx(i)}, dims(i), tflag); 83 | end 84 | % All done 85 | return; 86 | end 87 | 88 | %% Check the second argument 89 | if ndims(V) ~= 2 90 | error('tensor/ttm: 2nd argument must be a matrix.'); 91 | end 92 | 93 | %% Check n 94 | if (numel(n) ~= 1 || (n < 0) || n > ndims(X)) 95 | error('Dimension N must be between 1 and NDIMS(X).'); 96 | end 97 | 98 | %% COMPUTE THE PRODUCT 99 | 100 | N = ndims(X); 101 | sz = size(X); 102 | % order = [n,1:n-1,n+1:N]; 103 | % newdata = double(permute(X,order)); 104 | % newdata = reshape(newdata,sz(n),prod(sz([1:n-1,n+1:N]))); 105 | % if tflag == 't' 106 | % newdata = V'*newdata; 107 | % p = size(V,2); 108 | % else 109 | % newdata = V*newdata; 110 | % p = size(V,1); 111 | % end 112 | % newsz = [p sz(1:n-1) sz(n+1:end)]; 113 | % Y = tensor(newdata,newsz); 114 | % Y = ipermute(Y,order); 115 | 116 | 117 | if (tflag == 't') 118 | V = V'; 119 | end 120 | if issparse(V) && isa(X.data,'single') 121 | V = full(V); 122 | end 123 | 124 | if n == 1 125 | newdata = reshape(X.data,sz(n),[]); 126 | newdata = V*newdata; 127 | elseif n == N 128 | newdata = reshape(X.data,[],sz(n)); 129 | newdata = newdata * V.'; 130 | else 131 | newdata = X.data; 132 | if N > 3 133 | newdata = reshape(newdata,prod(sz(1:n-1)),sz(n),[]); 134 | end 135 | newdata = permute(newdata,[2 1 3]); 136 | newdata = V * reshape(newdata,sz(n),[]); % error when V: sparse ans newdata single 137 | newdata = reshape(newdata,[],prod(sz(1:n-1)),prod(sz(n+1:end))); 138 | newdata = ipermute(newdata,[2 1 3]); 139 | 140 | %newdata = reshape(X.data,prod(sz(1:n-1)),sz(n),1,[]); 141 | %newdata = bsxfun(@times,newdata,reshape(V,1,sz(n),size(V,2))); 142 | %newdata = sum(newdata,n); 143 | end 144 | sz(n) = size(V,1); 145 | Y = tensor(newdata,sz); 146 | %Y = ipermute(Y,order); 147 | 148 | 149 | return; 150 | 151 | end 152 | -------------------------------------------------------------------------------- /@tensor/ttv.m: -------------------------------------------------------------------------------- 1 | function c = ttv(a,v,dims) 2 | %TTV Tensor times vector. 3 | % 4 | % Y = TTV(X,A,N) computes the product of tensor X with a (column) 5 | % vector A. The integer N specifies the dimension in X along which 6 | % A is multiplied. If size(A) = [I,1], then X must have size(X,N) = 7 | % I. Note that ndims(Y) = ndims(X) - 1 because the N-th dimension 8 | % is removed. 9 | % 10 | % Y = TTV(X,{A,B,C,...}) computes the product of tensor X with a 11 | % sequence of vectors in the cell array. The products are computed 12 | % sequentially along all dimensions (or modes) of X. The cell array 13 | % contains ndims(X) vectors. 14 | % 15 | % Y = TTV(X,{A,B,C,...},DIMS) computes the sequence of tensor-vector 16 | % products along the dimensions specified by DIMS. 17 | % 18 | % Examples 19 | % X = tensor(rand(5,3,4,2)); 20 | % A = rand(5,1); B = rand(3,1); C = rand(4,1); D = rand(2,1); 21 | % Y = ttv(X, A, 1) %<-- X times A in mode 1 22 | % Y = ttv(X, {A,B,C,D}, 1) %<-- same as above 23 | % Y = ttv(X, {A,B,C,D}, [1 2 3 4]) %<-- All-mode multiply 24 | % Y = ttv(X, {D,C,B,A}, [4 3 2 1]) %<-- same as above 25 | % Y = ttv(X, {A,B,C,D}) %<-- same as above 26 | % Y = ttv(X, {C,D}, [3 4]) %<-- X times C in mode-3 & D in mode-4 27 | % Y = ttv(X, {A,B,C,D}, [3 4]) %<-- same as above 28 | % Y = ttv(X, {A,B,D}, [1 2 4]) %<-- 3-way mutplication 29 | % Y = ttv(X, {A,B,C,D}, [1 2 4]) %<-- same as above 30 | % Y = ttv(X, {A,B,D}, -3) %<-- same as above 31 | % Y = ttv(X, {A,B,C,D}, -3) %<-- same as above 32 | % 33 | % See also TENSOR, TENSOR/TTT, TENSOR/TTM. 34 | % 35 | %MATLAB Tensor Toolbox. 36 | %Copyright 2010, Sandia Corporation. 37 | 38 | % This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. 39 | % http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. 40 | % Copyright (2010) Sandia Corporation. Under the terms of Contract 41 | % DE-AC04-94AL85000, there is a non-exclusive license for use of this 42 | % work by or on behalf of the U.S. Government. Export of this data may 43 | % require a license from the United States Government. 44 | % The full license terms can be found in tensor_toolbox/LICENSE.txt 45 | % $Id: ttv.m,v 1.11 2010/03/19 23:46:31 tgkolda Exp $ 46 | 47 | % Check the number of arguments 48 | if (nargin < 2) 49 | error('TTV requires at least two arguments.'); 50 | end 51 | 52 | % Check for 3rd argument 53 | if ~exist('dims','var') 54 | dims = []; 55 | end 56 | 57 | % Check that 2nd argument is cell array. If not, recall with v as a 58 | % cell array with one element. 59 | if ~iscell(v) 60 | c = ttv(a,{v},dims); 61 | return; 62 | end 63 | 64 | % Get sorted dims and index for multiplicands 65 | [dims,vidx] = tt_dimscheck(dims,ndims(a),numel(v)); 66 | 67 | % Check that each multiplicand is the right size. 68 | for i = 1:numel(dims) 69 | if ~isequal(size(v{vidx(i)}),[size(a,dims(i)) 1]) 70 | error('Multiplicand is wrong size'); 71 | end 72 | end 73 | 74 | % Extract the MDA 75 | c = a.data; 76 | 77 | % Permute it so that the dimensions we're working with come last 78 | remdims = setdiff(1:ndims(a),dims); 79 | if (ndims(a) > 1) 80 | c = permute(c,[remdims dims]); 81 | end 82 | 83 | % Do each multiply in sequence, doing the highest index first, 84 | % which is important for vector multiplies. 85 | n = ndims(a); 86 | sz = a.size([remdims dims]); 87 | for i = numel(dims) : -1 : 1 88 | c = reshape(c,prod(sz(1:n-1)),sz(n)); 89 | c = c * conj(v{vidx(i)}); 90 | n = n-1; 91 | end 92 | 93 | % If needed, convert the final result back to a tensor 94 | if (n > 0) 95 | c = tensor(c,sz(1:n)); 96 | end 97 | 98 | -------------------------------------------------------------------------------- /@ttensor/convn.m: -------------------------------------------------------------------------------- 1 | function Z = convn(X,Y) 2 | % Convolution between two order-N T-tensors X and Y 3 | % 4 | % Phan Anh Huy, 2016 5 | % 6 | Nx = ndims(X);Ny = ndims(Y); 7 | if Nx<=Ny 8 | [X,Y] = deal(Y,X); 9 | [Nx,Ny] = deal(Ny,Nx); 10 | end 11 | 12 | R = size(X.u{1},2); 13 | S = size(Y.u{1},2); 14 | szX = size(X); 15 | szY = size(Y); 16 | 17 | Z = X.u; 18 | 19 | for k = 1:Ny 20 | u1 = X.u{k}; 21 | u2 = Y.u{k}; 22 | 23 | u1 = [zeros(szY(k),R) ; u1]; 24 | u2 = [zeros(szX(k),S) ; u2]; 25 | u3 = ifft((khatrirao(fft(u1,[],1).', fft(u2,[],1).').'),[],1); 26 | u3 = u3(1:end-1,:); 27 | Z{k} = u3; 28 | end 29 | 30 | for k = Ny+1:Nx 31 | Z{k} = kron(Z{k},ones(1,S)); 32 | end 33 | Z = ttensor(tensor(nkron(X.core,Y.core)),Z); -------------------------------------------------------------------------------- /@ttensor/innerprod.m: -------------------------------------------------------------------------------- 1 | function res = innerprod(X,Y) 2 | %INNERPROD Efficient inner product with a ttensor. 3 | % 4 | % R = INNERPROD(X,Y) efficiently computes the inner product between 5 | % two tensors X and Y. If Y is a tensor or sptensor, the inner 6 | % product is computed directly and the computational complexity 7 | % is... If Y is a ktensor, the inner product method for that type 8 | % of tensor is called. 9 | % 10 | % See also TTENSOR, KTENSOR/INNERPROD 11 | % 12 | %MATLAB Tensor Toolbox. 13 | %Copyright 2010, Sandia Corporation. 14 | 15 | % This is the MATLAB Tensor Toolbox by Brett Bader and Tamara Kolda. 16 | % http://csmr.ca.sandia.gov/~tgkolda/TensorToolbox. 17 | % Copyright (2010) Sandia Corporation. Under the terms of Contract 18 | % DE-AC04-94AL85000, there is a non-exclusive license for use of this 19 | % work by or on behalf of the U.S. Government. Export of this data may 20 | % require a license from the United States Government. 21 | % The full license terms can be found in tensor_toolbox/LICENSE.txt 22 | % $Id: innerprod.m,v 1.13 2010/03/19 23:46:31 tgkolda Exp $ 23 | 24 | % X is a ttensor 25 | switch class(Y) 26 | 27 | case {'ttensor'} 28 | if ~isequal(size(X),size(Y)) 29 | error('X and Y must be the same size.'); 30 | end 31 | if prod(size(X.core)) > prod(size(Y.core)) 32 | % Reverse argument and call this function again so that the 33 | % tensor with the smaller core is the first argument. 34 | res = innerprod(Y,X); 35 | res = conj(res); % Fixed for complex-valued tensor 36 | return 37 | end 38 | W = cell(ndims(X),1); 39 | for n = 1:ndims(X) 40 | W{n} = X.u{n}'*Y.u{n}; 41 | end 42 | J = ttm(Y.core, W); 43 | res = innerprod(X.core,J); 44 | return 45 | 46 | case {'tensor','sptensor'} 47 | if ~isequal(size(X),size(Y)) 48 | error('X and Y must be the same size.'); 49 | end 50 | if (prod(size(X)) < prod(size(X.core))) 51 | Z = full(X); 52 | res = innerprod(Z,Y); 53 | return; 54 | end 55 | Z = ttm(Y,X.u,'t'); 56 | res = innerprod(Z, X.core); 57 | return 58 | 59 | case {'ktensor'} 60 | % Reverse arguments to call ktensor implementation 61 | res = innerprod(Y,X); 62 | res = conj(res); % Fixed for complex-valued tensor 63 | return 64 | 65 | otherwise 66 | disp(['Inner product not available for class ' class(Y)]); 67 | return 68 | end 69 | 70 | 71 | -------------------------------------------------------------------------------- /BestRank1/bestrank1_222.m: -------------------------------------------------------------------------------- 1 | function [A,B,C,smax] = bestrank1_222(Y) 2 | % Find best rank-1 tensor approximation to the tensor Y of size 2x2x2 3 | % by solving a polynomial of degree-6 4 | % 5 | % Phan Anh-Huy, 2017 6 | % August 16, 2017 7 | % 8 | 9 | t1 = @(y) (sum(sum(y(:,:,1).^2)) - sum(sum(y(:,:,2).^2)))/2; 10 | t2 = @(y) (sum(sum(y(:,:,1).^2)) + sum(sum(y(:,:,2).^2)))/2; 11 | % t3 = @(y) sum(sum(y(:,:,1).*y(:,:,2))); 12 | t4 = @(y) - y(1)*y(4) + y(2)*y(3) - y(5)*y(8) + y(6)*y(7); 13 | t5 = @(y) - y(1)*y(4) + y(2)*y(3) + y(5)*y(8) - y(6)*y(7); 14 | t6 = @(y) -y(1)*y(8) + y(2)*y(7) + y(3)*y(6) - y(4)*y(5); 15 | 16 | % Find orthonormal rotation matrix along mode-3 of Y 17 | [~,s,Z] = svd(reshape(Y,[],2)); 18 | Yz = reshape(reshape(Y,[],2)*Z,[2 2 2]); % Y x3 Z^T 19 | 20 | t_1 = t1(Yz); 21 | t_2 = t2(Yz); 22 | % t_3 = t3(Yz); 23 | t_4 = t4(Yz); 24 | t_5 = t5(Yz); 25 | t_6 = t6(Yz); 26 | 27 | % Coefficients of the degree-6 polynomial 28 | c(1) = t_4*t_6^2 - t_5*t_6^2; 29 | c(2) = 4*t_1^2*t_6 - 4*t_2*t_1*t_6 - 4*t_5^2*t_6 + 4*t_4*t_5*t_6 + 2*t_6^3; 30 | c(3) = 4*t_1^2*t_5 + 4*t_4*t_1^2 - 8*t_2*t_1*t_5 - 4*t_5^3 + 4*t_4*t_5^2 + 11*t_5*t_6^2 - t_4*t_6^2; 31 | c(4) = 16*t_5^2*t_6 - 4*t_6^3; 32 | c(5) = - 4*t_1^2*t_5 + 4*t_4*t_1^2 - 8*t_2*t_1*t_5 + 4*t_5^3 + 4*t_4*t_5^2 - 11*t_5*t_6^2 - t_4*t_6^2; 33 | c(6) = 4*t_1^2*t_6 + 4*t_2*t_1*t_6 - 4*t_5^2*t_6 - 4*t_4*t_5*t_6 + 2*t_6^3; 34 | c(7) = t_4*t_6^2 + t_5*t_6^2; 35 | 36 | % x = atan(z), whereas z is a root of p(z) 37 | 38 | z = roots(c); 39 | ireal=find(abs(imag(z))<1e-8); 40 | x=[atan(real(z(ireal)));-pi/2;pi/2]; 41 | 42 | % smax=-1; 43 | % for i1=1:length(x) 44 | % c=cos(x(i1)); s=sin(x(i1)); 45 | % M=Yz(:,:,1)*c+Yz(:,:,2)*s; 46 | % [U,S,V]=svd(M); 47 | % s0=max(diag(S)); 48 | % if s0>smax 49 | % A=U(:,1); 50 | % B=V(:,1); 51 | % C=[c;s]; 52 | % smax=s0; 53 | % end 54 | % end 55 | 56 | % choose the best root which yields the largest singular value of Y. 57 | % svd of the projected matrix is 58 | % a(x) + sqrt(a^2 - b^2) 59 | % or 60 | % b(x)*b'(x)/a'(x) 61 | % 62 | a = @(x) t_1 *cos(2*x) + t_2; % t3 is omitted since t3= 0 63 | b = @(x) t_5 *cos(2*x) + t_6 * sin(2*x) + t_4; 64 | 65 | ax = a(x); 66 | bx = b(x); 67 | s = ax + sqrt(ax.^2 - bx.^2); % the best singular value is one of s. 68 | [smax,ix] = max(sqrt(s/2)); 69 | 70 | c=cos(x(ix)); s=sin(x(ix)); 71 | M=Yz(:,:,1)*c+Yz(:,:,2)*s; 72 | [U,S,V]=svd(M); 73 | S = diag(S); [~,is] = max(S); 74 | A=U(:,is); 75 | B=V(:,is); 76 | C = Z*[c;s]; % rotate c back by Z -------------------------------------------------------------------------------- /BestRank1/bestrank1_2222.m: -------------------------------------------------------------------------------- 1 | function [P,cost] = bestrank1_2222(Y,opts) 2 | % Find best rank-1 tensor approximation to the tensor Y of size 2x2x2x2 3 | % The algorithm exploits the closed-form best rank-1 tensor approximation 4 | % to an order-3 tensor 5 | % 6 | % cost = Y x {u} 7 | % 8 | % Phan Anh-Huy, 2017 9 | % August 16, 2017 10 | % 11 | 12 | if ~exist('opts','var'), opts = struct; end 13 | param = parseInput(opts); 14 | if nargin == 0 15 | P = param; return 16 | end 17 | N = ndims(Y); 18 | U = cp_init(Y,1,param); 19 | P = normalize(ktensor(U)); 20 | U = P.u; 21 | 22 | cost = zeros(param.maxiters,N); % Y x {u_n} 23 | 24 | for kiter = 1:param.maxiters 25 | 26 | for n = 1:N 27 | Y4 = ttv(Y,U,n); 28 | m = [1:n-1 n+1:N]; 29 | [U{m(1)},U{m(2)},U{m(3)},smax] = bestrank1_222(double(Y4)); 30 | 31 | t4 = double(ttv(Y,U,-n)); 32 | cost(kiter,n) = norm(t4); 33 | U{n} = t4/cost(kiter,n); 34 | end 35 | 36 | if mod(kiter,param.printitn)==0 37 | fprintf(' Iter %2d: ',kiter); 38 | % if param.TraceFit 39 | if kiter>1 40 | dchange = cost(kiter-1)-cost(kiter); 41 | else 42 | dchange = 0; 43 | end 44 | fprintf('Cost = %e delta = %7.1e ', cost(kiter), dchange); 45 | % end 46 | fprintf('\n'); 47 | end 48 | 49 | if (kiter>2) && abs(cost(kiter)-cost(kiter-1))< param.tol 50 | break 51 | end 52 | end 53 | cost = cost(1:kiter,:); 54 | P = ktensor(cost(end),U); 55 | 56 | 57 | %% 58 | % [v3d,v4d] = meshgrid(6:-1:0,6:-1:0); 59 | % [A,B,C1,C2] = gen_poly(Y); 60 | % % sol=polynsolve({[C1(:) v4d(:) v3d(:)] [C2(:) v4d(:) v3d(:)]}); 61 | % 62 | % Eq2 = ''; 63 | % Eq1 = ''; 64 | % 65 | % for k = 1:49 66 | % Eq1 = [Eq1 ' + ' sprintf('(%d) * x1^%d * x2^%d ',C1(k),v3d(k),v4d(k))]; 67 | % Eq2 = [Eq2 ' + ' sprintf('(%d) * x1^%d * x2^%d ',C2(k),v3d(k),v4d(k))]; 68 | % end 69 | % 70 | % %% 71 | % [PowersMat, CoeffsArray, MaxPowersArray] = IritEquationParser(2, {Eq1 Eq2}); 72 | % ii2 = sub2ind([7 7],OutPowersMat{1}(1,:)'+1,OutPowersMat{1}(2,:)'+1); 73 | % [~,iij] = sort(ii2); 74 | % 75 | % CoeffsArray{1}(iij) = C1(:)'; 76 | % CoeffsArray{2}(iij) = C2(:)'; 77 | % 78 | % % Call mex function to receive solution. % 79 | % Properties.LowerBounds = [v3v-5 v4v-5]; 80 | % Properties.UpperBounds = [v3v+5 v4v+5]; 81 | % Properties.Constraints = zeros(1,2); 82 | % Properties.NumericTol = 1e-15; 83 | % Properties.SubdivTol = 1e-3; 84 | % Properties.Step = 1e-5; 85 | % 86 | % [Sol, T] = IritPolynomialSolverMex(2, PowersMat, CoeffsArray, MaxPowersArray, Properties.LowerBounds, Properties.UpperBounds, Properties.Constraints, Properties.NumericTol, Properties.SubdivTol, Properties.Step); 87 | % % 88 | % % fsigma_sv = zeros(size(Sol,1),1); 89 | % % for ks = 1:size(Sol,1) 90 | % % v3s_num = Sol(ks,1); 91 | % % v4s_num = Sol(ks,2); 92 | % % fsigma_sv(ks) = double(subs(fsigma,[st; sw; x3;x4],[tyv; wyv; atan(v3s_num) ; atan(v4s_num)])); 93 | % % end 94 | %% 95 | % error 96 | % error = norm(Y)^2 - cost.^2; 97 | end 98 | 99 | 100 | 101 | %% Parse input xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 102 | function param = parseInput(opts) 103 | %% Set algorithm parameters from input or by using defaults 104 | param = inputParser; 105 | param.KeepUnmatched = true; 106 | param.addOptional('init','random',@(x) (iscell(x) || isa(x,'ktensor')||... 107 | ismember(x(1:4),{'rand' 'nvec' 'fibe' 'orth' 'dtld'}))); 108 | param.addOptional('maxiters',200); 109 | param.addOptional('tol',1e-6); 110 | param.addOptional('printitn',0); 111 | param.addOptional('fitmax',1-1e-10); 112 | 113 | param.parse(opts); 114 | param = param.Results; 115 | end 116 | 117 | 118 | function [A,B,C1,C2] = gen_poly(y) 119 | 120 | % generate two matrices of size 3x3 , A and B 121 | 122 | tc3c4 = 1/4* (y(1)^2 + y(2)^2 + y(3)^2 + y(4)^2 - y(5)^2 - y(6)^2 - y(7)^2 - y(8)^2 - y(9)^2 - y(10)^2 - y(11)^2 - y(12)^2 + y(13)^2 + y(14)^2 + y(15)^2 + y(16)^2); 123 | tc3s4 = 1/2*(y(1)*y(9) + y(2)*y(10) + y(3)*y(11) + y(4)*y(12) - y(5)*y(13) - y(6)*y(14) - y(7)*y(15) - y(8)*y(16)); 124 | ts3c4 = 1/2*(y(1)*y(5) + y(2)*y(6) + y(3)*y(7) + y(4)*y(8) - y(9)*y(13) - y(10)*y(14) - y(11)*y(15) - y(12)*y(16)); 125 | ts3s4 = 1/2*(y(1)*y(13) + y(5)*y(9) + y(2)*y(14) + y(6)*y(10) + y(3)*y(15) + y(7)*y(11) + y(4)*y(16) + y(8)*y(12)); 126 | ts3 = 1/2*(y(1)*y(5) + y(2)*y(6) + y(3)*y(7) + y(4)*y(8) + y(9)*y(13) + y(10)*y(14) + y(11)*y(15) + y(12)*y(16)); 127 | ts4 = 1/2*(y(1)*y(9) + y(2)*y(10) + y(3)*y(11) + y(4)*y(12) + y(5)*y(13) + y(6)*y(14) + y(7)*y(15) + y(8)*y(16)); 128 | tc3 = 1/4*(y(1)^2 + y(2)^2 + y(3)^2 + y(4)^2 - y(5)^2 - y(6)^2 - y(7)^2 - y(8)^2 + y(9)^2 + y(10)^2 + y(11)^2 + y(12)^2 - y(13)^2 - y(14)^2 - y(15)^2 - y(16)^2); 129 | tc4 = 1/4*(y(1)^2 + y(2)^2 + y(3)^2 + y(4)^2 + y(5)^2 + y(6)^2 + y(7)^2 + y(8)^2 - y(9)^2 - y(10)^2 - y(11)^2 - y(12)^2 - y(13)^2 - y(14)^2 - y(15)^2 - y(16)^2); 130 | t00 = 1/4*(y(1)^2 + y(2)^2 + y(3)^2 + y(4)^2 + y(5)^2 + y(6)^2 + y(7)^2 + y(8)^2 + y(9)^2 + y(10)^2 + y(11)^2 + y(12)^2 + y(13)^2 + y(14)^2 + y(15)^2 + y(16)^2); 131 | 132 | 133 | A = reshape([tc3c4 134 | ts3c4 135 | tc4 136 | tc3s4 137 | ts3s4 138 | ts4 139 | tc3 140 | ts3 141 | t00],3,3); 142 | 143 | 144 | wc3c4 = (y(1)*y(4) - y(2)*y(3) - y(5)*y(8) + y(6)*y(7) - y(9)*y(12) + y(10)*y(11) + y(13)*y(16) - y(14)*y(15))/2; 145 | wc3s4 = (y(1)*y(12) - y(2)*y(11) - y(3)*y(10) + y(4)*y(9) - y(5)*y(16) + y(6)*y(15) + y(7)*y(14) - y(8)*y(13))/2; 146 | ws3c4 = (y(1)*y(8) - y(2)*y(7) - y(3)*y(6) + y(4)*y(5) - y(9)*y(16) + y(10)*y(15) + y(11)*y(14) - y(12)*y(13))/2; 147 | ws3s4 = (y(1)*y(16) - y(2)*y(15) - y(3)*y(14) + y(4)*y(13) + y(5)*y(12) - y(6)*y(11) - y(7)*y(10) + y(8)*y(9))/2; 148 | wc3 = (y(1)*y(4) - y(2)*y(3) - y(5)*y(8) + y(6)*y(7) + y(9)*y(12) - y(10)*y(11) - y(13)*y(16) + y(14)*y(15))/2; 149 | wc4 = (y(1)*y(4) - y(2)*y(3) + y(5)*y(8) - y(6)*y(7) - y(9)*y(12) + y(10)*y(11) - y(13)*y(16) + y(14)*y(15))/2; 150 | ws3 = (y(1)*y(8) - y(2)*y(7) - y(3)*y(6) + y(4)*y(5) + y(9)*y(16) - y(10)*y(15) - y(11)*y(14) + y(12)*y(13))/2; 151 | ws4 = (y(1)*y(12) - y(2)*y(11) - y(3)*y(10) + y(4)*y(9) + y(5)*y(16) - y(6)*y(15) - y(7)*y(14) + y(8)*y(13))/2; 152 | w00 = (y(1)*y(4) - y(2)*y(3) + y(5)*y(8) - y(6)*y(7) + y(9)*y(12) - y(10)*y(11) + y(13)*y(16) - y(14)*y(15))/2; 153 | 154 | 155 | B = reshape([wc3c4 156 | ws3c4 157 | wc4 158 | wc3s4 159 | ws3s4 160 | ws4 161 | wc3 162 | ws3 163 | w00],3,3); 164 | 165 | % generate two matrices of size 7x7 , C1 and C2 as coefficients of bi-variate polynomials 166 | % derived from the gradients 167 | % 168 | % gn = sum_{k,l} Cn(k,l) * v3^(7-k) v4^(7-l) 169 | % Ka = Kp*Kp2*Kp3; 170 | K = [ 171 | -1 0 3 0 -3 0 1 172 | 0 2 0 -4 0 2 0 173 | 1 0 -1 0 -1 0 1 174 | 0 2 0 -4 0 2 0 175 | 0 0 -4 0 4 0 0 176 | 0 -2 0 0 0 2 0 177 | 1 0 -1 0 -1 0 1 178 | 0 -2 0 0 0 2 0 179 | -1 0 -1 0 1 0 1 180 | 0 2 0 -4 0 2 0 181 | 0 0 -4 0 4 0 0 182 | 0 -2 0 0 0 2 0 183 | 0 0 -4 0 4 0 0 184 | 0 0 0 8 0 0 0 185 | 0 0 4 0 4 0 0 186 | 0 -2 0 0 0 2 0 187 | 0 0 4 0 4 0 0 188 | 0 2 0 4 0 2 0 189 | 1 0 -1 0 -1 0 1 190 | 0 -2 0 0 0 2 0 191 | -1 0 -1 0 1 0 1 192 | 0 -2 0 0 0 2 0 193 | 0 0 4 0 4 0 0 194 | 0 2 0 4 0 2 0 195 | -1 0 -1 0 1 0 1 196 | 0 2 0 4 0 2 0 197 | 1 0 3 0 3 0 1]; 198 | 199 | F = [ 0 -1 0 200 | 1 0 0 201 | 0 0 0]; 202 | 203 | % tic 204 | C1 = K'*(kron(B,kron(F'*A,F'*A)+kron(F'*B,F'*B)) - 2 * kron(A,kron(F'*A,F'*B)))*K; 205 | C2 = K'*(kron(B,kron(A*F,A*F)+kron(B*F,B*F)) - 2 * kron(A,kron(A*F,B*F)))*K; 206 | % toc 207 | end -------------------------------------------------------------------------------- /BestRank1/bestrank1tensorapprox.m: -------------------------------------------------------------------------------- 1 | function [P,out] = bestrank1tensorapprox(Y,opts) 2 | % Best rank-1 tensor approximation to a tensor X 3 | % 4 | % TENSORBOX, 2018 5 | 6 | if ~exist('opts','var'), opts = struct; end 7 | param = parseInput(opts); 8 | if nargin == 0 9 | P = param; return 10 | end 11 | 12 | 13 | N = ndims(Y); 14 | 15 | permYs = []; 16 | if strcmp(param.init,'sqpr') 17 | % sequential projection and truncation 18 | permYs = perms(1:N); 19 | end 20 | r1_alg = param.r1_alg; 21 | 22 | 23 | best_err = inf; 24 | for kp = 1:size(permYs,1)+1 25 | 26 | if kp<=size(permYs,1) 27 | % Sequential Projection and Truncation 28 | 29 | permY = permYs(kp,:); 30 | Y0 = permute(Y,permY); 31 | 32 | Usqprj = seqproj_trunc(tensor(Y0),1); 33 | else 34 | % SVD for the last initilization method 35 | Usqprj = cp_init(tensor(Y),1,struct('init','nvecs')); 36 | permY = 1:N; 37 | end 38 | 39 | %% optimize the rank-1 norm lda 40 | u = Usqprj; 41 | lda = ttv(Y,u); 42 | yu = normalize(ktensor(lda,u)); 43 | u = cellfun(@(x) x* (yu.lambda)^(1/(N)),yu.u,'uni',0); 44 | 45 | Yt = ktensor(u); 46 | Yt = normalize(Yt); 47 | Yt = ipermute(Yt,permY); 48 | 49 | % first pass through ALS 50 | cp_opts = cp_fastals(); 51 | % cp_opts.dimorder = 1:N; 52 | % cp_opts.printitn = 1; 53 | cp_opts.tol = param.tol; 54 | 55 | cp_opts.init = Yt; 56 | cp_opts.maxiters = 10; 57 | 58 | [Pxh_0,outh] = cp_fastals(Y,1,cp_opts); 59 | 60 | Pxh_0 = normalize(Pxh_0); 61 | 62 | %Err_perm3(kp) = normY^2 + norm(Pxh_0)^2 - 2 * innerprod(Y,Pxh_0); 63 | 64 | %% Best rank-1 algorithm 65 | cp_opts.maxiters = 10; 66 | cp_opts.linesearch = 0; 67 | cp_opts.init = Pxh_0.u; 68 | 69 | % RORO rank-1 rotational algorithm 70 | try 71 | [P_r1ru,out_r1ru] = r1_alg(Y,cp_opts); 72 | catch 73 | [P_r1ru,out_r1ru] = r1_alg(Y,1,cp_opts); 74 | end 75 | 76 | err_r1ru = 1-out_r1ru.Fit(end,2); 77 | %Err_r1ru{kp} = 1-out_r1ru.Fit(:,2); 78 | 79 | if best_err > err_r1ru 80 | best_err = err_r1ru; 81 | P_best = P_r1ru; 82 | end 83 | %% error of all algorithms 84 | end 85 | 86 | 87 | %% STAGE 2 88 | cp_opts.maxiters = param.maxiters; 89 | % cp_opts.linesearch = 0; 90 | cp_opts.init = P_best; 91 | 92 | % RORO rank-1 rotational algorithm 93 | try 94 | [P,out] = r1_alg(Y,cp_opts); 95 | catch 96 | [P,out] = r1_alg(Y,1,cp_opts); 97 | end 98 | 99 | 100 | % err_r1ru = 1-out_r1ru.Fit(end,2); 101 | % Err_r1ru{kp} = 1-out_r1ru.Fit(:,2); 102 | 103 | end 104 | 105 | 106 | 107 | 108 | %% Parse input xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 109 | function param = parseInput(opts) 110 | %% Set algorithm parameters from input or by using defaults 111 | param = inputParser; 112 | param.KeepUnmatched = true; 113 | param.addOptional('init','random',@(x) (iscell(x) || isa(x,'ktensor')||... 114 | ismember(x(1:4),{'rand' 'nvec' 'fibe' 'orth' 'dtld' 'sqpr'}))); 115 | param.addOptional('maxiters',200); 116 | param.addOptional('tol',1e-6); 117 | param.addOptional('printitn',0); 118 | param.addOptional('fitmax',1-1e-10); 119 | param.addOptional('r1_alg',@cp_roro); % cp_fastals 120 | 121 | param.parse(opts); 122 | param = param.Results; 123 | end -------------------------------------------------------------------------------- /BestRank1/cp_r1lm_optmu.m: -------------------------------------------------------------------------------- 1 | function [P,out] = cp_r1lm_optmu(Y,opts) 2 | % LM algorithm for best rank-1 tensor approximation 3 | % 4 | % Phan Anh Huy 2017 5 | 6 | if ~exist('opts','var'), opts = struct; end 7 | param = parseInput(opts); 8 | if nargin == 0 9 | P = param; return 10 | end 11 | 12 | %% 13 | % param.cp_func = str2func(mfilename); 14 | Uinit = cp_init(Y,1,param); u = Uinit; 15 | % P = ktensor(U); 16 | 17 | %% Output 18 | if param.printitn ~=0 19 | fprintf('\LM algorithm for best Rank-One tensor approximation\n'); 20 | end 21 | 22 | N = ndims(Y); 23 | err = 0; 24 | 25 | % u = Pxh_0.u; 26 | % u = Pxh.u; 27 | gamma_ = zeros(N,1); 28 | tn_ = u; 29 | 30 | for kiter = 1:param.maxiters 31 | 32 | for n = 1:N 33 | gamma_(n) = u{n}'*u{n}; 34 | end 35 | gamma = prod(gamma_); 36 | lda = ttv(Y,u)/gamma; 37 | if lda<0 38 | u{1} = -u{1}; 39 | lda = -lda; 40 | end 41 | 42 | alpha = gamma^(1/N/2) * lda^(1/N); 43 | alpha2 = alpha^2; 44 | for n = 1:N 45 | u{n} = u{n}/sqrt(gamma_(n)) * alpha; 46 | end 47 | gamma = lda^2*gamma; 48 | %mu = gamma; 49 | 50 | 51 | % mu = 0 52 | mu_opt = 2; % try mu = [0 alpha^ 53 | if mu_opt == 0 54 | mu = 0; 55 | %mu = alpha2^(N-1); 56 | % mu = alpha2^(N-2); 57 | for n = 1:N 58 | tn = double(ttv(Y,u,-n)); 59 | %unew{n} = tn/alpha2^(N-1); 60 | %u{n} = tn/alpha2^(N-1); 61 | % unew{n} = (mu* u{n} + tn)/(mu + alpha2^(N-1)); 62 | u{n} = (mu* u{n} + tn)/(mu + alpha2^(N-1)); 63 | end 64 | % u = unew; 65 | 66 | elseif mu_opt == 1 67 | % mu = inf 68 | % current error 69 | current_err = -gamma; % + normY^2 = norm(Y-full(ktensor(u))); 70 | 71 | for n = N:-1:1 72 | tn = double(ttv(Y,u,-n)); 73 | tn_{n} = tn; 74 | end 75 | 76 | % mu = 0 77 | Ptn =ktensor(1/gamma^(N-1),tn_); 78 | muzero_err = norm(Ptn)^2 - 2 * innerprod(Y,Ptn); 79 | 80 | % mu = alpha2^(N-1); 81 | mu = alpha2^(N-2); 82 | unew = cellfun(@(x,y) (x*mu+y)/(mu + alpha2^(N-1)),u,tn_,'uni',0); 83 | Ptn2 =ktensor(unew); 84 | mu2_err = norm(Ptn2)^2 - 2 * innerprod(Y,Ptn2); 85 | 86 | if mu2_err 1e-8 108 | % v{n} = v{n}/cn(n); 109 | % else 110 | % v{n}(:) = 0; 111 | % cn(n) = 0; 112 | % end 113 | 114 | uv{n} = [u{n} v{n}]; 115 | end 116 | 117 | Yuv = double(ttm(Y,uv,'t')); % 2x2x...x2 118 | 119 | % generate polynomial of norm of Yx = [[uv{n} * [1 ; eta] ]] 120 | % f1 : of degree 2N 121 | %syms eta; 122 | % f1 = prod(alpha2+cn.^2*eta^2); 123 | for n = 1:N 124 | if n == 1 125 | f1 = [cn(n).^2 0 alpha2]; 126 | else 127 | f1 = conv(f1,[cn(n).^2 0 alpha2]); 128 | end 129 | end 130 | 131 | % Polynomial of the second term of degree N 132 | f2 = gen_poly_kron_1x(Yuv(:),N); 133 | % f2 = [1; eta]; 134 | % for n = 1:N-1 135 | % f2 = kron(f2, [1; eta]); 136 | % end 137 | % f2 = Yuv(:)'*f2; 138 | 139 | fcost = f1; 140 | fcost(N+1:end) = fcost(N+1:end) - 2*f2; 141 | df = polyder(fcost); 142 | etas = roots(df); 143 | % eta should be in [0 1/alpha^(N-1)] 144 | etas = etas(abs(imag(etas))<1e-8); 145 | eta = etas((0<=etas)&(etas<1/alpha^(N-1))); 146 | eta = [eta; 0 ;1/alpha^(N-1)]; 147 | if numel(eta)>1 148 | fcost_etas = polyval(fcost,eta); 149 | [~,ietas] = min(fcost_etas); 150 | eta = eta(ietas); 151 | end 152 | 153 | %eta = fminbnd(@(x) double(subs(fcost,eta,x)),0,1/gamma_ns1); 154 | unew = u; 155 | for n = 1:N 156 | unew{n} = u{n} + v{n}*eta; 157 | end 158 | u = unew; 159 | 160 | %% 161 | if 0 162 | mu = alpha2^(N-1); 163 | syms nu; 164 | 165 | KUT = 1;c2 = 1; 166 | 167 | f2 = 1; 168 | for n = N:-1:1 169 | tn = double(ttv(Y,u,-n)); 170 | 171 | tn_{n} = tn; 172 | if n == N 173 | KUT = [u{n} tn]; 174 | else 175 | KUT = kron(KUT,[u{n} tn]); 176 | end 177 | 178 | c2 = kron(c2,[nu ;1]); 179 | 180 | f2 = f2 *([nu 1]*([alpha2 gamma ; gamma tn'*tn]) * [nu ; 1]); 181 | end 182 | c1 = Y(:)'*KUT; 183 | 184 | fcost = f2/(nu + alpha2^(N-1))^(2*N) - 2*(c1*c2) * 1/(nu + alpha2^(N-1))^N; 185 | 186 | while 1 187 | [mu2,FVAL,EXITFLAG] = fmincon(@(x) double(subs(fcost,nu,x)),mu,[],[],[],[],0,2*mu); 188 | if EXITFLAG == 1 189 | break 190 | else 191 | mu = 2*mu; 192 | end 193 | end 194 | mu = double(mu2); 195 | 196 | for n = 1:N 197 | unew{n} = (mu* u{n} + tn_{n})/(mu + alpha2^(N-1)); 198 | end 199 | % u = unew; 200 | %fcost2 = double(subs(fcost,nu,mu))+normY2; 201 | end 202 | end 203 | 204 | 205 | err(kiter) = norm(Y-full(ktensor(u))); 206 | 207 | fprintf('%d err %d \n',kiter,err(kiter)) 208 | if (kiter>1) && abs(err(kiter)-err(kiter-1))< 1e-8 209 | break 210 | end 211 | end 212 | 213 | P = ktensor(u); 214 | out.Fit = [(1:numel(err))' 1-err(:)/norm(Y)]; 215 | 216 | 217 | end 218 | 219 | 220 | 221 | 222 | 223 | %% Parse input xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 224 | function param = parseInput(opts) 225 | %% Set algorithm parameters from input or by using defaults 226 | param = inputParser; 227 | param.KeepUnmatched = true; 228 | param.addOptional('init','random',@(x) (iscell(x) || isa(x,'ktensor')||... 229 | ismember(x(1:4),{'rand' 'nvec' 'fibe' 'orth' 'dtld'}))); 230 | param.addOptional('maxiters',200); 231 | param.addOptional('tol',1e-6); 232 | param.addOptional('printitn',0); 233 | param.addOptional('fitmax',1-1e-10); 234 | 235 | param.addOptional('normX',[]); 236 | 237 | 238 | param.parse(opts); 239 | param = param.Results; 240 | 241 | end -------------------------------------------------------------------------------- /BestRank1/cp_roro.m: -------------------------------------------------------------------------------- 1 | function [P,out] = cp_roro(Y,opts) 2 | % Rotational update algorithm for best Rank-One tensor approximation 3 | % 4 | % Phan Anh-Huy, August, 2017, 5 | % 6 | % TENSORBOX, 2018 7 | 8 | if ~exist('opts','var'), opts = struct; end 9 | param = parseInput(opts); 10 | if nargin == 0 11 | P = param; return 12 | end 13 | 14 | 15 | N = ndims(Y); 16 | err = 0; 17 | normY = norm(Y); 18 | 19 | %% 20 | % param.cp_func = str2func(mfilename); 21 | Uinit = cp_init(Y,1,param); u = Uinit; 22 | P = normalize(ktensor(u)); 23 | u = P.u; 24 | 25 | %% Output 26 | if param.printitn ~=0 27 | fprintf('\Rotational algorithm for best Rank-One tensor approximation:\n'); 28 | end 29 | 30 | %% NIcholson ALS - new form works as ALS 31 | % 32 | cgn = zeros(N,1); 33 | clear err; 34 | v = cell(N,1); 35 | 36 | for kiter = 1:param.maxiters 37 | if 0 %mod(kiter,5) == 1% run als 38 | for n = 1:N 39 | tn = double(ttv(Y,u,-n)); 40 | u{n} = tn/norm(tn); 41 | end 42 | 43 | else 44 | tn_ = cp_gradients(Y,u); 45 | gn = cell(N,1); 46 | 47 | for n = 1:N 48 | tn = tn_{n}; 49 | xi = tn'*u{n}; 50 | 51 | %gn{n} = (-tn + u{n}*xi)*xi; 52 | % due to the normalization xi is omitted 53 | gn{n} = (-tn + u{n}*xi); 54 | cgn(n) = norm(gn{n}); 55 | 56 | if cgn(n) < 1e-10 57 | cgn(n) = 0; 58 | gn{n}(:) = 0; 59 | else 60 | gn{n} = gn{n}/cgn(n); 61 | end 62 | end 63 | 64 | % gn = cell(N,1); 65 | % 66 | % for n = 1:N 67 | % tn = double(ttv(Y,u,-n)); 68 | % xi = tn'*u{n}; 69 | % 70 | % %gn{n} = (-tn + u{n}*xi)*xi; 71 | % % due to the normalization xi is omitted 72 | % gn{n} = (-tn + u{n}*xi); 73 | % cgn(n) = norm(gn{n}); 74 | % 75 | % if cgn(n) < 1e-10 76 | % cgn(n) = 0; 77 | % gn{n}(:) = 0; 78 | % else 79 | % gn{n} = gn{n}/cgn(n); 80 | % end 81 | % end 82 | 83 | zc2 = find(cgn > 0); 84 | % numel(zc2) 85 | 86 | ug = u; 87 | ug(zc2) = cellfun(@(x,y) [x y], u(zc2),gn(zc2),'uni',0); 88 | 89 | %% best rank-1 of tensor 2x2x2 90 | % Yug = ttm(Y,ug,'t'); slow because of permute and ipermute 91 | Yug = fullprojection(Y,ug); 92 | 93 | Yug = squeeze(tensor(Yug)); 94 | N2 = ndims(Yug); 95 | %v = tucker_als(Yug,1,struct('init','nvecs','tol',1e-8)); 96 | %v = mtucker_als(Yug,ones(1,ndims(Yug)),struct('init','nvecs','tol',1e-8,'maxiter',1000),'nvecs'); 97 | % 98 | 99 | if N2 > 4 100 | 101 | cp_opts2.maxiters = 1000; 102 | cp_opts2.dimorder = 1:N; 103 | cp_opts2.printitn = 0; 104 | cp_opts2.tol = 1e-12; 105 | cp_opts2.alsinit = 0; 106 | cp_opts2.init = {'dtld' 'nvec'}; 107 | 108 | v = cp_fastals(Yug,1,cp_opts2); 109 | cp_opts2.init = {'dtld' 'nvec' v}; 110 | v = cp_r1LM(Yug,1,cp_opts2); 111 | v = normalize(v); 112 | lv = v.lambda; 113 | v = v.u; 114 | 115 | elseif N2 == 4 116 | [p4,cost] = bestrank1_2222(Y,opts); 117 | v = p4.u; 118 | 119 | elseif N2 == 3 120 | % closed form to find best rank-1 tensor of 2x2x2 121 | % y3 = squeeze(double(c(:,:,1))*cos(x) + double(Yug(:,:,2))*sin(x)); 122 | % 123 | % s1 = sum(y3(:).^2); 124 | % s2 = sqrt((y3(1)^2 + y3(3)^2 - y3(2)^2 - y3(4)^2)^2 + 4 * (y3(1)*y3(2)+y3(3)*y3(4))^2); 125 | % 126 | % sigma2 = (s1+s2)/2; % = svd(y3)^2 127 | % [xs,fv] = fminbnd(@(v) -double(subs(sigma2,x,v)),0,pi); 128 | 129 | [v{1},v{2},v{3}] = bestrank1_222(double(Yug)); 130 | 131 | %[v2,sigma] = bestrank1_222_iter(double(Yug)); 132 | %if ttv(tensor(Yug),v) < ttv(tensor(Yug),v2)-1e-10 133 | % 1 134 | % break 135 | %end 136 | 137 | elseif N2 == 2 138 | [uy,sy,vy] = svd(double(Yug)); 139 | sy = diag(sy); [~,is] = max(sy); 140 | v{1} = uy(:,is); 141 | v{2} = vy(:,is); 142 | else % ndims(Yug) == 1 143 | v{1} = double(Yug)/norm(Yug); 144 | end 145 | % norm(lv - sqrt(-fv)) 146 | 147 | %% 148 | 149 | unew = u; 150 | for n = 1:numel(zc2) 151 | %unew{zc2(n)} = ug{zc2(n)} * (v{n}*sign(v{n}(1))); 152 | unew{zc2(n)} = ug{zc2(n)} * v{n}; 153 | unew{zc2(n)} = unew{zc2(n)}/norm(unew{zc2(n)}); 154 | end 155 | 156 | u = unew; 157 | 158 | end 159 | 160 | % lda = ttv(Y,u); 161 | lda = fullprojection(Y,u); 162 | err(kiter) = sqrt(normY^2 - double(lda)^2)/normY; 163 | 164 | if mod(kiter,param.printitn)==0 165 | fprintf(' Iter %2d: ',kiter); 166 | if kiter>1 167 | fprintf('fit = %e fitdelta = %7.1e \n', 1-err(kiter), err(kiter)-err(kiter-1)); 168 | else 169 | fprintf('fit = %e \n', 1-err(kiter)); 170 | end 171 | end 172 | 173 | if (kiter>1) && abs(err(kiter)-err(kiter-1))< param.tol 174 | break 175 | end 176 | end 177 | P = ktensor(lda,u); 178 | out.Fit = [(1:numel(err))' 1-err(:)]; 179 | 180 | 181 | end 182 | 183 | 184 | 185 | %% Parse input xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 186 | function param = parseInput(opts) 187 | %% Set algorithm parameters from input or by using defaults 188 | param = inputParser; 189 | param.KeepUnmatched = true; 190 | param.addOptional('init','random',@(x) (iscell(x) || isa(x,'ktensor')||... 191 | ismember(x(1:4),{'rand' 'nvec' 'fibe' 'orth' 'dtld'}))); 192 | param.addOptional('maxiters',200); 193 | param.addOptional('tol',1e-6); 194 | param.addOptional('printitn',0); 195 | param.addOptional('fitmax',1-1e-10); 196 | param.addOptional('linesearch',true); 197 | %param.addParamValue('verify_convergence',true,@islogical); 198 | param.addParamValue('TraceFit',true,@islogical); 199 | param.addParamValue('TraceMSAE',false,@islogical); 200 | 201 | param.addParamValue('TraceRank1Norm',false,@islogical); 202 | param.addParamValue('max_rank1norm',inf); 203 | 204 | param.addParamValue('gamma',1e-3); 205 | param.addParamValue('adjust_gamma',false,@islogical); 206 | param.addOptional('normX',[]); 207 | 208 | 209 | param.parse(opts); 210 | param = param.Results; 211 | param.verify_convergence = param.TraceFit || param.TraceMSAE; 212 | end 213 | 214 | 215 | function X = fullprojection(Y,u) 216 | szY = size(Y); 217 | szYnew = cellfun(@(x) size(x,2),u,'uni',1); 218 | X = reshape(Y.data,[],szY(end))*u{end}; 219 | X = X'; % RN x I1...I(N-1) 220 | for n = ndims(Y)-1:-1:1 221 | X = reshape(X,[],szY(n))*u{n}; % R(n+1)...RN I1...I(n-1) x Rn 222 | X = X'; % Rn R(n+1)...RN I1...I(n-1) 223 | end 224 | X = reshape(X,szYnew'); 225 | end -------------------------------------------------------------------------------- /BestRank1/lmrank1_update.m: -------------------------------------------------------------------------------- 1 | function [unew,mu,g,d] = lmrank1_update(Y,u,mu,mu_opt) 2 | % LM update for best rank-1 tensor approximation 3 | % 4 | % TENSORBOX, 2018 5 | 6 | if nargin < 4 7 | mu_opt = 0; 8 | end 9 | % lda_opt = true; 10 | lda_opt = false; 11 | 12 | %% normalize 13 | szY = size(Y); 14 | 15 | N = numel(u); 16 | 17 | gamma_ = zeros(N,1); 18 | for n = 1:N 19 | gamma_(n) = u{n}'*u{n}; 20 | end 21 | gamma = prod(gamma_); 22 | 23 | 24 | if lda_opt 25 | lda = ttv(Y,u)/gamma; 26 | else 27 | lda = 1; 28 | end 29 | 30 | alpha = gamma^(1/N/2) * lda^(1/N); 31 | alpha2 = alpha^2; 32 | for n = 1:N 33 | u{n} = u{n}/sqrt(gamma_(n)) * alpha; 34 | end 35 | 36 | 37 | 38 | %% 39 | beta = mu + N * alpha2^(N-1); 40 | 41 | % xi = ttv(Y,u); 42 | 43 | csz = cumsum([0 szY]); 44 | t = zeros(sum(szY),1); 45 | for n = 1:N 46 | tn = double(ttv(Y,u,-n)); 47 | t(csz(n)+1:csz(n+1)) = (tn); 48 | end 49 | xi = u{N}'*tn; 50 | 51 | theta = cell2mat(u(:)); 52 | %% 53 | % unew = 1/beta * ((alpha2^(N-1) + (N-1)*xi/mu) * theta - t); 54 | 55 | % d = alpha2^(N-2)/beta * (alpha2 + (N-1)*xi/(alpha2^(N-1)+mu)) * theta - 1/(alpha2^(N-1)+mu) * t ; 56 | 57 | %unew = (1 - alpha2^(N-2)/beta * (alpha2 + (N-1)*xi/(alpha2^(N-1)+mu))) * theta + 1/(alpha2^(N-1)+mu) * t ; 58 | 59 | unew = 1/(alpha2^(N-1)+mu) * ((mu + (N-1)*alpha2^(N-2)*(alpha2^N-xi)/beta) * theta + t ); 60 | 61 | %% 62 | debug = 0; 63 | if debug 64 | Z = blkdiag(u{1},u{2},u{3}); 65 | H = (alpha2^(N-1)+mu) * eye(sum(szY)) + Z*(ones(N) - eye(N))*Z' * alpha2^(N-2); 66 | norm(H - (F+ theta*theta'*alpha2^(N-2)),'fro') 67 | F = (alpha2^(N-1)+mu) * eye(sum(szY)) - Z*Z'*alpha2^(N-2); 68 | norm(inv(F) - 1/(alpha2^(N-1)+mu) * (eye(size(H)) + alpha2^(N-2)/mu * Z*Z'),'fro') 69 | norm((inv(F)*theta ) - 1/mu* theta) 70 | norm(inv(H) - (inv(F) - alpha2^(N-2)/(mu^2 + alpha2^(N-1)*mu * N) * theta * theta'),'fro') 71 | norm(inv(H) - (1/(alpha2^(N-1)+mu) * (eye(size(H)) + alpha2^(N-2)/mu * Z*Z')),'fro') 72 | inv(H)*t - 1/(alpha2^(N-1)+mu) * (t - alpha2^(N-2)*xi*(N-1)/beta * theta) 73 | inv(H)*theta - 1/beta * theta 74 | end 75 | g = -theta * alpha2^(N-1) + t; 76 | % 77 | % H = cp_hessian(u); 78 | % unew2 = -H\g; 79 | 80 | %% optimize mu 81 | 82 | if mu_opt 83 | syms nu; 84 | beta_nu = nu + N * alpha2^(N-1); 85 | b = 1/(alpha2^(N-1)+nu); 86 | a = (nu + (N-1)*alpha2^(N-2)*(alpha2^N-xi)/beta_nu) * b; 87 | 88 | KUT = 1;c2 = 1; 89 | 90 | f2 = 1; 91 | for n = N:-1:1 92 | tn = double(ttv(Y,u,-n)); 93 | if n == N 94 | KUT = [u{n} tn]; 95 | else 96 | KUT = kron(KUT,[u{n} tn]); 97 | end 98 | c2 = kron(c2,[a ;b]); 99 | 100 | %f2 = f2*([a b]*([u{n} tn]'*[u{n} tn]) * [a ; b]); 101 | f2 = f2*([a b]*([alpha2 xi ; xi tn'*tn]) * [a ; b]); 102 | end 103 | c1 = Y(:)'*KUT; 104 | 105 | 106 | % [un,tn]*[a; b] 107 | 108 | fcost = f2 -2*c1*c2 ; 109 | mu = fmincon(@(x) double(subs(fcost,nu,x)),1000*mu,[],[],[],[],0,mu*1000); 110 | mu = double(mu); 111 | beta = mu + N * alpha2^(N-1); 112 | unew = 1/(alpha2^(N-1)+mu) * ( (mu + (N-1)*alpha2^(N-2)*(alpha2^N-xi)/beta) * theta + t ); 113 | end 114 | 115 | d = unew - theta; 116 | unew = mat2cell(unew,szY); 117 | end 118 | -------------------------------------------------------------------------------- /BestRank1/seqproj_trunc.m: -------------------------------------------------------------------------------- 1 | function U = seqproj_trunc(X,R) 2 | % Sequential projection and truncation for best rank R 3 | % 4 | % Like TT-SVD 5 | % Phan Anh Huy, 2017 6 | % 7 | Nf = ndims(X); 8 | U = cell(Nf,1); 9 | dimorder = 1:Nf; 10 | if numel(R)==1 11 | R = R(ones(1,Nf)); 12 | end 13 | for n = 1:Nf-1 14 | % try 15 | if n==1 16 | U{dimorder(n)} = nvecs(X,dimorder(n),R(n)); 17 | else 18 | if n==2 19 | T = ttm(X,U{dimorder(n-1)},n-1,'t'); 20 | else 21 | T = ttm(T,U{dimorder(n-1)},n-1,'t'); 22 | end 23 | U{dimorder(n)} = nvecs(T,dimorder(n),R((n))); 24 | end 25 | % catch me 26 | % Xn = double(tenmat(X,dimorder(n))); 27 | % Xn = Xn*Xn'; 28 | % R((n)) = min(rank(Xn),R((n))); 29 | % U{dimorder(n)} = nvecs(X,dimorder(n),R((nwhich ))); 30 | % end 31 | end 32 | U{dimorder(end)} = squeeze(double(ttm(T,U{dimorder(end-1)},Nf-1,'t'))); -------------------------------------------------------------------------------- /Deconvolution/convolutive_to_bcd.m: -------------------------------------------------------------------------------- 1 | function [H,U] = convolutive_to_bcd(H,U) 2 | % Conversion of a convolutive model to a block tensor component 3 | % 4 | % 5 | % H is a cell array of Hr which should be of the same size. 6 | % U is a cell array of Ur 7 | % 8 | % TENSORBOX, 2018 9 | 10 | SzH = size(H{1}); 11 | R = numel(H); 12 | N = numel(U{1}); 13 | 14 | H = reshape(cell2mat(cellfun(@(x) x(:),H(:)','uni',0)),[1 SzH,R]); 15 | 16 | U2 = cell(N,1); 17 | for r = 1:R 18 | for n = 1:N 19 | if r == 1 20 | U2{n} = convmtx(U{r}{n},SzH(n)); 21 | else 22 | U2{n} = cat(3,U2{n},convmtx(U{r}{n},SzH(n))); 23 | end 24 | end 25 | end 26 | U = U2; -------------------------------------------------------------------------------- /Deconvolution/demo_mnist_ts_deconvolution.m: -------------------------------------------------------------------------------- 1 | % This file illustrates feature extraction for the MNIST handwritten 2 | % digits using the Rank-1 Tensor Deconvolution. 3 | % 4 | % 5 | % TENSORBOX v.2015. 6 | 7 | %% Load the MNIST handwritten digit dataset for only two digits 8 | clear all 9 | 10 | compare_tdc_vs_cpd = false; % true to compare TDC with CPD with the same number of features 11 | % 12 | digits = [2 6]; % digits to be analyzed 13 | Nosamples = 100; % number of images per digit 14 | Nclasses = numel(digits); 15 | 16 | X = [];TrueLabels = []; 17 | for n = 1:Nclasses 18 | 19 | data1_st = sprintf('train%d',digits(n)); 20 | try 21 | data1 = load('mnist_all.mat',data1_st); 22 | catch 23 | fprintf('Data file ''mnist_all.mat'' does not exist, or is not in the Matlab path.\n') 24 | fprintf('The mat file can be found at https://drive.google.com/file/d/0B6hgADLGQOkPaWVWTmJpWDM5MjQ/view \n') 25 | end 26 | data1 = data1.(data1_st); 27 | 28 | %% Concatenate tensors of digit1 and digit2 into one 29 | X = cat(1,X,reshape(double(data1(1:Nosamples,:)),[],28,28)); 30 | 31 | % Define the true labels for the digits 32 | TrueLabels = [TrueLabels ; n*ones(Nosamples,1)]; 33 | end 34 | 35 | X = permute(X,[3 2 1]); % data size 28 x 28 x 2*Nosamples 36 | 37 | % Normalization and cropping digits 38 | X = X/max(abs(double(X(:)))); 39 | X = X(3:end-2,3:end-2,:); % trim images to size of 24 x 24 40 | 41 | SzX = size(X);N = ndims(X); 42 | 43 | %% Stage 1: Initialization for the rank-1 tensor deconvolution 44 | R = 2; % Two patterns will yield two features. 45 | SzH = [8 8 1]; % Size of patterns, i.e. size of the core tensors H_r. 46 | % When SzH = [1 1 1], the rank-1 tensor deconvolution becomes CPD of 47 | % rank R. 48 | 49 | init_opts = ts_deconv_init; 50 | init_opts.init = 'cpd1'; 51 | [Hn,U] = ts_deconv_init(X,R,SzH,init_opts); 52 | 53 | %% Stage 2: run ALS algorithm for the rank-1 tensor deconvolution 54 | Xcp = tensor(permute(double(X),[4 1 2 3])); 55 | 56 | % Set parameters for the ALS algorithm 57 | opts = ts_deconv_rank1_als; 58 | opts.maxiters = 1000; 59 | opts.tol = 1e-8; 60 | opts.printitn = 1; 61 | opts.orthomode = 0; 62 | % opts.sparse = [1 2 3]; 63 | 64 | for kiter = 1:20 65 | tic; 66 | [Hn,U,outputk] = ts_deconv_rank1_als(Xcp,U,double(Hn),opts); 67 | t_chtd = toc; 68 | 69 | if kiter > 1 70 | if abs(output.Error(end) - outputk.Error(end)) < opts.tol 71 | break 72 | end 73 | output = struct('Error',[output.Error outputk.Error],'NoIters',output.NoIters + outputk.NoIters); 74 | else 75 | output = outputk; 76 | end 77 | end 78 | 79 | figure(10);clf 80 | loglog(output.Error); 81 | xlabel('Iterations') 82 | ylabel('Approximation Error') 83 | 84 | %% Stage 3: Extract Features and perform clustering 85 | 86 | % Feature matrices 87 | Feat = U{N}(1:SzX(N),:); 88 | Feat = bsxfun(@rdivide,Feat,sqrt(sum(Feat.^2))); 89 | 90 | % KMEANS clustering 91 | [idx,ctrs] = kmeans(Feat,Nclasses,'Distance','sqEuclidean','Replicates',500); 92 | idx = bestMap(TrueLabels,idx); 93 | %============= evaluate AC: accuracy ============== 94 | acc = length(find(TrueLabels == idx))/length(TrueLabels); 95 | 96 | 97 | %% Stage 4: Visualize the results 98 | 99 | % Construct the approximates 100 | hX = squeeze(gen_ts_conv(Hn,U)); 101 | 102 | % Assess the relative approximation error 103 | err = norm(tensor(hX - squeeze(X)))/norm(X(:)); 104 | 105 | fprintf('Tensor deconvolution: (R = %d) patterns of size %d x %d x %d\n',R,SzH); 106 | fprintf('Approximation Error \t %.4f\nClustering Accuracy \t %.2f \n',err, acc) 107 | 108 | res_tdeconv = struct('ACC',acc,'Error',err); 109 | 110 | figure(2);clf 111 | montage(reshape(double(hX),[size(hX,1) size(hX,2) 1 size(hX,3)]),'Size',[SzX(N)/20 20]) 112 | title('Approximation using TDC') 113 | 114 | % Construct basis images learnt by the tensor deconvolution. 115 | % There are J basis images for each feature. So the total number of basis 116 | % images are R *J. 117 | 118 | Patt = []; 119 | SzHn = size(Hn); 120 | for r = 1:R 121 | Ur = cellfun(@(x) x(:,:,r), U,'uni',0); 122 | patr = ttm(tensor(Hn(:,:,:,:,r),[1 SzH]),Ur(1:2),[2 3]); 123 | patr = permute((patr),[2 3 1 4]); 124 | patr = double(patr); 125 | patr_rec = patr; 126 | 127 | Patt = [Patt double(reshape(patr_rec,SzX(1)*SzX(2),[]))]; 128 | end 129 | 130 | Patt = bsxfun(@minus,Patt,mean(Patt)); 131 | Patt = bsxfun(@rdivide,Patt,sqrt(sum(Patt.^2))); 132 | 133 | figure(3);clf 134 | visual(Patt,SzX(1),R); 135 | title('Basis patterns estimated by TDC') 136 | 137 | % Scatter plot of feature 1 vs feature 2 138 | figure(5) 139 | h = gscatter(U{N}(1:SzX(N),1,1),U{N}(1:SzX(N),1,2),TrueLabels); 140 | 141 | xlabel('Feature 1') 142 | ylabel('Feature 2') 143 | legend(h,arrayfun(@(x) num2str(x),digits,'uni',0)) 144 | 145 | 146 | %% Run this part to see performance using CPD of rank-R 147 | 148 | if compare_tdc_vs_cpd 149 | opts = cp_fLMa; 150 | opts.init = {'dtld' 'nvec' 'random'}; 151 | opts.maxiters = 5000; 152 | opts.printitn = 1; 153 | opts.maxboost = 1; 154 | 155 | [Pcp,out_cp] = cp_fLMa(tensor(squeeze(X)),R,opts); 156 | 157 | % Feature matrices 158 | Feat = Pcp.u{N}(1:SzX(N),:); 159 | 160 | % Feat = bsxfun(@minus,Feat,mean(Feat)); 161 | Feat = bsxfun(@rdivide,Feat,sqrt(sum(Feat.^2))); 162 | 163 | % KMEANS clustering 164 | [idx,ctrs] = kmeans(Feat,Nclasses,'Distance','sqEuclidean','Replicates',500); 165 | idx = bestMap(TrueLabels,idx); 166 | %============= evaluate AC: accuracy ============== 167 | acc = length(find(TrueLabels == idx))/length(TrueLabels); 168 | 169 | fprintf('CPD of rank R = %d\n',R); 170 | fprintf('Approximation Error \t %.4f\nClustering Accuracy \t %.2f \n',1-out_cp.Fit(end), acc) 171 | end -------------------------------------------------------------------------------- /Deconvolution/demo_rank1_ts_deconv.m: -------------------------------------------------------------------------------- 1 | % This file illustrates Rank-1 Rensor Deconvolution 2 | % which explains data through a convolutive model 3 | % 4 | % X = H_1 * (a_1 o b_1 o c_1) + ... + H_R * (a_R o b_R o c_R) 5 | % 6 | % where X is a tensor of size I1 x I2 x I3, 7 | % H_r are R patterns of size J1 x J2 x J3, 8 | % and (a_r o b_r o c_r) are rank-1 tensors of size K1 x K2 x K3, 9 | % In = Jn + Kn -1. 10 | % 11 | % 12 | % TENSORBOX 13 | % 14 | % Phan Anh Huy, Aug 2014 15 | 16 | clear all; 17 | 18 | SzU = [15 16 17]; % size of rank-1 activating tensors 19 | SzH = [2 2 2]; % Size of pattern tensors H: J1=J2=J3=J. 20 | R = 4; % no of patterns, i.e, the number of H_r 21 | N = numel(SzU); 22 | SNR = 30; % Noise level (dB) 23 | 24 | % Generate tensor X from random patterns H_r and rank-1 activating tensors 25 | % a_r o b_r o c_r 26 | [X,H0,U0] = gen_ts_conv(SzU,SzH,R); 27 | 28 | 29 | %% Add Gaussian noise into the tensor X 30 | sigma_noise = 10^(-SNR/20)*std(double(X(:))); 31 | X = X + sigma_noise * randn(size(X)); 32 | X = tensor(X); 33 | 34 | %% Rank-1 tensor deconvolution using the ALS algorithm 35 | fprintf('ALS algorithm. \n The decomposition may run several times to get the best result.\n') 36 | 37 | % Initialization for the tensor deconvolution 38 | opts = ts_deconv_init; 39 | opts.init = {'tedia' 'cpd1' 'cpd2'} ; % or {'tedia' 'cpd1' 'cpd2'} 40 | [Hn,Un] = ts_deconv_init(X,R,SzH,opts); 41 | 42 | % Run ALS 43 | opts = ts_deconv_rank1_als; 44 | opts.maxiters = 2000; 45 | opts.printitn = 1; 46 | opts.tol = 1e-9; 47 | 48 | tic; 49 | [Hn,Un,output] = ts_deconv_rank1_als(X,Un,Hn, opts); 50 | t_exec = toc; 51 | % Hn are estimates of the tensors Hn 52 | % 53 | % Un{n} = [U{n,1}, ..., U{n,r}, ..., U{n,R}]: estimates of Un{r} 54 | 55 | %% Evaluate performance 56 | % Compute the squared angular error 57 | 58 | for r = 1:R 59 | u = cell(N,1); 60 | for n = 1:N 61 | u{n} = Un{n}(1:SzU(n),1,r); 62 | end 63 | 64 | Pr = ktensor(u);Pr = arrange(Pr); 65 | 66 | for s = 1:R 67 | [msae1,msae2,sae1,sae2] = SAE(U0{s},Pr.u(:)); 68 | msae(r,s) = msae1; 69 | end 70 | end 71 | 72 | msae = min(msae); 73 | 74 | fprintf('SAE (dB) %s\n', sprintf('%.2f, ', -10*log10(msae))) 75 | fprintf('Relative error %d\n',output.Error(end)) 76 | fprintf('Execution time %d seconds\n',t_exec) 77 | 78 | return -------------------------------------------------------------------------------- /Deconvolution/gen_ts_conv.m: -------------------------------------------------------------------------------- 1 | function varargout = gen_ts_conv(varargin) 2 | % [X,H,U] = gen_ts_conv(SzU,SzH,R) 3 | % or 4 | % X = gen_ts_conv(H,U) 5 | % 6 | % Generate a tensor X from core tensors (patterns) H_r and rank-1 7 | % activating tensors whose loading components are U{n}(:,r). 8 | 9 | % [X,H,U] = gen_ts_conv(SzU,SzH,R) 10 | % 11 | % TENSORBOX, 2018 12 | 13 | if (nargin == 3) && isvector(varargin{1}) && isvector(varargin{2}) && isscalar(varargin{3}) 14 | [SzU,SzH,R] = deal(varargin{1},varargin{2},varargin{3}); 15 | 16 | N = numel(SzU); 17 | H = cell(N,1); U = cell(1,R); 18 | 19 | density = 100; 20 | 21 | X = 0; 22 | for r = 1:R 23 | Hr = randn(SzH); 24 | ur = cell(N,1); 25 | ortho = false; 26 | for n = 1:N 27 | ur{n} = randn(SzU(n),1); 28 | W = nmf_gen(SzU(n),1,density,ortho); 29 | ur{n} = ur{n}.*W; 30 | end 31 | 32 | H{r} = Hr;U{r} = ur; 33 | 34 | 35 | X = X + full(convn(Hr,ktensor(ur))); 36 | end 37 | 38 | %% Generate X from H and U 39 | %X = gen_ts_conv(H,U); 40 | 41 | % Set output 42 | if nargout >=1 43 | varargout{1} = X; 44 | end 45 | if nargout >=2 46 | varargout{2} = H; 47 | end 48 | if nargout >=3 49 | varargout{3} = U; 50 | end 51 | 52 | elseif (nargin == 2) % X = gen_ts_conv(H,U) 53 | H = varargin{1}; 54 | U = varargin{2}; 55 | 56 | if ~iscell(H) % Block model of the convolutive tensor mixtures 57 | % H is an array of size "? x SzH(1) x SzH(2) x...xSzH(N) x R" 58 | % U: is a cell array, each entry comprises concatenation of 59 | % loadings of the same order, i.e., U{n} is of size (In+Jn-1) x Jn x R. 60 | szs = cell2mat(cellfun(@(x) size(x),U,'uni',0)); 61 | SzX = szs(:,1); 62 | %SzH = szs(:,2); 63 | R = szs(1,3); 64 | N = numel(U); 65 | SzH = size(H); 66 | % H must be of size 67 | Hr = reshape(double(H),[],R); 68 | X = 0; 69 | for r = 1:R 70 | X = X+ ttm(tensor(Hr(:,r),SzH(1:end-1)),... 71 | cellfun(@(x) x(:,:,r), U,'uni',0),2:N+1); 72 | end 73 | 74 | 75 | else % generate the tensor X from the convolutive model of H x U 76 | 77 | R = numel(H); 78 | X = 0; 79 | for r = 1:R 80 | % Generate the r-th term X_r, X = sum_r X_r. 81 | Xr = convn(H{r},ktensor(U{r})); 82 | X = X + Xr; 83 | end 84 | end 85 | varargout{1} = X; 86 | end 87 | 88 | % H = reshape(cell2mat(cellfun(@(x) x(:),H(:)','uni',0)),[SzH,R]); 89 | % 90 | % for n = 1:N 91 | % U{n,1} = cell2mat(U(n,:)); 92 | % end 93 | % U = U(:,1); 94 | 95 | % for n = 1:N 96 | % U{n,1} = cell2mat(cellfun(@(x) convmtx(x,SzH(n)),U(n,:),'uni',0)); 97 | % U{n,1} = reshape(U{n,1},[SzU(n)+SzH(n)-1 SzH(n) R]); 98 | % end 99 | % U = U(:,1); 100 | end 101 | 102 | 103 | 104 | function Az = nmf_gen(I,R,density,orthogonal) 105 | 106 | if nargin < 4 107 | orthogonal = 0; 108 | end 109 | % Sparse ratio 110 | density = min(density,1-(R-1)/I(1)); 111 | 112 | if orthogonal 113 | % Generate orthogonal nonnegative matrix 114 | % Generate num of non-zeros for columns nnz_A = n1 + n2 + ... + nR 115 | nnz_A = 2/I + rand(1,R) * (1-(R-3)/I); 116 | nnz_A = I*nnz_A/sum(nnz_A); 117 | nnz_A = ceil(sort(nnz_A)); 118 | nnz_A(end-(sum(nnz_A) - I)+1:end) = nnz_A(end-(sum(nnz_A) - I)+1:end)-1; 119 | nnz_A = nnz_A(randperm(R)); 120 | 121 | innz = 1:I; 122 | innz = innz(randperm(I)); 123 | cnnz_A = cumsum([0 nnz_A]); 124 | Az = zeros(I,R); 125 | for r = 1:R 126 | Az(innz(cnnz_A(r)+1:cnnz_A(r+1)),r) = 1; 127 | end 128 | else 129 | while 1 130 | Az = binornd(1,density,[I(1) R]); 131 | dd = pdist(Az',@(x,y) sum(bsxfun(@and,x,y),2)>= bsxfun(@min,sum(y,2),sum(x))); 132 | if all(dd==0) 133 | break 134 | end 135 | end 136 | end 137 | 138 | end -------------------------------------------------------------------------------- /Deconvolution/tedia4R.m: -------------------------------------------------------------------------------- 1 | function [A0 B0 C0 T G X iter]=tedia4R(T0,numit,A0,B0,C0) 2 | % 3 | % Limit tensor diagonalization algorithm - version 1.0 4 | % 5 | % Input: cubic tensor of dimension n x n x n 6 | % Former output: matrices A,B,C such that 7 | % T = T0 x1 A x2 B x3 C is nearly diagonal (diagonal as much as possible) 8 | % 9 | % Initial matrice A0, B0, C0 are optional (if available, they can be used). 10 | % 11 | % Normalization: A,B,C are normalized so that det(A)=det(B)=det(C)=1. 12 | % There is no other normalization, therefore WN, without normalization. 13 | % 14 | % New output: A0=inv(A), B0=inv(B0), C0=inv(C) 15 | % T .... diagonalized (core) tensor 16 | % G .... matrix of gradients (should be zero at the end) 17 | % X .... matrix computed from T, revealing (block-)diagonality 18 | % iter ... criterion versus iteration 19 | % 20 | % Programmed: Petr Tichavsky, November 2013 21 | % 22 | [n,n1,n2,n3]=size(T0); 23 | it=0; 24 | if nargin<5 25 | A0 = eye(n); B0 = A0; C0=A0; T=T0; 26 | else 27 | T=multi(T0,inv(A0),inv(B0),inv(C0)); 28 | end 29 | eps=1e-6; 30 | tol=10; 31 | iter=kolik3(T); %%% criterion, counting sum of off-diagonal elements 32 | if nargin<2 33 | numit=20; 34 | end 35 | G=zeros(n,n); 36 | while iteps 37 | it=it+1; 38 | tol=0; 39 | A1=eye(n); B1=A1; C1=A1; T1=T; 40 | for i2=1:n 41 | for i1=[1:i2-1 i2+1:n] 42 | [A B C Ty val0 val1 nx S q]=onestepG(T,i1,i2); 43 | G(i1,i2)=norm(q); 44 | A1([i1 i2],:)=A*A1([i1 i2],:); B1([i1 i2],:)=B*B1([i1 i2],:); C1([i1 i2],:)=C*C1([i1 i2],:); 45 | T=Ty; 46 | tol=tol+nx; 47 | end 48 | end 49 | A0=A0/A1; B0=B0/B1; C0=C0/C1; 50 | valy=kolik3(T); 51 | iter=[iter valy]; 52 | end 53 | % iter 54 | Tx=sum(abs(T),4); 55 | X=sum(Tx,3)+squeeze(sum(Tx,2))+squeeze(sum(Tx,1)); 56 | J=serad(X+X'); 57 | X=X(J,J); 58 | T=T(J,J,J,:); 59 | A0=A0(:,J); 60 | B0=B0(:,J); 61 | C0=C0(:,J); 62 | end 63 | 64 | function [A B C T val0 val nx HH gg]=onestepG(T,i1,i2) 65 | [n,n1,n2,n3]=size(T); 66 | eps=1e-6; 67 | % val0=kolik3(T); 68 | val0=kolik5c(T,i1,i2); 69 | T1=T([i1 i2],[i1 i2],[i1,i2],:); T1=sum(T1.*conj(T1),4); 70 | t=[T1(1,1,1)+T1(2,2,2),T1(1,2,2)+T1(2,1,1) T1(2,2,1)+T1(1,1,2),T1(2,1,2)+T1(1,2,1)]; 71 | [m it]=max(t); 72 | switch it 73 | case 2 74 | T([i1,i2],:,:,:)=T([i2 i1],:,:,:); 75 | case 3 76 | T(:,:,[i1,i2],:)=T(:,:,[i2 i1],:); 77 | case 4 78 | T(:,[i1,i2],:,:)=T(:,[i2 i1],:,:); 79 | end 80 | d=n; 81 | Ds=sum(reshape(T([i1,i2],[i1,i2],:,:),2,2,n2*n3).^2,3); 82 | gg=sum(reshape(T(i2,i2,:,:).*T(i1,i1,:,:),1,n2*n3),2); Dx=sum(reshape(T(i1,i2,:,:).*T(i2,i1,:,:),1,n2*n3),2); 83 | E=permute(T([i1 i2],:,[i1 i2],:),[1 3 2 4]); 84 | Es=sum(reshape(E.^2,2,2,n2*n3),3); 85 | hh=sum(reshape(E(2,2,:,:).*E(1,1,:,:),1,n2*n3),2); Ex=sum(reshape(E(1,2,:,:).*E(2,1,:,:),1,n2*n3),2); 86 | F=permute(T(:,[i1 i2],[i1 i2],:),[2 3 1 4]); 87 | Fs=sum(reshape(F.^2,2,2,n2*n3),3); %Fs=sum(F([1,2],[1,2],:).^2,3); 88 | jj=sum(reshape(F(2,2,:,:).*F(1,1,:,:),1,n2*n3),2); Fx=sum(reshape(F(1,2,:,:).*F(2,1,:,:),1,n2*n3),2); 89 | X=zeros(6,6); 90 | h1=Dx+gg; h2=Ex+hh; h3=Fx+jj; 91 | aux=T(i1,:,:,:).*T(i2,:,:,:); ggg1=sum(aux(:)); 92 | aux=T(:,i1,:,:).*T(:,i2,:,:); ggg2=sum(aux(:)); 93 | aux=T(:,:,i1,:).*T(:,:,i2,:); ggg3=sum(aux(:)); 94 | aux=T(i1,:,:,:).^2; hhh(1)=sum(aux(:)); aux=T(i2,:,:,:).^2; hhh(2)=sum(aux(:)); 95 | aux=T(:,i1,:,:).^2; hhh(3)=sum(aux(:)); aux=T(:,i2,:,:).^2; hhh(4)=sum(aux(:)); 96 | aux=T(:,:,i1,:).^2; hhh(5)=sum(aux(:)); aux=T(:,:,i2,:).^2; hhh(6)=sum(aux(:)); 97 | hhx=hhh-sum([T(i1,i2,i2,:).^2 T(i2,i1,i1,:).^2 T(i2,i1,i2,:).^2 T(i1,i2,i1,:).^2 T(i2,i2,i1,:).^2 T(i1,i1,i2,:).^2],4); 98 | X(1,4)=h1; X(2,3)=h1; X(1,6)=h2; X(2,5)=h2; X(3,6)=h3; X(4,5)=h3; 99 | X(1,2)=0.5*(hhh(1)+hhh(2)-sum(T(i2,i2,i2,:).^2+T(i1,i1,i1,:).^2)); 100 | X(3,4)=0.5*(hhh(3)+hhh(4)-sum(T(i2,i2,i2,:).^2+T(i1,i1,i1,:).^2)); 101 | X(5,6)=0.5*(hhh(5)+hhh(6)-sum(T(i2,i2,i2,:).^2+T(i1,i1,i1,:).^2)); 102 | X(2,4)=h1 - sum(T(i1,i2,i1,:).*T(i2,i1,i1,:) + T(i1,i1,i1,:).*T(i2,i2,i1,:)); 103 | X(2,6)=h2 - sum(T(i1,i1,i2,:).*T(i2,i1,i1,:) + T(i1,i1,i1,:).*T(i2,i1,i2,:)); 104 | X(3,5)=h3 - sum(T(i2,i1,i1,:).*T(i2,i2,i2,:) + T(i2,i1,i2,:).*T(i2,i2,i1,:)); 105 | X(4,6)=h3 - sum(T(i1,i1,i2,:).*T(i1,i2,i1,:) + T(i1,i1,i1,:).*T(i1,i2,i2,:)); 106 | X(1,3)=h1 - sum(T(i1,i1,i2,:).*T(i2,i2,i2,:) + T(i1,i2,i2,:).*T(i2,i1,i2,:)); 107 | X(1,5)=h2 - sum(T(i1,i2,i1,:).*T(i2,i2,i2,:) + T(i1,i2,i2,:).*T(i2,i2,i1,:)); 108 | X=X+X'; 109 | gg=[ggg1-sum(T(i1,i2,i2,:).*T(i2,i2,i2,:)) ggg1-sum(T(i2,i1,i1,:).*T(i1,i1,i1,:)) ggg2-sum(T(i2,i1,i2,:).*T(i2,i2,i2,:)) ... 110 | ggg2-sum(T(i1,i2,i1,:).*T(i1,i1,i1,:)) ggg3-sum(T(i2,i2,i1,:).*T(i2,i2,i2,:)) ggg3-sum(T(i1,i1,i2,:).*T(i1,i1,i1,:))]; 111 | hh=gg; 112 | HH=X+diag(hhx); 113 | iH0=diag(HH)val0 134 | % criterion did not decrease => switch to damped GN algorithm 135 | % nx=1; 136 | mu=min(diag(HH)); 137 | end 138 | while val>val0 139 | x=-((HH+mu*eye(6))\gg')'; 140 | dx1=sqrt(1+x(1)*x(2)); dx2=sqrt(1+x(3)*x(4)); dx3=sqrt(1+x(5)*x(6)); 141 | A=[dx1 x(2); x(1) dx1]; B=[dx2 x(4); x(3) dx2]; C=[dx3 x(6); x(5) dx3]; 142 | T=T0; 143 | T([i1 i2],:,:,:) = reshape(A*reshape(T([i1 i2],:,:,:),2,[]),2,n1,n2,n3); 144 | T(:,[i1 i2],:,:) = permute(reshape(B*reshape(permute(T(:,[i1 i2],:),[2 1 3 4]),2,[]),2,n,n2,n3),[2 1 3 4]); 145 | T(:,:,[i1 i2],:) = permute(reshape(C*reshape(permute(T(:,:,[i1 i2],:),[3 1 2 4]),2,[]),2,n,n1,n3),[2 3 1 4]); 146 | if min([x(1)*x(2) x(3)*x(4) x(5)*x(6)])<-1 147 | val=1e10; 148 | else 149 | % val=kolik3(T); 150 | val=kolik5c(T,i1,i2); 151 | end 152 | mu=2*mu; 153 | end 154 | switch it 155 | case 2 156 | A=A(:,[2 1]); 157 | case 3 158 | C=C(:,[2 1]); 159 | case 4 160 | B=B(:,[2 1]); 161 | end 162 | end 163 | 164 | function val=kolik3(T) 165 | [n n2 n3 n4]=size(T); 166 | T=reshape(T,n*n2*n3,n4); 167 | T(1:n^2+n+1:n^3,:)=0; 168 | val=sum(T(:).*conj(T(:))); 169 | end 170 | 171 | function val=kolik5c(T,i1,i2) 172 | % 173 | [n1 n2 n3 n4]=size(T); 174 | T6=T([i1 i2],[i1 i2],:,:); T7=T(:,[i1 i2],[i1 i2],:); T8=T([i1 i2],:,[i1 i2],:); 175 | T4=reshape(T([i1 i2],[i1 i2],[i1 i2],:),8,n4); 176 | T1=T([i1 i2],:,:,:); T2=T(:,[i1 i2],:,:); T3=T(:,:,[i1 i2],:); 177 | val=sum(T1(:).*conj(T1(:)))+sum(T2(:).*conj(T2(:)))+sum(T3(:).*conj(T3(:)))... 178 | -sum(T6(:).*conj(T6(:)))-sum(T7(:).*conj(T7(:)))-sum(T8(:).*conj(T8(:)))+sum(sum(T4(2:7,:).*conj(T4(2:7,:)))); 179 | end 180 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 181 | function ord=serad(X) 182 | % 183 | % Hierarchical clustering for tensor diagonalization 184 | % Input: matrix of similarities (symmetric, nonnegative elements) 185 | % Output: order of components such that X(ord,ord) is approximately block diagonal 186 | % 187 | % Coded: Petr Tichavsky, November 2013 188 | [n n2]=size(X); 189 | X(1:n+1:n^2)=0; 190 | if sum(X(:).^2)<1e-6 191 | ord=1:n; 192 | else 193 | srt=repmat((1:n)',1,n); 194 | len=ones(n,1); 195 | for in=n:-1:2 196 | [m1,ii]=max(X(1:in,1:in)); 197 | [m2 i1]=max(m1); 198 | [m3 i2]=max(X(:,i1)); 199 | if i1>i2 200 | aux=i1; i1=i2; i2=aux; 201 | end 202 | lennew=len(i1)+len(i2); 203 | srtnew=[srt(i1,1:len(i1)) srt(i2,1:len(i2)) zeros(1,n-lennew)]; 204 | indl=[1:i1-1 i1+1:i2-1 i2+1:in]; 205 | Xnew=(len(i1)*X(i1,indl)+len(i2)*X(i2,indl))/lennew; 206 | X=[0 Xnew; Xnew' X(indl,indl)]; 207 | srt=[srtnew; srt(indl,:)]; 208 | len=[lennew; len(indl)]; 209 | end 210 | ord=srt(1,:); 211 | end 212 | end 213 | 214 | function T2=multi(T,A,B,C) 215 | [n1 n2 n3]=size(T); 216 | r1=size(A,1); r2=size(B,1); r3=size(C,1); 217 | T1=A*reshape(T,n1,n2*n3); 218 | T2=reshape(T1,r1*n2,n3)*C.'; 219 | T2=permute(reshape(B*reshape(permute(reshape(T2,r1,n2,r3),[2 1 3]),n2,r1*r3),r2,r1,r3),[2 1 3]); 220 | end -------------------------------------------------------------------------------- /Deconvolution/toeplitz_factor.m: -------------------------------------------------------------------------------- 1 | function [H,S,s,err]=toeplitz_factor(X) 2 | %TOEPLITZ_FACTOR Factorize X as X=H*S with H unstructured and S Toeplitz. 3 | % Works for real and complex data. 4 | % PROBLEM: 5 | % Factorize an LxJ observed matrix X (J>L) as 6 | % X = H * S, 7 | % where H is LxL and S is an LxJ Toeplitz matrix 8 | % 9 | % INPUT: 10 | % - X : full row-rank matrix LxJ (J>L) 11 | % 12 | % OUTPUTS: 13 | % - H (LxL) : estimate of H 14 | % - S (LxJ) : estimate of S 15 | % - s = {s1,s2} : cell holding the generator vectors of S, 16 | % s1 (1xL) is the first column of S, 17 | % s2 (1xJ) is the first row of S, with s1(1)=s2(1), 18 | % such that S=toeplitz(s1,s2); 19 | % - err : frobenius norm of residual, i.e., norm(X-H*S,'fro') 20 | % 21 | % REFERENCE: 22 | % E. Moulines, P. Duhamel, J.-F. Cardoso and S. Mayrargue, "Subspace Methods for 23 | % the Blind Identification of Multichannel FIR Filters", IEEE Trans. on Signal 24 | % Processing, vol. 43, no.2, Feb. 1995 25 | % 26 | % EXAMPLE: 27 | % J=20; 28 | % L=6; 29 | % SNR=inf; % Signal To Noise Ratio in dB, choose SNR=inf for an exact model 30 | % s1=randn(1,L)+j*randn(1,L); 31 | % s2=randn(1,J)+j*randn(1,J); 32 | % s2(1)=s1(1); 33 | % s={s1,s2}; 34 | % S=toeplitz(s1,s2); 35 | % H=randn(L,L)+j*randn(L,L); 36 | % X=H*S; 37 | % [H_est,S_est,s_est,err]=toeplitz_factor(X); 38 | 39 | % @Copyright 2008 40 | % Dimitri Nion (feedback: dimitri.nion@gmail.com) 41 | % 42 | % For non-commercial use only 43 | % 44 | % Fast version is implemented in Aug, 2014 by Phan Anh Huy 45 | 46 | 47 | [L J]=size(X); 48 | if L>J 49 | error('The input observed matrix has to be fat') 50 | end 51 | 52 | %---------------------------------------------- 53 | % STEP 1 : estimate noise subspace from SVD 54 | %---------------------------------------------- 55 | [U temp temp]=svd(X.'); 56 | 57 | %-------------------------------- 58 | % STEP 2 : Compute quadartic form 59 | %-------------------------------- 60 | % Fast computation : Anh Huy Phan Aug, 2014 61 | if L> J/2 62 | Q=zeros(J+L-1,J+L-1); 63 | Un=U(:,L+1:J); 64 | for p=1:J-L 65 | u_gen=Un(:,p); 66 | Up=toeplitz([u_gen(end:-1:1).', zeros(1,L-1)],[Un(end,p),zeros(1,L-1)]); 67 | Q=Q+Up*Up'; 68 | end 69 | else 70 | Q=zeros(J+L-1,J+L-1); 71 | for p=1:L 72 | u_gen=U(:,p); 73 | Up=toeplitz([u_gen(end:-1:1).', zeros(1,L-1)],[U(end,p),zeros(1,L-1)]); 74 | Q=Q+Up*Up'; 75 | end 76 | Q = diag([1:L-1 L*ones(1,J-L+1) L-1:-1:1]) - Q; 77 | end 78 | 79 | %------------------------------------------------------------- 80 | % STEP 3 : Minimization of quadratic form 81 | % take the eigenvector associated to the smallest eigenvalue 82 | %------------------------------------------------------------- 83 | % [Eq Dq]=eig(Q); 84 | % Dq=diag(Dq); 85 | % m=find(Dq==min(Dq)); 86 | % sg=Eq(:,m); % noise eigenvector associated to smallest eigenvalue 87 | [sg,dqs] = eigs(Q,1,'SM'); % Anh Huy Phan Aug, 2014 88 | sg=sg(end:-1:1).'; % generator vector of Toeplitz matrix 89 | s1=sg(L:-1:1); % first column of Toeplitz matrix 90 | s2=sg(L:end); % first row 91 | s={s1,s2}; % output s 92 | S=toeplitz(s1,s2); % fat toeplitz matrix 93 | H=X/S; % Estimate matrix H 94 | err=norm(X-H*S,'fro'); -------------------------------------------------------------------------------- /Deconvolution/ts_deconv_init.m: -------------------------------------------------------------------------------- 1 | function [H,U] = ts_deconv_init(X,R,J,opts) 2 | % Initialization for the rank-1 tensor deconvolution 3 | % 4 | % R: number of rank-1 terms 5 | % J: size of patten tensors 6 | % opts.init = 'cpd1', 'cpd2','random' or 'tedia' 7 | % 8 | % REF: 9 | % 10 | % [1] A. -H. Phan , P. Tichavsk?, and A. Cichocki, Low rank tensor 11 | % deconvolution, in IEEE International Conference on Acoustics, Speech and 12 | % Signal Processing (ICASSP), pp. 2169 - 2173, 2015. 13 | % 14 | % TENSOR BOX, v.2015 15 | 16 | %% Set algorithm parameters from input or by using defaults 17 | param = inputParser; 18 | param.KeepUnmatched = true; 19 | param.addOptional('init','cpd1',@(x) (iscell(x) || isa(x,'ktensor')||... 20 | ((numel(x)>3) && ismember(x(1:4),{'rand' 'tedi' 'cpd1' 'cpd2'}) ))); 21 | param.addOptional('exec_func',@ts_deconv_rank1_als,@(x) isa(x,'function_handle')); 22 | 23 | if ~exist('opts','var'), opts = struct; end 24 | param.parse(opts);param = param.Results; 25 | if nargin == 0 26 | H = param; return 27 | end 28 | 29 | N = ndims(X); 30 | 31 | %% Initialization TEDIA to the compressed data using Tucker decomposition 32 | % Tucker Compression to size of RJ x RJ 33 | % init = 'tedia'; 34 | % init = 'cpd'; 35 | % Stage1: Generate initial point using TEDIA or CPD 36 | init = param.init; 37 | SzX = size(X); 38 | 39 | if iscell(init) 40 | 41 | if (numel(init)== 2) && iscell(init{1}) && iscell(init{2}) && ... 42 | (numel(init{1}) == numel(init{2})) && ... 43 | all(diff(cell2mat(cellfun(@size,init{1},'uni',0)))==0) && ... 44 | all(diff(cell2mat(cellfun(@size,init{2},'uni',0)))==0) 45 | 46 | U = init{2}; H = init{1}; 47 | 48 | else % small iteratons to find the best initialization 49 | 50 | %normX = norm(X(:)); 51 | bestfit = 0;Pbest = {}; 52 | for ki = 1:numel(init) 53 | initk = param.init{ki}; 54 | if iscell(initk) || ... 55 | (ischar(initk) && ismember(initk(1:4), ... 56 | {'rand' 'cpd1' 'cpd2' 'tedi'})) % multi-initialization 57 | if ischar(initk) 58 | cprintf('blue','Init. %d - %s\n',ki,initk) 59 | else 60 | cprintf('blue','Init. %d - %s\n',ki,class(initk)) 61 | end 62 | 63 | initparam = param;initparam.maxiters = 10; 64 | initparam.init = initk; 65 | [H,U] = ts_deconv_init(X,R,J,initparam); 66 | [H,U,output] = param.exec_func(X,U,H,initparam); 67 | 68 | fitinit = 1- output.Error(end); 69 | if real(fitinit) > bestfit 70 | Pbest = {H,U}; 71 | bestfit = fitinit;kibest = ki; 72 | end 73 | end 74 | end 75 | cprintf('blue','Choose the best initial value: %d.\n',kibest); 76 | H = Pbest{1}; 77 | U = Pbest{2}; 78 | 79 | end 80 | 81 | elseif ischar(init) 82 | 83 | switch init 84 | case 'random' 85 | U = cell(N,1); 86 | for n = 1:N 87 | U{n} = randn(SzX(n),J(n),R); 88 | end 89 | 90 | case 'tedia' 91 | if J(N) ~= 1 92 | Xc = mtucker_als(tensor(X),R*max(J)*ones(1,N),struct('dimorder',1:N)); 93 | Utd = cell(N,1); 94 | 95 | [Utd{1} Utd{2} Utd{3} St G xblk iter]=tedia4R(double(Xc.core),100); 96 | Utd = cellfun(@(x,y) x*y, Xc.U,Utd,'uni',0); 97 | 98 | 99 | else 100 | % Tucker Compression to size of RJ x RJ 101 | Xc = mtucker_als(tensor(X),R*max(J)*ones(1,N-1),struct('dimorder',1:N-1)); 102 | 103 | % TEDIA to the compressed tensor Xc.core 104 | Utd = cell(N-1,1); 105 | [Utd{1} Utd{2} St xblk iter]=tedia2P(double(Xc.core)/max(abs(double(Xc.core(:)))),1000); 106 | Utd = cellfun(@(x,y) x*real(y),Xc.U(1:N-1),Utd,'uni',0); 107 | end 108 | 109 | 110 | % Sts = sum(abs(St),4); 111 | % Visualize the diagonal block structure 112 | % figure(1); clf; 113 | % imagesc(xblk) 114 | 115 | 116 | % Generate Toeplitz matrices from outcomes of TEDIA 117 | U = cell(N,1); 118 | for n = 1:N 119 | if J(n) ~= 1 120 | U{n} = reshape(Utd{n},size(Utd{n},1),[],R); 121 | for r = 1:R 122 | [u_est,Sr_est,s_est,err] = toeplitz_factor(U{n}(:,:,r).'); 123 | U{n}(:,:,r) = Sr_est.'; 124 | end 125 | U{n} = U{n}(:,1:J(n),:); 126 | end 127 | end 128 | 129 | case 'cpd1' 130 | 131 | % CPD -based initialization 132 | opts = cp_fLMa; 133 | opts.init = {'dtld' 'nvec' 'random' 'random' 'random'}; 134 | opts.maxiters = 1000; 135 | opts.printitn = 1; 136 | if R<=20 137 | Pcp = cp_fLMa(tensor(squeeze(sum(double(X),N+1))),R,opts); 138 | else 139 | opts.linesearch = true; 140 | Pcp = cp_fastals(tensor(squeeze(sum(double(X),N+1))),R,opts); 141 | end 142 | 143 | SzX = size(X); 144 | U = cell(N,1); 145 | for n = 1:N 146 | U{n} = zeros(SzX(n),J(n),R); 147 | for r = 1:R 148 | U{n}(:,:,r) = convmtx(Pcp.u{n}(1:SzX(n)-J(n)+1,r),J(n)); 149 | end 150 | end 151 | 152 | 153 | case 'cpd2' 154 | % CPD -based initialization 155 | opts = cp_fLMa; 156 | opts.init = {'dtld' 'nvec' 'random' 'random' 'random'}; 157 | opts.maxiters = 1000; 158 | opts.printitn = 1; 159 | 160 | if R*max(J)<30 161 | Pcp = cp_fLMa(tensor(squeeze(sum(double(X),N+1))),R*max(J),opts); 162 | else 163 | opts.linesearch = true; 164 | Pcp = cp_fastals(tensor(squeeze(sum(double(X),N+1))),R*max(J),opts); 165 | end 166 | 167 | %Pcp = cp_fLMa(tensor(squeeze(sum(double(X),N+1))),R*max(J),opts); 168 | [Perm,P] = perm_vectranst(max(J),R); 169 | Ucp = cellfun(@(x) x(:,Perm),Pcp.u,'uni',0); 170 | 171 | % Generate Toeplitz matrices from outcomes of TEDIA 172 | U = cell(N,1); 173 | for n = 1:N 174 | if J(n) ~= 1 175 | U{n} = reshape(Ucp{n},size(Ucp{n},1),[],R); 176 | for r = 1:R 177 | [u_est,Sr_est,s_est,err] = toeplitz_factor(U{n}(:,:,r).'); 178 | U{n}(:,:,r) = Sr_est.'; 179 | end 180 | U{n} = U{n}(:,1:J(n),:); 181 | end 182 | end 183 | 184 | end 185 | 186 | % Estimate Hr 187 | if J(N) ~= 1 188 | LN = prod(J); 189 | ZZ2 = zeros(LN*R,LN*R); 190 | ZY = zeros(LN*R,1); 191 | for r = 1:R 192 | for s = r:R 193 | temp = U{1}(:,:,r)'*U{1}(:,:,s); 194 | for n = 2:N 195 | temp = kron(U{n}(:,:,r)'*U{n}(:,:,s),temp); 196 | end 197 | ZZ2(LN*(r-1)+1:LN*r,LN*(s-1)+1:LN*s) = temp; 198 | ZZ2(LN*(s-1)+1:LN*s,LN*(r-1)+1:LN*r) = temp'; 199 | end 200 | 201 | Ur = cellfun(@(x) x(:,:,r), U,'uni',0); 202 | zy = ttm(tensor(X),Ur,1:N,'t'); 203 | zy = reshape(double(zy),LN,[]); 204 | 205 | ZY(LN*(r-1)+1:LN*r,:) = zy; 206 | end 207 | HH = pinv(ZZ2)*ZY; % RLP*I% HH = ZZ \ YH; % RLP*I 208 | H = tensor(HH', [1 J R]); 209 | 210 | else 211 | 212 | LN = prod(J); 213 | ZZ2 = zeros(LN*R,LN*R); 214 | ZY = zeros(LN*R,SzX(N)); 215 | for r = 1:R 216 | for s = r:R 217 | temp = U{1}(:,:,r)'*U{1}(:,:,s); 218 | for n = 2:N-1 219 | temp = kron(U{n}(:,:,r)'*U{n}(:,:,s),temp); 220 | end 221 | ZZ2(LN*(r-1)+1:LN*r,LN*(s-1)+1:LN*s) = temp; 222 | ZZ2(LN*(s-1)+1:LN*s,LN*(r-1)+1:LN*r) = temp'; 223 | end 224 | 225 | Ur = cellfun(@(x) x(:,:,r),U(1:N-1),'uni',0); 226 | zy = ttm(tensor(X),Ur,1:N-1,'t'); 227 | 228 | ZY(LN*(r-1)+1:LN*r,:) = reshape(double(zy),[],SzX(N)); 229 | end 230 | HH = pinv(ZZ2)*ZY; 231 | 232 | HH = reshape(HH',[SzX(N) prod(J) R]); 233 | H = zeros(prod(J),R); 234 | for r = 1:R 235 | [u,s,v] = svds(HH(:,:,r),1); 236 | U{N}(:,1,r) = u; 237 | H(:,r) = s*v; 238 | end 239 | 240 | H = tensor(H, [1 J R]); 241 | end 242 | end 243 | end -------------------------------------------------------------------------------- /Denoising/function_LumChrom2rgb.m: -------------------------------------------------------------------------------- 1 | 2 | 3 | function yRGB=function_LumChrom2rgb(x,colormode) 4 | % Inverse color-space transformation ( forward transformation is function_rgb2LumChrom.m ) 5 | % 6 | % Alessandro Foi - Tampere University of Technology - 2005 - 2006 Public release v1.03 (March 2006) 7 | % ----------------------------------------------------------------------------------------------------------------------------------------------- 8 | % 9 | % SYNTAX: 10 | % 11 | % yRGB = function_LumChrom2rgb(x,colormode); 12 | % 13 | % INPUTS: 14 | % x is color-transformed image (with range typically included in or equal to [0 1]^3, depending on the transformation matrix) 15 | % 16 | % colormode = 'opp', 'yCbCr', or a custom 3x3 matrix (e.g. provided by the forward transform when 'pca' is selected) 17 | % 18 | % 'opp' opponent color space ('opp' is equirange version) 19 | % 'yCbCr' standard yCbCr (e.g. for JPEG images) 20 | % 21 | % OUTPUTS: 22 | % x is RGB image (with range [0 1]^3) 23 | % 24 | % 25 | % NOTE: 'opp' is used by default if no colormode is specified 26 | % 27 | 28 | if nargin==1 29 | colormode='opp'; 30 | end 31 | if size(colormode)==[3 3] 32 | A=colormode; 33 | B=inv(A); 34 | else 35 | if strcmp(colormode,'opp') 36 | A =[1/3 1/3 1/3; 0.5 0 -0.5; 0.25 -0.5 0.25]; 37 | B =[1 1 2/3;1 0 -4/3;1 -1 2/3]; 38 | end 39 | if strcmp(colormode,'yCbCr') 40 | A=[0.299 0.587 0.114; -0.16873660714285 -0.33126339285715 0.5; 0.5 -0.4186875 -0.0813125]; 41 | B=inv(A); 42 | end 43 | end 44 | 45 | %%%% Make sure that each channel's intensity range is [0,1] 46 | maxV = sum(A.*(A>0),2); 47 | minV = sum(A.*(A<0),2); 48 | xNormal = reshape(x,[size(x,1)*size(x,2) 3]) * diag(maxV-minV) + repmat(minV, [1 size(x,1)*size(x,2)])'; % put in range [0,1] 49 | yRGB = reshape(xNormal * B', [ size(x,1) size(x,2) 3]); 50 | 51 | return; 52 | -------------------------------------------------------------------------------- /Denoising/function_rgb2LumChrom.m: -------------------------------------------------------------------------------- 1 | function [y, A, l2normLumChrom]=function_rgb2LumChrom(xRGB, colormode) 2 | % Forward color-space transformation ( inverse transformation is function_LumChrom2rgb.m ) 3 | % 4 | % Alessandro Foi - Tampere University of Technology - 2005 - 2006 Public release v1.03 (March 2006) 5 | % ----------------------------------------------------------------------------------------------------------------------------------------------- 6 | % 7 | % SYNTAX: 8 | % 9 | % [y A l2normLumChrom] = function_rgb2LumChrom(xRGB, colormode); 10 | % 11 | % INPUTS: 12 | % xRGB is RGB image with range [0 1]^3 13 | % 14 | % colormode = 'opp', 'yCbCr', 'pca', or a custom 3x3 matrix 15 | % 16 | % 'opp' Opponent color space ('opp' is equirange version) 17 | % 'yCbCr' The standard yCbCr (e.g. for JPEG images) 18 | % 'pca' Principal components (note that this transformation is renormalized to be equirange) 19 | % 20 | % OUTPUTS: 21 | % y is color-transformed image (with range typically included in or equal to [0 1]^3, depending on the transformation matrix) 22 | % 23 | % l2normLumChrom (optional) l2-norm of the transformation (useful for noise std calculation) 24 | % A transformation matrix (used necessarily if colormode='pca') 25 | % 26 | % NOTES: - If only two outputs are used, then the second output is l2normLumChrom, unless colormode='pca'; 27 | % - 'opp' is used by default if no colormode is specified. 28 | % 29 | % 30 | % USAGE EXAMPLE FOR PCA TRANSFORMATION: 31 | % %%%% -- forward color transformation -- 32 | % if colormode=='pca' 33 | % [zLumChrom colormode] = function_rgb2LumChrom(zRGB,colormode); % 'colormode' is assigned a 3x3 transform matrix 34 | % else 35 | % zLumChrom = function_rgb2LumChrom(zRGB,colormode); 36 | % end 37 | % 38 | % %%%% [ ... ] Some processing [ ... ] 39 | % 40 | % %%%% -- inverse color transformation -- 41 | % zRGB=function_LumChrom2rgb(zLumChrom,colormode); 42 | % 43 | 44 | if nargin==1 45 | colormode='opp'; 46 | end 47 | change_output=0; 48 | if size(colormode)==[3 3] 49 | A=colormode; 50 | l2normLumChrom=sqrt(sum(A.^2,2)); 51 | else 52 | if strcmp(colormode,'opp') 53 | A=[1/3 1/3 1/3; 0.5 0 -0.5; 0.25 -0.5 0.25]; 54 | end 55 | if strcmp(colormode,'yCbCr') 56 | A=[0.299 0.587 0.114; -0.16873660714285 -0.33126339285715 0.5; 0.5 -0.4186875 -0.0813125]; 57 | end 58 | if strcmp(colormode,'pca') 59 | A=princomp(reshape(xRGB,[size(xRGB,1)*size(xRGB,2) 3]))'; 60 | A=A./repmat(sum(A.*(A>0),2)-sum(A.*(A<0),2),[1 3]); %% ranges are normalized to unitary length; 61 | else 62 | if nargout==2 63 | change_output=1; 64 | end 65 | end 66 | end 67 | 68 | %%%% Make sure that each channel's intensity range is [0,1] 69 | maxV = sum(A.*(A>0),2); 70 | minV = sum(A.*(A<0),2); 71 | yNormal = (reshape(xRGB,[size(xRGB,1)*size(xRGB,2) 3]) * A' - repmat(minV, [1 size(xRGB,1)*size(xRGB,2)])') * diag(1./(maxV-minV)); % put in range [0,1] 72 | y = reshape(yNormal, [size(xRGB,1) size(xRGB,2) 3]); 73 | 74 | %%%% The l2-norm of each of the 3 transform basis elements 75 | l2normLumChrom = diag(1./(maxV-minV))*sqrt(sum(A.^2,2)); 76 | 77 | if change_output 78 | A=l2normLumChrom; 79 | end 80 | 81 | return; -------------------------------------------------------------------------------- /Denoising/tt_block_denoise.m: -------------------------------------------------------------------------------- 1 | function rec_block = tt_block_denoise(block_struct,Y,noise_level) 2 | % 3 | % TENSORBOX, 2018 4 | 5 | %% 6 | %cprintf('r_','(%d,%d)',i,j) 7 | % select block 8 | fprintf('(%d,%d)\n',block_struct.location(1),block_struct.location(2)) 9 | % rec_block = nan(block_struct.blockSize); 10 | 11 | % return 12 | blk_data = block_struct.data; 13 | 14 | blk_size_x = block_struct.blockSize; 15 | if (blk_size_x(1) ~= blk_size_x(2)) || any(blk_size_x~= 24) 16 | rec_block = nan(size(blk_data)); 17 | return 18 | end 19 | blk_size= blk_size_x/3; 20 | % select blocks which are similar to the center block, i.e., (2,2) 21 | ctr_blk = blk_data(blk_size(1)+1:2*blk_size(1),blk_size(2)+1:2*blk_size(2),:); 22 | 23 | 24 | %% select blocks which are similar to the current block 25 | step = [4 4]; 26 | Noshifts = prod(2*step+1); 27 | cnt = 1; 28 | sel_blocks = zeros([blk_size*3 size(ctr_blk,3)]); 29 | xc_sel = []; 30 | for kshift = 1:Noshifts 31 | shift_ix = ind2sub_full(2*step+1,kshift); 32 | shift_ix = shift_ix - step - 1; 33 | Ys = circshift(Y,shift_ix); 34 | 35 | xfun = @(block_struct,ref) corr2(block_struct.data,ref); 36 | xc_blk = blockproc(Ys,blk_size,@(x) xfun(x,ctr_blk)); 37 | [xc_blks,ii] = sort(abs(xc_blk(:)),'descend'); 38 | if xc_blks(1) == 1 39 | xc_blks(1) = []; 40 | ii(1) = []; 41 | end 42 | 43 | ii = ii((xc_blks>.3)); 44 | sub_ii = ind2sub_full(size(xc_blk),ii); 45 | sub_ii = blk_size(1)*(sub_ii-1)+1; 46 | 47 | if ~isempty(ii) 48 | for ki = 1:numel(ii) 49 | try 50 | sel_blocks(:,:,cnt) = Ys(sub_ii(ki,1)-blk_size(1):sub_ii(ki,1)+blk_size(1)*2-1,... 51 | sub_ii(ki,2)-blk_size(2):sub_ii(ki,2)+blk_size(2)*2-1,:); 52 | 53 | xc_sel(cnt) = xc_blks(ki); 54 | cnt = cnt+1; 55 | catch 56 | % sub_ii(ki,:) 57 | end 58 | end 59 | else 60 | % % 111 61 | end 62 | end 63 | size(sel_blocks) 64 | 65 | %% REshape the selected blocks 66 | if cnt > 1 67 | data_sel = cat(3,blk_data,sel_blocks); 68 | else 69 | data_sel = blk_data; 70 | end 71 | data_sel = permute(reshape(data_sel,blk_size(1),3,blk_size(2),3,[]),[1 3 2 4 5]); 72 | data_sel = reshape(data_sel,blk_size(1),blk_size(2),3,3,[]); 73 | 74 | % mean_blk = mean(mean(data_sel,1),2); 75 | % data_sel = bsxfun(@minus,data_sel,mean_blk); 76 | 77 | mean_blk = mean(mean(mean(data_sel,5),4),3); 78 | data_sel = bsxfun(@minus,data_sel,mean_blk); 79 | 80 | %% TT-decomposition 81 | % tt_1 = tt_tensor(data_sel,1e-3); 82 | 83 | %noise_level = sigma_noise^2*numel(data_sel)*(ndims(data_sel)-1); 84 | % noise_level = sigma_noise^2*numel(data_sel)*sqrt(2)*factx; 85 | %tt_1 = tt_tensor(data_sel,noise_level); 86 | 87 | accuracy = noise_level^2*numel(data_sel)*sqrt(2); 88 | 89 | tt_1 = tt_tensor_denoise(data_sel,accuracy); 90 | 91 | % err0 = norm(data_sel(:) - full(tt_1))^2/norm(data_sel(:))^2; 92 | % % 93 | % err0 94 | 95 | tt_2 = tt_1; 96 | 97 | % fig = figure(1); 98 | % clf; hold on 99 | % clear h 100 | % h(1) = plot(1,err0,'o'); 101 | % set(h(1),'markersize',18) 102 | % 103 | 104 | % % 2a ACULRO to data 105 | % rankR = []; 106 | % opts = tt_aculro; 107 | % opts.compression = 0; 108 | % opts.maxiters = 200;%maxiters; 109 | % opts.tol = 1e-6; 110 | % opts.init = tt_1; 111 | % %noise_level = sigma_noise^2*numel(data_sel); 112 | % % noise_level = 1e-2; 113 | % opts.noise_level = noise_level;% * prod(size(Y)); 114 | % 115 | % 116 | % % ACULRO to data Y 117 | % tic 118 | % [tt_2,out2a] = tt_aculro(data_sel,rankR,opts); 119 | % t2a = toc; 120 | 121 | 122 | % err1 = 1-out2a.Fit; 123 | % 124 | % fig = figure(1); hold on 125 | % h(2) = plot(err1); 126 | % set(h(2),'linestyle','--','linewidth',3) 127 | % 128 | % 129 | tt_2x = reshape(full(tt_2),size(tt_2)); 130 | tt_2x = bsxfun(@plus,tt_2x,mean_blk); 131 | 132 | tt_2x = ipermute(reshape(tt_2x(:,:,:,:,1),blk_size(1),blk_size(2),3,3),[1 3 2 4]); 133 | tt_2x = reshape(tt_2x,blk_size*3); 134 | rec_block = tt_2x; 135 | 136 | % imagesc(upd) 137 | end -------------------------------------------------------------------------------- /Denoising/tt_image_denoising_neighbour_.m: -------------------------------------------------------------------------------- 1 | function Yhm = tt_image_denoising_neighbour_(Y,blk_size,neighb_range,sigma_noise, decomposition_method,shiftstep,get_rank,colorspace,Y0,im_name_) 2 | %%% 3 | % TENSORBOX, 2018 4 | 5 | if nargin < 2 6 | blk_size = 8 * ones(1,2); % block size s 7 | end 8 | if nargin < 3 9 | neighb_range = 3; 10 | end 11 | if nargin <4 12 | % if noise level is not provided, it will be estimated from high 13 | % frequency coefficients 14 | sigma_noise = noise_estimate(Y); 15 | end 16 | if nargin < 5 17 | % TT-algorithm to decompose a tensor 18 | decomposition_method = 'tt_ascu'; %% tt_truncation, cpd, tucker 19 | end 20 | if nargin < 6 21 | shiftstep = 2; 22 | end 23 | 24 | if nargin < 7 25 | get_rank = false; 26 | end 27 | 28 | if nargin < 8 29 | colorspace = 'rgb'; % 'opp 30 | end 31 | 32 | if nargin<10 33 | im_name_ = 'im'; 34 | end 35 | 36 | step = ceil((blk_size(1)+neighb_range*2)/2); 37 | 38 | shift_ix = unique([-step:shiftstep:step 0]); 39 | Noshifts = numel(shift_ix)^2; 40 | Yh = nan(numel(Y),Noshifts); 41 | 42 | % Parameters for the denoising 43 | tt_options = tt_block_denoise_neighbour; 44 | tt_options.noise_level = sigma_noise; 45 | tt_options.neighb_range = neighb_range; 46 | tt_options.block_size = blk_size; 47 | tt_options.spatial_dictionary = 'dct'; % or predefined dictionary 48 | tt_options.decomposition_method = decomposition_method; % truncation or alternating update with noise given 49 | tt_options.get_rank = get_rank; 50 | 51 | 52 | %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 53 | %%%% Change colorspace, compute the l2-norms of the new color channels 54 | %%%% 55 | if strcmp(colorspace,'opp') 56 | % transform the image to another color space 57 | [Y A l2normLumChrom] = function_rgb2LumChrom(Y, 'opp'); 58 | % compute the scaling factor for the noise level 59 | 60 | % the noise level is recalculated after transforming the image % 61 | % 62 | % |Y-Yn|_F^2 = sigma^2 * No_pixels * N_color_layers 63 | % 64 | % N_color_layers = 3 65 | % 66 | % Denote A the linear transform , 67 | % E = Y-Yn = sigma* sqrt(No_pixels) * I_N_layer 68 | % then 69 | % |(Y-Yn)*A|_F^2 = trace(A' * E'*E*A) 70 | % = sigma^2* No_pixels * trace(A'*A) 71 | % = sigma^2* No_pixels * |A|_F^2 72 | N_layers = size(Y,3); 73 | sigma_noise = sigma_noise * norm(A(:))/sqrt(N_layers); 74 | tt_options.noise_level = sigma_noise; 75 | end 76 | 77 | %% 78 | tt_options.process_name = im_name_; 79 | fprocessed_ = sprintf('%s_block_processed',im_name_); 80 | 81 | kshift = 0; 82 | %% Shift the data to fast block processing 83 | for s1 = shift_ix 84 | for s2 = shift_ix 85 | 86 | 87 | kshift = kshift+1; 88 | fprintf('Shift %d/%d \n' , kshift,Noshifts) 89 | shift_ix2 = [s1 s2]; 90 | 91 | fcurr_block_processed = sprintf('%s_%d.mat',fprocessed_,kshift); 92 | 93 | Yshift = circshift(Y,shift_ix2); 94 | tt_options.process_id = kshift; 95 | 96 | %% Process blockes 8x8 and its neighbours 97 | tic 98 | Yx_shift = blockproc(Yshift,blk_size+2*neighb_range,... 99 | @(x) tt_block_denoise_neighbour(x,Yshift,tt_options),... 100 | 'UseParallel',true); 101 | toc 102 | 103 | % tic 104 | % Yx_shift = blockproc(Yshift,blk_size+2*neighb_range+2,... 105 | % @(x) tt_block_denoise_neighbour_level2(x,Yshift,tt_options),... 106 | % 'UseParallel',true); 107 | % toc 108 | Yx_shifti = circshift(Yx_shift,-shift_ix2); 109 | Yh(:,kshift) = Yx_shifti(:); 110 | 111 | 112 | save(fcurr_block_processed,'kshift','Yx_shifti'); 113 | 114 | end 115 | end 116 | 117 | %% Reconstruct the image 118 | Yhm = nanmedian(Yh,2); 119 | Yhm = reshape(Yhm,size(Y)); 120 | Yhm(isnan(Yhm)) = Y(isnan(Yhm)); 121 | 122 | %% Convert back to RGB colorspace 123 | if strcmp(colorspace,'opp') 124 | Yhm = function_LumChrom2rgb(Yhm, 'opp'); 125 | end 126 | -------------------------------------------------------------------------------- /Denoising/tt_tensor_denoise.m: -------------------------------------------------------------------------------- 1 | function t = tt_tensor_denoise(varargin) 2 | %TT-tensor constructor 3 | % T=TT_TENSOR(ARRAY) Converts from a full array with accuracy 1e-14 4 | % T=TT_TENSOR(ARRAY,EPS) Converts from a full array with accuracy EPS 5 | % T=TT_TENSOR(ARRAY,EPS,SZ,R1,R2) Converts from a full array which is 6 | % treated as an array with mode sizes SZ and tail ranks R1 and R2. The 7 | % accuracy is set to EPS 8 | % 9 | % T=TT_TENSOR(TT1) Copies TT1 to TT 10 | % 11 | % T=TT_TENSOR(TT_MATRIX) Unfolds a TT-matrix into a TT-tensor 12 | % 13 | % T=TT_TENSOR(TT_ARRAY) Unfolds a TT-array 14 | % 15 | % T=TT_TENSOR(FILENAME) Reads from the SDV format 16 | % 17 | % T=TT_TENSOR(CELL_ARRAY) Converts from TT1 format OR 18 | % 19 | % T=TT_TENSOR(CAN_CELL_ARRAY) Converts from the canonical format, given 20 | % as a cell array of factors 21 | % 22 | % 23 | % TT-Toolbox 2.2, 2009-2012 24 | % 25 | %This is TT Toolbox, written by Ivan Oseledets et al. 26 | %Institute of Numerical Mathematics, Moscow, Russia 27 | %webpage: http://spring.inm.ras.ru/osel 28 | % 29 | %For all questions, bugs and suggestions please mail 30 | %ivan.oseledets@gmail.com 31 | %--------------------------- 32 | 33 | if (nargin == 0) 34 | t.d = 0; 35 | t.r = 0; 36 | t.n = 0; 37 | t.core = 0; % empty tensor 38 | t.ps = 0; 39 | t.over = 0; % estimate of the rank over the optimal 40 | t = class(t, 'tt_tensor'); 41 | return; 42 | end 43 | 44 | % Copy CONSTRUCTOR 45 | if (nargin == 1) && isa(varargin{1}, 'tt_tensor') 46 | t = tt_tensor; 47 | t.d = varargin{1}.d; 48 | t.r = varargin{1}.r; 49 | t.n = varargin{1}.n; 50 | t.core=varargin{1}.core; 51 | t.ps = varargin{1}.ps; 52 | t.over = varargin{1}.over; 53 | return; 54 | end 55 | %From tt_matrix (unfold) 56 | if ( nargin == 1 ) && isa(varargin{1},'tt_matrix'); 57 | tm=varargin{1}; 58 | t=tm.tt; 59 | return; 60 | end 61 | %From tt_array (stack) 62 | if ( nargin == 1 ) && isa(varargin{1},'tt_array'); 63 | ta=varargin{1}; 64 | t=ta.tt; 65 | return; 66 | end 67 | %From old format 68 | if ( nargin == 1 ) && isa(varargin{1},'cell') 69 | %Check if it is a canonical format 70 | tt=varargin{1}; 71 | d=numel(tt); 72 | rc=zeros(d,1); 73 | all_2d=true; 74 | for i=1:d 75 | rc(i)=size(tt{i},2); 76 | if (size(tt{i},3) ~= 1 ) 77 | all_2d = false; 78 | end 79 | end 80 | if ( numel(unique(rc)) == 1 && all_2d) 81 | is_can = true; 82 | rc=rc(1); 83 | else 84 | is_can = false; 85 | end 86 | if ( ~is_can ) 87 | t=tt_tensor; 88 | t.d = d; 89 | t.r = tt_ranks(tt); 90 | t.r = [1;t.r;1]; 91 | t.n=tt_size(tt); 92 | t.core=zeros(tt_mem(tt),1); 93 | ps=cumsum([1;t.n.*t.r(1:d).*t.r(2:d+1)]); 94 | t.core(ps(1):ps(2)-1)=tt{1}(:); 95 | for i=2:d-1 96 | cr=tt{i}; cr=permute(cr,[2,1,3]); 97 | t.core(ps(i):ps(i+1)-1) = cr(:); 98 | end 99 | cr=tt{d}; cr=permute(cr,[2,1]); 100 | t.core(ps(d):ps(d+1)-1) = cr(:); 101 | t.ps=ps; 102 | t.over=0; 103 | return 104 | else 105 | t=tt_tensor; 106 | t.d=d; 107 | r=rc*ones(d+1,1); 108 | r(1)=1; r(d+1)=1; 109 | t.r=r; 110 | n=zeros(d,1); 111 | for i=1:d 112 | n(i)=size(tt{i},1); 113 | end 114 | t.n=n; 115 | t.ps = cumsum([1;t.n.*t.r(1:t.d).*t.r(2:t.d+1)]); 116 | crp=zeros(t.ps(d+1)-1,1); 117 | cc=tt{1}; 118 | crp(t.ps(1):t.ps(2)-1)=cc(:); 119 | cc=tt{d}; 120 | cc=cc.'; 121 | crp(t.ps(d):t.ps(d+1)-1)=cc(:); 122 | for i=2:d-1 123 | cc=tt{i}; 124 | cr=zeros(r(i),n(i),r(i+1)); 125 | for j=1:n(i) 126 | cr(:,j,:)=diag(cc(j,:)); 127 | end 128 | crp(t.ps(i):t.ps(i+1)-1)=cr(:); 129 | end 130 | t.core=crp; 131 | t.over=0; 132 | return 133 | end 134 | end 135 | 136 | % From a simple tt_tensor struct without class definition 137 | if (nargin == 1) && isa(varargin{1}, 'struct') 138 | t.d = varargin{1}.d; 139 | t.r = varargin{1}.r; 140 | t.n = varargin{1}.n; 141 | t.core = varargin{1}.core; % empty tensor 142 | t.ps = cumsum([1;t.n.*t.r(1:t.d).*t.r(2:t.d+1)]); 143 | t.over = varargin{1}.over; 144 | t = class(t, 'tt_tensor'); 145 | return; 146 | end; 147 | 148 | % From a SDV file 149 | if (nargin == 1) && isa(varargin{1}, 'char') 150 | [d,r,n,core] = tt_read(varargin{1}); 151 | 152 | if (d<1) 153 | fprintf('tt_read reported d=%d\n', d); 154 | return; 155 | end; 156 | 157 | t.d = d; 158 | t.r = r; 159 | t.n = n; 160 | t.core = core; 161 | t.ps=cumsum([1;t.n.*t.r(1:d).*t.r(2:d+1)]); 162 | t.over = 0; 163 | t = class(t, 'tt_tensor'); 164 | return 165 | end; 166 | 167 | %From qtt_tucker format 168 | 169 | if ( nargin == 1 && isa(varargin{1}, 'qtt_tucker') ) 170 | t=qtttucker_to_tt(varargin{1}.tuck,varargin{1}.core); 171 | return 172 | end 173 | 174 | %From full format 175 | if isa(varargin{1},'double') 176 | t=tt_tensor; 177 | b=varargin{1}; 178 | if ( nargin >= 2 && isa(varargin{2},'double') && (~isempty(varargin{2}))) 179 | eps=varargin{2}; 180 | else 181 | eps=1e-14; 182 | end 183 | 184 | % check for a custom n 185 | if ( nargin >= 3 && isa(varargin{3},'double') && (~isempty(varargin{3}))) 186 | n = varargin{3}; 187 | else 188 | n = size(b); 189 | end; 190 | n = n(:); 191 | d = numel(n); 192 | r = ones(d+1,1); 193 | % check for tailing ranks 194 | if (nargin >= 4 && isa(varargin{4},'double') && numel(varargin{4})==1) 195 | r(1) = varargin{4}; 196 | end; 197 | if (nargin >= 5 && isa(varargin{5},'double') && numel(varargin{5})==1) 198 | r(d+1) = varargin{5}; 199 | end; 200 | 201 | if ((numel(n) == 2 && min(n) == 1) || (numel(n)==1) || (issparse(b))) %Singleton or sparse tensor 202 | r = [r(1); r(d+1)]; 203 | d=1; n=prod(n); 204 | core=b(:); 205 | ps=cumsum([1;n.*r(1:d).*r(2:d+1)]); 206 | t.d=d; 207 | t.n=n; 208 | t.r=r; 209 | t.ps=ps; 210 | t.core=core; 211 | t.over=0; 212 | return 213 | end 214 | 215 | c=b; 216 | core=[]; 217 | pos=1; 218 | % ep=eps/sqrt(d-1); 219 | ep = eps/(d-1);% noise level 220 | % ep = eps;% noise level 221 | for i=1:d-1 222 | m=n(i)*r(i); c=reshape(c,[m,numel(c)/m]); 223 | [u,s,v]=svd(c,'econ'); 224 | s=diag(s); 225 | %r1=my_chop2(s,ep*norm(s)); 226 | % norm(s(r1:end))^2 < ep; 227 | cs = cumsum(s.^2); 228 | r1 = find((cs(end) - cs) < ep,1,'first'); 229 | u=u(:,1:r1); s=s(1:r1); 230 | r(i+1)=r1; 231 | core(pos:pos+r(i)*n(i)*r(i+1)-1)=u(:); 232 | v=v(:,1:r1); 233 | v=v*diag(s); c=v'; 234 | pos=pos+r(i)*n(i)*r(i+1); 235 | end 236 | core(pos:pos+r(d)*n(d)*r(d+1)-1)=c(:); 237 | core=core(:); 238 | ps=cumsum([1;n.*r(1:d).*r(2:d+1)]); 239 | t.d=d; 240 | t.n=n; 241 | t.r=r; 242 | t.ps=ps; 243 | t.core=core; 244 | %t.over=0; 245 | return; 246 | end; 247 | 248 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TensorBox 2 | TENSORBOX is a Matlab package containing state-of-the-art algorithms 3 | for decompositions of multiway array data into rank-1 tensors such as 4 | - CANDECOMP/PARAFAC 5 | - Tucker decomposition 6 | - Generalized Kronecker tensor decomposition 7 | - Tensor deconvolution 8 | - Tensor train decomposition 9 | - Best rank-1 tensor approximation 10 | - Tensor decomposition with given error bound (or the denoising problem) 11 | - Application for BSS, harmonic retrieval, image denoising, image 12 | completion, dictionary learning, ... 13 | 14 | # Algorithms for CANDECOMP/PARAFAC decomposition (CPD) 15 | 16 | - FastALS : fast ALS algorithm employs the fast method to compute CP 17 | gradients. 18 | Other alternating and all-at-once algorithms for CPD can be 19 | accelerated using the similar method. 20 | See HALS, QALS, MLS, fLM and subfunction of FastALS: 21 | cp_gradient. 22 | 23 | - HALS hierarchical ALS algorithm for nonnegative CPD (NCPD) 24 | - QALS recursive ALS algorithm for nonnegative CPD (NCPD) 25 | - MLS multiplicative algorithm for NCPD 26 | - fLM fast damped Gauss-Newton or Levenberg-Marquardt algorithm for 27 | CPD and NCPD 28 | (see cp_fLMa and cpx_fLMa, ncp_fLM) 29 | - FCP fast algorithm for higher order CPD through tensor unfolding 30 | - XGRAM extended generalized rank annihilation method (GRAM) and 31 | direct trilinear decomposition (DLTD) to higher order CPD 32 | 33 | - CPO-ALS1 ALS algorithm for CPD with column-wise orthogonal factor 34 | - CPO-ALS2 ALS algorithm for CPD with column-wise orthogonal factor 35 | 36 | - CRIB Cramer-Rao Induced Bound for CPD. 37 | 38 | # Algorithms for Tensor Deflation and Rank-1 tensor extraction 39 | - ASU Alternating Subspace update. The algorithm extracts a rank-1 40 | tensor from a rank-R tensor, i.e., deflation. It can be used 41 | to sequentially decompose a rank-R tensor over R rank-1 42 | tensor extraction. 43 | 44 | - CRB for the tensor deflation 45 | 46 | # Algorithms for Tucker decomposition (TD) 47 | - HALS hierarchical ALS algorithm for nonnegative TD. 48 | - LM Levenberg-Marquardt algorithm with log-barrier function. 49 | - LMPU A simplified version of the LM algorithm which updates only 50 | one factor matrix and a core tensor at a time. 51 | - O2LB A simplified version of the LM algorithm which updates only 52 | one factor matrix or a core tensor at a time. 53 | - CrNc Crank-Nicholson algorithm for orthogonal Tucker decomposition. 54 | 55 | # Algorithms for Error Preserving Correction method 56 | which solves the optimization problem 57 | min sum_r |norm_of_rank-1_tensor_r-th|_F^2 58 | s.t. |Y - X|_F^2 <= error_bound 59 | 60 | - ANC alternating correction algorithm 61 | - SQP sequential QP algorithm 62 | - ITP Iterior point algorithm 63 | 64 | # Algorithms for CPD with bound constraint 65 | which solves the optimization problem 66 | min |Y - X|_F^2 67 | s.t. sum_r |norm_of_rank-1_tensor_r-th|_F^2 <= error_bound 68 | 69 | - ANC alternating correction algorithm 70 | - SQP sequential QP algorithm 71 | - ITP Iterior point algorithm 72 | 73 | # Algorithms for best rank-1 tensor approximation 74 | - Closed form expression to find best rank-1 for tensor 2x2x2 75 | - Closed form expression to find best rank-1 for tensor 2x2x2x2 76 | - LM iterative algorithm with optimal damping parameter 77 | 78 | - RORO rotational rank-1 tensor approximation 79 | 80 | # Algorithms for rank-(L o M) block term decompositions 81 | - bcdLoR_als 82 | 83 | # Algorithms for tensor denoising 84 | i.e. min rank(C) s.t. |Y - X|_F^2 <= error_bound 85 | 86 | # Algorithms for Tensor train decomposition 87 | - ASCU alternating single core update 88 | - ADCU alternating double core update 89 | - A3CU alternating trible core update 90 | 91 | # Algorithms for Tensor to CPD conversion 92 | - Exact conversion between CPS and TT tensors 93 | - Iterative algorithms for fiting a CP tensor to a TT-tensor 94 | 95 | # Algorithms for BSS based on Tensor network decomposition 96 | - Exact conversion between CPS and TT tensors 97 | - Iterative algorithms for fiting a CP tensor to a TT-tensor 98 | 99 | # Algorithms for Rank-1 Tensor Deconvolution 100 | 101 | # Algorithms for generalized Kronecker Tensor decomposition 102 | with low-rank constraint and sparsity constraints 103 | 104 | Examples for image denoising and completion 105 | 106 | # Algorithm for Quadratic Programming over sphere (QPS) 107 | -------------------------------------------------------------------------------- /btd/bdiagtimematrix.m: -------------------------------------------------------------------------------- 1 | function X = bdiagtimematrix(A,B) 2 | % A or B is a diagonal matrix 3 | % TENSORBOX, 2018 4 | 5 | if isstruct(A) && (strcmp(A.type,'bdiag')) 6 | if isstruct(B) 7 | for n = 1:size(A.mat,3) 8 | X(:,:,n) = A.mat(:,:,n) * B.mat(:,:,n); 9 | end 10 | X.type = B.type; 11 | else 12 | for n = 1:size(A.mat,3) 13 | X(:,:,n) = A.mat(:,:,n) * B(); 14 | end 15 | end 16 | else 17 | end -------------------------------------------------------------------------------- /btd/btd3.m: -------------------------------------------------------------------------------- 1 | function [A B C S iter]=btd3(T,LL,met) 2 | % 3 | % Block tensor decomposition; 4 | % T is assumed to be a cube of dimension m x m x m 5 | % LL are sizes of the blocks, sum(LL)=m; 6 | % A,B,C should be the estimated factor matrices 7 | % S should be a diagonalized tensor (with blocks along its 8 | % main spatial diagonal) ... not yet implemented 9 | % 10 | % TENSORBOX, 2018 11 | 12 | [m m1 m2]=size(T); 13 | eps=1e-6; 14 | if ~(m==sum(LL)) 15 | 'sizes of the blocks are not appropriate' 16 | LL=ones(1,m); %% default=CPD 17 | end 18 | if nargin<3, met = 1; end 19 | switch met 20 | case 1 21 | % [A B C S iter]=tedia3g(T,100); 22 | [A B C S iter]=tedia3c(T,100); 23 | case 2 24 | [A B C S iter]=tedia3b_pf(T,100); 25 | case 3 26 | % [A B C S iter]=tedia3b_pf1(T,100); 27 | % case 4 28 | [A B C S iter]=tedia3b_pf2(T,100); 29 | case 4 30 | [A B C S iter]=tediaX(T,100); 31 | case 5 32 | [A B C S iter]=tedia3f(T,100); 33 | 34 | end 35 | 36 | % %% 37 | % % Sort components of A and B 38 | % SS=sum(abs(S),3); 39 | % [u,s,v] = svds(SS - mean(SS(:)),1); 40 | % [u,ord1] = sort(u,'descend'); 41 | % [v,ord2] = sort(v,'descend'); 42 | % S = S(ord1,ord2,:); 43 | % A = A(ord1,:); 44 | % B = B(ord2,:); 45 | % 46 | % SS = squeeze(sum(abs(S),2)); 47 | % [u,s,v] = svds(SS - mean(SS(:)),1); 48 | % %[u,ord1] = sort(u,'descend'); 49 | % [v,ord2] = sort(v,'descend'); 50 | % S = S(:,:,ord2); 51 | % C = C(ord2,:); 52 | 53 | %% 54 | SS=sum(abs(S),3)+squeeze(sum(abs(S),2))+squeeze(sum(abs(S),1)); 55 | ord=srovnej(SS+SS',LL); 56 | % imagesc(SS(ord,ord)) 57 | A=A(ord,:); B=B(ord,:); C=C(ord,:); 58 | 59 | 60 | il0=0; 61 | for ib=1:length(LL) 62 | ind=il0+1:il0+LL(ib); 63 | [U Lam V]=svd(A(ind,:)); % finding orthogonal basis of subspaces 64 | A(ind,:)=V(:,1:LL(ib))'; 65 | [U Lam V]=svd(B(ind,:)); 66 | B(ind,:)=V(:,1:LL(ib))'; 67 | [U Lam V]=svd(C(ind,:)); 68 | C(ind,:)=V(:,1:LL(ib))'; 69 | il0=il0+LL(ib); 70 | end 71 | S=T; 72 | for n=1:m 73 | S(:,:,n)=A*T(:,:,n)*B'; 74 | end 75 | for i=1:n 76 | S(i,:,:)=squeeze(S(i,:,:))*C'; 77 | end 78 | % imagesc(sum(abs(S),3)) 79 | end 80 | % 81 | function ord=srovnej(D,LL) 82 | % 83 | d=size(D,1); 84 | nb=length(LL); 85 | ord=1:d; 86 | D0=D; 87 | ind=0; 88 | for k=1:nb-1 89 | sb=LL(k); 90 | [h m]=sort(-D); 91 | [h2 imd2]=sort(-h(sb+1,:)); 92 | iny=imd2(ind+sb); 93 | im=m(1:sb,iny); 94 | ord(ind+1:ind+sb)=im; 95 | D(im,:)=-ones(sb,d); 96 | D(:,im)=-ones(d,sb); 97 | ind=ind+sb; 98 | end 99 | aux=1:d; 100 | aux(ord(1:ind))=[]; 101 | ord(ind+1:d)=aux; 102 | end 103 | 104 | -------------------------------------------------------------------------------- /btd/btd_ajd.m: -------------------------------------------------------------------------------- 1 | function [A B S]=btd(T,LL) 2 | % 3 | % Block tensor decomposition; 4 | % T is assumed to be a cube of dimension m x m x m 5 | % LL are sizes of the blocks, sum(LL)=m; 6 | % A,B,C should be the estimated factor matrices 7 | % S should be a diagonalized tensor (with blocks along its 8 | % main spatial diagonal) ... not yet implemented 9 | % 10 | % TENSORBOX, 2018 11 | 12 | [m m1 m2]=size(T); 13 | eps=1e-6; 14 | if ~(m==sum(LL)) % 'sizes of the blocks are not appropriate' 15 | LL=ones(1,m); %% default=CPD 16 | end 17 | [A1 B1]=I_DIEM_NS(T); 18 | %P = cp_gram(tensor(T),m);A1 = P.U{1};B1 = P.U{2}; 19 | ir=0; 20 | for i=1:m 21 | im=max(imag(A1(:,i))); 22 | if im>eps 23 | if ir==0 24 | A1(:,i)=real(A1(:,i)); 25 | ir=1; 26 | else 27 | A1(:,i)=imag(A1(:,i)); 28 | ir=0; 29 | end 30 | end 31 | end 32 | ir=0; 33 | for i=1:m 34 | im=max(imag(B1(:,i))); 35 | if im>eps 36 | if ir==0 37 | B1(:,i)=real(B1(:,i)); 38 | ir=1; 39 | else 40 | B1(:,i)=imag(B1(:,i)); 41 | ir=0; 42 | end 43 | end 44 | end 45 | % A1 = bsxfun(@rdivide,A1,sqrt(sum(A1.^2,1))); 46 | % B1 = bsxfun(@rdivide,B1,sqrt(sum(B1.^2,1))); 47 | A=pinv(A1); 48 | B=pinv(B1); 49 | S=T; 50 | for n=1:m 51 | S(:,:,n)=A*T(:,:,n)*B'; 52 | end 53 | SS=sum(abs(S),3); 54 | [u,s,v] = svds(SS - mean(SS(:)),1); 55 | % [u,s,v] = svds(SS+SS' - mean(SS(:)),1); 56 | % [u,s,v] = svds(SS-mean(SS,2)*mean(SS,1),1); 57 | [u,ord1] = sort(u,'descend'); 58 | [v,ord2] = sort(v,'descend'); 59 | A=A(ord1,:); B=B(ord2,:); 60 | 61 | % ord=srovnej(SS+SS',LL); 62 | % imagesc(SS(ord,ord)) 63 | % A=A(ord,:); B=B(ord,:); 64 | il0=0; 65 | for ib=1:length(LL) 66 | ind=il0+1:il0+LL(ib); 67 | [U Lam V]=svd(A(ind,:)); % finding orthogonal basis of subspaces 68 | A(ind,:)=V(:,1:LL(ib))'; 69 | [U Lam V]=svd(B(ind,:)); 70 | B(ind,:)=V(:,1:LL(ib))'; 71 | il0=il0+LL(ib); 72 | end 73 | S=T; 74 | for n=1:m 75 | S(:,:,n)=A*T(:,:,n)*B'; 76 | end 77 | 78 | % S=permute(S,[3,2,1]); 79 | % C=update(S,eye(d)); 80 | 81 | % imagesc(sum(abs(S),3)) 82 | end 83 | % 84 | function ord=srovnej(D,LL) 85 | % 86 | d=size(D,1); 87 | nb=length(LL); 88 | ord=1:d; 89 | D0=D; 90 | ind=0; 91 | for k=1:nb-1 92 | sb=LL(k); 93 | [h m]=sort(-D); 94 | [h2 imd2]=sort(-h(sb+1,:)); 95 | iny=imd2(ind+sb); 96 | im=m(1:sb,iny); 97 | ord(ind+1:ind+sb)=im; 98 | D(im,:)=-ones(sb,d); 99 | D(:,im)=-ones(d,sb); 100 | ind=ind+sb; 101 | end 102 | aux=1:d; 103 | aux(ord(1:ind))=[]; 104 | ord(ind+1:d)=aux; 105 | end 106 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 107 | % 108 | % ____________________ 109 | % ____ _/_____ /__(_)___________ ___ 110 | % __ / _ __ /__ /_ _ \_ __ `__ \ 111 | % __/ / / /_/ / _ / / __/ / / / / / DIagonalization using Equivalent 112 | % /___/ \__,_/ /_/ \___//_/ /_/ /_/ Matrices (improved non-symmetrical 113 | % version) 114 | % 115 | % 116 | % Usage: '[A_L,A_R] = I_DIEM_NS(T)'. 117 | % 118 | % Input: 119 | % 120 | % T- a N x N x K array collecting K (K>=N) (complex) 'target matrices' T_k. 121 | % 122 | % Output: 123 | % 124 | % A_L- the N x N left diagonalizing matrix. 125 | % A_R- the N x N right diagonalizing matrix. 126 | % 127 | % 128 | % This algorithm computes a non-iterative minimizing solution for 129 | % the direct-fit least-squares criterion: 130 | % 131 | % $$\sum_k \|T_k - A_L Delta_k A_R^H\|_F^2.$$ 132 | % 133 | % By Gilles CHABRIEL and Jean BARRERE. 134 | % 135 | % (c) 2009, IM2NP, UMR 6242 CNRS-USTV, FRANCE. 136 | 137 | 138 | function [A_L,A_R] = I_DIEM_NS(T) 139 | 140 | [N,N,K] = size(T); 141 | 142 | if KFac); 12 | opts = struct('printitn',0,'tol',1e-6,'maxiters',5,'dimorder',dimorder); 13 | T = mtucker_als(X,Fac,opts); 14 | Gt = T.core.data; 15 | 16 | U = T.U; 17 | % Fit GRAM to compressed data 18 | [Ag,Bg,Cg]=gram(Gt(:,:,1),Gt(:,:,2),F); 19 | 20 | % Z1 = (Ag\Gt(:,:,1))/Bg; 21 | % Z2 = (Ag\Gt(:,:,2))/Bg; 22 | % Z = abs(Z1)+abs(Z2); 23 | % [u,s,v] = svds(Z - mean(Z(:)),1); 24 | % [u,ord1] = sort(u,'descend'); 25 | % [v,ord2] = sort(v,'descend'); 26 | % Ag=Ag(:,ord1); Bg=Bg(:,ord2); 27 | 28 | 29 | AL = U{1}*Ag; 30 | AR = U{2}*Bg; 31 | 32 | A=inv(AL); 33 | B=inv(AR); 34 | S = ttm(X,{A B},[1 2]); 35 | SS=sum(abs(double(S)),3); 36 | [u,s,v] = svds(SS - mean(SS(:)),1); 37 | [u,ord1] = sort(u,'descend'); 38 | [v,ord2] = sort(v,'descend'); 39 | AL=AL(:,ord1); AR=AR(:,ord2); 40 | 41 | % ord=srovnej(SS+SS',LL); 42 | % imagesc(SS(ord,ord)) 43 | % A=A(ord,:); B=B(ord,:); 44 | il0=0; 45 | for ib=1:length(R) 46 | ind=il0+1:il0+R(ib); 47 | [U Lam V]=svd(AL(:,ind)); % finding orthogonal basis of subspaces 48 | AL(:,ind)=U(:,1:R(ib)); 49 | [U Lam V]=svd(AR(:,ind)); 50 | AR(:,ind)=U(:,1:R(ib)); 51 | il0=il0+R(ib); 52 | end 53 | 54 | A = inv(AL); 55 | B = inv(AR); 56 | S = ttm(X,{A B},[1 2]); 57 | end 58 | 59 | 60 | function [A,B,C]=gram(X1,X2,F) 61 | 62 | %GRAM generalized rank annihilation method 63 | % 64 | % [A,B,C]=gram(X1,X2,F); 65 | % 66 | % cGRAM - Complex Generalized Rank Annihilation Method 67 | % Fits the PARAFAC model directly for the case of a 68 | % three-way array with only two frontal slabs. 69 | % For noise-free trilinear data the algorithm is exact. 70 | % If input is not complex, similarity transformations 71 | % are used for assuring a real solutions (Henk Kiers 72 | % is thanked for providing the similarity transformations) 73 | % 74 | % INPUTS: 75 | % X1 : I x J matrix of data from observation one 76 | % X2 : I x J matrix of data from observation two 77 | % Fac : Number of factors 78 | % 79 | % OUTPUTS: 80 | % A : Components in the row mode (I x F) 81 | % B : Components in the column mode (J x F) 82 | % C : Weights for each slab; C(1,:) are the component 83 | % weights for first slab such that the approximation 84 | % of X1 is equivalent to X1 = A*diag(C(1,:))*B.' 85 | % 86 | 87 | % Copyright (C) 1995-2006 Rasmus Bro & Claus Andersson 88 | % Copenhagen University, DK-1958 Frederiksberg, Denmark, rb@life.ku.dk 89 | % 90 | % This program is free software; you can redistribute it and/or modify it under 91 | % the terms of the GNU General Public License as published by the Free Software 92 | % Foundation; either version 2 of the License, or (at your option) any later version. 93 | % 94 | % This program is distributed in the hope that it will be useful, but WITHOUT 95 | % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 96 | % FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 97 | % You should have received a copy of the GNU General Public License along with 98 | % this program; if not, write to the Free Software Foundation, Inc., 51 Franklin 99 | % Street, Fifth Floor, Boston, MA 02110-1301, USA. 100 | 101 | % $ Version 1.02 $ Date 28. July 1998 $ Not compiled $ 102 | % $ Version 1.03 $ Date 22. February 1999 $ Not compiled $ 103 | % Modified by Anh-Huy Phan, 2013 104 | 105 | IsReal=0; % If complex data, complex solutions allowed. 106 | if all(isreal(X1))&all(isreal(X2)) 107 | IsReal=1; 108 | end 109 | 110 | % Find optimal bases in F x F subspace 111 | [U,s,V]=svd(X1+X2,0); 112 | U=U(:,1:F); 113 | V=V(:,1:F); 114 | 115 | % Reduce to an F x F dimensional subspace 116 | S1=U'*X1*V; 117 | S2=U'*X2*V; 118 | 119 | % Solve eigenvalue-problem and sort according to size 120 | [k,l]=eig(S1\S2); 121 | l=diag(l); 122 | ii=abs(l)>eps; 123 | k=k(:,ii); 124 | l=l(ii); 125 | p=length(l); 126 | [l,ii]=sort(l); 127 | j=p:-1:1; 128 | l=l(j); 129 | l=diag(l); 130 | k=k(:,ii(j)); 131 | k=k/norm(k); 132 | 133 | if IsReal % Do not allow complex solutions if only reals are considered 134 | [k,l] = cdf2rdf(k,l); % simplified here 135 | end 136 | 137 | C(2,:)=ones(1,F); 138 | C(1,:)=diag(l)'; 139 | A = U*S1*k; 140 | B=V/k'; 141 | end -------------------------------------------------------------------------------- /btd/cribBCDLoR.m: -------------------------------------------------------------------------------- 1 | function [criball,cribf,H] = cribBCDLoR(U,LR,rankRdim) 2 | % Cramer-Rao- induced lower bound ofr rank-LoM structured CPD 3 | % The noise is assumed to be i.i.d. Gaussian of a variance sigma^2, 4 | % the output CRB is proportional to sigma^2, and without any loss in generality it is assumed that 5 | % is equal to 1. 6 | % 7 | % 8 | % 9 | % Ref: P. Tichavsk?y, A. H. Phan, and Z. Koldovsk?y, ?Cram?er-Rao-Induced Bounds 10 | % for CANDECOMP/PARAFAC tensor decomposition,? ArXiv e-prints, Sept. 2012, 11 | % http://arxiv.org/abs/1209.3215. 12 | % 13 | 14 | 15 | I = cellfun(@(x) size(x,1),U);I = I(:)'; 16 | In = I; 17 | N = numel(U); 18 | 19 | rankLdim = setdiff(1:N,rankRdim); 20 | 21 | %% Method 4 : COnstruct Hessian 22 | R = sum(prod(LR,1)); % total rank structured CPD 23 | NoPat = size(LR,2); 24 | 25 | Eleft = []; 26 | Eright = []; 27 | for p = 1:NoPat 28 | Eleft = blkdiag(Eleft,kron(eye(LR(1,p)),ones(1,LR(2,p)))); 29 | Eright = blkdiag(Eright,kron(ones(1,LR(1,p)),eye(LR(2,p)))); 30 | end 31 | 32 | [Prr,Ptr] = per_vectrans(R,R); 33 | 34 | E = cell(N,1); 35 | E(rankLdim) = {Eleft}; 36 | E(rankRdim) = {Eright}; 37 | 38 | for n = 1:N 39 | if ismember(n,rankLdim) 40 | A{n} = U{n} * Eleft; 41 | else 42 | A{n} = U{n} * Eright; 43 | end 44 | end 45 | 46 | AtA = zeros(R,R,N); 47 | for n = 1: N 48 | AtA(:,:,n) = A{n}'*A{n}; 49 | end 50 | 51 | G =[]; 52 | for n = 1:N 53 | gnn = prod(AtA(:,:,setdiff(1:N,[n])),3); 54 | if ismember(n,rankRdim) 55 | gnn = Eright * gnn * Eright'; 56 | else 57 | gnn = Eleft * gnn * Eleft'; 58 | end 59 | G = blkdiag(G,kron(gnn, eye(In(n)))); 60 | end 61 | 62 | Z = []; 63 | for n = 1: N 64 | Zn = kron(eye(size(E{n},1)),U{n}); 65 | Z = blkdiag(Z,Zn); 66 | end 67 | 68 | 69 | % cR = cumsum([0 R^2*ones(1,N)]); 70 | % K = zeros(N*R^2); 71 | 72 | Rf = [sum(LR(1,:))^2*ones(1,numel(rankLdim)) sum(LR(2,:))^2*ones(1,numel(rankRdim))]; 73 | Rf([rankLdim rankRdim]) = Rf; 74 | cR = cumsum([0 Rf]); 75 | % cR([rankLdim rank1dim]) 76 | P = numel(rankLdim); 77 | K = zeros(P*sum(LR(1,:))^2 + (N-P) * sum(LR(2,:))^2); 78 | % cR = cumsum([0 R^2*ones(1,P) Rs*R*ones(1,N-P)]); 79 | % K = zeros(P*R^2 + (N-P) * Rs^2); 80 | for n = 1:N-1 81 | for m = n+1:N 82 | gmn = prod(AtA(:,:,setdiff(1:N,[n,m])),3); 83 | Knm = Prr*diag(gmn(:)); 84 | 85 | 86 | Knm = kron(E{n},E{n}) * Knm * kron(E{m}',E{m}'); 87 | 88 | 89 | K(cR(n)+1:cR(n+1),cR(m)+1:cR(m+1)) = Knm; 90 | K(cR(m)+1:cR(m+1),cR(n)+1:cR(n+1)) = Knm'; 91 | end 92 | end 93 | 94 | H = G + Z * K * Z'; % Hessian 95 | 96 | %% 97 | len=size(H,1); 98 | Ind=1:len; 99 | 100 | subrank = [sum(LR(1,:))*ones(1,P) sum(LR(2,:))*ones(1,N-P)]; 101 | subrank([rankLdim rankRdim]) = subrank; 102 | 103 | 104 | cIR = cumsum(I.*subrank); % need to fix order here 105 | cIR = [0 cIR]; 106 | 107 | 108 | Hi = inv(H+1e-8*eye(size(H,1))); 109 | criball = nan(N,max(sum(LR,2))); 110 | for n = 1:N 111 | for k = 1:size(U{n},2) 112 | Pa1=eye(I(n))-U{n}(:,k)*U{n}(:,k)'/sum(U{n}(:,k).^2); 113 | k1=cIR(n)+(k-1)*I(n); 114 | criball(n,k)=sum(diag(Pa1*Hi(k1+1:k1+I(n),k1+1:k1+I(n))))/sum(U{n}(:,k).^2); 115 | end 116 | end 117 | cribf = []; 118 | 119 | % %% INVERSE Hessian 120 | % idx = []; 121 | % for n = 2:N 122 | % idx =[idx cIR(n)+1:I(n):cIR(n+1)]; 123 | % end 124 | % Ind(idx) = []; 125 | % Hi2=inv(H(Ind,Ind)); 126 | % 127 | % %% 128 | % %crib=sum(diag(Pa1*Hi2(1:Ia,1:Ia)))/sum(A(:,1).^2); 129 | % criball = zeros(1,1); 130 | % n = 1; 131 | % for k=1:1 132 | % Pa1=eye(I(n))-U{n}(:,k)*U{n}(:,k)'/sum(U{n}(:,k).^2); 133 | % k1=cIR(n)+(k-1)*I(n); 134 | % criball(1,k)=sum(diag(Pa1*Hi2(k1+1:k1+I(n),k1+1:k1+I(n))))/sum(U{n}(:,k).^2); 135 | % end 136 | -------------------------------------------------------------------------------- /cpd/comparefoldings.m: -------------------------------------------------------------------------------- 1 | function decision = comparefoldings(fold1,fold2) 2 | % Compare two two tensor unfolding rules fold1, fold2. 3 | % 4 | % decision = false : if they are different. 5 | % 6 | % This algorithm is a part of the TENSORBOX, 2012. 7 | % 8 | % Copyright Phan Anh Huy, 04/2012 9 | 10 | decision = true; 11 | if numel(fold1) ~= numel(fold2) 12 | decision = false; % different folding rules 13 | return 14 | end 15 | 16 | fold1 = cellfun(@sort,fold1,'uni',0); 17 | fold2 = cellfun(@sort,fold2,'uni',0); 18 | 19 | for k = 1:numel(fold1) 20 | fidx = cellfun(@(x) isequal(x,fold1{k}),fold2); 21 | if all(fidx==0) 22 | decision = false; % different folding rules 23 | return 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /cpd/cost_als.m: -------------------------------------------------------------------------------- 1 | function [ns,bestord,mincost,Allcomb] = cost_als(I) 2 | % I should be in ascending order 3 | % 4 | % Phan Anh Huy , 2013 5 | N = numel(I);% N should be smaller than 15 6 | % Compute total cost of the fastALS 7 | %ns 8 | Allcomb= []; 9 | AllTn = []; 10 | for ns = ceil(N/2):N-1 11 | % Jn = cumprod(I); Kn = [Jn(end) Jn(end)./Jn(1:end-1)]; 12 | allcomb = nchoosek(1:N,ns); 13 | temp = zeros(size(allcomb,1),N-ns); 14 | for k = 1:size(allcomb,1) 15 | temp(k,:) = setdiff(1:N,allcomb(k,:)); 16 | end 17 | allcomb = [allcomb temp]; 18 | 19 | Jn = cumprod(I(allcomb),2); 20 | Kn = [Jn(:,end) bsxfun(@rdivide,Jn(:,end),Jn(:,1:end-1))]; 21 | 22 | %% 23 | Tn = 0; 24 | for n = [ns:-1:1 ns+1:N] 25 | if (n == ns) 26 | Mn = sum(Jn(:,2:n-1),2) + min(Jn(:,n),Kn(:,n)) + ... 27 | sum(Jn(:,n+2:N),2)./Jn(:,n); 28 | elseif n== ns+1 29 | Mn = sum(Jn(:,2:n-1),2) + (nsns+1 34 | Mn = Kn(:,n-1) + (n~= N) * Kn(:,n) + sum(Jn(:,n+2:N),2)./Jn(:,n); 35 | end 36 | Tn = Tn + Mn; 37 | end 38 | if nargout >= 4 39 | Allcomb = [Allcomb; allcomb Tn(:) ns*ones(size(allcomb,1),1) ]; 40 | else 41 | [mincost,idbest] = min(Tn(:)); 42 | bestord = allcomb(idbest,1:N); 43 | Allcomb = [Allcomb; bestord mincost ns]; 44 | end 45 | end 46 | 47 | [mincost,idbest] = min(Allcomb(:,N+1)); 48 | bestord = Allcomb(idbest,1:N); 49 | ns = Allcomb(idbest,end); -------------------------------------------------------------------------------- /cpd/cp_ajd.m: -------------------------------------------------------------------------------- 1 | function [A B C,curve]=CP_AJD(T,r) 2 | %% TENSORBOX, 2018 3 | 4 | % fast CP decomposition using nonsymmetric joint diagonalization; 5 | % The tensor T is assumed to be of order 3 and dimension m x m x p 6 | % and rank r <= min(m,p) 7 | % 8 | [A0 B0 S, curve]=scot(T); 9 | % 10 | ss=diag(sum(abs(S),3)); 11 | [is iord]=sort(-ss); 12 | [m m1 p]=size(T); 13 | A=inv(A0); 14 | A=A(:,iord(1:r)); 15 | B=inv(conj(B0)); 16 | B=B(:,iord(1:r)); 17 | C=zeros(p,r); 18 | for k=1:r 19 | C(:,k)=squeeze(S(iord(k),iord(k),:)); 20 | end 21 | 22 | function [A B S,curve]=scot(T) 23 | % 24 | % Approximate nonsymmetric joint diagonalization of a tensor 25 | % of order 3 and size m x m x p. 26 | % 27 | [m m1 p]=size(T); 28 | T2=T; 29 | for n=1:p 30 | T2(:,:,n)=T(:,:,n)'; 31 | end 32 | [Ai L]=eig(T(:,:,2)/T(:,:,1)); 33 | [Bi L]=eig((T(:,:,2)'/T(:,:,1)')); 34 | A=inv(Ai); B=inv(Bi); %%% initial values 35 | A=A./(sqrt(sum(A.*conj(A),2))*ones(1,m)); 36 | B=B./(sqrt(sum(B.*conj(B),2))*ones(1,m)); 37 | incr=10; 38 | value=kolik(T,A,B); 39 | curve=value; 40 | iter=0; 41 | while value>1e-8*curve(1) && iter<1000 && abs(incr)>1e-8*value 42 | iter=iter+1; 43 | valold=value; 44 | A=update(T,B); 45 | % kolik(T,A,B) 46 | B=update(T2,A); 47 | value=kolik(T,A,B); 48 | incr=-value+valold; 49 | curve=[curve value]; 50 | end 51 | % curve 52 | S=T; 53 | for n=1:p 54 | S(:,:,n)=A*T(:,:,n)*B'; 55 | end 56 | % 57 | function A=update(T,B) 58 | [m m1 p]=size(T); 59 | S=zeros(m,m,m); 60 | for n=1:m 61 | U=zeros(m,m); 62 | for i=1:p 63 | u=T(:,:,i)*B(n,:)'; 64 | U=U+u*u'; 65 | end 66 | S(:,:,n)=U; 67 | end 68 | V=sum(S,3); 69 | for n=1:m 70 | [W Lam]=eig(S(:,:,n),V-S(:,:,n)); 71 | [Lmin,imin]=max(diag(Lam)); 72 | % A(j,:)=A(j,:)/norm(A(j,:)) 73 | A(n,:)=W(:,imin)'; 74 | A(n,:)=A(n,:)/norm(A(n,:)); 75 | end 76 | 77 | function val=kolik(T,A,B) 78 | [m m1 p]=size(T); 79 | mask=ones(m,m)-eye(m); 80 | val=0; val2=0; 81 | for n=1:p 82 | aux=abs(A*T(:,:,n)*B').^2; 83 | val=val+sum(sum(mask.*aux)); 84 | val2=val2+sum(diag(aux)); 85 | end 86 | val=val/val2; -------------------------------------------------------------------------------- /cpd/cp_ajdv2.m: -------------------------------------------------------------------------------- 1 | function [A B C,curve]=CP_AJD(T,r) 2 | % 3 | % fast CP decomposition using nonsymmetric joint diagonalization; 4 | % The tensor T is assumed to be of order 3 and dimension m x m x p 5 | % and rank r <= min(m,p) 6 | %% TENSORBOX, 2018 7 | 8 | [A0 B0 S, curve]=scot(T); 9 | % 10 | ss=diag(sum(abs(S),3)); 11 | [is iord]=sort(-ss); 12 | [m m1 p]=size(T); 13 | A=inv(A0); 14 | A=A(:,iord(1:r)); 15 | B=inv(conj(B0)); 16 | B=B(:,iord(1:r)); 17 | C=zeros(p,r); 18 | for k=1:r 19 | C(:,k)=squeeze(S(iord(k),iord(k),:)); 20 | end 21 | end 22 | 23 | function [A B S,curve]=scot(T) 24 | % 25 | % Approximate nonsymmetric joint diagonalization of a tensor 26 | % of order 3 and size m x m x p. 27 | % 28 | [m m1 p]=size(T); 29 | T2= permute(T,[2 1 3]); 30 | 31 | [Ai L]=eig(T(:,:,2),T(:,:,1)); %[Ai L]=eig(T(:,:,2)/T(:,:,1)); 32 | [Bi L]=eig(T(:,:,2)',T(:,:,1)');%[Bi L]=eig((T(:,:,2)'/T(:,:,1)')); 33 | 34 | A=inv(Ai); B=inv(Bi); %%% initial values 35 | A=A./(sqrt(sum(A.*conj(A),2))*ones(1,m)); 36 | B=B./(sqrt(sum(B.*conj(B),2))*ones(1,m)); 37 | incr=10; 38 | value=kolik(T,A,B); 39 | curve=value; 40 | iter=0; 41 | while value>1e-6*curve(1) && iter<1000 && abs(incr)>1e-6*value 42 | iter=iter+1; 43 | valold=value; 44 | A=update(T,B); 45 | % kolik(T,A,B) 46 | B=update(T2,A); 47 | value=kolik(T,A,B); 48 | incr=-value+valold; 49 | curve=[curve value]; 50 | end 51 | % curve 52 | S=T; 53 | for n=1:p 54 | S(:,:,n)=A*T(:,:,n)*B'; 55 | end 56 | end 57 | % 58 | function A=update(T,B) 59 | [m m1 p]=size(T); 60 | S=zeros(m,m,m); 61 | % for n=1:m 62 | % U=zeros(m,m); 63 | % for i=1:p 64 | % u=T(:,:,i)*B(n,:)'; 65 | % U=U+u*u'; 66 | % end 67 | % S(:,:,n)=U; 68 | % end 69 | 70 | U2 = B*reshape(T,m,[]);U2 = reshape(U2,m,m,[]); %U2 = permute(U2,[2 3 1]); 71 | for n = 1:m 72 | uu = squeeze(U2(n,:,:)); 73 | S(:,:,n)=uu*uu'; 74 | end 75 | 76 | % eigopts.disp = 0; 77 | V=sum(S,3);A = zeros(m,m);%A2 = A ; 78 | for n=1:m 79 | % tic 80 | [W Lam]=eig(S(:,:,n),V-S(:,:,n)); 81 | % toc 82 | [Lmin,imin]=max(diag(Lam)); 83 | A(n,:) = W(:,imin); 84 | A(n,:)=A(n,:)/norm(A(n,:)); 85 | % A2(n,:) = A(n,:); 86 | % [A(n,:),Lam] = eigs(S(:,:,n),V-S(:,:,n),1,'LA',eigopts); 87 | % norm(A(n,:)' - W(:,imin),'fro') 88 | % A(n,:)=A(n,:)/norm(A(n,:)); 89 | end 90 | end 91 | 92 | function val=kolik(T,A,B) 93 | [m m1 p]=size(T); 94 | mask=ones(m,m)-eye(m); 95 | val=0; val2=0; 96 | for n=1:p 97 | aux=abs(A*T(:,:,n)*B').^2; 98 | val=val+sum(sum(mask.*aux)); 99 | val2=val2+sum(diag(aux)); 100 | end 101 | val=val/val2; 102 | end -------------------------------------------------------------------------------- /cpd/cp_congruence.m: -------------------------------------------------------------------------------- 1 | function C = cp_congruence(P) 2 | % Compute congruence coefficients for the Kruskal tensor P 3 | % 4 | % TENSORBOX, 2018 5 | P = arrange(normalize(P)); 6 | R = size(P.u{1},2); 7 | C = prod(reshape(cell2mat(cellfun(@(x) x'*x,P.u(:),'uni',0))',R,R,[]),3); 8 | end -------------------------------------------------------------------------------- /cpd/cp_gradient.m: -------------------------------------------------------------------------------- 1 | function [G,Pmat] = cp_gradient(Pmat,A,n) 2 | %% mode-n CP Gradient of X with respect to A 3 | % input X needs only as n == ns and n == ns+1, i.e., 4 | % if (n == ns) || (n == ns+1) 5 | % [Gxn{n},Pmat] = cp_gradient(X,U,n); % compute CP gradients 6 | % else 7 | % [Gxn{n},Pmat] = cp_gradient(Pmat,U,n); % compute CP gradients 8 | % end 9 | % 10 | % Phan Anh Huy, 11 | % TENSORBOX, 2012. 12 | N = numel(A); 13 | In = cellfun(@(x) size(x,1), A); 14 | R = size(A{1},2); 15 | 16 | if ~issorted(In) 17 | error('Rearrange data''s dimensions in ascending order : %s.\nThen try again.', ... 18 | [sprintf('%d x ',sort(In(1:end-1))) num2str(In(end))]) 19 | end 20 | 21 | % Find the first n* such that I1...In* > I(n*+1) ... IN 22 | Jn = cumprod(In); Kn = Jn(end)./Jn; 23 | ns = find(Jn>Kn,1); 24 | if ((ns >= (N-1)) && (ns > 2)) 25 | ns = ns -1; 26 | end 27 | 28 | right = N:-1:n+1; left = n-1:-1:1; 29 | % check dimensions 30 | if (n == ns) || (n == ns+1) 31 | if any(size(Pmat) ~= In(:)') 32 | error('Dimensions of data tensor and factors do not match.') 33 | end 34 | elseif n< ns 35 | if any(numel(Pmat) ~= R*In(right(end))*In(n)) 36 | warning('Matlab:invalid_dim',... 37 | 'Invalid dimension. %s should have %d elements.\n',... 38 | inputname(1),R*prod(In(right(end)))*In(n)) 39 | end 40 | end 41 | 42 | 43 | if n <= ns 44 | if n == ns 45 | if numel(right) == 1 46 | KRP_right = A{right}; 47 | elseif numel(right) > 1 48 | KRP_right = khatrirao(A(right)); %KRP_right = khatrirao(A(right)); 49 | end 50 | 51 | Pmat = reshape(double(Pmat),[],prod(In(right))); % Right-side projection 52 | Pmat = Pmat * KRP_right ; 53 | else 54 | Pmat = reshape(Pmat,[],In(right(end)),R); 55 | if R>1 56 | Pmat = bsxfun(@times,Pmat,reshape(A{right(end)},[],In(right(end)),R)); 57 | Pmat = sum(Pmat,2); % fast Right-side projection 58 | else 59 | Pmat = Pmat * A{right(end)}; 60 | end 61 | end 62 | 63 | if ~isempty(left) % Left-side projection 64 | KRP_left = khatrirao(A(left)); 65 | T = reshape(Pmat,prod(In(left)),In(n),[]); 66 | if R>1 67 | T = bsxfun(@times,T,reshape(KRP_left,[],1,R)); 68 | T = sum(T,1); 69 | G = squeeze(T); 70 | else 71 | G = (KRP_left'*T)'; 72 | end 73 | else 74 | G = squeeze(Pmat); 75 | end 76 | 77 | elseif n >=ns+1 78 | if n ==ns+1 79 | if numel(left) == 1 80 | KRP_left = A{left}; 81 | elseif numel(left) > 1 82 | KRP_left = khatrirao(A(left)); 83 | end 84 | T = reshape(double(Pmat),prod(In(left)),[]); 85 | Pmat = KRP_left' * T; % Left-side projection 86 | else 87 | if R>1 88 | Pmat = reshape(Pmat,R,In(left(1)),[]); 89 | Pmat = bsxfun(@times,Pmat,A{left(1)}'); 90 | Pmat = sum(Pmat,2); % Fast Left-side projection 91 | else 92 | Pmat = reshape(Pmat,In(left(1)),[]); 93 | Pmat = A{left(1)}'* Pmat; 94 | end 95 | end 96 | 97 | if ~isempty(right) 98 | T = reshape(Pmat,[],In(n),prod(In(right))); 99 | KRP_right = khatrirao(A(right)); 100 | if R>1 101 | T = bsxfun(@times,T,reshape(KRP_right',R,1,[])); 102 | T = sum(T,3); 103 | G = squeeze(T)'; % Right-side projection 104 | else 105 | G = squeeze(T) * KRP_right; 106 | end 107 | else 108 | G = squeeze(Pmat)'; 109 | end 110 | 111 | end 112 | end 113 | -------------------------------------------------------------------------------- /cpd/cp_gradient2.m: -------------------------------------------------------------------------------- 1 | %% CP Gradient with respect to mode n 2 | function [G,Pmat] = cp_gradient(A,n,Pmat) 3 | persistent KRP_right0; 4 | 5 | N = numel(A); 6 | In = cellfun(@(x) size(x,1), A);In = In(:)'; 7 | R = size(A{1},2); 8 | 9 | if ~issorted(In) 10 | error('Rearrange data''s dimensions in ascending order : %s.\nThen try again.', ... 11 | [sprintf('%d x ',sort(In(1:end-1))) num2str(In(end))]) 12 | end 13 | 14 | % Find the first n* such that I1...In* > I(n*+1) ... IN 15 | Jn = cumprod(In); Kn = [Jn(end) Jn(end)./Jn(1:end-1)]; 16 | ns = find(Jn<=Kn,1,'last'); 17 | 18 | right = N:-1:n+1; left = n-1:-1:1; 19 | 20 | % check dimensions 21 | if (n == ns) || (n == ns+1) 22 | if any(size(Pmat) ~= In(:)') 23 | error('Dimensions of data tensor and factors do not match.') 24 | end 25 | elseif n< ns 26 | if any(numel(Pmat) ~= R*In(right(end))*In(n)) 27 | warning('Matlab:invalid_dim',... 28 | 'Invalid dimension. %s should have %d elements.\n',... 29 | inputname(1),R*prod(In(right(end)))*In(n)) 30 | end 31 | end 32 | 33 | % KRP_right =[]; KRP_left = []; 34 | if n <= ns 35 | if n == ns 36 | if numel(right) == 1 37 | KRP_right = A{right}; 38 | elseif numel(right) > 2 39 | [KRP_right,KRP_right0] = khatrirao(A(right)); 40 | elseif numel(right) > 1 41 | KRP_right = khatrirao(A(right)); 42 | else 43 | KRP_right = 1; 44 | end 45 | 46 | if isa(Pmat,'tensor') 47 | Pmat = reshape(Pmat.data,[],prod(In(right))); % Right-side projection 48 | elseif isa(Pmat,'sptensor') 49 | Pmat = reshape(Pmat,[prod(size(Pmat))/prod(In(right)),prod(In(right))]); % Right-side projection 50 | Pmat = spmatrix(Pmat); 51 | else 52 | Pmat = reshape(Pmat,[],prod(In(right))); % Right-side projection 53 | end 54 | Pmat = Pmat * KRP_right ; 55 | else 56 | Pmat = reshape(Pmat,[],In(right(end)),R); 57 | if R>1 58 | Pmat = bsxfun(@times,Pmat,reshape(A{right(end)},[],In(right(end)),R)); 59 | Pmat = sum(Pmat,2); % fast Right-side projection 60 | else 61 | Pmat = Pmat * A{right(end)}; 62 | end 63 | end 64 | 65 | if ~isempty(left) % Left-side projection 66 | KRP_left = khatrirao(A(left)); 67 | % if (isempty(KRP_2) && (numel(left) > 2)) 68 | % [KRP_left,KRP_2] = khatrirao(A(left)); 69 | % elseif isempty(KRP_2) 70 | % KRP_left = khatrirao(A(left)); 71 | % %KRP_2 = []; 72 | % else 73 | % KRP_left = KRP_2; KRP_2 = []; 74 | % end 75 | T = reshape(Pmat,prod(In(left)),In(n),[]); 76 | if R>1 77 | T = bsxfun(@times,T,reshape(KRP_left,[],1,R)); 78 | T = sum(T,1); 79 | %G = squeeze(T); 80 | G = reshape(T,[],R); 81 | else 82 | G = (KRP_left'*T)'; 83 | end 84 | else 85 | %G = squeeze(Pmat); 86 | G = reshape(Pmat,[],R); 87 | end 88 | 89 | elseif n >=ns+1 90 | if n ==ns+1 91 | if numel(left) == 1 92 | KRP_left = A{left}'; 93 | elseif numel(left) > 1 94 | KRP_left = khatrirao_t(A(left)); 95 | %KRP_left = khatrirao(A(left));KRP_left = KRP_left'; 96 | else 97 | KRP_left = 1; 98 | end 99 | if isa(Pmat,'tensor') 100 | T = reshape(Pmat.data,prod(In(left)),[]); 101 | elseif isa(Pmat,'sptensor') 102 | T = reshape(Pmat,[prod(In(left)) prod(size(Pmat))/prod(In(left))]); % Right-side projection 103 | T = spmatrix(T); 104 | else 105 | T = reshape(Pmat,prod(In(left)),[]); 106 | end 107 | % 108 | Pmat = KRP_left * T; % Left-side projection 109 | else 110 | if R>1 111 | Pmat = reshape(Pmat,R,In(left(1)),[]); 112 | Pmat = bsxfun(@times,Pmat,A{left(1)}'); 113 | Pmat = sum(Pmat,2); % Fast Left-side projection 114 | else 115 | Pmat = reshape(Pmat,In(left(1)),[]); 116 | Pmat = A{left(1)}'* Pmat; 117 | end 118 | end 119 | 120 | if ~isempty(right) 121 | T = reshape(Pmat,[],In(n),prod(In(right))); 122 | 123 | if (n == (ns+1)) && (numel(right)>=2) 124 | %KRP_right = KRP_right0; 125 | if R>1 126 | T = bsxfun(@times,T,reshape(KRP_right0',R,1,[])); 127 | T = sum(T,3); 128 | %G = squeeze(T)'; % Right-side projection 129 | G = reshape(T, R,[])'; 130 | else 131 | %G = squeeze(T) * KRP_right0; 132 | G = reshape(T,[],prod(In(right))) * KRP_right0; 133 | end 134 | else 135 | KRP_right = khatrirao(A(right)); 136 | if R>1 137 | T = bsxfun(@times,T,reshape(KRP_right',R,1,[])); 138 | T = sum(T,3); 139 | %G = squeeze(T)'; % Right-side projection 140 | G = reshape(T,R,[])'; % Right-side projection 141 | else 142 | %G = squeeze(T) * KRP_right; 143 | G = reshape(T,In(n),[]) * KRP_right; 144 | end 145 | end 146 | else 147 | %G = squeeze(Pmat)'; 148 | G = reshape(Pmat,R,[])'; 149 | end 150 | 151 | end 152 | 153 | % fprintf('n = %d, Pmat %d x %d, \t Left %d x %d,\t Right %d x %d\n',... 154 | % n, size(squeeze(Pmat),1),size(squeeze(Pmat),2),... 155 | % size(KRP_left,1),size(KRP_left,2),... 156 | % size(KRP_right,1),size(KRP_right,2)) 157 | end 158 | 159 | 160 | %% xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 161 | function [K,K2] = khatrirao(A) 162 | % Fast Khatri-Rao product 163 | % P = fastkhatrirao({A,B,C}) 164 | % 165 | %Copyright 2012, Phan Anh Huy. 166 | 167 | R = size(A{1},2); 168 | K = A{1}; 169 | if nargout == 1 170 | for i = 2:numel(A) 171 | K = bsxfun(@times,reshape(A{i},[],1,R),reshape(K,1,[],R)); 172 | end 173 | elseif numel(A) > 2 174 | for i = 2:numel(A)-1 175 | K = bsxfun(@times,reshape(A{i},[],1,R),reshape(K,1,[],R)); 176 | end 177 | K2 = reshape(K,[],R); 178 | K = bsxfun(@times,reshape(A{end},[],1,R),reshape(K,1,[],R)); 179 | end 180 | K = reshape(K,[],R); 181 | end 182 | 183 | 184 | %% xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 185 | function [K,K2] = khatrirao_t(A) 186 | % Fast Khatri-Rao product 187 | % P = fastkhatrirao({A,B,C}) 188 | % 189 | %Copyright 2012, Phan Anh Huy. 190 | 191 | R = size(A{1},2); 192 | K = A{1}'; 193 | 194 | for i = 2:numel(A) 195 | K = bsxfun(@times,reshape(A{i}',R,[]),reshape(K,R,1,[])); 196 | end 197 | K = reshape(K,R,[]); 198 | 199 | end 200 | 201 | %% 202 | function K = kron(A,B) 203 | % Fast implementation of Kronecker product of A and B 204 | % 205 | % Copyright 2012 Phan Anh Huy 206 | % $Date: 2012/3/18$ 207 | 208 | if ndims(A) > 2 || ndims(B) > 2 209 | error(message('See ndkron.m')); 210 | end 211 | I = size(A); J = size(B); 212 | 213 | if ~issparse(A) && ~issparse(B) 214 | K = bsxfun(@times,reshape(B,J(1),1,J(2),1),reshape(A,1,I(1),1,I(2))); 215 | K = reshape(K,I(1)*J(1),[]); 216 | else 217 | K = kron(A,B); 218 | end 219 | end -------------------------------------------------------------------------------- /cpd/cp_gradients.m: -------------------------------------------------------------------------------- 1 | function Gxn = cp_gradients(X,U) 2 | % 3 | % for n = 1:N 4 | % tn = double(ttv(Y,u,-n)); 5 | % end 6 | R = size(U{1},2); 7 | I = size(X);N = ndims(X); 8 | 9 | % Find the first n* such that I1...In* > I(n*+1) ... IN 10 | Jn = cumprod(I); Kn = [Jn(end) Jn(end)./Jn(1:end-1)]; 11 | ns = find(Jn<=Kn,1,'last'); 12 | 13 | 14 | % CP-gradient X(n) * Khatri-Rao(U) except Un 15 | Gxn = cell(N,1); 16 | Pmat = []; 17 | for n = [ns:-1:1 ns+1:N] 18 | % Calculate Unew = X_(n) * khatrirao(all U except n, 'r'). 19 | if isa(X,'ktensor') || isa(X,'ttensor') || (N<=2) 20 | Gxn{n} = mttkrp(X,U,n); 21 | elseif isa(X,'tensor') || isa(X,'sptensor') 22 | if (n == ns) || (n == ns+1) 23 | [Gxn{n},Pmat] = cp_gradient(U,n,X); 24 | else 25 | [Gxn{n},Pmat] = cp_gradient(U,n,Pmat); 26 | end 27 | end 28 | end 29 | 30 | 31 | function [G,Pmat] = cp_gradient(A,n,Pmat) 32 | persistent KRP_right0; 33 | right = N:-1:n+1; left = n-1:-1:1; 34 | % KRP_right =[]; KRP_left = []; 35 | if n <= ns 36 | if n == ns 37 | if numel(right) == 1 38 | KRP_right = A{right}; 39 | elseif numel(right) > 2 40 | [KRP_right,KRP_right0] = khatrirao(A(right)); 41 | elseif numel(right) > 1 42 | KRP_right = khatrirao(A(right)); 43 | else 44 | KRP_right = 1; 45 | end 46 | 47 | if isa(Pmat,'tensor') 48 | Pmat = reshape(Pmat.data,[],prod(I(right))); % Right-side projection 49 | elseif isa(Pmat,'sptensor') 50 | Pmat = reshape(Pmat,[prod(size(Pmat))/prod(I(right)),prod(I(right))]); % Right-side projection 51 | Pmat = spmatrix(Pmat); 52 | else 53 | Pmat = reshape(Pmat,[],prod(I(right))); % Right-side projection 54 | end 55 | Pmat = Pmat * KRP_right ; 56 | else 57 | Pmat = reshape(Pmat,[],I(right(end)),R); 58 | if R>1 59 | Pmat = bsxfun(@times,Pmat,reshape(A{right(end)},[],I(right(end)),R)); 60 | Pmat = sum(Pmat,2); % fast Right-side projection 61 | else 62 | Pmat = Pmat * A{right(end)}; 63 | end 64 | end 65 | 66 | if ~isempty(left) % Left-side projection 67 | KRP_left = khatrirao(A(left)); 68 | % if (isempty(KRP_2) && (numel(left) > 2)) 69 | % [KRP_left,KRP_2] = khatrirao(A(left)); 70 | % elseif isempty(KRP_2) 71 | % KRP_left = khatrirao(A(left)); 72 | % %KRP_2 = []; 73 | % else 74 | % KRP_left = KRP_2; KRP_2 = []; 75 | % end 76 | T = reshape(Pmat,prod(I(left)),I(n),[]); 77 | if R>1 78 | T = bsxfun(@times,T,reshape(KRP_left,[],1,R)); 79 | T = sum(T,1); 80 | %G = squeeze(T); 81 | G = reshape(T,[],R); 82 | else 83 | G = (KRP_left'*T)'; 84 | end 85 | else 86 | %G = squeeze(Pmat); 87 | G = reshape(Pmat,[],R); 88 | end 89 | 90 | elseif n >=ns+1 91 | if n ==ns+1 92 | if numel(left) == 1 93 | KRP_left = A{left}'; 94 | elseif numel(left) > 1 95 | KRP_left = khatrirao_t(A(left)); 96 | %KRP_left = khatrirao(A(left));KRP_left = KRP_left'; 97 | else 98 | KRP_left = 1; 99 | end 100 | if isa(Pmat,'tensor') 101 | T = reshape(Pmat.data,prod(I(left)),[]); 102 | elseif isa(Pmat,'sptensor') 103 | T = reshape(Pmat,[prod(I(left)) prod(size(Pmat))/prod(I(left))]); % Right-side projection 104 | T = spmatrix(T); 105 | else 106 | T = reshape(Pmat,prod(I(left)),[]); 107 | end 108 | % 109 | Pmat = KRP_left * T; % Left-side projection 110 | else 111 | if R>1 112 | Pmat = reshape(Pmat,R,I(left(1)),[]); 113 | Pmat = bsxfun(@times,Pmat,A{left(1)}'); 114 | Pmat = sum(Pmat,2); % Fast Left-side projection 115 | else 116 | Pmat = reshape(Pmat,I(left(1)),[]); 117 | Pmat = A{left(1)}'* Pmat; 118 | end 119 | end 120 | 121 | if ~isempty(right) 122 | T = reshape(Pmat,[],I(n),prod(I(right))); 123 | 124 | if (n == (ns+1)) && (numel(right)>=2) 125 | %KRP_right = KRP_right0; 126 | if R>1 127 | T = bsxfun(@times,T,reshape(KRP_right0',R,1,[])); 128 | T = sum(T,3); 129 | %G = squeeze(T)'; % Right-side projection 130 | G = reshape(T, R,[])'; 131 | else 132 | %G = squeeze(T) * KRP_right0; 133 | G = reshape(T,[],prod(I(right))) * KRP_right0; 134 | end 135 | else 136 | KRP_right = khatrirao(A(right)); 137 | if R>1 138 | T = bsxfun(@times,T,reshape(KRP_right',R,1,[])); 139 | T = sum(T,3); 140 | %G = squeeze(T)'; % Right-side projection 141 | G = reshape(T,R,[])'; % Right-side projection 142 | else 143 | %G = squeeze(T) * KRP_right; 144 | G = reshape(T,I(n),[]) * KRP_right; 145 | end 146 | end 147 | else 148 | %G = squeeze(Pmat)'; 149 | G = reshape(Pmat,R,[])'; 150 | end 151 | 152 | end 153 | end 154 | end 155 | 156 | 157 | 158 | %% xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 159 | function [K,K2] = khatrirao(A) 160 | % Fast Khatri-Rao product 161 | % P = fastkhatrirao({A,B,C}) 162 | % 163 | %Copyright 2012, Phan Anh Huy. 164 | 165 | R = size(A{1},2); 166 | K = A{1}; 167 | if nargout == 1 168 | for i = 2:numel(A) 169 | K = bsxfun(@times,reshape(A{i},[],1,R),reshape(K,1,[],R)); 170 | end 171 | elseif numel(A) > 2 172 | for i = 2:numel(A)-1 173 | K = bsxfun(@times,reshape(A{i},[],1,R),reshape(K,1,[],R)); 174 | end 175 | K2 = reshape(K,[],R); 176 | K = bsxfun(@times,reshape(A{end},[],1,R),reshape(K,1,[],R)); 177 | end 178 | K = reshape(K,[],R); 179 | end 180 | 181 | 182 | %% xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 183 | function [K,K2] = khatrirao_t(A) 184 | % Fast Khatri-Rao product 185 | % P = fastkhatrirao({A,B,C}) 186 | % 187 | %Copyright 2012, Phan Anh Huy. 188 | 189 | R = size(A{1},2); 190 | K = A{1}'; 191 | 192 | for i = 2:numel(A) 193 | K = bsxfun(@times,reshape(A{i}',R,[]),reshape(K,R,1,[])); 194 | end 195 | K = reshape(K,R,[]); 196 | 197 | end 198 | 199 | 200 | %% 201 | function K = kron(A,B) 202 | % Fast implementation of Kronecker product of A and B 203 | % 204 | % Copyright 2012 Phan Anh Huy 205 | % $Date: 2012/3/18$ 206 | 207 | if ndims(A) > 2 || ndims(B) > 2 208 | error(message('See ndkron.m')); 209 | end 210 | I = size(A); J = size(B); 211 | 212 | if ~issparse(A) && ~issparse(B) 213 | K = bsxfun(@times,reshape(B,J(1),1,J(2),1),reshape(A,1,I(1),1,I(2))); 214 | K = reshape(K,I(1)*J(1),[]); 215 | else 216 | K = kron(A,B); 217 | end 218 | end -------------------------------------------------------------------------------- /cpd/cp_gram.m: -------------------------------------------------------------------------------- 1 | function P = cp_gram(X,R,complexloading) 2 | % Extended GRAM and direct trilinear decomposition to higher order CPD. 3 | % This decomposition is often used to initialize CP algorithms. 4 | % 5 | % REF: 6 | % [1] E. Sanchez and B.R. Kowalski, ?Tensorial resolution: a direct trilinear 7 | % decomposition,? J. Chemometrics, vol. 4, pp. 29?45, 1990. 8 | % 9 | % [2] C.A. Andersson and R. Bro, ?The N-way toolbox for MATLAB,? 10 | % Chemometrics and Intelligent Laboratory Systems, vol. 52, no. 1, pp. 11 | % 1-4, 2000. 12 | % [3] Anh-Huy Phan, Petr Tichavsky, Andrzej Cichocki, "CANDECOMP/PARAFAC 13 | % Decomposition of High-order Tensors Through Tensor Reshaping", arXiv, 14 | % http://arxiv.org/abs/1211.3796, 2012 15 | % 16 | % See also: cp_init, cp_fcp, dtld and gram of N-way toolbox 17 | % 18 | % TENSOR BOX, v1. 2012, 2013 19 | % Copyright 2011, Phan Anh Huy. 20 | 21 | if nargin<3 22 | complexloading = 0; 23 | end 24 | 25 | if ndims(X) > 3 26 | opts = cp_fcp; 27 | opts.compress_param.compress = false; 28 | % opts.compress_param.maxiters = 4; 29 | % opts.compress_param.tol = 1e-5; 30 | % opts.Rfold = R; 31 | 32 | opts.var_thresh = 0.9999; 33 | opts.refine = 1;%N-1; 34 | opts.fullrefine = false; 35 | opts.TraceFit = true; 36 | opts.foldingrule = 'direct';%[1 1 4]; % 'one' 'half' 'direct' 37 | opts.mindim = 3; 38 | 39 | opts.cp_param.complex = complexloading; 40 | opts.cp_func = @cp_mdltd; % @cp_fLMa_v2; %@cp_fastals; % @cp_fLMa_v2 cp_fastals 41 | opts.cp_reffunc = @cp_fastals; 42 | 43 | % ts = tic; 44 | [P,output,BagofOut] = cp_fcp(X,R,opts); 45 | % t3 = toc(ts); 46 | else 47 | [P,fit] = dtld(X,R,complexloading); 48 | output.Fit = [1 fit]; 49 | end 50 | end 51 | 52 | %% ###################################################################### 53 | function [P,output] = cp_mdltd(X,R,opts) 54 | % X: order-3 tensor 55 | [P,fit] = dtld(X,R,opts.complex); 56 | output.Fit = [1 fit]; 57 | end 58 | 59 | %% ###################################################################### 60 | function [P,fit]=dtld(X,F,Complexloading) 61 | 62 | %DTLD direct trilinear decomposition 63 | % 64 | % See also: 65 | % 'gram', 'parafac' 66 | % 67 | % 68 | % DIRECT TRILINEAR DECOMPOSITION 69 | % 70 | % calculate the parameters of the three- 71 | % way PARAFAC model directly. The model 72 | % is not the least-squares but will be close 73 | % to for precise data with little model-error 74 | % 75 | % This implementation works with an optimal 76 | % compression using least-squares Tucker3 fitting 77 | % to generate two pseudo-observation matrices that 78 | % maximally span the variation of all samples. per 79 | % default the mode of smallest dimension is compressed 80 | % to two samples, while the remaining modes are 81 | % compressed to dimension F. 82 | % 83 | % For large arrays it is fastest to have the smallest 84 | % dimension in the first mode 85 | % 86 | % INPUT 87 | % [A,B,C]=dtld(X,F); 88 | % X is the I x J x K array 89 | % F is the number of factors to fit 90 | % An optional parameter may be given to enforce which 91 | % mode is to be compressed to dimension two 92 | % 93 | 94 | % Copyright (C) 1995-2006 Rasmus Bro & Claus Andersson 95 | % Copenhagen University, DK-1958 Frederiksberg, Denmark, rb@life.ku.dk 96 | % 97 | % This program is free software; you can redistribute it and/or modify it under 98 | % the terms of the GNU General Public License as published by the Free Software 99 | % Foundation; either version 2 of the License, or (at your option) any later version. 100 | % 101 | % This program is distributed in the hope that it will be useful, but WITHOUT 102 | % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 103 | % FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 104 | % You should have received a copy of the GNU General Public License along with 105 | % this program; if not, write to the Free Software Foundation, Inc., 51 Franklin 106 | % Street, Fifth Floor, Boston, MA 02110-1301, USA. 107 | 108 | 109 | % $ Version 2.00 $ May 2001 $ Changed to array notation $ RB $ Not compiled $ 110 | % $ Version 1.02 $ Date 28. July 1998 $ Not compiled $ 111 | % $ Version 1.03 $ Date 25. April 1999 $ Not compiled $ 112 | % Modified by Anh-Huy Phan, 2013 113 | 114 | if nargin < 3 115 | Complexloading = 0; 116 | end 117 | DimX = size(X); 118 | order = []; 119 | if ~issorted(DimX) 120 | [DimX,order] = sort(DimX); 121 | X = permute(X,order); 122 | end 123 | 124 | Fac = [2 F F]; 125 | 126 | f=F; 127 | if F==1; 128 | Fac = [2 2 2]; 129 | f=2; 130 | end 131 | 132 | if DimX(1) < 2 133 | error(' The smallest dimension must be > 1') 134 | end 135 | 136 | if any(DimX(2:3)-Fac(2:3)<0) 137 | error(' This algorithm requires that two modes are of dimension not less the number of components') 138 | end 139 | 140 | 141 | % Compress data into a 2 x F x F array. Only 10 iterations are used since 142 | % exact SL fit is insignificant; only obtaining good truncated bases is 143 | % important 144 | dimorder = find(DimX>Fac); 145 | if ~isempty(dimorder) 146 | opts = struct('printitn',0,'tol',1e-6,'maxiters',5,'dimorder',dimorder); 147 | T = mtucker_als(X,Fac,opts); 148 | Gt = T.core.data; 149 | U = T.U; % note that two factor matrices U{n} are identity matrices, n # dimorder 150 | else 151 | Gt = X.data; 152 | U{1} = eye(DimX(1)); 153 | U{2} = eye(DimX(2)); 154 | U{3} = eye(DimX(3)); 155 | end 156 | 157 | 158 | % Fit GRAM to compressed data 159 | [Bg,Cg,Ag]=gram(squeeze(Gt(1,:,:)),squeeze(Gt(2,:,:)),F,Complexloading); 160 | 161 | U{2} = U{2}*Bg; 162 | U{3} = U{3}*Cg; 163 | CkB = bsxfun(@times,reshape(U{2},[],1,size(U{2},2)),reshape(U{3},1,[],size(U{3},2))); 164 | CkB = reshape(CkB,[],size(U{3},2)); 165 | X = reshape(X.data,[DimX(1),prod(DimX(2:end))]); 166 | U{1} = X*CkB * pinv((U{2}'*U{2}).*(U{3}'*U{3})); 167 | 168 | fit = sum(sum(abs(X - U{1}*CkB.').^2)); 169 | 170 | P = ktensor(U); 171 | if ~isempty(order) 172 | P = ipermute(P,order); 173 | end 174 | end 175 | 176 | 177 | function [A,B,C]=gram(X1,X2,F,Complexloading) 178 | 179 | %GRAM generalized rank annihilation method 180 | % 181 | % [A,B,C]=gram(X1,X2,F); 182 | % 183 | % cGRAM - Complex Generalized Rank Annihilation Method 184 | % Fits the PARAFAC model directly for the case of a 185 | % three-way array with only two frontal slabs. 186 | % For noise-free trilinear data the algorithm is exact. 187 | % If input is not complex, similarity transformations 188 | % are used for assuring a real solutions (Henk Kiers 189 | % is thanked for providing the similarity transformations) 190 | % 191 | % INPUTS: 192 | % X1 : I x J matrix of data from observation one 193 | % X2 : I x J matrix of data from observation two 194 | % Fac : Number of factors 195 | % 196 | % OUTPUTS: 197 | % A : Components in the row mode (I x F) 198 | % B : Components in the column mode (J x F) 199 | % C : Weights for each slab; C(1,:) are the component 200 | % weights for first slab such that the approximation 201 | % of X1 is equivalent to X1 = A*diag(C(1,:))*B.' 202 | % 203 | 204 | % Copyright (C) 1995-2006 Rasmus Bro & Claus Andersson 205 | % Copenhagen University, DK-1958 Frederiksberg, Denmark, rb@life.ku.dk 206 | % 207 | % This program is free software; you can redistribute it and/or modify it under 208 | % the terms of the GNU General Public License as published by the Free Software 209 | % Foundation; either version 2 of the License, or (at your option) any later version. 210 | % 211 | % This program is distributed in the hope that it will be useful, but WITHOUT 212 | % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 213 | % FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 214 | % You should have received a copy of the GNU General Public License along with 215 | % this program; if not, write to the Free Software Foundation, Inc., 51 Franklin 216 | % Street, Fifth Floor, Boston, MA 02110-1301, USA. 217 | 218 | % $ Version 1.02 $ Date 28. July 1998 $ Not compiled $ 219 | % $ Version 1.03 $ Date 22. February 1999 $ Not compiled $ 220 | % Modified by Anh-Huy Phan, 2013 221 | 222 | if nargin<4 223 | Complexloading = 0; 224 | end 225 | 226 | if Complexloading == 0 227 | IsReal=0; % If complex data, complex solutions allowed. 228 | if all(isreal(X1))&&all(isreal(X2)) 229 | IsReal=1; 230 | end 231 | else 232 | IsReal = 0; 233 | end 234 | 235 | % Find optimal bases in F x F subspace 236 | [U,s,V]=svd(X1+X2,0); 237 | U=U(:,1:F); 238 | V=V(:,1:F); 239 | 240 | % Reduce to an F x F dimensional subspace 241 | S1=U'*X1*V; 242 | S2=U'*X2*V; 243 | 244 | % Solve eigenvalue-problem and sort according to size 245 | [k,l]=eig(S1\S2); 246 | l=diag(l); 247 | ii=abs(l)>eps; 248 | k=k(:,ii); 249 | l=l(ii); 250 | p=length(l); 251 | [l,ii]=sort(l); 252 | j=p:-1:1; 253 | l=l(j); 254 | l=diag(l); 255 | k=k(:,ii(j)); 256 | %k=k/norm(k); 257 | 258 | if IsReal % Do not allow complex solutions if only reals are considered 259 | [k,l] = cdf2rdf(k,l); % simplified here 260 | end 261 | 262 | C(1,:)=ones(1,F); 263 | C(2,:)=diag(l)'; 264 | A = U*S1*k; 265 | B=V/k'; 266 | end -------------------------------------------------------------------------------- /cpd/cp_hessian.m: -------------------------------------------------------------------------------- 1 | function [H] = cp_hessian(U) 2 | % Generate the Hessian of the CP model of the factor matrices Un 3 | % H_mu = J'*J + \mu * I 4 | % 5 | % Phan Anh Huy 6 | % 7 | % 8 | %% Jacobian 9 | N = numel(U); 10 | In = cellfun(@(x) size(x,1),U,'uni',1); 11 | R = size(U{1},2); 12 | 13 | %% Hessian 14 | % H = G + Z*K*Z' 15 | % or 16 | 17 | H = hessian_form2; 18 | 19 | %% 20 | 21 | function [H,J] = hessian_jacobian 22 | % H = J'*J 23 | J = []; 24 | for n = 1: N 25 | Pn = permute_vec(In,n); 26 | Jn = kron(khatrirao(U(setdiff(1:N,n)),'r'),eye(In(n))); 27 | J = [J Pn' * Jn]; 28 | end 29 | H = J'*J; 30 | end 31 | 32 | 33 | function H = hessian_form1 34 | % H = G + Z * K * Z' 35 | Z = []; 36 | for n = 1: N 37 | Z = blkdiag(Z,kron(eye(R),U{n})); 38 | end 39 | 40 | K = zeros(N*R^2); 41 | for n = 1: N 42 | for m = setdiff(1:N,n) 43 | gmn = prod(Gamma_n(:,:,setdiff(1:N,[n,m])),3); 44 | K((n-1)*R^2+1:(n)*R^2,(m-1)*R^2+1:(m)*R^2) = Prr*diag(gmn(:)); 45 | end 46 | end 47 | H = G + Z * K * Z'; 48 | end 49 | 50 | 51 | function H = hessian_form2 52 | % H = G + Z*K0*Z' + V * K1 * V' 53 | % 54 | Prr = per_vectrans(R,R); 55 | 56 | Gamma_n = zeros(R,R,N); 57 | for n = 1: N 58 | Gamma_n(:,:,n) = U{n}'*U{n}; 59 | end 60 | 61 | G =[]; 62 | for n = 1:N 63 | gnn = prod(Gamma_n(:,:,[1:n-1 n+1:N]),3); 64 | G = blkdiag(G,kron(gnn, eye(In(n)))); 65 | end 66 | 67 | Z = []; 68 | for n = 1: N 69 | Z = blkdiag(Z,kron(eye(R),U{n})); 70 | end 71 | 72 | Gamma = prod(Gamma_n,3); 73 | F = diag(Gamma(:)); 74 | 75 | K0 = -diag(reshape(bsxfun(@rdivide,Gamma,Gamma_n.^2),[],1)); 76 | K0 = kron(eye(N),Prr) * K0; 77 | 78 | % kron(eye(N),Prr) *D = D * Prr; 79 | Zd = []; 80 | for n = 1:N 81 | Dn = diag(1./reshape(Gamma_n(:,:,n),[],1)); 82 | temp = kron(eye(R),U{n}) * Dn; 83 | Zd = [Zd;temp]; 84 | end 85 | Hblkdiag = G + Z * K0 * Z'; 86 | H = Hblkdiag + Zd * (Prr* F) * Zd'; 87 | end 88 | end 89 | -------------------------------------------------------------------------------- /cpd/cp_paro.m: -------------------------------------------------------------------------------- 1 | function [P,output] = cp_paro(T,R,opts) 2 | % 3 | % PArallel Rank-One Tensor Update Algorithm for CPD 4 | % 5 | % The algorithm updates rank-1 tensors simultaneously 6 | % x_r = best_rank1(xr + err) for r = 1, ..., R 7 | % 8 | % 9 | % INPUT: 10 | % T: N-way data which can be a tensor or a ktensor. 11 | % R: rank of the approximate tensor 12 | % OPTS: optional parameters 13 | % .tol: tolerance on difference in fit {1.0e-4} 14 | % .maxiters: Maximum number of iterations {200} 15 | % .init: Initial guess [{'random'}|'nvecs'| 'orthogonal'|'fiber'| ktensor| cell array] 16 | % init can be a cell array whose each entry specifies an intial 17 | % value. The algorithm will chose the best one after small runs. 18 | % For example, 19 | % opts.init = {'random' 'random' 'nvec'}; 20 | % .printitn: Print fit every n iterations {1} 21 | % .fitmax 22 | % .TraceFit: check fit values as stoping condition. 23 | % .TraceMSAE: check mean square angular error as stoping condition 24 | % 25 | % OUTPUT: 26 | % P: ktensor of estimated factors 27 | % output: 28 | % .Fit 29 | % .NoIters 30 | % 31 | % REF: 32 | % 33 | % TENSOR BOX, v1. 2012 34 | % Copyright 2011, Phan Anh Huy. 35 | % Phan Anh Huy, 2017 36 | 37 | 38 | %% Fill in optional variable 39 | if ~exist('opts','var'), opts = struct; end 40 | param = parseInput(opts); 41 | if nargin == 0 42 | P = param; return 43 | end 44 | 45 | N = ndims(T); 46 | szT = size(T); 47 | 48 | %% Initialize factors U 49 | param.cp_func = str2func(mfilename); 50 | Uinit = cp_init(T,R,param); U = Uinit; 51 | P = ktensor(U); 52 | 53 | %% Output 54 | if param.printitn ~=0 55 | fprintf('\nCP-PARO:\n'); 56 | end 57 | 58 | if nargout >=2 59 | output = struct('Uinit',{Uinit},'NoIters',[]); 60 | % if param.TraceFit 61 | output.Fit = []; 62 | % end 63 | end 64 | 65 | if isempty(param.normX) 66 | normX = norm(T); 67 | else 68 | normX = param.normX; 69 | end 70 | 71 | adjust_mu = param.adjust_gamma; 72 | check_gamma = param.check_gamma; 73 | 74 | gamma = param.gamma; 75 | 76 | lambda = P.lambda; 77 | U = P.U; 78 | x = khatrirao(U,'r')*diag(lambda); 79 | 80 | T = T(:); 81 | 82 | % For fast version 83 | xb = sum(x,2); 84 | mu = 1/gamma; 85 | err = (T - xb); % the mean error 86 | eb = err/(mu + R); 87 | curr_norm = norm(err); 88 | 89 | 90 | % for best rank-1 algorithm 91 | r1_opts = bestrank1tensorapprox(); 92 | r1_opts.maxiters = 100; 93 | r1_opts.r1_alg = param.r1_alg; 94 | r1_opts.init = 'nvec'; 95 | 96 | %% Mainloop 97 | flagtol =0; normchange = 0; 98 | pre_iter_adjust_mu = 0; 99 | accepted_mu_ = mu; 100 | chk_stop = 0; 101 | 102 | 103 | %% 104 | for iter = 1:param.maxiters 105 | pre_norm = curr_norm; 106 | 107 | [Upre,lambda_pre] = deal(U,lambda); 108 | 109 | % xr = argmin cpd ( x_r + 1/(1/gamma + R) * (t - yb - xb)) 110 | % Parallel loop here to estimate best rank-1 tensors x_r 111 | Pr_ = cell(1,R); 112 | % for r = 1:R 113 | parfor r = 1:R 114 | Txr = x(:,r) + eb; 115 | Txr= tensor(Txr,szT); 116 | 117 | % cp_opts = cp_fLMa; 118 | % cp_opts.maxiters = 1000; 119 | % cp_opts.dimorder = 1:N; 120 | % %Pr = mtucker_als(Txr,ones(1,N),cp_opts,cellfun(@(x) x(:,r),U,'uni',0)); 121 | % %cp_opts.init = {'nvec' cellfun(@(x) x(:,r),U,'uni',0)}; 122 | % cp_opts.init = 'nvec'; 123 | %Pr = cp_fastals(Txr,1,r1_opts); 124 | 125 | 126 | %r1_opts.r1_alg = @cp_fastals; 127 | %r1_opts.r1_alg = @cp_r1LM; 128 | %r1_opts.r1_alg = @cp_r1lm_optmu; 129 | % best rank-1 of Txr 130 | 131 | % init 1 132 | [Pr,out_] = bestrank1tensorapprox(Txr,r1_opts); 133 | 134 | 135 | %% init 2 136 | if 0 137 | [Pr2] = mtucker_als(Txr,ones(1,N),cp_opts,'nvecs'); 138 | 139 | %% fLM - stage 2 140 | cp_opts = cp_fLMa; 141 | cp_opts.maxiters = 1000; 142 | cp_opts.printitn = 0; 143 | cp_opts.tol = 1e-8; 144 | cp_opts.init = {Pr Pr2}; 145 | 146 | Pr = cp_fLMa(Txr,1,cp_opts); 147 | end 148 | %% 149 | 150 | 151 | Pr_{r} = Pr; 152 | end 153 | 154 | for r = 1:R 155 | Pr = Pr_{r}; 156 | for n = 1:numel(U) 157 | U{n}(:,r) = Pr.u{n}; 158 | end 159 | lambda(r) = Pr.lambda; 160 | end 161 | 162 | xnew = khatrirao(U,'r')*diag(lambda); 163 | xb_new = sum(xnew,2); 164 | 165 | % update the error 166 | err = T-xb_new; 167 | 168 | % evaluate cost function 169 | curr_norm = norm(err); 170 | fit = 1 - (curr_norm/ normX); %fraction explained by model 171 | 172 | if iter >= 1 173 | if (pre_norm < curr_norm) && (adjust_mu || check_gamma) 174 | 175 | if ( iter > 5) && check_gamma 176 | [U,lambda] = deal(Upre,lambda_pre); 177 | % function is non-decreasing Stop and run again with higher gamma 178 | break; 179 | end 180 | if adjust_mu 181 | flagtol = 0; 182 | % adjust mu % increase mu and eb 183 | eb(:) = 0; 184 | % eb = eb*(mu + R)/(accepted_mu_(end) + R); 185 | mu = accepted_mu_(end); 186 | [U,lambda] = deal(Upre,lambda_pre); 187 | curr_norm = pre_norm; 188 | end 189 | else 190 | % update the mean residue 191 | % when mu = R, the average mean eb = err/R; 192 | % eb = err/R; % mu = R 193 | % 194 | % eb = T - 2*xb_new + xb + R/(mu + R) *eb; 195 | eb = (err - xb_new + xb + R *eb)/(mu + R); 196 | 197 | %eb = (err - xb_new + xb + R *eb)/(mu + R); 198 | 199 | x = xnew; 200 | xb = xb_new; 201 | 202 | normchange = abs(pre_norm - curr_norm); 203 | if (iter > 1) && (normchange < param.tol) % Check for convergence 204 | flagtol = flagtol + 1; 205 | else 206 | flagtol = 0; 207 | end 208 | chk_stop(1) = flagtol >= 10; 209 | 210 | %chk_stop(3) = fit >= param.fitmax; 211 | if nargout >=2 212 | output.Fit = [output.Fit; iter fit]; 213 | end 214 | 215 | if (adjust_mu == 1) && (iter - pre_iter_adjust_mu)>20 216 | % we can lower mu to be smaller if the algorithm works well 217 | % for the current mu 218 | accepted_mu_ = [accepted_mu_ mu]; 219 | 220 | mu = mu / 1.15; 221 | pre_iter_adjust_mu = iter; 222 | end 223 | end 224 | end 225 | 226 | if mod(iter,param.printitn)==0 227 | fprintf(' Iter %2d: ',iter); 228 | fprintf('fit = %e fitdelta = %7.1e , mu % d', fit, normchange,mu); 229 | fprintf('\n'); 230 | end 231 | 232 | 233 | % Check for convergence 234 | if (iter > 1) && any(chk_stop) 235 | break; 236 | end 237 | end 238 | 239 | P = ktensor(lambda,U); 240 | 241 | if nargout >=2 242 | output.NoIters = iter; 243 | end 244 | 245 | 246 | end 247 | 248 | 249 | 250 | 251 | 252 | %% Parse input xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 253 | function param = parseInput(opts) 254 | %% Set algorithm parameters from input or by using defaults 255 | param = inputParser; 256 | param.KeepUnmatched = true; 257 | param.addOptional('init','random',@(x) (iscell(x) || isa(x,'ktensor')||... 258 | ismember(x(1:4),{'rand' 'nvec' 'fibe' 'orth' 'dtld'}))); 259 | param.addOptional('maxiters',200); 260 | param.addOptional('tol',1e-6); 261 | param.addOptional('printitn',0); 262 | param.addOptional('fitmax',1-1e-10); 263 | param.addOptional('linesearch',true); 264 | 265 | 266 | %param.addParamValue('verify_convergence',true,@islogical); 267 | % param.addParamValue('TraceFit',true,@islogical); 268 | % param.addParamValue('TraceMSAE',false,@islogical); 269 | 270 | % param.addParamValue('TraceRank1Norm',false,@islogical); 271 | % param.addParamValue('max_rank1norm',inf); 272 | 273 | param.addOptional('gamma',1e-3); 274 | param.addOptional('adjust_gamma',false,@islogical); 275 | param.addOptional('normX',[]); 276 | 277 | param.addOptional('check_gamma',true,@islogical); 278 | 279 | param.addOptional('r1_alg',@cp_roro); 280 | 281 | param.parse(opts); 282 | param = param.Results; 283 | % param.verify_convergence = param.TraceFit || param.TraceMSAE; 284 | end -------------------------------------------------------------------------------- /cpd/cp_paro_v2.m: -------------------------------------------------------------------------------- 1 | function [P,output] = cp_paro(T,R,opts) 2 | % 3 | % PArallel Rank-One Tensor Update Algorithm for CPD 4 | % 5 | % The algorithm updates rank-1 tensors simultaneously 6 | % x_r = best_rank1(xr + err) for r = 1, ..., R 7 | % 8 | % 9 | % INPUT: 10 | % T: N-way data which can be a tensor or a ktensor. 11 | % R: rank of the approximate tensor 12 | % OPTS: optional parameters 13 | % .tol: tolerance on difference in fit {1.0e-4} 14 | % .maxiters: Maximum number of iterations {200} 15 | % .init: Initial guess [{'random'}|'nvecs'| 'orthogonal'|'fiber'| ktensor| cell array] 16 | % init can be a cell array whose each entry specifies an intial 17 | % value. The algorithm will chose the best one after small runs. 18 | % For example, 19 | % opts.init = {'random' 'random' 'nvec'}; 20 | % .printitn: Print fit every n iterations {1} 21 | % .fitmax 22 | % .TraceFit: check fit values as stoping condition. 23 | % .TraceMSAE: check mean square angular error as stoping condition 24 | % 25 | % OUTPUT: 26 | % P: ktensor of estimated factors 27 | % output: 28 | % .Fit 29 | % .NoIters 30 | % 31 | % REF: 32 | % 33 | % TENSOR BOX, v1. 2012 34 | % Copyright 2011, Phan Anh Huy. 35 | % Phan Anh Huy, 2017 36 | 37 | 38 | %% Fill in optional variable 39 | if ~exist('opts','var'), opts = struct; end 40 | param = parseInput(opts); 41 | if nargin == 0 42 | P = param; return 43 | end 44 | 45 | N = ndims(T); 46 | szT = size(T); 47 | 48 | %% Initialize factors U 49 | param.cp_func = str2func(mfilename); 50 | Uinit = cp_init(T,R,param); U = Uinit; 51 | P = ktensor(U); 52 | 53 | %% Output 54 | if param.printitn ~=0 55 | fprintf('\nCP-PARO:\n'); 56 | end 57 | 58 | if nargout >=2 59 | output = struct('Uinit',{Uinit},'NoIters',[]); 60 | % if param.TraceFit 61 | output.Fit = []; 62 | % end 63 | end 64 | 65 | if isempty(param.normX) 66 | normX = norm(T); 67 | else 68 | normX = param.normX; 69 | end 70 | 71 | adjust_mu = param.adjust_gamma; 72 | check_gamma = param.check_gamma; 73 | 74 | gamma = param.gamma; 75 | 76 | lambda = P.lambda; 77 | U = P.U; 78 | x = khatrirao(U,'r')*diag(lambda); 79 | 80 | T = T(:); 81 | 82 | % For fast version 83 | xb = sum(x,2); 84 | mu = 1/gamma; 85 | err = (T - xb); % the mean error 86 | 87 | % Initialize the residue tensor 88 | % 89 | if isempty(param.residue_estimate_tensor)% = x(k) - x(k-1) 90 | eb = err/(mu + R); 91 | else 92 | eb = (err - param.residue_estimate_tensor(:))/(mu + R); 93 | end 94 | curr_norm = norm(err); 95 | 96 | 97 | % for best rank-1 algorithm 98 | r1_opts = bestrank1tensorapprox(); 99 | r1_opts.maxiters = 100; 100 | r1_opts.r1_alg = param.r1_alg; 101 | r1_opts.init = 'nvec'; 102 | 103 | %% Mainloop 104 | flagtol =0; normchange = 0; 105 | pre_iter_adjust_mu = 0; 106 | accepted_mu_ = mu; 107 | chk_stop = 0; 108 | 109 | 110 | %% 111 | for iter = 1:param.maxiters 112 | pre_norm = curr_norm; 113 | 114 | [Upre,lambda_pre] = deal(U,lambda); 115 | 116 | % xr = argmin cpd ( x_r + 1/(1/gamma + R) * (t - yb - xb)) 117 | % Parallel loop here to estimate best rank-1 tensors x_r 118 | Pr_ = cell(1,R); 119 | % for r = 1:R 120 | parfor r = 1:R 121 | Txr = x(:,r) + eb; 122 | Txr= tensor(Txr,szT); 123 | 124 | % cp_opts = cp_fLMa; 125 | % cp_opts.maxiters = 1000; 126 | % cp_opts.dimorder = 1:N; 127 | % %Pr = mtucker_als(Txr,ones(1,N),cp_opts,cellfun(@(x) x(:,r),U,'uni',0)); 128 | % %cp_opts.init = {'nvec' cellfun(@(x) x(:,r),U,'uni',0)}; 129 | % cp_opts.init = 'nvec'; 130 | %Pr = cp_fastals(Txr,1,r1_opts); 131 | 132 | 133 | %r1_opts.r1_alg = @cp_fastals; 134 | %r1_opts.r1_alg = @cp_r1LM; 135 | %r1_opts.r1_alg = @cp_r1lm_optmu; 136 | % best rank-1 of Txr 137 | 138 | % init 1 139 | [Pr,out_] = bestrank1tensorapprox(Txr,r1_opts); 140 | 141 | 142 | %% init 2 143 | if 0 144 | [Pr2] = mtucker_als(Txr,ones(1,N),cp_opts,'nvecs'); 145 | 146 | %% fLM - stage 2 147 | cp_opts = cp_fLMa; 148 | cp_opts.maxiters = 1000; 149 | cp_opts.printitn = 0; 150 | cp_opts.tol = 1e-8; 151 | cp_opts.init = {Pr Pr2}; 152 | 153 | Pr = cp_fLMa(Txr,1,cp_opts); 154 | end 155 | %% 156 | 157 | 158 | Pr_{r} = Pr; 159 | end 160 | 161 | for r = 1:R 162 | Pr = Pr_{r}; 163 | for n = 1:numel(U) 164 | U{n}(:,r) = Pr.u{n}; 165 | end 166 | lambda(r) = Pr.lambda; 167 | end 168 | 169 | xnew = khatrirao(U,'r')*diag(lambda); 170 | xb_new = sum(xnew,2); 171 | 172 | % update the error 173 | err = T-xb_new; 174 | 175 | % evaluate cost function 176 | curr_norm = norm(err); 177 | fit = 1 - (curr_norm/ normX); %fraction explained by model 178 | 179 | if iter > 1 180 | if (pre_norm < curr_norm) && (adjust_mu || check_gamma) 181 | 182 | if ( iter > 5) && check_gamma 183 | [U,lambda] = deal(Upre,lambda_pre); 184 | % function is non-decreasing Stop and run again with higher gamma 185 | break; 186 | end 187 | if adjust_mu 188 | flagtol = 0; 189 | % adjust mu % increase mu and eb 190 | eb(:) = 0; 191 | % eb = eb*(mu + R)/(accepted_mu_(end) + R); 192 | mu = accepted_mu_(end); 193 | [U,lambda] = deal(Upre,lambda_pre); 194 | curr_norm = pre_norm; 195 | end 196 | else 197 | % update the mean residue 198 | % when mu = R, the average mean eb = err/R; 199 | % eb = err/R; % mu = R 200 | % 201 | % eb = T - 2*xb_new + xb + R/(mu + R) *eb; 202 | eb = (err - xb_new + xb + R *eb)/(mu + R); 203 | 204 | %eb = (err - xb_new + xb + R *eb)/(mu + R); 205 | 206 | x = xnew; 207 | xb = xb_new; 208 | 209 | normchange = abs(pre_norm - curr_norm); 210 | if (iter > 1) && (normchange < param.tol) % Check for convergence 211 | flagtol = flagtol + 1; 212 | else 213 | flagtol = 0; 214 | end 215 | chk_stop(1) = flagtol >= 10; 216 | 217 | %chk_stop(3) = fit >= param.fitmax; 218 | if nargout >=2 219 | output.Fit = [output.Fit; iter fit]; 220 | end 221 | 222 | if (adjust_mu == 1) && (iter - pre_iter_adjust_mu)>20 223 | % we can lower mu to be smaller if the algorithm works well 224 | % for the current mu 225 | accepted_mu_ = [accepted_mu_ mu]; 226 | 227 | mu = mu / 1.15; 228 | pre_iter_adjust_mu = iter; 229 | end 230 | end 231 | end 232 | 233 | if mod(iter,param.printitn)==0 234 | fprintf(' Iter %2d: ',iter); 235 | fprintf('fit = %e fitdelta = %7.1e , mu % d', fit, normchange,mu); 236 | fprintf('\n'); 237 | end 238 | 239 | 240 | % Check for convergence 241 | if (iter > 1) && any(chk_stop) 242 | break; 243 | end 244 | end 245 | 246 | P = ktensor(lambda,U); 247 | 248 | if nargout >=2 249 | output.NoIters = iter; 250 | end 251 | 252 | 253 | end 254 | 255 | 256 | 257 | 258 | 259 | %% Parse input xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 260 | function param = parseInput(opts) 261 | %% Set algorithm parameters from input or by using defaults 262 | param = inputParser; 263 | param.KeepUnmatched = true; 264 | param.addOptional('init','random',@(x) (iscell(x) || isa(x,'ktensor')||... 265 | ismember(x(1:4),{'rand' 'nvec' 'fibe' 'orth' 'dtld'}))); 266 | param.addOptional('maxiters',200); 267 | param.addOptional('tol',1e-6); 268 | param.addOptional('printitn',0); 269 | param.addOptional('fitmax',1-1e-10); 270 | param.addOptional('linesearch',true); 271 | param.addOptional('residue_estimate_tensor',[]); 272 | 273 | 274 | %param.addParamValue('verify_convergence',true,@islogical); 275 | % param.addParamValue('TraceFit',true,@islogical); 276 | % param.addParamValue('TraceMSAE',false,@islogical); 277 | 278 | % param.addParamValue('TraceRank1Norm',false,@islogical); 279 | % param.addParamValue('max_rank1norm',inf); 280 | 281 | param.addOptional('gamma',1e-3); 282 | param.addOptional('adjust_gamma',false,@islogical); 283 | param.addOptional('normX',[]); 284 | 285 | param.addOptional('check_gamma',true,@islogical); 286 | 287 | param.addOptional('r1_alg',@cp_roro); 288 | 289 | param.parse(opts); 290 | param = param.Results; 291 | % param.verify_convergence = param.TraceFit || param.TraceMSAE; 292 | end -------------------------------------------------------------------------------- /cpd/cp_rankdetermination.m: -------------------------------------------------------------------------------- 1 | function [P,R,apxrank] = cp_rankdetermination(Y,delta,Rinit,opts) 2 | %% RANK Detection with a prescribed noise level 3 | % The method is based on the EPC method 4 | % 5 | % 6 | % TENSORBOX, 2018 7 | % 8 | if ~exist('opts','var'), opts = struct; end 9 | opt_cp = parseInput(opts); 10 | if nargin == 0 11 | P = opt_cp; return 12 | end 13 | 14 | %% accuracy = C*noise_level*sqrt(numel(Y)); % C = 1.01 15 | accuracy = delta; 16 | 17 | apxrank = []; 18 | 19 | doing_estimation = true; 20 | best_result = []; 21 | 22 | Rcp = Rinit; 23 | 24 | opts = opt_cp; 25 | 26 | while doing_estimation 27 | fprintf('Rank %d ...\n',Rcp); 28 | 29 | 30 | %% 31 | try 32 | fprintf('step 1'); 33 | [Pbx,outputx] = cp_anc(Y,Rcp,accuracy,opt_cp); 34 | 35 | %% 36 | fprintf('step 2'); 37 | 38 | opts.maxiters = 1000; 39 | opts.init = Pbx; 40 | catch 41 | opts = opt_cp; 42 | end 43 | [tt_approx] = cp_nc_sqp(Y,Rcp,accuracy,opts); 44 | tt_approx = normalize(tt_approx); 45 | tt_approx = arrange(tt_approx); 46 | 47 | err_cp = norm(Y - full(tt_approx)); 48 | norm_lda = norm(tt_approx.lambda(:)); 49 | 50 | %% 51 | if err_cp <= accuracy + 1e-5 52 | % the estimated result seems to be good 53 | if isempty(best_result) || (Rcp < best_result(1)) 54 | best_tt_approx = tt_approx; 55 | best_result = [Rcp err_cp norm_lda]; 56 | end 57 | 58 | if (Rcp > 1) % try the estimation with a lower rank 59 | Rcp_new = Rcp-1; 60 | else 61 | doing_estimation = false; 62 | end 63 | else 64 | Rcp_new = Rcp+1; 65 | end 66 | 67 | apxrank = [apxrank ; [Rcp err_cp norm_lda]]; 68 | if any(apxrank(:,1) == Rcp_new) 69 | doing_estimation = false; 70 | end 71 | Rcp = Rcp_new; 72 | end 73 | 74 | %% 75 | R = best_result(1); 76 | P = best_tt_approx; 77 | fprintf('Estimated Rank %d\n',R); 78 | 79 | end 80 | 81 | %% Parse input xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 82 | function param = parseInput(opts) 83 | %% Set algorithm parameters from input or by using defaults 84 | param = inputParser; 85 | param.KeepUnmatched = true; 86 | param.addOptional('init',[repmat({'rand'},1,20) 'nvec'],@(x) (iscell(x) || isa(x,'ktensor')||... 87 | ismember(x(1:4),{'rand' 'nvec' 'fibe' 'orth' 'dtld'}))); 88 | param.addOptional('maxiters',1000); 89 | param.addOptional('tol',1e-6); 90 | param.addOptional('printitn',0); 91 | param.addOptional('fitmax',1-1e-10); 92 | param.addOptional('linesearch',true); 93 | %param.addParamValue('verify_convergence',true,@islogical); 94 | param.addParamValue('TraceFit',true,@islogical); 95 | param.addParamValue('TraceMSAE',false,@islogical); 96 | 97 | param.addParamValue('TraceRank1Norm',false,@islogical); 98 | param.addParamValue('max_rank1norm',inf); 99 | 100 | param.addOptional('normX',[]); 101 | 102 | param.parse(opts); 103 | param = param.Results; 104 | param.verify_convergence = param.TraceFit || param.TraceMSAE; 105 | end 106 | 107 | 108 | -------------------------------------------------------------------------------- /cpd/cp_to_tt.m: -------------------------------------------------------------------------------- 1 | function Y = cp_to_tt(A) 2 | % 3 | % Exact CP to TT conversion 4 | % 5 | % Inputs are factor matrices A{n} 6 | % Output is a TT-tensor Y whose core tensors [[An,I,I]] 7 | % TENSORBOX, 2018 8 | % 9 | d = numel(A); 10 | R = size(A{1},2); 11 | G = cell(d,1); 12 | % G{1} = reshape(A{1},1,[],R);G{d} = A{1}'; 13 | % for k = 2: d-1 14 | % G{k} = full(ktensor({eye(R),A{k},eye(R)})); 15 | % end 16 | 17 | G{1} = A{1};G{d} = A{end}; 18 | for k = 2: d-1 19 | G{k} = full(ktensor({A{k},eye(R),eye(R)})); 20 | end 21 | 22 | Y = tt_tensor(G); 23 | -------------------------------------------------------------------------------- /cpd/cprintf.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phananhhuy/TensorBox/8b96a0c8a4f7799d838f4be16a1c6b4de80b5765/cpd/cprintf.m -------------------------------------------------------------------------------- /cpd/cribCP.m: -------------------------------------------------------------------------------- 1 | function criball = cribCP(U,Weights,noisevar) 2 | % Cramer Rao Induced bound of the squared angular error for estimation of 3 | % loading components in a CANDECOMP/PARAFAC decomposition 4 | % U: factor matrices U{1}, U{2}, ..., U{N} 5 | % Weights: indicator tensor of 0 (missing entries) and 1. 6 | % noisevar : variance of Gaussian noise (1) 7 | % 8 | % Ref: 9 | % P. Tichavsk?, A.-H. Phan, and Z. Koldovsk?, ?Cram?r-Rao-induced bounds 10 | % for CANDECOMP/PARAFAC tensor decomposition,? IEEE Trans. Signal Process., 11 | % vol. 61, no. 8, pp. 1986?1997, 2013. 12 | % 13 | % TENSORBOX, 2014 14 | % 15 | if nargin < 2 16 | Weights = []; 17 | end 18 | 19 | if nargin < 3 20 | noisevar = 1; 21 | end 22 | 23 | N = numel(U);R = size(U{1},2); 24 | criball = zeros(N,R); 25 | for n = 1:N 26 | criball(n,:) = cribCP1(U([n 1:n-1 n+1:end]),Weights); 27 | end 28 | criball = criball*noisevar; 29 | end -------------------------------------------------------------------------------- /cross/crossindexes.m: -------------------------------------------------------------------------------- 1 | %% Function that finds a good submatrix 2 | function [indrows,indcols]=crossindexes(A,K) 3 | % 4 | % TENSORBOX, 2018 5 | 6 | [m,n]=size(A); 7 | 8 | indcols=zeros(K,1) ; %Initialize a null column indexes 9 | indrows=zeros(K,1) ; %Initialize a null row indexes 10 | 11 | C=zeros(m,K); 12 | R=zeros(K,n); 13 | 14 | %indrows(1)=ceil(m*rand()); %Selects the first row at random 15 | indcols(1)=ceil(n*rand); %Selects the first column at random 16 | % indcols(1)=1; %Selects the first column at random 17 | 18 | %R(1,:)=A(indrows(1),:); 19 | C(:,1)=A(:,indcols(1)); 20 | [aux,newrowind]=max((C(:,1))); % Selects the first row pivoting in maximum entry 21 | indrows(1)=newrowind; 22 | R(1,:)=A(indrows(1),:); 23 | 24 | U=1/(A(indrows(1),indcols(1))); 25 | 26 | %Aest=C(:,1)*U*R(1,:); 27 | Eant=A(indrows(1),:); 28 | 29 | %start a loop for columns and rows from number 2 30 | current=2; 31 | 32 | CU = C(:,1)*U; 33 | UR = U*R(1,:); 34 | while current <= K 35 | % Search for the best row to add 36 | indcols(current) = addrowCross_fast(indcols(1:current-1), Eant'); 37 | c = A(:,indcols(current)); 38 | x = c(indrows(1:current-1)); 39 | CUx = CU * x; 40 | E=A(:,indcols(current)) - CUx; 41 | 42 | indrows(current) = addrowCross_fast(indrows(1:current-1), E); 43 | r = A(indrows(current),:); 44 | y = r(indcols(1:current-1)); 45 | yUR = y*UR; 46 | Eant = A(indrows(current),:) - yUR; 47 | 48 | z = r(indcols(current)); 49 | 50 | yU=y*U; %the product for repeated use 51 | Ux=U*x; %the (1,2)th block 52 | q = 1/(z-yU*x); %the (2,2)th block 53 | 54 | t1 = q*(CUx - c); 55 | CU = [CU+t1*yU, -t1]; 56 | 57 | t1 = q*(yUR-r); 58 | UR = [UR+Ux * t1 ; -t1]; 59 | 60 | U = [U+q*Ux*yU -q*Ux; -yU*q q]; %updated inverse 61 | current=current+1; 62 | end 63 | 64 | function ind=addrowCross_fast(indrows,C) 65 | ind = 1:numel(C); 66 | ind(indrows) = []; 67 | [maxC,loc] = max(abs(C(ind))); 68 | ind = ind(loc); -------------------------------------------------------------------------------- /data/amino.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phananhhuy/TensorBox/8b96a0c8a4f7799d838f4be16a1c6b4de80b5765/data/amino.mat -------------------------------------------------------------------------------- /data/lena_std.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phananhhuy/TensorBox/8b96a0c8a4f7799d838f4be16a1c6b4de80b5765/data/lena_std.tiff -------------------------------------------------------------------------------- /linreg/linreg_bound.m: -------------------------------------------------------------------------------- 1 | function [X,cone_d] = linreg_bound(y,A,delta,method) 2 | % Solving the linear regresion 3 | % 4 | % min \| X \|_F^2 5 | % 6 | % subject to \| y - A*vec(X)\| < delta 7 | % 8 | % where y is a vector of length K, 9 | % A is required to be full column rank matrix of size K x I, K>=I 10 | % 11 | % The bound delta must satisfy 12 | % norm(y)^2 - norm(F'*y)^2 <= delta^2 <= norm(y)^2 13 | % 14 | % where F is an orthonormal basis of A 15 | % 16 | % Phan Anh Huy, 19/05/2017 17 | 18 | if nargin<4 19 | method = 'closeform'; 20 | end 21 | sz = size(A); 22 | delta = max(0,delta); 23 | %% Compression when K exceeds number of elements of X 24 | % A = Q*F 25 | % \| y - A*x\| = \|Q'*y - F*x\| 26 | compression = sz(1) > sz(2); 27 | if compression 28 | y0 = y;normy2 = norm(y0)^2; 29 | delta0 = delta; 30 | 31 | % Find subspace of A 32 | eig_compression = true; 33 | if eig_compression 34 | % this method can be cheaper since no need compute the basis of A 35 | Q = A'*A; 36 | [Vq,Sq] = eig(Q); 37 | Sq = max(diag(Sq),0); 38 | Sq = sqrt(Sq); 39 | %Uq = A*Vq'/Sq; 40 | 41 | if min(Sq) == 0 42 | warning('A should be a full column rank matrix.\nUse "linreg_lrmx" to solve \min |X|_* + mu * |X|_F^2 subject to | Y - A(X)|_F^2 < delta') 43 | iss = find(Sq>1e-12); 44 | y = (Vq(:,iss)'*(A'*y))./Sq(iss); % compressed y 45 | U = diag(Sq(iss))*Vq(:,iss)'; 46 | else 47 | y = (Vq'*(A'*y))./(Sq); 48 | U = diag(Sq)*Vq'; 49 | end 50 | else 51 | % QR-based compression of A 52 | [F,U] = qr(A,0); 53 | y = F'*y0; 54 | end 55 | gamma = normy2-norm(y)^2; 56 | delta2 = delta^2; 57 | % gamma < delta^2 < norm(y) 58 | if (delta2 < gamma) 59 | error('delta is now smaler than norm(y - A*A\y)\n. It must be in the range [norm(y - A*A\y), norm(y)]') 60 | end 61 | if (delta > normy2) 62 | error('delta is greater than norm(y)\n. It must be in the range [norm(y - A*A\y), norm(y)]') 63 | end 64 | 65 | delta2 = delta2 - gamma; 66 | delta = sqrt(delta2); 67 | else 68 | U = A; 69 | end 70 | 71 | 72 | if (size(U,1) < size(U,2)) || strcmp(method,'cvx') 73 | % non square matrix case 74 | cvx_begin 75 | cvx_precision best 76 | variable X(sz(2),1) 77 | minimize sum_square(X) 78 | subject to 79 | norm(U*(X) - y ) <= delta 80 | cvx_end 81 | 82 | 83 | % Aop = linop_matrix(U,'R2R'); 84 | % tf_opts = []; 85 | % tf_opts.alg = 'AT'; % gradien descend 'AT' 'LLM'; 'GRA' N83 86 | % tf_opts.maxIts = 5000; 87 | % tf_opts.continuation = 0; 88 | % [X,out] = tfocs_SCD( [], { Aop, -y }, prox_l2(delta), 1, [], [], tf_opts); 89 | 90 | else 91 | % closed form 92 | B = inv(U); 93 | b = B*y; % == A\y 94 | % x = pinv(U)*(y2+delta2*r) = b + delta2* inv(U)*r , r^T * r = 1 95 | % min |b + delta2 * B*r|^2 s.t. r^T*r = 1 96 | % 97 | % min r'*(B'*B)*r + 2/delta2*b'*B*r s.t. r^T*r = 1 98 | Q = B'*B; 99 | [r,fval,lda] = squadprog(Q,B'*b/delta); 100 | 101 | X = b + delta*B*r; 102 | end 103 | X = X(:,1); 104 | cone_d = norm(y - U*X); 105 | if compression 106 | cone_d = sqrt(cone_d^2 + gamma); 107 | end 108 | 109 | %% 110 | 111 | 112 | 113 | 114 | function op = prox_l2( q ) 115 | 116 | %PROX_L2 L2 norm. 117 | % OP = PROX_L2( q ) implements the nonsmooth function 118 | % OP(X) = q * norm(X,'fro'). 119 | % Q is optional; if omitted, Q=1 is assumed. But if Q is supplied, 120 | % then it must be a positive real scalar. 121 | % If Q is a vector or matrix of the same size and dimensions as X, 122 | % then this uses an experimental code to compute the proximity operator 123 | % of OP(x) = norm( q.*X, 'fro' ) 124 | % In the limit q --> 0, this function acts like prox_0 (aka proj_Rn) 125 | % Dual: proj_l2.m 126 | % For the proximity operator of the l2 squared norm (that is, norm(X,'fro')^2) 127 | % use smooth_quad.m (which can be used in either a smooth gradient-based fashion 128 | % but also supports proximity usage). Note smooth_quad() is self-dual. 129 | % See also proj_l2, prox_0, proj_Rn 130 | 131 | % Feb '11, allowing for q to be a vector 132 | % This is complicated, so not for certain 133 | % A safer method is to use a linear operator to scale the variables 134 | 135 | if nargin == 0, 136 | q = 1; 137 | % elseif ~isnumeric( q ) || ~isreal( q ) || numel( q ) ~= 1 || q <= 0, 138 | elseif ~isnumeric( q ) || ~isreal( q ) %|| any( q < 0 ) || all(q==0) 139 | error( 'Argument must be positive.' ); 140 | end 141 | if isscalar(q) 142 | if any( q <= 0 ) 143 | error('Scaling argument must be positive, real scalar. If q=0, use prox_0 instead'); 144 | end 145 | op = @(varargin)prox_l2_q( q, varargin{:} ); 146 | else 147 | if all(q==0), error('Argument must be nonzero'); end 148 | warning('TFOCS:experimental','Using experimental feature of TFOCS'); 149 | op = @(varargin)prox_l2_vector( q, varargin{:} ); 150 | end 151 | 152 | function [ v, x ] = prox_l2_q( q, x, t ) 153 | if nargin < 2, 154 | error( 'Not enough arguments.' ); 155 | end 156 | v = sqrt( tfocs_normsq( x ) ); 157 | if nargin == 3, 158 | s = 1 - 1 ./ max( v / ( t * q ), 1 ); 159 | 160 | x = x * s; 161 | v = v * s; % version A 162 | elseif nargout == 2, 163 | error( 'This function is not differentiable.' ); 164 | end 165 | v = q * v; % version A 166 | 167 | 168 | % --------- experimental code ----------------------- 169 | function [ v, x ] = prox_l2_vector( q, x, t ) 170 | if nargin < 2, 171 | error( 'Not enough arguments.' ); 172 | end 173 | v = sqrt( tfocs_normsq( q.*x ) ); % version B 174 | if nargin == 3, 175 | %{ 176 | we need to solve for a scalar variable s = ||q.*x|| 177 | (where x is the unknown solution) 178 | 179 | we have a fixed point equation: 180 | s = f(s) := norm( q.*x_k ) where x_k = x_0/( 1 + t*q/s ) 181 | 182 | to solve this, we'll use Matlab's "fzero" to find the zero 183 | of the function F(s) = f(s) - s 184 | 185 | Clearly, we need s >= 0, since it is ||q.*x|| 186 | 187 | If q is a scalar, we can solve explicitly: s = q*(norm(x0) - t) 188 | 189 | %} 190 | 191 | xk = @(s) x./( 1 + t*(q.^2)/s ); 192 | f = @(s) norm( q.*xk(s) ); 193 | % F = @(s) f(s) - s; 194 | tq2 = t*(q.^2); 195 | F = @(s) norm( (q.*x)./( 1 + tq2/s ) ) - s; 196 | [s,sVal] = fzero( F, 1); 197 | if abs( sVal ) > 1e-4 198 | error('cannot find a zero'); 199 | end 200 | if s <= 0 201 | x = 0*x; 202 | else 203 | x = xk(s); 204 | end 205 | v = sqrt( tfocs_normsq( q.*x ) ); % version B 206 | elseif nargout == 2, 207 | error( 'This function is not differentiable.' ); 208 | end 209 | 210 | % TFOCS v1.3 by Stephen Becker, Emmanuel Candes, and Michael Grant. 211 | % Copyright 2013 California Institute of Technology and CVX Research. 212 | % See the file LICENSE for full license information. 213 | -------------------------------------------------------------------------------- /linreg/linreg_lrmx_als.m: -------------------------------------------------------------------------------- 1 | function [X,fcost] = linreg_lrmx_als(y,U,R,szX,opts) 2 | % Alternating algorithm to solve the linear regression problem 3 | % 4 | % min \| y - U' * vec(X) \|^2 + mu * \|X\|_F^2 5 | % 6 | % where X = A*B' is of rank R and size I1 x I2, 7 | % 8 | % U is a matrix (I1I2) x K 9 | % 10 | % 11 | % Parameters 12 | % 13 | % init: 'nvec' initialization method 14 | % maxiters: 200 maximal number of iterations 15 | % mu: damping parameter 16 | % 17 | % printitn: 0 18 | % tol: 1.0000e-06 19 | % 20 | % Phan Anh Huy, 2017 21 | % 22 | 23 | 24 | %% Fill in optional variable 25 | if ~exist('opts','var'), opts = struct; end 26 | param = parseInput(opts); 27 | if nargin == 0 28 | X = param; return 29 | end 30 | 31 | 32 | %% 33 | if param.printitn ~=0 34 | fprintf('\nAlternating Single Core Update Algorithm for Single-term Multivariate Polynomial Regression\n'); 35 | fprintf(' min sum_k | y_k - < X , (uk1 o uk2 o ... o ukN)> |^2\n') 36 | fprintf(' subject to : X = A * B''') 37 | end 38 | 39 | 40 | damping = param.damping; 41 | 42 | % Initialization 43 | if isa(param.init,'ktensor') 44 | X = param.init; 45 | X = X.U; 46 | elseif iscell(param.init) 47 | X = param.init; 48 | % elseif isa(param.init,'TTeMPS') 49 | % X = param.init; 50 | elseif isstruct(param.init) 51 | X = {param.init.U param.init.V}; 52 | else 53 | switch param.init 54 | case 'rand' 55 | X = arrayfun(@(n) randn(n,R),szX,'uni',0)'; 56 | X = cellfun(@(x) x/norm(x,'fro'),X,'uni',0); 57 | end 58 | end 59 | 60 | X{1} = orth(X{1}); 61 | 62 | %% 63 | KRaostruct = iscell(U); 64 | 65 | if ~KRaostruct 66 | % U is a numerical array 67 | 68 | % min x'*(UU+mu*I) *x - 2 g'*x + y'*y 69 | % where x = vec(A*B'), g = U*y 70 | % 71 | % or x'*UU*x - 2*trace(A'*G*B) 72 | % 73 | UU = U*U'; 74 | if damping ~= 0 75 | UU(1:prod(szX)+1:end) = UU(1:prod(szX)+1:end)+damping; 76 | end 77 | UU = tensor(reshape(UU,[szX szX])); 78 | g = U*y; 79 | G = reshape(g,szX); 80 | end 81 | normy2 = norm(y)^2; 82 | 83 | %% Iterate the main algorithm 84 | fcost = zeros(param.maxiters,1); 85 | cnt = 0; 86 | eps_ = 1e-7; 87 | 88 | for kiter = 1:param.maxiters 89 | 90 | for n = [2 1] 91 | cnt = cnt +1; 92 | 93 | % alternating update X1 and X2 94 | if n == 2 95 | m = 1; 96 | else 97 | m = 2; 98 | end 99 | 100 | %% least squares 101 | 102 | if KRaostruct 103 | % If U is a Khatri-Rao structured matrix, i.e. 104 | % min \| y - P^T * vec(X) \|^2 + mu/2 * \|X\|_F^2 (1) 105 | % P = khatrirao(U2,U1) 106 | % 107 | % In order to update X1, X2 is orthogonalized, then 108 | % solve the sub-problem for X1 109 | % min \| y - Pn^T * vec(X1) \|^2 + mu * \|X1\|_F^2 110 | % 111 | % min | y - Pn*x|^2 + mu/2 |x|^2 112 | Zm = X{m}'*U{m}; 113 | Pn = khatrirao(Zm,U{n}); 114 | gn = Pn*y; 115 | PnPn = Pn*Pn'; 116 | if damping ~= 0 117 | PnPn(1:size(PnPn,1)+1:end) = PnPn(1:size(PnPn,1)+1:end) + damping; 118 | end 119 | xn = PnPn\gn; 120 | 121 | Xn = reshape(xn,[],R); 122 | 123 | fcost(cnt) = normy2 - gn'*xn; 124 | 125 | else % a numerical array 126 | % Update X1 127 | % min vec(X1)^T * Q1 * vec(X1) - 2 trace(X1'*G*X2) 128 | % 129 | % where Q1 = (X2 ox I)^T * UU *(X2 ox I) 130 | % Update X2 131 | % min vec(X2)^T * Q2 * vec(X2) - 2 trace(X1'*G*X2) 132 | % 133 | % where Q2 = (I ox X1)^T * UU *(I ox X1) 134 | Qn = ttm(UU,{X{m} X{m}},[m m+2],'t'); 135 | Qn = reshape(double(Qn),szX(n)*R,[]); 136 | 137 | if n == 2 % update X2 138 | gn = X{m}'*G; 139 | else % update X1 140 | gn = G*X{m}; 141 | end 142 | xn = Qn\gn(:); 143 | 144 | if n == 1 % update X2 145 | Xn = reshape(xn,[],R); 146 | else 147 | Xn = reshape(xn,R,[])'; 148 | end 149 | 150 | fcost(cnt) = normy2 - gn(:)'*xn(:); 151 | end 152 | 153 | % orthogonalise Xn 154 | [QQ,RR] = qr(Xn,0); 155 | % check and truncate the rank 156 | ss = sum(abs(RR).^2,2); 157 | ixs = ss > eps_*sum(ss); 158 | R = sum(ixs); % % rank may change 159 | X{n} = QQ(:,ixs);X{m} = X{m}*RR(ixs,:)'; 160 | 161 | 162 | end 163 | 164 | % 165 | if mod(kiter,param.printitn)==0 166 | fprintf('(%d,%d)- %d\n',kiter,cnt,fcost(cnt)) 167 | end 168 | 169 | 170 | % check stopping criteria 171 | if (cnt > 2) && (abs(fcost(cnt) - fcost(cnt-2))