4
4
5
5
// Solves a dual version of problem (4) of https://arxiv.org/pdf/1306.3171.pdf
6
6
7
- // Dual problem: \text{min}_{\theta} 1/2 \theta^T \Sigma \theta - l^T\theta + \mu \|\theta\|_1
8
- // where l is `linear_func` below
7
+ // Dual problem: \text{min}_{\theta} 1/2 \theta^T \Sigma \theta - e_i^T\theta + \mu \|\theta\|_1
9
8
10
9
// This is the "negative" of the problem as in https://gist.github.com/jonathan-taylor/07774d209173f8bc4e42aa37712339bf
11
10
// Therefore we don't have to negate the answer to get theta.
12
11
// Update one coordinate
13
12
14
13
double objective (double * Sigma_ptr , /* A covariance matrix: X^TX/n */
15
- double * linear_func_ptr , /* Linear term in objective */
16
14
int * ever_active_ptr , /* Ever active set: 0-based */
17
- int * nactive_ptr , /* Size of ever active set */
18
- int nrow , /* how many rows in Sigma */
19
- double bound , /* Lagrange multipler for \ell_1 */
20
- double * theta ) /* current value */
15
+ int * nactive_ptr , /* Size of ever active set */
16
+ int nrow , /* how many rows in Sigma */
17
+ int row , /* which row: 0-based */
18
+ double bound , /* Lagrange multipler for \ell_1 */
19
+ double * theta ) /* current value */
21
20
{
22
21
int irow , icol ;
23
22
double value = 0 ;
24
23
double * Sigma_ptr_tmp = Sigma_ptr ;
25
- double * linear_func_ptr_tmp = linear_func_ptr ;
26
24
double * theta_row_ptr , * theta_col_ptr ;
27
25
int * active_row_ptr , * active_col_ptr ;
28
26
int active_row , active_col ;
@@ -47,15 +45,12 @@ double objective(double *Sigma_ptr, /* A covariance matrix: X^TX/n */
47
45
48
46
value += 0.5 * (* Sigma_ptr_tmp ) * (* theta_row_ptr ) * (* theta_col_ptr );
49
47
}
50
- value += bound * fabs ((* theta_row_ptr )); // the \ell_1 term
51
-
52
- // The linear term in the objective
48
+ value = value + bound * fabs ((* theta_row_ptr )); // the \ell_1 term
49
+ }
53
50
54
- linear_func_ptr_tmp = ((double * ) linear_func_ptr + active_row );
55
- value + = (* linear_func_ptr_tmp ) * ( * theta_row_ptr );
51
+ theta_row_ptr = ((double * ) theta + row );
52
+ value - = (* theta_row_ptr ); // the elementary basis vector term
56
53
57
- }
58
-
59
54
return (value );
60
55
}
61
56
@@ -71,14 +66,14 @@ int update_ever_active(int coord,
71
66
72
67
for (iactive = 0 ; iactive < nactive ; iactive ++ ) {
73
68
ever_active_ptr_tmp = ((int * ) ever_active_ptr + iactive );
74
- active_var = * ever_active_ptr_tmp ;
69
+ active_var = ( * ever_active_ptr_tmp ) ;
75
70
if (active_var == coord ) {
76
71
return (1 );
77
72
}
78
73
}
79
-
80
- // If we haven't returned yet, this means the coord was not in
81
- // ever_active.
74
+
75
+ // If we have not returned yet, this variable
76
+ // was not in ever_active
82
77
83
78
// Add it to the active set and increment the
84
79
// number of active variables
@@ -93,6 +88,7 @@ int update_ever_active(int coord,
93
88
int check_KKT (double * theta , /* current theta */
94
89
double * gradient_ptr , /* Sigma times theta */
95
90
int nrow , /* how many rows in Sigma */
91
+ int row , /* which row: 0-based */
96
92
double bound ) /* Lagrange multipler for \ell_1 */
97
93
{
98
94
// First check inactive
@@ -110,36 +106,39 @@ int check_KKT(double *theta, /* current theta */
110
106
// Compute this coordinate of the gradient
111
107
112
108
gradient = * gradient_ptr_tmp ;
109
+ if (row == irow ) {
110
+ gradient -= 1 ;
111
+ }
113
112
114
113
if (* theta_ptr != 0 ) { // these coordinates of gradients should be equal to -bound
115
114
if ((* theta_ptr > 0 ) && (fabs (gradient + bound ) > tol * bound )) {
116
- return ( 0 ) ;
115
+ fail += 1 ;
117
116
}
118
117
else if ((* theta_ptr < 0 ) && (fabs (gradient - bound ) > tol * bound )) {
119
- return ( 0 ) ;
118
+ fail += 1 ;
120
119
}
121
120
}
122
121
else {
123
122
if (fabs (gradient ) > (1. + tol ) * bound ) {
124
- return ( 0 ) ;
123
+ fail += 1 ;
125
124
}
126
125
}
127
126
}
128
127
129
- return (1 );
128
+ return (fail == 0 );
130
129
}
131
130
132
131
double update_one_coord (double * Sigma_ptr , /* A covariance matrix: X^TX/n */
133
- double * linear_func_ptr , /* Linear term in objective */
134
132
double * Sigma_diag_ptr , /* Diagonal entries of Sigma */
135
- double * gradient_ptr , /* Sigma times theta */
133
+ double * gradient_ptr , /* Sigma times theta */
136
134
int * ever_active_ptr , /* Ever active set: 0-based */
137
- int * nactive_ptr , /* Size of ever active set */
138
- int nrow , /* How many rows in Sigma */
139
- double bound , /* feasibility parameter */
140
- double * theta , /* current value */
141
- int coord , /* which coordinate to update: 0-based */
142
- int is_active ) /* Is this part of ever_active */
135
+ int * nactive_ptr , /* Size of ever active set */
136
+ int nrow , /* How many rows in Sigma */
137
+ double bound , /* feasibility parameter */
138
+ double * theta , /* current value */
139
+ int row , /* which row: 0-based */
140
+ int coord , /* which coordinate to update: 0-based */
141
+ int is_active ) /* Is this part of ever_active */
143
142
{
144
143
145
144
double delta ;
@@ -154,6 +153,8 @@ double update_one_coord(double *Sigma_ptr, /* A covariance matrix: X^T
154
153
double * quadratic_ptr = ((double * ) Sigma_diag_ptr + coord );
155
154
double quadratic_term = * quadratic_ptr ;
156
155
156
+ // int *ever_active_ptr_tmp;
157
+
157
158
gradient_ptr_tmp = ((double * ) gradient_ptr + coord );
158
159
linear_term = * gradient_ptr_tmp ;
159
160
@@ -163,9 +164,12 @@ double update_one_coord(double *Sigma_ptr, /* A covariance matrix: X^T
163
164
// The coord entry of gradient_ptr term has a diagonal term in it:
164
165
// Sigma[coord, coord] * theta[coord]
165
166
// This removes it.
166
-
167
167
linear_term -= quadratic_term * old_value ;
168
168
169
+ if (row == coord ) {
170
+ linear_term -= 1 ;
171
+ }
172
+
169
173
// Now soft-threshold the coord entry of theta
170
174
171
175
// Objective is t \mapsto q/2 * t^2 + l * t + bound |t|
@@ -183,7 +187,7 @@ double update_one_coord(double *Sigma_ptr, /* A covariance matrix: X^T
183
187
184
188
// Add to active set if necessary
185
189
186
- if (is_active == 0 ) {
190
+ if (( is_active == 0 ) && ( value != 0 ) ) {
187
191
update_ever_active (coord , ever_active_ptr , nactive_ptr );
188
192
}
189
193
@@ -211,31 +215,31 @@ double update_one_coord(double *Sigma_ptr, /* A covariance matrix: X^T
211
215
}
212
216
213
217
int find_one_row_ (double * Sigma_ptr , /* A covariance matrix: X^TX/n */
214
- double * linear_func_ptr , /* Linear term in objective */
215
218
double * Sigma_diag_ptr , /* Diagonal entry of covariance matrix */
216
- double * gradient_ptr , /* Sigma times theta */
219
+ double * gradient_ptr , /* Sigma times theta */
217
220
int * ever_active_ptr , /* Ever active set: 0-based */
218
- int * nactive_ptr , /* Size of ever active set */
219
- int nrow , /* How many rows in Sigma */
220
- double bound , /* feasibility parameter */
221
- double * theta , /* current value */
222
- int maxiter )
221
+ int * nactive_ptr , /* Size of ever active set */
222
+ int nrow , /* How many rows in Sigma */
223
+ double bound , /* feasibility parameter */
224
+ double * theta , /* current value */
225
+ int maxiter , /* how many iterations */
226
+ int row ) /* which coordinate to update: 0-based */
223
227
{
224
228
225
229
int iter = 0 ;
226
230
int icoord = 0 ;
227
231
int iactive = 0 ;
228
232
int * active_ptr ;
229
233
230
- /* double old_value = objective(Sigma_ptr, */
231
- /* linear_func_ptr, */
232
- /* ever_active_ptr, */
233
- /* nactive_ptr, */
234
- /* nrow, */
235
- /* bound, */
236
- /* theta); */
234
+ double old_value = objective (Sigma_ptr ,
235
+ ever_active_ptr ,
236
+ nactive_ptr ,
237
+ nrow ,
238
+ row ,
239
+ bound ,
240
+ theta );
237
241
double new_value ;
238
- double tol = 1.e-8 ;
242
+ double tol = 1.e-5 ;
239
243
240
244
for (iter = 0 ; iter < maxiter ; iter ++ ) {
241
245
@@ -245,14 +249,14 @@ int find_one_row_(double *Sigma_ptr, /* A covariance matrix: X^TX/n */
245
249
246
250
for (iactive = 0 ; iactive < * nactive_ptr ; iactive ++ ) {
247
251
update_one_coord (Sigma_ptr ,
248
- linear_func_ptr ,
249
252
Sigma_diag_ptr ,
250
253
gradient_ptr ,
251
254
ever_active_ptr ,
252
255
nactive_ptr ,
253
256
nrow ,
254
257
bound ,
255
258
theta ,
259
+ row ,
256
260
* active_ptr ,
257
261
1 );
258
262
active_ptr ++ ;
@@ -263,6 +267,7 @@ int find_one_row_(double *Sigma_ptr, /* A covariance matrix: X^TX/n */
263
267
if (check_KKT (theta ,
264
268
gradient_ptr ,
265
269
nrow ,
270
+ row ,
266
271
bound ) == 1 ) {
267
272
break ;
268
273
}
@@ -272,14 +277,14 @@ int find_one_row_(double *Sigma_ptr, /* A covariance matrix: X^TX/n */
272
277
for (icoord = 0 ; icoord < nrow ; icoord ++ ) {
273
278
274
279
update_one_coord (Sigma_ptr ,
275
- linear_func_ptr ,
276
280
Sigma_diag_ptr ,
277
281
gradient_ptr ,
278
282
ever_active_ptr ,
279
283
nactive_ptr ,
280
284
nrow ,
281
285
bound ,
282
286
theta ,
287
+ row ,
283
288
icoord ,
284
289
0 );
285
290
}
@@ -289,23 +294,24 @@ int find_one_row_(double *Sigma_ptr, /* A covariance matrix: X^TX/n */
289
294
if (check_KKT (theta ,
290
295
gradient_ptr ,
291
296
nrow ,
297
+ row ,
292
298
bound ) == 1 ) {
293
299
break ;
294
300
}
295
301
296
- /* new_value = objective(Sigma_ptr, */
297
- /* linear_func_ptr, */
298
- /* ever_active_ptr, */
299
- /* nactive_ptr, */
300
- /* nrow, */
301
- /* bound, */
302
- /* theta); */
303
-
304
- /* if (((old_value - new_value) < tol * fabs(new_value)) && (iter > 0)) { */
305
- /* break; */
306
- /* } */
307
-
308
- // old_value = new_value;
302
+ new_value = objective (Sigma_ptr ,
303
+ ever_active_ptr ,
304
+ nactive_ptr ,
305
+ nrow ,
306
+ row ,
307
+ bound ,
308
+ theta );
309
+
310
+ if (((old_value - new_value ) < tol * fabs (new_value )) && (iter > 0 )) {
311
+ break ;
312
+ }
313
+
314
+ old_value = new_value ;
309
315
}
310
316
return (iter );
311
317
}
0 commit comments