Skip to content

Commit 83b0426

Browse files
bug found in qp solver -- look at tests/test_QP.R
1 parent 2439d73 commit 83b0426

File tree

9 files changed

+204
-8
lines changed

9 files changed

+204
-8
lines changed

selectiveInference/NAMESPACE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,4 @@ importFrom("stats", dnorm, lsfit, pexp, pnorm, predict,
4444
importFrom("stats", "coef", "df", "lm", "pf")
4545
importFrom("stats", "glm", "residuals", "vcov")
4646
importFrom("Rcpp", "sourceCpp")
47-
47+
importFrom("distr", "Norm", "DExp")

selectiveInference/R/funs.fixed.R

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ debiasingMatrix = function(Xinfo, # could be X or t(X) %*% X / n d
327327
warn_kkt=FALSE, # warn if KKT does not seem to be satisfied?
328328
max_iter=100, # how many iterations for each optimization problem
329329
kkt_tol=1.e-4, # tolerance for the KKT conditions
330+
parameter_tol=1.e-4, # tolerance for relative convergence of parameter
330331
objective_tol=1.e-8 # tolerance for relative decrease in objective
331332
) {
332333

@@ -363,6 +364,7 @@ debiasingMatrix = function(Xinfo, # could be X or t(X) %*% X / n d
363364
warn_kkt=FALSE,
364365
max_iter=max_iter,
365366
kkt_tol=kkt_tol,
367+
parameter_tol=parameter_tol,
366368
objective_tol=objective_tol)
367369

368370
if (warn_kkt && (!output$kkt_check)) {
@@ -393,6 +395,7 @@ debiasingRow = function (Xinfo, # could be X or t(X) %*% X / n dep
393395
warn_kkt=FALSE, # warn if KKT does not seem to be satisfied?
394396
max_iter=100, # how many iterations for each optimization problem
395397
kkt_tol=1.e-4, # tolerance for the KKT conditions
398+
parameter_tol=1.e-4, # tolerance for relative convergence of parameter
396399
objective_tol=1.e-8 # tolerance for relative decrease in objective
397400
) {
398401

@@ -433,6 +436,7 @@ debiasingRow = function (Xinfo, # could be X or t(X) %*% X / n dep
433436
nactive,
434437
kkt_tol,
435438
objective_tol,
439+
parameter_tol,
436440
max_active,
437441
FALSE, # objective_stop
438442
FALSE, # kkt_stop
@@ -451,6 +455,7 @@ debiasingRow = function (Xinfo, # could be X or t(X) %*% X / n dep
451455
nactive,
452456
kkt_tol,
453457
objective_tol,
458+
parameter_tol,
454459
max_active,
455460
FALSE, # objective_stop
456461
FALSE, # kkt_stop

selectiveInference/R/funs.randomized.R

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ fit_randomized_lasso = function(X,
1111
noise_type=c('gaussian', 'laplace'),
1212
max_iter=100, # how many iterations for each optimization problem
1313
kkt_tol=1.e-4, # tolerance for the KKT conditions
14+
parameter_tol=1.e-8, # tolerance for relative convergence of parameter
1415
objective_tol=1.e-8, # tolerance for relative decrease in objective
1516
objective_stop=FALSE,
1617
kkt_stop=TRUE,
@@ -56,6 +57,7 @@ fit_randomized_lasso = function(X,
5657
nactive,
5758
kkt_tol,
5859
objective_tol,
60+
parameter_tol,
5961
p,
6062
objective_stop, # objective_stop
6163
kkt_stop, # kkt_stop

selectiveInference/src/Rcpp-debias.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Rcpp::List solve_QP(Rcpp::NumericMatrix Sigma,
1515
Rcpp::IntegerVector nactive,
1616
double kkt_tol,
1717
double objective_tol,
18+
double parameter_tol,
1819
int max_active,
1920
int objective_stop,
2021
int kkt_stop,
@@ -52,6 +53,7 @@ Rcpp::List solve_QP(Rcpp::NumericMatrix Sigma,
5253
maxiter,
5354
kkt_tol,
5455
objective_tol,
56+
parameter_tol,
5557
max_active,
5658
objective_stop,
5759
kkt_stop,
@@ -92,6 +94,7 @@ Rcpp::List solve_QP_wide(Rcpp::NumericMatrix X,
9294
Rcpp::IntegerVector nactive,
9395
double kkt_tol,
9496
double objective_tol,
97+
double parameter_tol,
9598
int max_active,
9699
int objective_stop,
97100
int kkt_stop,
@@ -142,6 +145,7 @@ Rcpp::List solve_QP_wide(Rcpp::NumericMatrix X,
142145
maxiter,
143146
kkt_tol,
144147
objective_tol,
148+
parameter_tol,
145149
max_active,
146150
objective_stop,
147151
kkt_stop,

selectiveInference/src/debias.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ int solve_qp(double *nndef_ptr, /* A non-negative definite matrix */
1616
int maxiter, /* max number of iterations */
1717
double kkt_tol, /* precision for checking KKT conditions */
1818
double objective_tol, /* precision for checking relative decrease in objective value */
19+
double parameter_tol, /* precision for checking relative convergence of parameter */
1920
int max_active, /* Upper limit for size of active set -- otherwise break */
2021
int objective_stop, /* Break based on convergence of objective value? */
2122
int kkt_stop, /* Break based on KKT? */
@@ -44,6 +45,7 @@ int solve_wide(double *X_ptr, /* Sqrt of non-neg def matrix -- X^TX
4445
int maxiter, /* max number of iterations */
4546
double kkt_tol, /* precision for checking KKT conditions */
4647
double objective_tol, /* precision for checking relative decrease in objective value */
48+
double parameter_tol, /* precision for checking relative convergence of parameter */
4749
int max_active, /* Upper limit for size of active set -- otherwise break */
4850
int objective_stop, /* Break based on convergence of objective value? */
4951
int kkt_stop, /* Break based on KKT? */

selectiveInference/src/quadratic_program.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ int solve_qp(double *nndef_ptr, /* A non-negative definite matrix */
273273
int maxiter, /* max number of iterations */
274274
double kkt_tol, /* precision for checking KKT conditions */
275275
double objective_tol, /* precision for checking relative decrease in objective value */
276+
double parameter_tol, /* precision for checking relative convergence of parameter */
276277
int max_active, /* Upper limit for size of active set -- otherwise break */
277278
int objective_stop, /* Break based on convergence of objective value? */
278279
int kkt_stop, /* Break based on KKT? */
@@ -292,7 +293,6 @@ int solve_qp(double *nndef_ptr, /* A non-negative definite matrix */
292293
double norm_diff = 1.;
293294
double norm_last = 1.;
294295
double delta;
295-
double threshold = 1.e-2;
296296
double *theta_ptr, *theta_old_ptr;
297297

298298
if (objective_stop) {
@@ -403,7 +403,7 @@ int solve_qp(double *nndef_ptr, /* A non-negative definite matrix */
403403
norm_diff = sqrt(norm_diff);
404404
norm_last = sqrt(norm_last);
405405

406-
if (norm_diff < threshold * norm_last) {
406+
if (norm_diff < parameter_tol * norm_last) {
407407
break;
408408
}
409409
}

selectiveInference/src/quadratic_program_wide.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

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

7-
// Dual problem: \text{min}_{\theta} 1/2 \|X\theta\|^2 - l^T\theta + \mu \|\theta\|_1 + \frac{\epsilon}{2} \|\theta\|^2_2
7+
// Dual problem: \text{min}_{\theta} 1/2 \|X\theta\|^2/n - l^T\theta + \mu \|\theta\|_1 + \frac{\epsilon}{2} \|\theta\|^2_2
88
// where l is `linear_func` below
99

1010
// This is the "negative" of the problem as in https://gist.github.com/jonathan-taylor/07774d209173f8bc4e42aa37712339bf
@@ -393,6 +393,7 @@ int solve_wide(double *X_ptr, /* Sqrt of non-neg def matrix -- X^TX
393393
int maxiter, /* max number of iterations */
394394
double kkt_tol, /* precision for checking KKT conditions */
395395
double objective_tol, /* precision for checking relative decrease in objective value */
396+
double parameter_tol, /* precision for checking relative convergence of parameter */
396397
int max_active, /* Upper limit for size of active set -- otherwise break */
397398
int objective_stop, /* Break based on convergence of objective value? */
398399
int kkt_stop, /* Break based on KKT? */
@@ -412,7 +413,6 @@ int solve_wide(double *X_ptr, /* Sqrt of non-neg def matrix -- X^TX
412413
double norm_diff = 1.;
413414
double norm_last = 1.;
414415
double delta;
415-
double threshold = 1.e-2;
416416
double *theta_ptr_tmp, *theta_old_ptr_tmp;
417417

418418
if (objective_stop) {
@@ -552,7 +552,7 @@ int solve_wide(double *X_ptr, /* Sqrt of non-neg def matrix -- X^TX
552552
norm_diff = sqrt(norm_diff);
553553
norm_last = sqrt(norm_last);
554554

555-
if (norm_diff < threshold * norm_last) {
555+
if (norm_diff < parameter_tol * norm_last) {
556556
break;
557557
}
558558
}

tests/test_QP.R

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
library(selectiveInference)
2+
### Test
3+
4+
n = 100; p = 50
5+
6+
X = matrix(rnorm(n * p), n, p)
7+
Y = rnorm(n)
8+
lam = 2
9+
10+
soln1 = selectiveInference:::fit_randomized_lasso(X, Y, lam, 1.e-12, 0)$soln
11+
G = glmnet(X, Y, intercept=FALSE, standardize=FALSE)
12+
soln2 = coef(G, s=1/n, exact=TRUE, x=X, y=Y)[-1]
13+
14+
print(soln1)
15+
print(soln2)

tests/test_debiasing.R

Lines changed: 170 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,143 @@
11
library(selectiveInference)
2-
source('oldcode.R')
32

4-
n = 500; p = 50
3+
4+
## Approximates inverse covariance matrix theta
5+
InverseLinfty <- function(sigma, n, resol=1.5, mu=NULL, maxiter=50, threshold=1e-10, verbose = TRUE) {
6+
isgiven <- 1;
7+
if (is.null(mu)){
8+
isgiven <- 0;
9+
}
10+
11+
p <- nrow(sigma);
12+
M <- matrix(0, p, p);
13+
xperc = 0;
14+
xp = round(p/10);
15+
for (i in 1:p) {
16+
if ((i %% xp)==0){
17+
xperc = xperc+10;
18+
if (verbose) {
19+
print(paste(xperc,"% done",sep="")); }
20+
}
21+
if (isgiven==0){
22+
mu <- (1/sqrt(n)) * qnorm(1-(0.1/(p^2)));
23+
}
24+
mu.stop <- 0;
25+
try.no <- 1;
26+
incr <- 0;
27+
while ((mu.stop != 1)&&(try.no<10)){
28+
last.beta <- beta
29+
output <- InverseLinftyOneRow(sigma, i, mu, maxiter=maxiter, threshold=threshold)
30+
beta <- output$optsol
31+
iter <- output$iter
32+
if (isgiven==1){
33+
mu.stop <- 1
34+
}
35+
else{
36+
if (try.no==1){
37+
if (iter == (maxiter+1)){
38+
incr <- 1;
39+
mu <- mu*resol;
40+
} else {
41+
incr <- 0;
42+
mu <- mu/resol;
43+
}
44+
}
45+
if (try.no > 1){
46+
if ((incr == 1)&&(iter == (maxiter+1))){
47+
mu <- mu*resol;
48+
}
49+
if ((incr == 1)&&(iter < (maxiter+1))){
50+
mu.stop <- 1;
51+
}
52+
if ((incr == 0)&&(iter < (maxiter+1))){
53+
mu <- mu/resol;
54+
}
55+
if ((incr == 0)&&(iter == (maxiter+1))){
56+
mu <- mu*resol;
57+
beta <- last.beta;
58+
mu.stop <- 1;
59+
}
60+
}
61+
}
62+
try.no <- try.no+1
63+
}
64+
M[i,] <- beta;
65+
}
66+
return(M)
67+
}
68+
69+
InverseLinftyOneRow <- function ( sigma, i, mu, maxiter=50, threshold=1e-10) {
70+
p <- nrow(sigma);
71+
rho <- max(abs(sigma[i,-i])) / sigma[i,i];
72+
mu0 <- rho/(1+rho);
73+
beta <- rep(0,p);
74+
75+
#if (mu >= mu0){
76+
# beta[i] <- (1-mu0)/sigma[i,i];
77+
# returnlist <- list("optsol" = beta, "iter" = 0);
78+
# return(returnlist);
79+
#}
80+
81+
diff.norm2 <- 1;
82+
last.norm2 <- 1;
83+
iter <- 1;
84+
iter.old <- 1;
85+
beta[i] <- (1-mu0)/sigma[i,i];
86+
beta.old <- beta;
87+
sigma.tilde <- sigma;
88+
diag(sigma.tilde) <- 0;
89+
vs <- -sigma.tilde%*%beta;
90+
91+
while ((iter <= maxiter) && (diff.norm2 >= threshold*last.norm2)){
92+
93+
for (j in 1:p){
94+
oldval <- beta[j];
95+
v <- vs[j];
96+
if (j==i)
97+
v <- v+1;
98+
beta[j] <- SoftThreshold(v,mu)/sigma[j,j];
99+
if (oldval != beta[j]){
100+
vs <- vs + (oldval-beta[j])*sigma.tilde[,j];
101+
}
102+
}
103+
104+
iter <- iter + 1;
105+
if (iter==2*iter.old){
106+
d <- beta - beta.old;
107+
diff.norm2 <- sqrt(sum(d*d));
108+
last.norm2 <-sqrt(sum(beta*beta));
109+
iter.old <- iter;
110+
beta.old <- beta;
111+
#if (iter>10)
112+
# vs <- -sigma.tilde%*%beta;
113+
}
114+
115+
# print(c(iter, maxiter, diff.norm2, threshold * last.norm2, threshold, mu))
116+
117+
}
118+
119+
returnlist <- list("optsol" = beta, "iter" = iter)
120+
return(returnlist)
121+
}
122+
123+
SoftThreshold <- function( x, lambda ) {
124+
#
125+
# Standard soft thresholding
126+
#
127+
if (x>lambda){
128+
return (x-lambda);}
129+
else {
130+
if (x< (-lambda)){
131+
return (x+lambda);}
132+
else {
133+
return (0); }
134+
}
135+
}
136+
137+
138+
### Test
139+
140+
n = 100; p = 50
5141

6142
X = matrix(rnorm(n * p), n, p)
7143
S = t(X) %*% X / n
@@ -25,3 +161,35 @@ plot(B1[1,], C1[1,])
25161
plot(A1[1,], A2[1,])
26162
plot(B1[1,], B2[1,])
27163
plot(C1[1,], C2[1,])
164+
165+
print(c('A', sum(A1[1,] == 0)))
166+
print(c('B', sum(B1[1,] == 0)))
167+
print(c('C', sum(C1[1,] == 0)))
168+
169+
## Are our points feasible
170+
171+
feasibility = function(S, soln, j, mu) {
172+
p = nrow(S)
173+
E = rep(0, p)
174+
E[j] = 1
175+
G = S %*% soln - E
176+
return(c(max(abs(G)), mu))
177+
}
178+
179+
print(c('feasibility A', feasibility(S, A1[1,], 1, mu)))
180+
print(c('feasibility B', feasibility(S, B1[1,], 1, mu)))
181+
print(c('feasibility C', feasibility(S, C1[1,], 1, mu)))
182+
183+
active_KKT = function(S, soln, j, mu) {
184+
p = nrow(S)
185+
E = rep(0, p)
186+
E[j] = 1
187+
G = S %*% soln - E
188+
return(c(G[soln != 0] * sign(soln)[soln != 0], mu))
189+
}
190+
191+
print(c('active_KKT A', active_KKT(S, A1[1,], 1, mu)))
192+
print(c('active_KKT B', active_KKT(S, B1[1,], 1, mu)))
193+
print(c('active_KKT C', active_KKT(S, C1[1,], 1, mu)))
194+
195+

0 commit comments

Comments
 (0)