Skip to content

Commit bbf7e19

Browse files
Merge pull request #27 from jonathan-taylor/max_active
Exporting debiasingMatrix, limit on size of active set.
2 parents 6dc80be + 3e9d62d commit bbf7e19

File tree

7 files changed

+303
-110
lines changed

7 files changed

+303
-110
lines changed

selectiveInference/NAMESPACE

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,15 @@ export(lar,fs,
66
print.larInf,print.fsInf,
77
plot.lar,plot.fs,
88
fixedLassoInf,print.fixedLassoInf,
9-
# fixedLogitLassoInf,print.fixedLogitLassoInf,
10-
# fixedCoxLassoInf,print.fixedCoxLassoInf,
119
forwardStop,
1210
estimateSigma,
1311
manyMeans,print.manyMeans,
1412
groupfs,groupfsInf,
1513
scaleGroups,factorDesign,
1614
TG.pvalue,
1715
TG.limits,
18-
TG.interval
16+
TG.interval,
17+
debiasingMatrix
1918
)
2019

2120
S3method("coef", "lar")

selectiveInference/R/funs.fixed.R

Lines changed: 153 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,8 @@ fixedLassoInf <- function(x, y, beta, lambda, family=c("gaussian","binomial","co
158158

159159
# Approximate inverse covariance matrix for when (n < p) from lasso_Inference.R
160160

161-
htheta <- InverseLinfty(hsigma, n, length(S), verbose=FALSE, max.try=linesearch.try)
162-
# htheta <- InverseLinfty(hsigma, n, verbose=FALSE)
163-
161+
htheta = debiasingMatrix(hsigma, n, 1:length(S), verbose=FALSE, max_try=linesearch.try, warn_kkt=TRUE)
162+
164163
FS = rbind(diag(length(S)),matrix(0,pp-length(S),length(S)))
165164
GS = cbind(diag(length(S)),matrix(0,length(S),pp-length(S)))
166165
ithetasigma = (GS-(htheta%*%hsigma))
@@ -265,123 +264,181 @@ fixedLasso.poly=
265264

266265
##############################
267266

268-
### Functions borrowed and slightly modified from lasso_inference.R
269-
270267
## Approximates inverse covariance matrix theta
271-
InverseLinfty <- function(sigma, n, e, resol=1.2, mu=NULL, maxiter=50, threshold=1e-2, verbose = TRUE, max.try=10) {
272-
isgiven <- 1;
273-
if (is.null(mu)){
274-
isgiven <- 0;
268+
## using coordinate descent
269+
270+
debiasingMatrix = function(Sigma,
271+
nsample,
272+
rows,
273+
verbose=FALSE,
274+
mu=NULL, # starting value of mu
275+
linesearch=TRUE, # do a linesearch?
276+
scaling_factor=1.5, # multiplicative factor for linesearch
277+
max_active=NULL, # how big can active set get?
278+
max_try=10, # how many steps in linesearch?
279+
warn_kkt=FALSE, # warn if KKT does not seem to be satisfied?
280+
max_iter=100, # how many iterations for each optimization problem
281+
kkt_tol=1.e-4, # tolerance for the KKT conditions
282+
objective_tol=1.e-8 # tolerance for relative decrease in objective
283+
) {
284+
285+
286+
if (is.null(max_active)) {
287+
max_active = max(50, 0.3 * nsample)
288+
}
289+
290+
p = nrow(Sigma);
291+
M = matrix(0, length(rows), p);
292+
293+
if (is.null(mu)) {
294+
mu = (1/sqrt(nsample)) * qnorm(1-(0.1/(p^2)))
275295
}
276-
277-
p <- nrow(sigma);
278-
M <- matrix(0, e, p);
296+
279297
xperc = 0;
280298
xp = round(p/10);
281-
for (i in 1:e) {
282-
if ((i %% xp)==0){
299+
idx = 1;
300+
for (row in rows) {
301+
302+
if ((idx %% xp)==0){
283303
xperc = xperc+10;
284304
if (verbose) {
285305
print(paste(xperc,"% done",sep="")); }
286306
}
287-
if (isgiven==0){
288-
mu <- (1/sqrt(n)) * qnorm(1-(0.1/(p^2)));
289-
}
290-
mu.stop <- 0;
291-
try.no <- 1;
292-
incr <- 0;
293-
294-
output = NULL
295-
296-
while ((mu.stop != 1) && (try.no<max.try) ){
297-
last.beta <- beta
298-
output <- InverseLinftyOneRow(sigma, i, mu, maxiter=maxiter, soln_result=output) # uses a warm start
299-
beta <- output$soln
300-
iter <- output$iter
301-
if (isgiven==1) {
302-
mu.stop <- 1
303-
}
304-
else{
305-
if (try.no==1){
306-
if (iter == (maxiter+1)){
307-
incr <- 1;
308-
mu <- mu*resol;
309-
} else {
310-
incr <- 0;
311-
mu <- mu/resol;
312-
}
313-
}
314-
if (try.no > 1){
315-
if ((incr == 1)&&(iter == (maxiter+1))){
316-
mu <- mu*resol;
317-
}
318-
if ((incr == 1)&&(iter < (maxiter+1))){
319-
mu.stop <- 1;
320-
}
321-
if ((incr == 0)&&(iter < (maxiter+1))){
322-
mu <- mu/resol;
323-
}
324-
if ((incr == 0)&&(iter == (maxiter+1))){
325-
mu <- mu*resol;
326-
beta <- last.beta;
327-
mu.stop <- 1;
328-
}
329-
}
330-
}
331-
try.no <- try.no+1
307+
308+
output = debiasingRow(Sigma,
309+
row,
310+
mu,
311+
linesearch=linesearch,
312+
scaling_factor=scaling_factor,
313+
max_active=max_active,
314+
max_try=max_try,
315+
warn_kkt=FALSE,
316+
max_iter=max_iter,
317+
kkt_tol=kkt_tol,
318+
objective_tol=objective_tol)
319+
320+
if (warn_kkt && (!output$kkt_check)) {
321+
warning("Solution for row of M does not seem to be feasible")
322+
}
323+
324+
if (!is.null(output$soln)) {
325+
M[idx,] = output$soln;
326+
} else {
327+
stop(paste("Unable to approximate inverse row ", row));
332328
}
333-
M[i,] <- beta;
329+
330+
idx = idx + 1;
334331
}
335332
return(M)
336333
}
337334

338-
InverseLinftyOneRow <- function (Sigma, i, mu, maxiter=50, soln_result=NULL, kkt_tol=1.e-6, objective_tol=1.e-6,
339-
use_QP=TRUE) {
340-
341-
# If soln_result is not Null, it is used as a warm start.
342-
# It should be a list
343-
# with entries "soln", "gradient", "ever_active", "nactive"
335+
# Find one row of the debiasing matrix
336+
337+
debiasingRow = function (Sigma,
338+
row,
339+
mu,
340+
linesearch=TRUE, # do a linesearch?
341+
scaling_factor=1.2, # multiplicative factor for linesearch
342+
max_active=NULL, # how big can active set get?
343+
max_try=10, # how many steps in linesearch?
344+
warn_kkt=FALSE, # warn if KKT does not seem to be satisfied?
345+
max_iter=100, # how many iterations for each optimization problem
346+
kkt_tol=1.e-4, # tolerance for the KKT conditions
347+
objective_tol=1.e-8 # tolerance for relative decrease in objective
348+
) {
344349

345350
p = nrow(Sigma)
346351

347-
if (is.null(soln_result)) {
348-
soln = rep(0, p)
349-
ever_active = rep(0, p)
350-
ever_active[1] = i # 1-based
351-
ever_active = as.integer(ever_active)
352-
nactive = as.integer(1)
353-
if (use_QP) {
354-
linear_func = rep(0, p)
355-
linear_func[i] = -1
356-
linear_func = as.numeric(linear_func)
357-
gradient = 1. * linear_func
358-
} else {
359-
gradient = rep(0, p)
360-
}
361-
}
362-
else {
363-
soln = soln_result$soln
364-
gradient = soln_result$gradient
365-
ever_active = as.integer(soln_result$ever_active)
366-
nactive = as.integer(soln_result$nactive)
367-
if (use_QP) {
368-
linear_func = soln_result$linear_func
369-
}
352+
if (is.null(max_active)) {
353+
max_active = nrow(Sigma)
370354
}
371355

372-
if (use_QP) {
373-
result = solve_QP(Sigma, mu, maxiter, soln, linear_func, gradient, ever_active, nactive, kkt_tol, objective_tol)
374-
} else {
375-
result = find_one_row_debiasingM(Sigma, i, mu, maxiter, soln, gradient, ever_active, nactive, kkt_tol, objective_tol) # C function uses 1-based indexing for active set
376-
}
356+
# Initialize variables
357+
358+
soln = rep(0, p)
359+
360+
ever_active = rep(0, p)
361+
ever_active[1] = row # 1-based
362+
ever_active = as.integer(ever_active)
363+
nactive = as.integer(1)
364+
365+
linear_func = rep(0, p)
366+
linear_func[row] = -1
367+
linear_func = as.numeric(linear_func)
368+
gradient = 1. * linear_func
369+
370+
counter_idx = 1;
371+
incr = 0;
372+
373+
last_output = NULL
374+
375+
while (counter_idx < max_try) {
376+
377+
result = solve_QP(Sigma,
378+
mu,
379+
max_iter,
380+
soln,
381+
linear_func,
382+
gradient,
383+
ever_active,
384+
nactive,
385+
kkt_tol,
386+
objective_tol,
387+
max_active)
388+
389+
iter = result$iter
390+
391+
# Logic for whether we should continue the line search
392+
393+
if (!linesearch) {
394+
break
395+
}
396+
397+
if (counter_idx == 1){
398+
if (iter == (max_iter+1)){
399+
incr = 1; # was the original problem feasible? 1 if not
400+
} else {
401+
incr = 0; # original problem was feasible
402+
}
403+
}
404+
405+
if (incr == 1) { # trying to find a feasible point
406+
if ((iter < (max_iter+1)) && (counter_idx > 1)) {
407+
break; # we've found a feasible point and solved the problem
408+
}
409+
mu = mu * scaling_factor;
410+
} else { # trying to drop the bound parameter further
411+
if ((iter == (max_iter + 1)) && (counter_idx > 1)) {
412+
result = last_output; # problem seems infeasible because we didn't solve it
413+
break; # so we revert to previously found solution
414+
}
415+
mu = mu / scaling_factor;
416+
}
417+
418+
# If the active set has grown to a certain size
419+
# then we stop, presuming problem has become
420+
# infeasible.
421+
422+
# We revert to the previous solution
423+
424+
if (result$max_active_check) {
425+
result = last_output;
426+
break;
427+
}
428+
429+
counter_idx = counter_idx + 1
430+
last_output = list(soln=result$soln,
431+
kkt_check=result$kkt_check)
432+
}
377433

378434
# Check feasibility
379435

380-
if (!result$kkt_check) {
436+
if (warn_kkt && (!result$kkt_check)) {
381437
warning("Solution for row of M does not seem to be feasible")
382438
}
383439

384-
return(result)
440+
return(list(soln=result$soln,
441+
kkt_check=result$kkt_check))
385442

386443
}
387444

0 commit comments

Comments
 (0)