%fill_prmm Compute the null-space and fill PRMM.
%
%   Parameters:

function [P,X, u1,u2, lambda, info] = fill_prmm(M, Idepths, central, ...
                                                opt, info)

[NULLSPACE, result] = create_nullspace(M, Idepths, central, ...
                                       opt.create_nullspace);

info.create_nullspace             = opt.create_nullspace;
info.sequence{end}.tried          = result.tried;
info.sequence{end}.tried_perc     = result.tried/comb(size(M,2), 4) *100;
info.sequence{end}.used           = result.used;
info.sequence{end}.used_perc      = result.used/result.tried *100;
info.sequence{end}.failed         = result.failed;
info.sequence{end}.size_nullspace = size(NULLSPACE);

if opt.verbose
  disp(sprintf('Tried/used: %d/%d (%.1e %%/ %2.1f %%)', result.tried, ...
               result.used, info.sequence{end}.tried_perc, ...
               info.sequence{end}.used_perc));
  disp(sprintf('%d x %d'' is size of the nullspace', size(NULLSPACE,2), ...
               size(NULLSPACE,1))); end

[m,n] = size(M); m = m/3;

if size(NULLSPACE,2) == 0
  P = []; X = []; u1 = 1:m; u2 = 1:n; lambda=[];
else
  r = 4;
  [L, S] = nullspace2L(NULLSPACE, r, opt);
  clear NULLSPACE;

  if isempty(opt.create_nullspace), threshold = .01;
  else, threshold = opt.create_nullspace.threshold; end
  if svd_suff_data(S, r, threshold)
    if opt.verbose
      dS = diag(S); %disp(diag(S));
      fprintf(1,'Smallest 2r singular values:%s.\n', sprintf(' %f', ...
                                                  dS(end-2*r:end))); end
    [Mdepths, lambda] = L2depths(L, M, Idepths, opt); info.Mdepths = Mdepths;
    [P,X, u1b,u2] = approximate(Mdepths, r, L, opt);
    u1 = union(ceil(u1b/3),[]); killb = setdiff(k2i(u1),u1b);
    if ~isempty(killb), r1b = setdiff(1:3*m,u1b); kill = killb;
      for ib = killb(1:end-1), lower = find(killb > ib);
        if kill(lower(1)-1) < kill(lower(1)) - 1,
          kill(lower) = kill(lower) -1; end; end
      P = P(setdiff(1:length(r1b),kill),:);end
    lambda = lambda(setdiff(1:m,u1),setdiff(1:n,u2)); % to fit P*X
  else P=[]; X=[]; u1=1:m; u2=1:n; lambda=[]; end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function [L,S] = nullspace2L(NULLSPACE, r, opt)
% Compute the basis of MM (L) from the null-space.

if opt.verbose, fprintf(1,'Computing the basis...'); tic; end
if size(NULLSPACE,2) < 10*size(NULLSPACE,1) % orig:[A,S,U] = svd(NULLSPACE',0);
  [U,S,V]             = svd(NULLSPACE);
else
  [U,SS]              = eig(NULLSPACE*NULLSPACE');
  dSS                 = diag(SS); l = length(dSS);
  [sortdSS(l:-1:1),I] = sort(dSS); I(l:-1:1) = I;  U = U(:,I);
  sortdSS             = max(sortdSS,zeros(1,l)); sortdSS=sqrt(sortdSS);
  for i=1:l, S(i,i) = sortdSS(i); end
end

lenU = length(U);
L = U(:,lenU+1-r:lenU);
if opt.verbose, disp(['(' num2str(toc) ' sec)']); end

function r = comb(n,k)

% returns combination number n over k

r=1;
for i=1:k
  r=r*(n-i+1)/i;
end

function y = svd_suff_data(S,r, threshold)

% S is the singular value part of the svd of the nullspaces of the column
% r-tuples.  We'll want to be able to take the r least significant columns
% of U.  This is right because the columns of U should span the whole space
% that M's columns might span.  That is, M is FxP.  The columns of U should
% span the F-dimensional Euclidean space, since U is FxF.  However, we want
% to make sure that the F-r-1'th singular value of S isn't tiny.  If it is,
% our answer is totally unreliable, because the nullspaces of the column
% r-tuples don't have sufficient rank.  If this happens, it means that the
% intersection of the column cross-product spaces is bigger than r-dimensional,
% and randomly choosing an r-dimensional subspace of that isn't likely to
% give the right answer.

Snumcols = size(S,2);
Snumrows = size(S,1);
if (Snumrows == 0 | Snumcols + r < Snumrows | Snumrows <= r)
  y = 0;
else
  y = S(Snumrows-r,Snumrows-r) > threshold;
end
