aboutsummaryrefslogtreecommitdiffstats
path: root/R/l1tf.R
blob: eab5208d300c4c2f4057e1e0aaf253aa81c8024b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
l1tf <- function(y,lambda){

# PARAMETERS
ALPHA     = 0.01;   # backtracking linesearch parameter (0,0.5]
BETA      = 0.5;    # backtracking linesearch parameter (0,1)
MU        = 2;      # IPM parameter: t update
MAXITER   = 40;     # IPM parameter: max iteration of IPM
MAXLSITER = 20;     # IPM parameter: max iteration of line search
TOL       = 1e-4;   # IPM parameter: tolerance

# DIMENSIONS
n   = length(y);    # length of signal x
m   = n-2;          # length of Dx


# OPERATOR MATRICES
I2  = diag(n-2);
O2  = matrix(0,n-2,1);
D   = cbind(I2,O2,O2) + cbind(O2-2*I2,O2) + cbind(O2,O2,I2);

DDT = D%*%t(D);
Dy  = D%*%y;

# VARIABLES
z   = rep(1,m);   % dual variable
mu1 = rep(1,m);    % dual of dual variable
mu2 = rep(1,m);    % dual of dual variable

t    = 1e-10; 
pobj =  Inf;
dobj =  0;
step =  Inf;
f1   =  z-lambda;
f2   = -z-lambda;

for(iters in 0:MAXITER){

    DTz  = t(t(z)%*%D);
    DDTz = D%*%DTz;
    w    = Dy-(mu1-mu2);
    
    pobj1 = 0.5*t(w)%*%solve(DDT,w)+lambda*sum(mu1+mu2);
    pobj2 = 0.5*t(DTz)%*%DTz+lambda*sum(abs(Dy-DDTz));
    pobj = min(pobj1,pobj2);
    dobj = -0.5*t(DTz)%*%DTz+t(Dy)%*%z;

    gap  =  pobj - dobj;

    # STOPPING CRITERION
    if (gap <= TOL){
        x = y-t(D)%*%z;
        return;
      }

    if (step >= 0.2){
        t =max(2*m*MU/gap, 1.2*t);
      }

    # CALCULATE NEWTON STEP
    
    rz      =  DDTz - w;
    S       =  DDT-sparse(1:m,1:m,mu1/f1+mu2/f2);
    r       = -DDTz + Dy + (1/t)/f1 - (1/t)/f2;
    dz      =  solve(S,r);
    dmu1    = -(mu1+((1/t)+dz*mu1)/f1);
    dmu2    = -(mu2+((1/t)-dz*mu2)/f2);

    resDual = rz;
    resCent = rbind(-mu1*f1-1/t, -mu2*f2-1/t);
    residual= rbind(resDual,resCent);

    # BACKTRACKING LINESEARCH
    negIdx1 = (dmu1 < 0); 
    negIdx2 = (dmu2 < 0);
    step = 1;
    if any(negIdx1){
        step = min( step, 0.99*min(-mu1[negIdx1)/dmu1[negIdx1]) );
      }
    if (any(negIdx2){
        step = min( step, 0.99*min(-mu2[negIdx2]/dmu2[negIdx2]) );
      }

    for( liter in 1:MAXLSITER){
        newz    =  z  + step*dz;
        newmu1  =  mu1 + step*dmu1;
        newmu2  =  mu2 + step*dmu2;
        newf1   =  newz - lambda;
        newf2   = -newz - lambda;

        # UPDATE RESIDUAL
        newResDual  = DDT*newz - Dy + newmu1 - newmu2;
        newResCent  = rbind(-newmu1.*newf1-1/t, -newmu2*newf2-1/t);
        newResidual = rbind(newResDual, newResCent);
        
        if ( max(max(newf1),max(newf2)) < 0 && ...
            norm(newResidual) <= (1-ALPHA*step)*norm(residual) )
            break;
      }
        step = BETA*step;
      }
    # UPDATE PRIMAL AND DUAL VARIABLES
    z  = newz; mu1 = newmu1; mu2 = newmu2; f1 = newf1; f2 = newf2;
  }

# The solution may be close at this point, but does not meet the stopping
# criterion (in terms of duality gap).
x = y-t(D)%*%z;
if (iters >= MAXITER){
    status = "maxiter exceeded";
    cat(status,"\n");
    return;
  }