function output = callsdplr(interfacedata)

% Author Johan Löfberg
% $Id: callsdplr.m,v 1.8 2005-12-15 13:21:16 joloef Exp $

% Retrieve needed data
options = interfacedata.options;
F_struc = interfacedata.F_struc;
c       = interfacedata.c;
K       = interfacedata.K;
ub      = interfacedata.ub;
lb      = interfacedata.lb;
lowrankdetails =  interfacedata.lowrankdetails;

% Create the parameter structure
pars = options.sdplr;
pars.printlevel = options.verbose;

% *********************************************
% Bounded variables converted to constraints
% N.B. Only happens when caller is BNB
% *********************************************
if ~isempty(ub)
    [F_struc,K] = addbounds(F_struc,K,ub,lb);
end

% rmfield is slow...
Knew.l = K.l;
Knew.s = K.s;
K = Knew;

if options.savedebug
    save sdplrdebug F_struc c K pars -V6
end

% *********************************************
%FIND LOW RANK STRUCTURES
% *********************************************
problem = 0;
lrA = [];
if ~isempty(lowrankdetails) | (options.sdplr.maxrank>0 & (K.s(1)>0))
    showprogress('Detecting low rank data',options.showprogress);
    sdploc = K.l+cumsum([1 K.s.^2]);
    k = 1;
    % FIX : Lazy code copy...
    [ix,jx,sx] = find(F_struc);
    if isempty(lowrankdetails)
        % Okay, this means we have to go through everything...
        % Get all data in F_struc for later
        for lmiid = 1:length(K.s)
            removethese = zeros(1,size(F_struc,2)-1);
            for i = 1:size(F_struc,2)-1
                Fi = reshape(F_struc(sdploc(lmiid):sdploc(lmiid+1)-1,i+1),K.s(lmiid),K.s(lmiid));
                if nnz(Fi)>0
                    [D,V] = getfactors(Fi);
                    if length(D) <= options.sdplr.maxrank
                        lrA(k).cons = i;
                        lrA(k).start = sdploc(lmiid);
                        lrA(k).D = D;
                        lrA(k).V = V;
                        k = k+1;
                        removethese(i) = 1;
                    end
                end
            end
            removethese = find(removethese);
            if ~isempty(removethese)
                these = find((sdploc(lmiid+1)-1>= ix) & (ix>=sdploc(lmiid)) & ismember(jx,1+removethese));
                sx(these) = 0;
            end
        end
    else
        % Just check those constraints declared low-rank by user
        for lrdef = 1:length(lowrankdetails)
            for lrconstraint = 1:length(lowrankdetails{lrdef}.id)
                lmiid = lowrankdetails{lrdef}.id(lrconstraint);
                removethese = zeros(1,size(F_struc,2)-1);
                checkthese = lowrankdetails{lrdef}.variables;
                if isempty(checkthese)
                    checkthese = 1:size(F_struc,2)-1;
                end
                for i = checkthese
                    Fi = reshape(F_struc(sdploc(lmiid):sdploc(lmiid+1)-1,i+1),K.s(lmiid),K.s(lmiid));
                    if nnz(Fi)>0
                        [D,V] = getfactors(Fi);
                        if (options.sdplr.maxrank == 0) | (options.sdplr.maxrank ~= 0 & (length(D) <= options.sdplr.maxrank))
                            lrA(k).cons = i;
                            lrA(k).start = sdploc(lmiid);
                            lrA(k).D = D;
                            lrA(k).V = V;
                            k = k+1;
                            removethese(i) = 1;
                        end
                    end
                end
                removethese = find(removethese);
                if ~isempty(removethese)
                    these = find((sdploc(lmiid+1)-1>= ix) & (ix>=sdploc(lmiid)) & ismember(jx,1+removethese));
                    sx(these) = 0;
                    %F_struc(sdploc(lmiid):sdploc(lmiid+1)-1,1+removethese) = 0;
                end
            end
        end
        F_struc = sparse(ix,jx,sx,size(F_struc,1),size(F_struc,2));
    end
end


% *********************************************
% CALL SDPLR
% *********************************************
if options.showprogress;showprogress(['Calling ' interfacedata.solver.tag],options.showprogress);end
solvertime = clock;
if isempty(lrA)    
   [x_s,y_s,info] = sdplr(F_struc(:,2:end),c,F_struc(:,1),K);
else   
   % pars.reduce = 0;
    [x_s,y_s,info] = sdplr(F_struc(:,2:end),full(c),full(F_struc(:,1)),K,pars,lrA);
end
solvertime = etime(clock,solvertime);

% YALMIP format
D_struc = x_s;
x = -y_s;

% No error codes currently...
problem = 0;

infostr = yalmiperror(problem,interfacedata.solver.tag);

% Save ALL data sent to solver
if options.savesolverinput
    solverinput.A = F_struc(:,2:end);
    solverinput.c = F_struc(:,1);
    solverinput.b = c;
    solverinput.K = K;
    solverinput.pars = pars;
else
    solverinput = [];
end

% Save ALL data from the solution?
if options.savesolveroutput
    solveroutput.x = x_s;
    solveroutput.y = y_s;
    solveroutput.info = info;
else
    solveroutput = [];
end

% Standard interface
output.Primal      = x(:);
output.Dual        = D_struc;
output.Slack       = [];
output.problem     = problem;
output.infostr     = infostr;
output.solverinput = solverinput;
output.solveroutput= solveroutput;
output.solvertime  = solvertime;

function [D,V] = getfactors(Fi)
if nnz(Fi)>0
    [v,d] = eig(full(Fi));
    d = diag(d);
    keep = find(abs(d)>1e-6);
    V = v(:,keep);
    D = d(keep);
    % lrA(k).cons = i;
    % lrA(k).start = sdploc(j);
    % lrA(k).D = D;
    % lrA(k).V = V;
    % k = k+1;
else
    D = [];
    V = [];
end


