function [x_best,fobjs,ts]=AccerlatedProximalGradientConstantStepsize(x,hObjSmooth,hObjNonSmooth,hProx,maxiter,timeLimit,timeIntervel,L)
% An implemnetation of "FISTA with constant stepsize".

% References: A Fast Iterative Shrinkage-Thresholding Algorithm for Linear
% Inverse Problems, Amir Beck, Marc Teboulle, SIIMS 2009.

% This program solves the following optimization problem:
% f(x) + g(x)
% where we assume that f is smooth g is non-smooth
% hObjSmooth:           x   ->  [fobj,grad]
% hObjNonSmooth:        x   ->  [fobj]
% hProx:          [a,theta] ->  arg min_{x} 0.5 || x - a ||^2 + theta*g(x)

% One xample:

% function example_LeastR
% clear, clc;
% %  min  1/2 || A x - y||^2 + lambda * ||x||_1
% % f(x) + g(x)
% % 0.5 L ||x-xt||^2 + <x-xt,g> + g(x)
% % 0.5 L ||x-(xt-g/L)||^2 + g(x)
% % proximal mapping:
%
% % 0.5 theta ||x - a||^2 + g(x)
%
%
% m=1000;  n=100;    % The data matrix is of size m x n
% A=randn(m,n);       % the data matrix
% y = randn(m,1);
% lambda=0.2;
% hObjSmooth = @(x)computeObj(x,A,y);
% hObjNonSmooth = @(x)lambda*sum(abs(x));
% x=zeros(n,1);
% hProx = @(theta,a)computeprox(theta,a,lambda);
% [x1, his]= AccerlatedProximalGradient(x,hObjSmooth,hObjNonSmooth,hProx);
% plot(his)
%
% function [fobj,grad] = computeObj(x,A,y)
% diff = A*x-y;
% fobj = 1/2*norm(diff)^2 ;
% grad = A'*diff ;
%
% function [x] = computeprox(theta,a,lambda)
% % 0.5 theta ||x - a||^2 + g(x)
% [x] = threadholding_l1(a,lambda*theta);
%
% function [x] = threadholding_l1(a,lambda)
% % solving the following OP:
% % min_{x} 0.5 ||x - a||^2 + lambda * sum(abs(x))
% x = sign(a).*max(0,abs(a)-lambda);




alpha=1;
xp=x;
y=x;
x_best = x;
hObjF = @(x)hObjSmooth(x) + hObjNonSmooth(x);

f_curr = hObjF(x);
f_best = f_curr;

initt = clock;
last_rec_clock = initt;
ts = []; fobjs = [];
fobjs = [fobjs;f_best];
ts = [ts;etime(clock,initt)];

for iterStep=1:maxiter,
    %     fprintf('*');
    [fobjy,grady] = hObjSmooth(y);
    xp = x;
    
    [x] = hProx(y-grady/L,1/L);
    Fnew = hObjF(x) ;

    alphap = alpha;
    alpha = 0.5*(1+ sqrt(4*alpha*alpha +1));
    beta = (alphap-1)/alpha;
    y = x + beta*(x-xp);
    
    f_curr = Fnew;
    if(f_curr<f_best)
        f_best = f_curr;
        x_best = x;
    end
 
    cur_clock = clock;
    if(etime(cur_clock,last_rec_clock) > timeIntervel)
        ElasTime =  etime(cur_clock,initt);
        fobjs  = [fobjs;f_curr];
        ts = [ts;ElasTime];
        last_rec_clock = cur_clock;
        if ElasTime > timeLimit
            break;
        end
    end

end

fobjs = fobjs(:);

function [r] = mdot(x,y)
r = sum(sum(x.*y));


function [x_best,fobjs,ts] = ProximalGradient1(x,HandleObjSmooth,HandleObjNonSmooth,HandleProx,maxiter,timeLimit,timeIntervel,L)
% This program solves the following optimization problem:
% f(x) + g(x)
% where we assume that f is smooth g is non-smooth
% HandleObjSmooth:           x   ->  [fobj,grad]
% HandleObjNonSmooth:        x   ->  [fobj]
% HandleProx:          [theta,a] ->  arg min_{x} 0.5 theta || x - a ||^2 + g(x)

% One xample:

% function example_LeastR
% clear, clc;
% %  min  1/2 || A x - y||^2 + lambda * ||x||_1
% % f(x) + g(x)
% % 0.5 L ||x-xt||^2 + <x-xt,g> + g(x)
% % 0.5 L ||x-(xt-g/L)||^2 + g(x)
% % proximal mapping:
%
% % 0.5 theta ||x - a||^2 + g(x)
%
%
% m=1000;  n=100;    % The data matrix is of size m x n
% A=randn(m,n);       % the data matrix
% y = randn(m,1);
% lambda=0.2;
% HandleObjSmooth = @(x)computeObj(x,A,y);
% HandleObjNonSmooth = @(x)lambda*sum(abs(x));
% x=zeros(n,1);
% HandleProx = @(theta,a)computeprox(theta,a,lambda);
% [x1, his]= AccerlatedProximalGradient(x,HandleObjSmooth,HandleObjNonSmooth,HandleProx);
% plot(his)
%
% function [fobj,grad] = computeObj(x,A,y)
% diff = A*x-y;
% fobj = 1/2*norm(diff)^2 ;
% grad = A'*diff ;
%
% function [x] = computeprox(theta,a,lambda)
% % 0.5 theta ||x - a||^2 + g(x)
% [x] = threadholding_l1(a,lambda/theta);
%
% function [x] = threadholding_l1(a,lambda)
% % solving the following OP:
% % min_{x} 0.5 ||x - a||^2 + lambda * sum(abs(x))
% x = sign(a).*max(0,abs(a)-lambda);


initt = clock;
last_rec_clock = initt;
ts = []; fobjs = [];
fobjs = [fobjs;HandleObjSmooth(x)];
ts = [ts;etime(clock,initt)];


[n,d]=size(x);

xp=x;
xxp=zeros(n,d);
alpha=1; s=x;
x_best = x;
f_best = HandleObjSmooth(x) + HandleObjNonSmooth(x);
for iterStep=1:maxiter,
    %     fprintf('*');
    [f_old,g_old] = HandleObjSmooth(s);
    xp=x;
    
    v=s-g_old/L;
    % min_{x} 0.5 L ||x-(xt-g/L)||^2 + z * ||x||_1
    [x]=HandleProx(L,v);
    f_new = HandleObjSmooth(x);
    alphap=alpha; alpha= (1+ sqrt(4*alpha*alpha +1))/2;
    beta=(alphap-1)/alpha;    s=x + beta* xxp;
    xxp=x-xp;
    f_curr = f_new  + HandleObjNonSmooth(x);
    if(f_curr<f_best)
        f_best = f_curr;
        x_best = x;
    end
    %     his(iterStep) = f_curr;
    %     if (iterStep>50 && flag),break;end
    
    cur_clock = clock;
    if(etime(cur_clock,last_rec_clock) > timeIntervel)
        ElasTime =  etime(cur_clock,initt);
        fobjs  = [fobjs;f_curr];
        ts = [ts;ElasTime];
        last_rec_clock = cur_clock;
        if ElasTime > timeLimit
            break;
        end
    end
    
    
end


