Skip to content

Commit 76f3e7e

Browse files
R code now produces almost identical answer when assuming wide or not
1 parent fb7f85f commit 76f3e7e

File tree

4 files changed

+116
-52
lines changed

4 files changed

+116
-52
lines changed

selectiveInference/R/funs.fixed.R

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,6 @@ debiasingMatrix = function(Xinfo, # could be X or t(X) %*% X / n d
300300
xp = round(p/10);
301301
idx = 1;
302302
for (row in rows) {
303-
304303
if ((idx %% xp)==0){
305304
xperc = xperc+10;
306305
if (verbose) {
@@ -354,13 +353,13 @@ debiasingRow = function (Xinfo, # could be X or t(X) %*% X / n dep
354353
p = ncol(Xinfo)
355354

356355
if (is.null(max_active)) {
357-
max_active = nrow(Xinfo)
356+
max_active = min(nrow(Xinfo), ncol(Xinfo))
358357
}
359358

360359
# Initialize variables
361360

362361
soln = rep(0, p)
363-
362+
Xsoln = rep(0, n)
364363
ever_active = rep(0, p)
365364
ever_active[1] = row # 1-based
366365
ever_active = as.integer(ever_active)
@@ -379,8 +378,7 @@ debiasingRow = function (Xinfo, # could be X or t(X) %*% X / n dep
379378
while (counter_idx < max_try) {
380379

381380
if (!is_wide) {
382-
Sigma = Xinfo
383-
result = solve_QP(Sigma,
381+
result = solve_QP(Xinfo, # this is non-neg-def matrix
384382
mu,
385383
max_iter,
386384
soln,
@@ -392,10 +390,7 @@ debiasingRow = function (Xinfo, # could be X or t(X) %*% X / n dep
392390
objective_tol,
393391
max_active)
394392
} else {
395-
X = Xinfo
396-
n = nrow(X)
397-
Xsoln = rep(0, n)
398-
result = solve_QP_wide(X,
393+
result = solve_QP_wide(Xinfo, # this is a design matrix
399394
mu,
400395
max_iter,
401396
soln,
@@ -409,6 +404,7 @@ debiasingRow = function (Xinfo, # could be X or t(X) %*% X / n dep
409404
max_active)
410405

411406
}
407+
412408
iter = result$iter
413409

414410
# Logic for whether we should continue the line search

selectiveInference/man/debiasingMatrix.Rd

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,9 @@ set.seed(10)
108108
n = 50
109109
p = 100
110110
X = matrix(rnorm(n * p), n, p)
111-
S = t(X) \%*\% X / n
111+
S = t(X) %*% X / n
112112
M = debiasingMatrix(S, FALSE, n, c(1,3,5))
113-
113+
M2 = debiasingMatrix(X, TRUE, n, c(1,3,5))
114+
max(M - M2)
114115
}
115116

selectiveInference/src/quadratic_program.c

Lines changed: 102 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ double objective_qp(double *nndef_ptr, /* A non-negative definite matrix *
1717
int *nactive_ptr, /* Size of ever active set */
1818
int nrow, /* how many rows in nndef */
1919
double bound, /* Lagrange multipler for \ell_1 */
20-
double *theta) /* current value */
20+
double *theta_ptr) /* current value */
2121
{
2222
int irow, icol;
2323
double value = 0;
@@ -28,20 +28,20 @@ double objective_qp(double *nndef_ptr, /* A non-negative definite matrix *
2828
int active_row, active_col;
2929
int nactive = *nactive_ptr;
3030

31-
theta_row_ptr = theta;
32-
theta_col_ptr = theta;
31+
theta_row_ptr = theta_ptr;
32+
theta_col_ptr = theta_ptr;
3333

3434
for (irow=0; irow<nactive; irow++) {
3535

3636
active_row_ptr = ((int *) ever_active_ptr + irow);
3737
active_row = *active_row_ptr - 1; // Ever-active is 1-based
38-
theta_row_ptr = ((double *) theta + active_row);
38+
theta_row_ptr = ((double *) theta_ptr + active_row);
3939

4040
for (icol=0; icol<nactive; icol++) {
4141

4242
active_col_ptr = ((int *) ever_active_ptr + icol);
4343
active_col = *active_col_ptr - 1; // Ever-active is 1-based
44-
theta_col_ptr = ((double *) theta + active_col);
44+
theta_col_ptr = ((double *) theta_ptr + active_col);
4545

4646
nndef_ptr_tmp = ((double *) nndef_ptr + nrow * active_col + active_row); // Matrices are column-major order
4747

@@ -90,7 +90,7 @@ int update_ever_active_qp(int coord,
9090
return(0);
9191
}
9292

93-
int check_KKT_qp(double *theta, /* current theta */
93+
int check_KKT_qp(double *theta_ptr, /* current theta */
9494
double *gradient_ptr, /* nndef times theta + linear_func */
9595
int nrow, /* how many rows in nndef */
9696
double bound, /* Lagrange multipler for \ell_1 */
@@ -99,22 +99,22 @@ int check_KKT_qp(double *theta, /* current theta */
9999
// First check inactive
100100

101101
int irow;
102-
double *theta_ptr, *gradient_ptr_tmp;
102+
double *theta_ptr_tmp, *gradient_ptr_tmp;
103103
double gradient;
104104

105105
for (irow=0; irow<nrow; irow++) {
106-
theta_ptr = ((double *) theta + irow);
106+
theta_ptr_tmp = ((double *) theta_ptr + irow);
107107
gradient_ptr_tmp = ((double *) gradient_ptr + irow);
108108

109109
// Compute this coordinate of the gradient
110110

111111
gradient = *gradient_ptr_tmp;
112112

113-
if (*theta_ptr != 0) { // these coordinates of gradients should be equal to -bound
114-
if ((*theta_ptr > 0) && (fabs(gradient + bound) > tol * bound)) {
113+
if (*theta_ptr_tmp != 0) { // these coordinates of gradients should be equal to -bound
114+
if ((*theta_ptr_tmp > 0) && (fabs(gradient + bound) > tol * bound)) {
115115
return(0);
116116
}
117-
else if ((*theta_ptr < 0) && (fabs(gradient - bound) > tol * bound)) {
117+
else if ((*theta_ptr_tmp < 0) && (fabs(gradient - bound) > tol * bound)) {
118118
return(0);
119119
}
120120
}
@@ -128,6 +128,57 @@ int check_KKT_qp(double *theta, /* current theta */
128128
return(1);
129129
}
130130

131+
int check_KKT_qp_active(int *ever_active_ptr, /* Ever active set: 0-based */
132+
int *nactive_ptr, /* Size of ever active set */
133+
double *theta_ptr, /* current theta */
134+
double *gradient_ptr, /* nndef times theta + linear_func */
135+
int nrow, /* how many rows in nndef */
136+
double bound, /* Lagrange multipler for \ell_1 */
137+
double tol) /* precision for checking KKT conditions */
138+
{
139+
// First check inactive
140+
141+
int iactive;
142+
double *theta_ptr_tmp;
143+
double gradient;
144+
double *gradient_ptr_tmp;
145+
int nactive = *nactive_ptr;
146+
int active_feature;
147+
int *active_feature_ptr;
148+
149+
for (iactive=0; iactive<nactive; iactive++) {
150+
151+
active_feature_ptr = ((int *) ever_active_ptr + iactive);
152+
active_feature = *active_feature_ptr - 1; // Ever-active is 1-based
153+
theta_ptr_tmp = ((double *) theta_ptr + active_feature);
154+
155+
gradient_ptr_tmp = ((double *) gradient_ptr + active_feature);
156+
157+
// Compute this coordinate of the gradient
158+
159+
gradient = *gradient_ptr_tmp;
160+
161+
if (*theta_ptr_tmp != 0) { // these coordinates of gradients should be equal to -bound
162+
163+
if ((*theta_ptr_tmp > 0) && (fabs(gradient + bound) > tol * bound)) {
164+
return(0);
165+
}
166+
else if ((*theta_ptr_tmp < 0) && (fabs(gradient - bound) > tol * bound)) {
167+
return(0);
168+
}
169+
170+
}
171+
else {
172+
if (fabs(gradient) > (1. + tol) * bound) {
173+
return(0);
174+
}
175+
}
176+
}
177+
178+
return(1);
179+
}
180+
181+
131182
double update_one_coord_qp(double *nndef_ptr, /* A non-negative definite matrix */
132183
double *linear_func_ptr, /* Linear term in objective */
133184
double *nndef_diag_ptr, /* Diagonal of nndef */
@@ -136,7 +187,7 @@ double update_one_coord_qp(double *nndef_ptr, /* A non-negative defini
136187
int *nactive_ptr, /* Size of ever active set */
137188
int nrow, /* How many rows in nndef */
138189
double bound, /* feasibility parameter */
139-
double *theta, /* current value */
190+
double *theta_ptr, /* current value */
140191
int coord, /* which coordinate to update: 0-based */
141192
int is_active) /* Is this coord in ever_active */
142193
{
@@ -147,7 +198,7 @@ double update_one_coord_qp(double *nndef_ptr, /* A non-negative defini
147198
double old_value;
148199
double *nndef_ptr_tmp;
149200
double *gradient_ptr_tmp;
150-
double *theta_ptr;
201+
double *theta_ptr_tmp;
151202
int icol = 0;
152203

153204
double *quadratic_ptr = ((double *) nndef_diag_ptr + coord);
@@ -156,8 +207,8 @@ double update_one_coord_qp(double *nndef_ptr, /* A non-negative defini
156207
gradient_ptr_tmp = ((double *) gradient_ptr + coord);
157208
linear_term = *gradient_ptr_tmp;
158209

159-
theta_ptr = ((double *) theta + coord);
160-
old_value = *theta_ptr;
210+
theta_ptr_tmp = ((double *) theta_ptr + coord);
211+
old_value = *theta_ptr_tmp;
161212

162213
// The coord entry of gradient_ptr term has a diagonal term in it:
163214
// nndef[coord, coord] * theta[coord]
@@ -200,8 +251,8 @@ double update_one_coord_qp(double *nndef_ptr, /* A non-negative defini
200251
nndef_ptr_tmp += 1;
201252
}
202253

203-
theta_ptr = ((double *) theta + coord);
204-
*theta_ptr = value;
254+
theta_ptr_tmp = ((double *) theta_ptr + coord);
255+
*theta_ptr_tmp = value;
205256

206257
}
207258

@@ -230,6 +281,8 @@ int solve_qp(double *nndef_ptr, /* A non-negative definite matrix */
230281
int *active_ptr;
231282

232283
int check_objective = 1;
284+
int iter_active;
285+
int niter_active=5;
233286

234287
double old_value, new_value;
235288

@@ -248,23 +301,38 @@ int solve_qp(double *nndef_ptr, /* A non-negative definite matrix */
248301

249302
for (iter=0; iter<maxiter; iter++) {
250303

251-
// Update the active variables first
252-
253-
active_ptr = (int *) ever_active_ptr;
254-
255-
for (iactive=0; iactive < *nactive_ptr; iactive++) {
256-
update_one_coord_qp(nndef_ptr,
257-
linear_func_ptr,
258-
nndef_diag_ptr,
259-
gradient_ptr,
260-
ever_active_ptr,
261-
nactive_ptr,
262-
nrow,
263-
bound,
264-
theta,
265-
*active_ptr - 1, // Ever-active is 1-based
266-
1);
267-
active_ptr++;
304+
// Update the active variables first -- do this niter_active times
305+
306+
for (iter_active=0; iter_active<niter_active; iter_active++) {
307+
308+
active_ptr = (int *) ever_active_ptr;
309+
for (iactive=0; iactive < *nactive_ptr; iactive++) {
310+
311+
update_one_coord_qp(nndef_ptr,
312+
linear_func_ptr,
313+
nndef_diag_ptr,
314+
gradient_ptr,
315+
ever_active_ptr,
316+
nactive_ptr,
317+
nrow,
318+
bound,
319+
theta,
320+
*active_ptr - 1, // Ever-active is 1-based
321+
1);
322+
active_ptr++;
323+
}
324+
325+
// Check KKT of active subproblem
326+
327+
if (check_KKT_qp_active(ever_active_ptr,
328+
nactive_ptr,
329+
theta,
330+
gradient_ptr,
331+
nrow,
332+
bound,
333+
kkt_tol) == 1) {
334+
break;
335+
}
268336
}
269337

270338
// Check KKT

selectiveInference/src/quadratic_program_wide.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#include <math.h> // for fabs
22

3-
// Find an approximate row of \hat{Sigma}^{-1}
3+
// Find an approximate row of \hat{nndef}^{-1}
44

55
// Solves a dual version of problem (4) of https://arxiv.org/pdf/1306.3171.pdf
66

@@ -222,7 +222,6 @@ int check_KKT_wide_active(int *ever_active_ptr, /* Ever active set: 0-
222222
int iactive;
223223
double *theta_ptr_tmp;
224224
double gradient;
225-
int ever_active_ptr_tmp;
226225
int nactive = *nactive_ptr;
227226
int active_feature;
228227
int *active_feature_ptr;
@@ -259,16 +258,16 @@ int check_KKT_wide_active(int *ever_active_ptr, /* Ever active set: 0-
259258

260259
double update_one_coord_wide(double *X_ptr, /* A design matrix*/
261260
double *linear_func_ptr, /* Linear term in objective */
262-
double *nndef_diag_ptr, /* Diagonal entries of Sigma */
263-
double *gradient_ptr, /* X^TX/ncase times theta + linear_func*/
261+
double *nndef_diag_ptr, /* Diagonal of nndef */
262+
double *gradient_ptr, /* X^TX/ncase times theta + linear_func*/
264263
int *ever_active_ptr, /* Ever active set: 1-based */
265264
int *nactive_ptr, /* Size of ever active set */
266265
double *X_theta_ptr, /* X\theta -- fitted values */
267266
int *need_update_ptr, /* Whether a gradient coordinate needs update or not */
268-
int ncase, /* How many rows in X */
269-
int nfeature, /* How many rows in X */
267+
int ncase, /* How many rows in X */
268+
int nfeature, /* How many rows in X */
270269
double bound, /* feasibility parameter */
271-
double *theta_ptr, /* current value */
270+
double *theta_ptr, /* current value */
272271
int coord, /* which coordinate to update: 0-based */
273272
int is_active) /* Is this coord in ever_active */
274273
{

0 commit comments

Comments
 (0)