function [X,fobjs,ts] = L0SPCA_OADMM_RR(X,A,NormA,const,rho1,rho2,data_k,max_iter,beta0,alg_xi,timeIntervel,timeLimit,flagDual,betaRADMM)
% min_X 0.5*||A-A*X*X'||_F^2 + rho (||X||_1 - ||X||_{topk} ), s.t. X'X = I, s.t. X'X = I
% min_X  0.5*||A-A*X*X'||_F^2 + rho ( ||X||_1 - ||X||_{topk} ), s.t. X'X = I
% min_X  -0.5/m*mdot(A,A*X*X') + const + rho ( ||Y||_1 - ||X||_{topk} ), s.t. Y = X, Y'Y = I
% L(Y,X,Z) = -0.5/m*mdot(A,A*X*X') + const  + rho ( ||Y||_1 - ||X||_{topk} ) + <X-Y,Z> + 0.5 beta ||Y-X||_F^2, s.t. X'X = I

% When betaRADMM is a fixed large number, this algorithm reduces to the RADMM

[m,n] = size(A);
Lsmooth = NormA^2/m;

initt = clock;
last_rec_clock = initt;
HandleObj = @(X)L0SPCA_ComputeObj(X,A,rho1,rho2,data_k,const,m);

r = size(X,2);
Y = X+randn(n,r)*0.01;
if(flagDual==1)
    Z = randn(n,r)*0.01;
else
    Z = randn(n,r)*0;
end
% Y = orth(randn(n,r));

[chi,sigma] = set_default_para_RR(alg_xi);

XP = X;
dtX = zeros(n,r);

ts = []; fobjs = [];
fobj = HandleObj(X);
fobjs = [fobjs;fobj];
ts = [ts;etime(clock,initt)];


gamma = 0.5;
delta = 1e-3;
% gamma = 0.1;
% delta = 1e-12;

if(flagDual==1)
    % multiplier
    if(betaRADMM==-1)
        fprintf('OADMM-RR: begin\n');
    else
        fprintf('RADMM: begin\n');
    end
else
    fprintf('SPGM-RR: begin\n');
end


for iter = 1:30000
    p = 1/3;
    if(betaRADMM==-1)
        beta = beta0*(1+alg_xi*iter^p);
    else
        beta = betaRADMM;
    end
    mu = chi/beta;
    
    hfun = @(X) ComputeObj(X,A,m,data_k,beta,Y,rho2,Z);
    [F,G] = hfun(X);
    dtX = G - X*G'*X;
    nrmG  = norm(dtX, 'fro');
    
%    if(betaRADMM==-1)
        %if(iter==1)
            tau = 1;
        %else
 %           S = X - XP;
 %           Y = dtX - dtXP;
 %         SY = mdot(S,Y);
 %           if mod(iter,2)==0; tau = mdot(S,S) / SY;
 %           else tau  = SY / mdot(Y,Y); end
 %           tau = max(min(tau,100),0.0001);
 %       end
 %   else
 %      tau = 0.01;
 %   end

    XP = X; FP = F;  dtXP = dtX;
    
    for jj = 1:1000
        eta = 1/beta*tau*gamma^jj;
        Delta = - eta*dtX;
        X = retr(XP,Delta);
        [F] = hfun(X);
        if abs(eta)<1e-10 || F <= FP-eta*delta*nrmG^2, break;end
    end
    
    % Update Y
    % -0.5/m*mdot(A,A*X*X') + const  + rho1 ||Y||_1 - rho2||X||_{topk}  + <X-Y,Z> + 0.5 beta ||Y-X||_F^2, s.t. X'X = I
    % rho ||Y||_1 + <X-Y,Z> + 0.5 beta ||Y-X||_F^2
    % rho ||Y||_1 + 0.5 beta ||Y-(X+Z/beta)||_F^2
    B = X+Z/beta;
    beta_bar = beta/rho1;
    %     if(flag==1)
    % min_Y  [||Y||_1]_{\mu} + 0.5 beta_bar ||Y - B||_F^2
    Y = smooth_prox_l1(B,mu,beta_bar);
    %     else
    % min_Y  ||Y||_1 + 0.5 beta_bar ||Y - B||_F^2
    %     Y = prox_l1(B,1/beta_bar);
    %     end
    
    % Update Z
    diff = X-Y;
    if(flagDual==1)
        Z = Z + sigma* beta*diff;
    else
        % Z = zeros(n,r);
    end
    e = norm(diff,'fro');
    cur_clock = clock;
    if(etime(cur_clock,last_rec_clock) > timeIntervel)
        fobj = HandleObj(X);
        ElasTime =  etime(cur_clock,initt);
        fobjs  = [fobjs;fobj];
        ts = [ts;ElasTime];
        last_rec_clock = cur_clock;
        if ElasTime > timeLimit,break;end
        fprintf('iter:%d, fobj:%f, dist:%f, beta:%f\n',iter,fobj,e,beta);
    end
end

if(flagDual==1)
    if(betaRADMM==-1)
        fprintf('OADMM-RR: end\n');
    else
        fprintf('RADMM: end\n');
    end
else
    fprintf('SPGM-RR: end\n');
end


function [F,G] = ComputeObj(X,A,m,data_k,beta,Y,rho2,Z)
HX = A'*(A*X)/m;
XY = X-Y;
F = -0.5*mdot(HX,X) + mdot(X,Z) + 0.5*beta*norm(XY,'fro')^2 - rho2* tksum(X,data_k);
if(nargout==2)
    G = -HX + Z + beta*XY  - rho2*top_k_subgrad(X,data_k);
end
