1313
1414class ASGL :
1515 def __init__ (self , model , penalization , intercept = True , tol = 1e-5 , lambda1 = 1 , alpha = 0.5 , tau = 0.5 ,
16- lasso_weights = None , gl_weights = None , parallel = False , num_cores = None , solver = None , max_iters = 500 ):
16+ lasso_weights = None , gl_weights = None , parallel = False , num_cores = None , solver = 'default' , max_iters = 500 ):
1717 """
1818 Parameters:
1919 model: model to be fit (accepts 'lm' or 'qr')
@@ -28,7 +28,7 @@ def __init__(self, model, penalization, intercept=True, tol=1e-5, lambda1=1, alp
2828 gl_weights: group lasso weights in adaptive penalizations
2929 parallel: boolean, whether to execute the code in parallel or sequentially
3030 num_cores: if parallel is set to true, the number of cores to use in the execution. Default is (max - 1)
31- solver: solver to be used by CVXPY. Default uses optimal alternative depending on the problem
31+ solver: solver to be used by CVXPY. default uses optimal alternative depending on the problem
3232 max_iters: CVXPY parameter. Default is 500
3333
3434 Returns:
@@ -51,13 +51,9 @@ def __init__(self, model, penalization, intercept=True, tol=1e-5, lambda1=1, alp
5151 self .num_cores = num_cores
5252 self .max_iters = max_iters
5353 self .coef_ = None
54- # Define solver param as a list of the three default solvers for CVXPY
55- if solver is None :
56- self .solver = ['ECOS' , 'OSQP' , 'SCS' ]
57- elif not isinstance (solver , list ):
58- self .solver = [solver ]
59- else :
60- self .solver = solver
54+ # CVXPY solver parameters
55+ self .solver_stats = None
56+ self .solver = solver
6157
6258 # Model checker related functions #################################################################################
6359
@@ -259,19 +255,28 @@ def unpenalized_solver(self, x, y):
259255 objective_function = (1.0 / n ) * cvxpy .sum (self ._quantile_function (x = (y - x @ beta_var )))
260256 objective = cvxpy .Minimize (objective_function )
261257 problem = cvxpy .Problem (objective )
262- # Solve the problem. Try first default CVXPY option, which is usually optimal for the problem. If a ValueError
263- # arises, try the solvers provided as input to the method.
258+ # Solve the problem. If solver is left as default, try optimal solver sugested by cvxpy.
259+ # If other name is provided, try the name provided
260+ # If these options fail, try default ECOS, OSQP, SCS options
264261 try :
265- problem .solve (warm_start = True )
262+ if self .solver == 'default' :
263+ problem .solve (warm_start = True )
264+ else :
265+ solver_dict = self ._cvxpy_solver_options (solver = self .solver )
266+ problem .solve (** solver_dict )
266267 except (ValueError , cvxpy .error .SolverError ):
267- for elt in self .solver :
268+ logging .warning ('Default solver failed. Using alternative options. Check solver and solver_stats for more '
269+ 'details' )
270+ solver = ['ECOS' , 'OSQP' , 'SCS' ]
271+ for elt in solver :
268272 solver_dict = self ._cvxpy_solver_options (solver = elt )
269273 try :
270274 problem .solve (** solver_dict )
271275 if 'optimal' in problem .status :
272276 break
273277 except (ValueError , cvxpy .error .SolverError ):
274278 continue
279+ self .solver_stats = problem .solver_stats
275280 if problem .status in ["infeasible" , "unbounded" ]:
276281 logging .warning ('Optimization problem status failure' )
277282 beta_sol = beta_var .value
@@ -305,19 +310,29 @@ def lasso(self, x, y, param):
305310 # Solve the problem iteratively for each parameter value
306311 for lam in param :
307312 lambda_param .value = lam
308- # Solve the problem. Try first default CVXPY option, which is usually optimal for the problem. If a
309- # ValueError arises, try the solvers provided as input to the method.
313+ # Solve the problem. If solver is left as default, try optimal solver sugested by cvxpy.
314+ # If other name is provided, try the name provided
315+ # If these options fail, try default ECOS, OSQP, SCS options
310316 try :
311- problem .solve (warm_start = True )
317+ if self .solver == 'default' :
318+ problem .solve (warm_start = True )
319+ else :
320+ solver_dict = self ._cvxpy_solver_options (solver = self .solver )
321+ problem .solve (** solver_dict )
312322 except (ValueError , cvxpy .error .SolverError ):
313- for elt in self .solver :
323+ logging .warning (
324+ 'Default solver failed. Using alternative options. Check solver and solver_stats for more '
325+ 'details' )
326+ solver = ['ECOS' , 'OSQP' , 'SCS' ]
327+ for elt in solver :
314328 solver_dict = self ._cvxpy_solver_options (solver = elt )
315329 try :
316330 problem .solve (** solver_dict )
317331 if 'optimal' in problem .status :
318332 break
319333 except (ValueError , cvxpy .error .SolverError ):
320334 continue
335+ self .solver_stats = problem .solver_stats
321336 if problem .status in ["infeasible" , "unbounded" ]:
322337 logging .warning ('Optimization problem status failure' )
323338 beta_sol = beta_var .value
@@ -332,6 +347,7 @@ def gl(self, x, y, group_index, param):
332347 """
333348 n = x .shape [0 ]
334349 # Check th group_index, find the unique groups, count how many vars are in each group (this is the group size)
350+ group_index = np .asarray (group_index ).astype (int )
335351 unique_group_index = np .unique (group_index )
336352 group_sizes , beta_var = self ._num_beta_var_from_group_index (group_index )
337353 num_groups = len (group_sizes )
@@ -365,19 +381,29 @@ def gl(self, x, y, group_index, param):
365381 # Solve the problem iteratively for each parameter value
366382 for lam in param :
367383 lambda_param .value = lam
368- # Solve the problem. Try first default CVXPY option, which is usually optimal for the problem. If a
369- # ValueError arises, try the solvers provided as input to the method.
384+ # Solve the problem. If solver is left as default, try optimal solver sugested by cvxpy.
385+ # If other name is provided, try the name provided
386+ # If these options fail, try default ECOS, OSQP, SCS options
370387 try :
371- problem .solve (warm_start = True )
388+ if self .solver == 'default' :
389+ problem .solve (warm_start = True )
390+ else :
391+ solver_dict = self ._cvxpy_solver_options (solver = self .solver )
392+ problem .solve (** solver_dict )
372393 except (ValueError , cvxpy .error .SolverError ):
373- for elt in self .solver :
394+ logging .warning (
395+ 'Default solver failed. Using alternative options. Check solver and solver_stats for more '
396+ 'details' )
397+ solver = ['ECOS' , 'OSQP' , 'SCS' ]
398+ for elt in solver :
374399 solver_dict = self ._cvxpy_solver_options (solver = elt )
375400 try :
376401 problem .solve (** solver_dict )
377402 if 'optimal' in problem .status :
378403 break
379404 except (ValueError , cvxpy .error .SolverError ):
380405 continue
406+ self .solver_stats = problem .solver_stats
381407 if problem .status in ["infeasible" , "unbounded" ]:
382408 logging .warning ('Optimization problem status failure' )
383409 beta_sol = np .concatenate ([b .value for b in beta_var ], axis = 0 )
@@ -391,6 +417,7 @@ def sgl(self, x, y, group_index, param):
391417 """
392418 n = x .shape [0 ]
393419 # Check th group_index, find the unique groups, count how many vars are in each group (this is the group size)
420+ group_index = np .asarray (group_index ).astype (int )
394421 unique_group_index = np .unique (group_index )
395422 group_sizes , beta_var = self ._num_beta_var_from_group_index (group_index )
396423 num_groups = len (group_sizes )
@@ -428,19 +455,29 @@ def sgl(self, x, y, group_index, param):
428455 for lam , al in param :
429456 lasso_param .value = lam * al
430457 grp_lasso_param .value = lam * (1 - al )
431- # Solve the problem. Try first default CVXPY option, which is usually optimal for the problem. If a
432- # ValueError arises, try the solvers provided as input to the method.
458+ # Solve the problem. If solver is left as default, try optimal solver sugested by cvxpy.
459+ # If other name is provided, try the name provided
460+ # If these options fail, try default ECOS, OSQP, SCS options
433461 try :
434- problem .solve (warm_start = True )
462+ if self .solver == 'default' :
463+ problem .solve (warm_start = True )
464+ else :
465+ solver_dict = self ._cvxpy_solver_options (solver = self .solver )
466+ problem .solve (** solver_dict )
435467 except (ValueError , cvxpy .error .SolverError ):
436- for elt in self .solver :
468+ logging .warning (
469+ 'Default solver failed. Using alternative options. Check solver and solver_stats for more '
470+ 'details' )
471+ solver = ['ECOS' , 'OSQP' , 'SCS' ]
472+ for elt in solver :
437473 solver_dict = self ._cvxpy_solver_options (solver = elt )
438474 try :
439475 problem .solve (** solver_dict )
440476 if 'optimal' in problem .status :
441477 break
442478 except (ValueError , cvxpy .error .SolverError ):
443479 continue
480+ self .solver_stats = problem .solver_stats
444481 if problem .status in ["infeasible" , "unbounded" ]:
445482 logging .warning ('Optimization problem status failure' )
446483 beta_sol = np .concatenate ([b .value for b in beta_var ], axis = 0 )
@@ -475,19 +512,29 @@ def alasso(self, x, y, param):
475512 # Solve the problem iteratively for each parameter value
476513 for lam , lw in param :
477514 l_weights_param .value = lam * lw
478- # Solve the problem. Try first default CVXPY option, which is usually optimal for the problem. If a
479- # ValueError arises, try the solvers provided as input to the method.
515+ # Solve the problem. If solver is left as default, try optimal solver sugested by cvxpy.
516+ # If other name is provided, try the name provided
517+ # If these options fail, try default ECOS, OSQP, SCS options
480518 try :
481- problem .solve (warm_start = True )
519+ if self .solver == 'default' :
520+ problem .solve (warm_start = True )
521+ else :
522+ solver_dict = self ._cvxpy_solver_options (solver = self .solver )
523+ problem .solve (** solver_dict )
482524 except (ValueError , cvxpy .error .SolverError ):
483- for elt in self .solver :
525+ logging .warning (
526+ 'Default solver failed. Using alternative options. Check solver and solver_stats for more '
527+ 'details' )
528+ solver = ['ECOS' , 'OSQP' , 'SCS' ]
529+ for elt in solver :
484530 solver_dict = self ._cvxpy_solver_options (solver = elt )
485531 try :
486532 problem .solve (** solver_dict )
487533 if 'optimal' in problem .status :
488534 break
489535 except (ValueError , cvxpy .error .SolverError ):
490536 continue
537+ self .solver_stats = problem .solver_stats
491538 if problem .status in ["infeasible" , "unbounded" ]:
492539 logging .warning ('Optimization problem status failure' )
493540 beta_sol = beta_var .value
@@ -502,6 +549,7 @@ def agl(self, x, y, group_index, param):
502549 """
503550 n = x .shape [0 ]
504551 # Check th group_index, find the unique groups, count how many vars are in each group (this is the group size)
552+ group_index = np .asarray (group_index ).astype (int )
505553 unique_group_index = np .unique (group_index )
506554 group_sizes , beta_var = self ._num_beta_var_from_group_index (group_index )
507555 num_groups = len (group_sizes )
@@ -535,19 +583,29 @@ def agl(self, x, y, group_index, param):
535583 # Solve the problem iteratively for each parameter value
536584 for lam , gl in param :
537585 gl_weights_param .value = lam * gl
538- # Solve the problem. Try first default CVXPY option, which is usually optimal for the problem. If a
539- # ValueError arises, try the solvers provided as input to the method.
586+ # Solve the problem. If solver is left as default, try optimal solver sugested by cvxpy.
587+ # If other name is provided, try the name provided
588+ # If these options fail, try default ECOS, OSQP, SCS options
540589 try :
541- problem .solve (warm_start = True )
590+ if self .solver == 'default' :
591+ problem .solve (warm_start = True )
592+ else :
593+ solver_dict = self ._cvxpy_solver_options (solver = self .solver )
594+ problem .solve (** solver_dict )
542595 except (ValueError , cvxpy .error .SolverError ):
543- for elt in self .solver :
596+ logging .warning (
597+ 'Default solver failed. Using alternative options. Check solver and solver_stats for more '
598+ 'details' )
599+ solver = ['ECOS' , 'OSQP' , 'SCS' ]
600+ for elt in solver :
544601 solver_dict = self ._cvxpy_solver_options (solver = elt )
545602 try :
546603 problem .solve (** solver_dict )
547604 if 'optimal' in problem .status :
548605 break
549606 except (ValueError , cvxpy .error .SolverError ):
550607 continue
608+ self .solver_stats = problem .solver_stats
551609 if problem .status in ["infeasible" , "unbounded" ]:
552610 logging .warning ('Optimization problem status failure' )
553611 beta_sol = np .concatenate ([b .value for b in beta_var ], axis = 0 )
@@ -561,6 +619,7 @@ def asgl(self, x, y, group_index, param):
561619 """
562620 n , m = x .shape
563621 # Check th group_index, find the unique groups, count how many vars are in each group (this is the group size)
622+ group_index = np .asarray (group_index ).astype (int )
564623 unique_group_index = np .unique (group_index )
565624 group_sizes , beta_var = self ._num_beta_var_from_group_index (group_index )
566625 num_groups = len (group_sizes )
@@ -600,19 +659,29 @@ def asgl(self, x, y, group_index, param):
600659 for lam , al , lw , glw in param :
601660 l_weights_param .value = lw * lam * al
602661 gl_weights_param .value = glw * lam * (1 - al )
603- # Solve the problem. Try first default CVXPY option, which is usually optimal for the problem. If a
604- # ValueError arises, try the solvers provided as input to the method.
662+ # Solve the problem. If solver is left as default, try optimal solver sugested by cvxpy.
663+ # If other name is provided, try the name provided
664+ # If these options fail, try default ECOS, OSQP, SCS options
605665 try :
606- problem .solve (warm_start = True )
666+ if self .solver == 'default' :
667+ problem .solve (warm_start = True )
668+ else :
669+ solver_dict = self ._cvxpy_solver_options (solver = self .solver )
670+ problem .solve (** solver_dict )
607671 except (ValueError , cvxpy .error .SolverError ):
608- for elt in self .solver :
672+ logging .warning (
673+ 'Default solver failed. Using alternative options. Check solver and solver_stats for more '
674+ 'details' )
675+ solver = ['ECOS' , 'OSQP' , 'SCS' ]
676+ for elt in solver :
609677 solver_dict = self ._cvxpy_solver_options (solver = elt )
610678 try :
611679 problem .solve (** solver_dict )
612680 if 'optimal' in problem .status :
613681 break
614682 except (ValueError , cvxpy .error .SolverError ):
615683 continue
684+ self .solver_stats = problem .solver_stats
616685 if problem .status in ["infeasible" , "unbounded" ]:
617686 logging .warning ('Optimization problem status failure' )
618687 beta_sol = np .concatenate ([b .value for b in beta_var ], axis = 0 )
@@ -676,7 +745,6 @@ def fit(self, x, y, group_index=None):
676745 this function solves the model and produces the regression coefficients
677746 """
678747 param = self ._preprocessing ()
679- group_index = np .asarray (group_index ).astype (int )
680748 if self .penalization is None :
681749 self .coef_ = self .unpenalized_solver (x = x , y = y )
682750 else :
0 commit comments