Contents
function [A,Out] = ncpc(data,known,ndim,r,opts)
Parameters and defaults
if isfield(opts,'tol'); tol = opts.tol; else tol = 1e-4; end
if isfield(opts,'maxit'); maxit = opts.maxit; else maxit = 500; end
if isfield(opts,'maxT'); maxT = opts.maxT; else maxT = 1e3; end
if isfield(opts,'rw'); rw = opts.rw; else rw = 1; end
Data preprocessing and initialization
[known,I] = sort(known);
data = data(I);
N = length(ndim);
M = zeros(ndim); M(known) = data; M0 = M;
nrmb = norm(data);
obj0 = 0.5*nrmb^2;
sizeN = zeros(1,N);
for n = 1:N; sizeN(n) = prod(ndim)/ndim(n); end
if isfield(opts,'A0')
A0 = opts.A0;
else
A0 = cell(1,N);
for n = 1:N
A0{n} = max(0,randn(ndim(n),r));
end
end
Asq = cell(1,N);
for n = 1:N
A0{n} = A0{n}/norm(A0{n},'fro')*nrmb^(1/N);
Asq{n} = A0{n}'*A0{n};
end
Am = A0; A = A0;
nstall = 0;
t0 = 1;
wA = ones(N,1);
L0 = ones(N,1); L = ones(N,1);
Store data to save computing time if it is not too large
if N*prod(ndim)<4000^2
storedata = true; kroA = cell(1,N);
for n = 1:N
kroA{n} = zeros(sizeN(n),r);
end
else
storedata = false;
kroA1 = zeros(prod(ndim)/ndim(1),r);
end
matorder = N:-1:2;
for j = 1:r
ab = A{matorder(1)}(:,j);
for i = matorder(2:N-1)
ab = A{i}(:,j) * ab(:).';
end
if storedata
kroA{1}(:,j) = ab(:);
else
kroA1(:,j) = ab(:);
end
end
Iterations of block-coordinate update
iteratively updated variables:
M: estimated tensor
Gn: gradients with respect to A{n}
A: current factors
A0: previous factors
Am: extrapolated factors
L, L0: current and previous Lipschitz bounds
obj, obj0: current and previous objective valuesstart_time = tic;
fprintf('Iteration: ');
for k = 1:maxit
fprintf('\b\b\b\b\b%5i',k);
Bsq = Asq{2};
for i = 3:N
Bsq = Bsq.*Asq{i};
end
L0(1) = L(1); L(1) = norm(Bsq);
MB = reshape(M, ndim(1), sizeN(1));
if storedata
MB = MB*kroA{1};
else
MB = MB*kroA1;
end
Gn = Am{1}*Bsq-MB;
A{1} = max(0,Am{1}-Gn/L(1));
Asq{1} = A{1}'*A{1};
for n = 2:N
matorder = [2:n-1,n+1:N];
Bsq = Asq{1};
for i = matorder
Bsq = Bsq.*Asq{i};
end
L0(n) = L(n); L(n) = norm(Bsq);
if storedata
matorder = [N:-1:n+1,n-1:-1:1];
for j = 1:r
ab = A{matorder(1)}(:,j);
for i = matorder(2:N-1)
ab = A{i}(:,j) * ab(:).';
end
kroA{n}(:,j) = ab(:);
end
MB = permute(M,[n,1:n-1,n+1:N]);
MB = reshape(MB, ndim(n), sizeN(n));
MB = MB*kroA{n};
else
MB = mttkrp(tensor(M),A,n);
end
Gn = Am{n}*Bsq-MB;
A{n} = max(0,Am{n}-Gn/L(n));
Asq{n} = A{n}'*A{n};
end
matorder = N:-1:2;
for j = 1:r
ab = A{matorder(1)}(:,j);
for i = matorder(2:N-1)
ab = A{i}(:,j) * ab(:).';
end
if storedata
kroA{1}(:,j) = ab(:);
else
kroA1(:,j) = ab(:);
end
end
if storedata; M = A{1}*kroA{1}'; else M = A{1}*kroA1'; end
obj = 0.5*norm(M(known)-data)^2;
M(known) = data; M = reshape(M,ndim);
relerr1 = abs(obj-obj0)/(obj0+1); relerr2 = (2*obj)^.5/nrmb;
Out.hist_obj(k) = obj;
Out.hist_rel(1,k) = relerr1;
Out.hist_rel(2,k) = relerr2;
crit = relerr1<tol;
if crit; nstall = nstall+1; else nstall = 0; end
if nstall>=3 || relerr2<tol; break; end
if toc(start_time)>maxT; break; end;
t = (1+sqrt(1+4*t0^2))/2;
if obj>=obj0
Am = A0; M = M0;
else
w = (t0-1)/t;
for n = 1:N
wA(n) = min([w,rw*sqrt(L0(n)/L(n))]);
Am{n} = A{n}+wA(n)*(A{n}-A0{n});
end
A0 = A; M0 = M; t0 = t; obj0 = obj;
end
end
fprintf('\n');
A = ktensor(A);
Out.iter = k;