function [estA,estH,estST]=TALS(X,M,estA,estH,estST,MAXNUMITER);

% Plain Vanilla Trilinear ALS
% X = KxNxP rank-M 3-way array

% Copyright, 1998 -
% This M-file and the code in it belongs to the holder of the
% copyrights and is made public under the following constraints:
% It must not be changed or modified and code cannot be added.
% The file must be regarded as read-only. In case of doubt,
% contact the holder of the copyrights.
%
% Copyright 1998
% Nikos Sidiropoulos
% Univ. Minnesota, nikos@ece.umn.edu
% and 
% Rasmus Bro
% KVL, Denmark, rb@kvl.dk

% Magic numbers, control TALS loop below:

SMALLNUMBER = eps;

[K,N,P]=size(X);

% initial estimates:

if (nargin < 5)
 disp('Using random initial estimates ...');
 estA = randn(K,M);
 estH = randn(P,M);
 estS = randn(M,N);
else
 estS = estST.';
end

if (nargin < 6)
 MAXNUMITER = 100000;
end

% Trilinear ALS:

% first construct the three different unfolded data matrices:

Xtilde = [];
ap1 = zeros(K,N);
for p=1:1:P,
 for k=1:1:K,
  for n=1:1:N,
   ap1(k,n) = X(k,n,p);
  end
 end
 Xtilde = [Xtilde; ap1];
end

Ytilde = [];
ap2 = zeros(N,P);
for k=1:1:K,
 for n=1:1:N,
  for p=1:1:P,
   ap2(n,p) = X(k,n,p);
  end
 end
 Ytilde = [Ytilde; ap2];
end

Ztilde = [];
ap3 = zeros(P,K);
for n=1:1:N,
 for p=1:1:P,
  for k=1:1:K,
   ap3(p,k) = X(k,n,p);
  end
 end
 Ztilde = [Ztilde; ap3];
end

% compute current fit:
fit = 0;
for p=1:P,
  fit = fit + norm(X(:,:,p) - estA*diag(estH(p,:))*estS,'fro')^2;
end
fprintf('fit = %12.10f\n',fit);
fitold = 2*fit;
fitinit = fit;
it     = 0;


while abs((fit-fitold)/fitold) > SMALLNUMBER & it < MAXNUMITER & fit > 10*eps
 it=it+1;
 fitold=fit;

 % re-estimate A:

 mix = [];
 for n=1:1:N,
  mix = [mix; estH*diag(estS(:,n))];
 end
 if (rank(mix) == M)
  estA = (pinv(mix)*Ztilde).';
 end

 % re-estimate H:

 mix = [];
 for k=1:1:K,
  mix = [mix; estS.'*diag(estA(k,:))];
 end
 if (rank(mix) == M)
  estH = (pinv(mix)*Ytilde).';
 end

 % re-estimate S:

 mix = [];
 for p=1:1:P,
  mix = [mix; estA*diag(estH(p,:))];
 end
 if (rank(mix) == M)
  estS = pinv(mix)*Xtilde;
 end

 % compute new fit:

 fit = 0;
 for p=1:P,
  fit = fit + norm(X(:,:,p) - estA*diag(estH(p,:))*estS,'fro')^2;
 end
 fprintf('fit = %12.10f\n',fit);
 
end % while loop 

estST = estS.';

% end of algorithm
