function demo_L0PCA1000
% min_X  0.5/m*||A-A*X*X'||_F^2 + rho ( ||X||_1 - ||X||_{topk} ), s.t. X'X = I
% min_X  0.5/m*||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 ( ||X||_1 - ||X||_{topk} ), s.t. X'X = I
% const = 0.5/m*fnorm(A)^2

clc;close all;clear all;
addpath('util','data','solver');
rand('seed',1);
randn('seed',1);

dat_rho = 5;

time_limits = [20 20 20 20 20 20 20 20];
rs          = [20 20 20 20 20 20 20 20];
i_data      = [11 12 21 22 31 32 41 42];



for iii = 1:8
    
    iwhich = i_data(iii);
    r = rs(iii);
    timeLimit = time_limits(iii);
    A = GetDataSetL0SPCA(iwhich);
    [m,n] = size(A);
    NormA = MatrixSpectralNorm(A);
    X0 = orth(randn(n,r));
    const = 0.5*fnorm(A)^2/m;
    k = round(n*r*0.5);
    beta0 = dat_rho*10;
    max_iter = 1e100;
    
    timeIntervel = 2; % Record the objective value in every timeIntervel second
    flag = 1;
    [X1,fobjs1,ts1] = L0SPCA_OADMM_EP(X0,A,NormA,const,dat_rho,dat_rho,k,max_iter,beta0,timeIntervel,timeLimit,flag);
    [X2,fobjs2,ts2] = L0SPCA_OADMM_RR(X0,A,NormA,const,dat_rho,dat_rho,k,max_iter,beta0,timeIntervel,timeLimit,flag);
    betaRADMM = 100;
    [X3,fobjs3,ts3] = L0SPCA_RADMM(X0,A,NormA,const,dat_rho,dat_rho,k,max_iter,betaRADMM,timeIntervel,timeLimit);
    betaRADMM = 10000;
    [X4,fobjs4,ts4] = L0SPCA_RADMM(X0,A,NormA,const,dat_rho,dat_rho,k,max_iter,betaRADMM,timeIntervel,timeLimit);
    flag = 0;
    [X5,fobjs5,ts5] = L0SPCA_OADMM_EP(X0,A,NormA,const,dat_rho,dat_rho,k,max_iter,beta0,timeIntervel,timeLimit,flag);
    [X6,fobjs6,ts6] = L0SPCA_OADMM_RR(X0,A,NormA,const,dat_rho,dat_rho,k,max_iter,beta0,timeIntervel,timeLimit,flag);
    [X7,fobjs7,ts7] = L0SPCA_SubGrad(X0,A,const,dat_rho,dat_rho,k,max_iter,timeIntervel,timeLimit);
    
    
    figure('color','w');
    myplot = @semilogy;
    pcolor = loadcolor;
    myplot(ts1,fobjs1,'--kv','LineWidth',3,'MarkerSize',5,'color', pcolor.red); hold on;
    myplot(ts2,fobjs2,'-.mo','LineWidth',3,'MarkerSize',5,'color',  pcolor.blue); hold on;
    myplot(ts3,fobjs3,'--kv','LineWidth',3,'MarkerSize',5,'color', pcolor.pink); hold on;
    myplot(ts4,fobjs4,'-.b^','LineWidth',3,'MarkerSize',5,'color', pcolor.purple); hold on;
    myplot(ts5,fobjs5,'--s','LineWidth',3,'MarkerSize',5,'color', pcolor.green); hold on;
    myplot(ts6,fobjs6,'-s','LineWidth',3,'MarkerSize',5,'color', pcolor.crimson); hold on;
    myplot(ts7,fobjs7,'--kd','LineWidth',3,'MarkerSize',5,'color', pcolor.orange); hold on;
    
    grid on;
    hleg=legend('OADMM-EP','OADMM-RR','RADMM-I','RADMM-II','SPGM-EP','SPGM-RR','SubGrad');
    set(hleg,'FontSize',20,'FontWeight','normal');
    set(hleg,'Fontname','times new Roman');
    set(hleg,'Location','NorthEast');
    set(gca,'Fontsize', 19);
    set(hleg, 'Color', 'none');
    xlabel('Time (seconds)','FontSize',20)
    ylabel('Objective','FontSize',20,'interpreter','latex')
    all_fobj = [fobjs1;fobjs2;fobjs3;fobjs4;fobjs5;fobjs6;fobjs7];
    axis([0,timeLimit+1,min(all_fobj),max(all_fobj)]);
    fprintf('\n');
    set(gcf,'paperpositionmode','auto')
    print(sprintf('%s_%d.eps',mfilename,iwhich),'-depsc2','-loose');
    print(sprintf('%s_%d.png',mfilename,iwhich),'-dpng');
    print(sprintf('%s_%d.pdf',mfilename,iwhich),'-dpdf', '-r0');
    
    One = [];
    One.ts1 = ts1; One.fobjs1 = fobjs1;
    One.ts2 = ts2; One.fobjs2 = fobjs2;
    One.ts3 = ts3; One.fobjs3 = fobjs3;
    One.ts4 = ts4; One.fobjs4 = fobjs4;
    One.ts5 = ts5; One.fobjs5 = fobjs5;
    One.ts6 = ts6; One.fobjs6 = fobjs6;
    One.ts7 = ts7; One.fobjs7 = fobjs7;
    result{iii} = One;
    savefile = sprintf('%s_%d.mat',mfilename,dat_rho);
    save(savefile, 'result');
end

function [X,fobjs,ts] = L0SPCA_OADMM_EP(X,A,NormA,const,rho1,rho2,data_k,max_iter,beta0,timeIntervel,timeLimit,flag)
% 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
[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(flag==1)
Z = randn(n,r)*0.01;
else
Z = randn(n,r)*0.0;
end



[chi,sigma,theta,xi,alpha] = set_default_para();



X_old = X;

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

if(flag==1)
fprintf('OADMM-EP: begin\n');
else
fprintf('SPGM_EP: begin\n');
end

for iter = 1:30000
    
    p = 1/3; beta = beta0*(1+xi*iter^p); mu = chi/beta;
    X_bar = X + alpha * (X-X_old);
    
    % Update X: 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
    h_grad = @(X) -A'*(A*X)/m + Z + beta*(X-Y);
    grad_X = h_grad(X_bar)- rho2*top_k_subgrad(X,data_k); %
    Lipschit_constant = Lsmooth + beta;
    X_old = X; X = OrthProj(X_bar - grad_X/(theta*Lipschit_constant));
    
    % Update Y: min_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
    % min_Y rho ||Y||_1 + <X-Y,Z> + 0.5 beta ||Y-X||_F^2
    % min_Y 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
    % min_Y  1/beta_bar*||Y||_1 + 0.5 ||Y - B||_F^2
    Y = prox_l1(B,1/beta_bar);
    end
    
    % Update Z
    diff = X-Y;
    if(flag==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(flag==1)
fprintf('OADMM-EP: end\n');
else
fprintf('SPGM_EP: end\n');
end

 


function [X,fobjs,ts] = L0SPCA_OADMM_RR(X,A,NormA,const,rho1,rho2,data_k,max_iter,beta0,timeIntervel,timeLimit,flag)
% 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
[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(flag==1)
Z = randn(n,r)*0.01;
else
Z = randn(n,r)*0;
end
% Y = orth(randn(n,r));

[chi,sigma,theta,xi,alpha] = set_default_para2();

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

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


gamma = 0.25;
delta = 1e-4;
if(flag==1)
fprintf('OADMM-RR: begin\n');
else
fprintf('SPGM-RR: begin\n');
end

for iter = 1:30000
    p = 1/3; 
    beta = beta0*(1+xi*iter^p); 
    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(iter==1)
           tau = 0.01;
%         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
    XP = X; FP = F;  dtXP = dtX;
    
    for jj = 1:1000
      eta = beta0/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(flag==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(flag==1)
fprintf('OADMM-RR: end\n');
else
fprintf('SPGM-RR: end\n');
end

function X = retr(X,Delta)
%  [n,r] = size(X);
%   W = @(xi) (eye(n) - 0.5*X*X')*xi *X' - X*xi'*(eye(n) - 0.5*X*X');
%  X = inv(eye(n) - 0.5*W(Delta))*(eye(n) + 0.5*W(Delta))*X;
% X=myQR(X+Delta,size(X,2));
%  [X] = myQR2(X+Delta);

% X = X+Delta;
% B_power = X'*X;
% [U,Sigma,V] = svd(B_power);
% SIGMA =diag(Sigma);
% X = X*(U*diag(sqrt(1./SIGMA))*V');

% polar retraction
% X = X+Delta;
% [U,Sigma] = eig(X'*X);
% SIGMA =diag(Sigma);
% X = X*(U*diag(sqrt(1./SIGMA))*U');

X = X+Delta;
X = X*(Delta'*Delta + eye(size(Delta,2)))^(-0.5);



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



function Y = smooth_prox_l1(B,mu,beta)
% min_Y  [||Y||_1]_{\mu} + 0.5 beta ||Y - B||_F^2
y_bar = prox_l1(B,(1+mu*beta)/beta);
Y =  ( y_bar/mu + beta*B) / (1/mu + beta)  ;

function f = l1_norm_mu(B,mu)
% Y_optimal = arg min_Y ||Y||_1 + 0.5/mu ||Y-B||_F^2
% Y_optimal = arg min_Y mu ||Y||_1 + 0.5 ||Y-B||_F^2
Y_optimal = prox_l1(B,mu);
f = norm(Y_optimal(:),1) + 0.5/mu* norm(Y_optimal-B,'fro')^2;


function [Q,R] = myQR2(X)
[Q, R] = qr(X,0);

function [Q, RR] = myQR(XX,k)
[Q, RR] = qr(XX, 0);
diagRR = sign(diag(RR)); ndr = diagRR < 0;
if nnz(ndr) > 0
    %     Q = Q*spdiags(diagRR,0,k,k);
    Q(:,ndr) = Q(:,ndr)*(-1);
end


function [x] = prox_l1(a,lambda)
% It solves the following OP:
% min_{x} 0.5||x-a||^2 + lambda * sum(abs(x))
x = sign(a).*max(0,abs(a)-lambda);




function [X,fobjs,ts] = L0SPCA_RADMM(X,A,NormA,const,rho1,rho2,data_k,max_iter,betaRADMM,timeIntervel,timeLimit)
% 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
[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;
Z = randn(n,r)*0.01;

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

ts = []; fobjs = [];
fobj = HandleObj(X);
fobjs = [fobjs;fobj];
ts = [ts;etime(clock,initt)];
 
mu = 1/betaRADMM;
gamma = 0.1;delta = 1e-4;
fprintf('RADMM: begin\n');
for iter = 1:30000
    
    % Solve the minimization problem:
    %  -0.5*mdot(HX,X) + mdot(X,Z) + 0.5*beta*norm(XY,'fro')^2 - rho2* tksum(X,data_k);

    fun = @(X) ComputeObj(X,A,m,data_k,betaRADMM,Y,rho2,Z);
    [F, G] = fun(X);
    dtX = G - X*G'*X;
    nrmG  = norm(dtX, 'fro');
    tau = 0.001;
    
    XP = X; FP = F;  dtXP = dtX;
    for jj = 1:1000
        eta = tau*gamma^jj; %1/betaRADMM*
        Delta = - eta*dtX;
        X = retr(XP,Delta);
        [F] = fun(X);
        if abs(eta)<1e-10 || F <= FP-eta*delta*nrmG^2;
            break;
        end
        
    end
    
    % Solve the minimization problem:
    % rho1 [||Y||_1]_{mu} + <X-Y,Z> + 0.5 beta ||Y-X||_F^2, s.t. X'X = I
    % where mu = 1 / beta
    % 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/betaRADMM;
    beta_bar = betaRADMM/rho1;
    % min_Y  [||Y||_1]_{\mu} + 0.5 beta_bar ||Y - B||_F^2
    Y = smooth_prox_l1(B,mu,beta_bar);
    
    % Update Z
    diff = X-Y; Z = Z + betaRADMM*diff;
    
    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,betaRADMM);
    end
end
fprintf('RADMM: end\n');

function [X,fobjs,ts] = L0SPCA_SPGM_RR(X,A,NormA,const,rho1,rho2,data_k,max_iter,beta0,alg_xi,alg_theta,timeIntervel,timeLimit)
% 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
[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;
Z = randn(n,r)*0;
Y = orth(randn(n,r));

sigma = 1.5;
xi = alg_xi;
theta = alg_theta;


alpha = 0.5*(theta-1) / ((theta+1)*(xi+2));
alpha = 0;

c0 = 1 + xi/(sigma^2) + xi / (2*sigma^2);
chi = sqrt(4*sigma^2*c0 / ((2-sigma)^2));

chi  = 1;

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

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


rho = 1/2;
delta = 0.25;gamma = 0.1;
fprintf('SPGM_RR: begin\n');
for iter = 1:30000
    
    p = 1/3; beta = beta0*(1+xi*iter^p); mu = chi/beta;
    
    fun = @(X) ComputeObj(X,A,m,data_k,beta,Y,rho2,Z);
    
    [F, G] = fun(X);
    dtX = G - X*G'*X;
    nrmG  = norm(dtX, 'fro');
    tau = 0.01;
    XP = X; FP = F;  dtXP = dtX;
    for jj = 1:1000
        eta = beta0/beta * tau*gamma^jj;
        %          [X] = XP - eta*dtX;
        Delta = - eta*dtX;
        X = retr(XP,Delta);
        %         [X] = orth(XP - eta*dtX);
        [F,G] = fun(X);
        if abs(eta)<1e-10 || F <= FP-eta*1e-12*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;
    % min_Y  [||Y||_1]_{\mu} + 0.5 beta_bar ||Y - B||_F^2
    Y = smooth_prox_l1(B,mu,beta_bar);
    
    % Update Z
    diff = X-Y;
    %    Z = Z + sigma* beta*diff;
    
    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
fprintf('SPGM_RR: end\n');

function [X,fobjs,ts] = L0SPCA_SubGrad(X,A,const,rho1,rho2,k,max_iter,timeIntervel,timeLimit)
% min_X  -0.5/m*mdot(A,A*X*X') + const + rho1 ||X||_1 - rho2 ||X||_{topk}, s.t. X'X = I
[m,n] = size(A);

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


r = size(X,2);
bottom = n*r - k;
X = OrthProj(X);

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

fprintf('SubGrad: begin\n');

for iter = 1:max_iter
    
    SubGrad = -1/m*A'*(A*X) + rho1*sign(X) - rho2*tksum(X,k);
    Delta = - 0.1*SubGrad/iter;
    X = OrthProj(X + Delta);
    %      X = retr(X,Delta);
    
    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\n',iter,fobj);
    end
end
fprintf('SubGrad: end\n');

function [X,fobjs,ts] = L0SPCA_SPGM_EP(X,A,NormA,const,rho1,rho2,data_k,max_iter,beta0,alg_xi,alg_theta,timeIntervel,timeLimit)
% 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
[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;
Z = randn(n,r)*0;
% Y = randn(n,r);

sigma = 1.5;
xi = alg_xi;
theta = alg_theta;
alpha = 0.5*(theta-1) / ((theta+1)*(xi+2));

c0 = 1 + xi/(sigma^2) + xi / (2*sigma^2);
chi = sqrt(4*sigma^2*c0 / ((2-sigma)^2));

X_old = X;

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

fprintf('SPGM_EP: begin\n');

for iter = 1:30000
    p = 1/3; beta = beta0*(1+xi*iter^p); mu = chi/beta;
    X_bar = X + alpha * (X - X_old);
    % Update X
    % 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
    h_grad = @(X) -A'*(A*X)/m + Z + beta*(X-Y);
    grad_X = h_grad(X_bar)- rho2*top_k_subgrad(X,data_k); %
    Lipschit_constant = Lsmooth + beta;
    X_old = X;
    X = OrthProj(X_bar - grad_X/(theta*Lipschit_constant));
    
    % 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;
    % min_Y  [||Y||_1]_{\mu} + 0.5 beta_bar ||Y - B||_F^2
    Y = smooth_prox_l1(B,mu,beta_bar);
    
    % Update Z
    diff = X-Y; %Z = Z + sigma*beta*diff;
    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
fprintf('SPGM_EP: end\n');
function [chi,sigma,theta,xi,alpha] = set_default_para2()
theta = 1.01;
sigma = 1.1;
xi = 0.5;
sigma_dd = (sigma / (2-sigma))^2;
omega = 1/sigma + xi / (2*sigma*sigma) + xi / (sigma*sigma);
chi = 1 + 4*omega*sigma_dd ;
alpha = 0;
chi = chi + 1e-12;

function [chi,sigma,theta,xi,alpha] = set_default_para()
theta = 1.01;
sigma = 1.1;
xi = 0.5;
sigma_dd = (sigma / (2-sigma))^2;
omega = 1/sigma + xi / (2*sigma*sigma) + xi / (sigma*sigma);
chi = 1 + 4*omega*sigma_dd ;
alpha = (theta - 1) / ((theta+1)*(xi+2));
chi = chi +1e-12;
alpha = alpha - 1e-12;

