1717from collections import namedtuple
1818from collections .abc import Callable , Generator
1919from pathlib import Path
20- from typing import TYPE_CHECKING , Any
20+ from typing import TYPE_CHECKING , Any , Generic , TypeVar
2121
2222import numpy as np
2323import pandas as pd
3232)
3333
3434if TYPE_CHECKING :
35+ import gurobipy
36+
3537 from linopy .model import Model
3638
39+ EnvType = TypeVar ("EnvType" )
40+
3741QUADRATIC_SOLVERS = [
3842 "gurobi" ,
3943 "xpress" ,
@@ -195,7 +199,7 @@ def maybe_adjust_objective_sign(
195199 return solution
196200
197201
198- class Solver (ABC ):
202+ class Solver (ABC , Generic [ EnvType ] ):
199203 """
200204 Abstract base class for solving a given linear problem.
201205
@@ -242,7 +246,7 @@ def solve_problem_from_model(
242246 log_fn : Path | None = None ,
243247 warmstart_fn : Path | None = None ,
244248 basis_fn : Path | None = None ,
245- env : None = None ,
249+ env : EnvType | None = None ,
246250 explicit_coordinate_names : bool = False ,
247251 ) -> Result :
248252 """
@@ -262,7 +266,7 @@ def solve_problem_from_file(
262266 log_fn : Path | None = None ,
263267 warmstart_fn : Path | None = None ,
264268 basis_fn : Path | None = None ,
265- env : None = None ,
269+ env : EnvType | None = None ,
266270 ) -> Result :
267271 """
268272 Abstract method to solve a linear problem from a problem file.
@@ -281,7 +285,7 @@ def solve_problem(
281285 log_fn : Path | None = None ,
282286 warmstart_fn : Path | None = None ,
283287 basis_fn : Path | None = None ,
284- env : None = None ,
288+ env : EnvType | None = None ,
285289 explicit_coordinate_names : bool = False ,
286290 ) -> Result :
287291 """
@@ -322,7 +326,7 @@ def solver_name(self) -> SolverName:
322326 return SolverName [self .__class__ .__name__ ]
323327
324328
325- class CBC (Solver ):
329+ class CBC (Solver [ None ] ):
326330 """
327331 Solver subclass for the CBC solver.
328332
@@ -503,7 +507,7 @@ def get_solver_solution() -> Solution:
503507 return Result (status , solution , CbcModel (mip_gap , runtime ))
504508
505509
506- class GLPK (Solver ):
510+ class GLPK (Solver [ None ] ):
507511 """
508512 Solver subclass for the GLPK solver.
509513
@@ -673,7 +677,7 @@ def get_solver_solution() -> Solution:
673677 return Result (status , solution )
674678
675679
676- class Highs (Solver ):
680+ class Highs (Solver [ None ] ):
677681 """
678682 Solver subclass for the Highs solver. Highs must be installed
679683 for usage. Find the documentation at https://www.maths.ed.ac.uk/hall/HiGHS/.
@@ -919,7 +923,7 @@ def get_solver_solution() -> Solution:
919923 return Result (status , solution , h )
920924
921925
922- class Gurobi (Solver ):
926+ class Gurobi (Solver [ gurobipy . Env | dict [ str , Any ] | None ] ):
923927 """
924928 Solver subclass for the gurobi solver.
925929
@@ -942,7 +946,7 @@ def solve_problem_from_model(
942946 log_fn : Path | None = None ,
943947 warmstart_fn : Path | None = None ,
944948 basis_fn : Path | None = None ,
945- env : None = None ,
949+ env : gurobipy . Env | dict [ str , Any ] | None = None ,
946950 explicit_coordinate_names : bool = False ,
947951 ) -> Result :
948952 """
@@ -962,8 +966,8 @@ def solve_problem_from_model(
962966 Path to the warmstart file.
963967 basis_fn : Path, optional
964968 Path to the basis file.
965- env : None , optional
966- Gurobi environment for the solver
969+ env : gurobipy.Env or dict , optional
970+ Gurobi environment for the solver, pass env directly or kwargs for creation.
967971 explicit_coordinate_names : bool, optional
968972 Transfer variable and constraint names to the solver (default: False)
969973
@@ -974,6 +978,8 @@ def solve_problem_from_model(
974978 with contextlib .ExitStack () as stack :
975979 if env is None :
976980 env_ = stack .enter_context (gurobipy .Env ())
981+ elif isinstance (env , dict ):
982+ env_ = stack .enter_context (gurobipy .Env (params = env ))
977983 else :
978984 env_ = env
979985
@@ -998,7 +1004,7 @@ def solve_problem_from_file(
9981004 log_fn : Path | None = None ,
9991005 warmstart_fn : Path | None = None ,
10001006 basis_fn : Path | None = None ,
1001- env : None = None ,
1007+ env : gurobipy . Env | dict [ str , Any ] | None = None ,
10021008 ) -> Result :
10031009 """
10041010 Solve a linear problem from a problem file using the Gurobi solver.
@@ -1017,8 +1023,8 @@ def solve_problem_from_file(
10171023 Path to the warmstart file.
10181024 basis_fn : Path, optional
10191025 Path to the basis file.
1020- env : None , optional
1021- Gurobi environment for the solver
1026+ env : gurobipy.Env or dict , optional
1027+ Gurobi environment for the solver, pass env directly or kwargs for creation.
10221028
10231029 Returns
10241030 -------
@@ -1031,6 +1037,8 @@ def solve_problem_from_file(
10311037 with contextlib .ExitStack () as stack :
10321038 if env is None :
10331039 env_ = stack .enter_context (gurobipy .Env ())
1040+ elif isinstance (env , dict ):
1041+ env_ = stack .enter_context (gurobipy .Env (params = env ))
10341042 else :
10351043 env_ = env
10361044
@@ -1150,7 +1158,7 @@ def get_solver_solution() -> Solution:
11501158 return Result (status , solution , m )
11511159
11521160
1153- class Cplex (Solver ):
1161+ class Cplex (Solver [ None ] ):
11541162 """
11551163 Solver subclass for the Cplex solver.
11561164
@@ -1306,7 +1314,7 @@ def get_solver_solution() -> Solution:
13061314 return Result (status , solution , m )
13071315
13081316
1309- class SCIP (Solver ):
1317+ class SCIP (Solver [ None ] ):
13101318 """
13111319 Solver subclass for the SCIP solver.
13121320
@@ -1459,7 +1467,7 @@ def get_solver_solution() -> Solution:
14591467 return Result (status , solution , m )
14601468
14611469
1462- class Xpress (Solver ):
1470+ class Xpress (Solver [ None ] ):
14631471 """
14641472 Solver subclass for the xpress solver.
14651473
@@ -1596,7 +1604,7 @@ def get_solver_solution() -> Solution:
15961604mosek_bas_re = re .compile (r" (XL|XU)\s+([^ \t]+)\s+([^ \t]+)| (LL|UL|BS)\s+([^ \t]+)" )
15971605
15981606
1599- class Mosek (Solver ):
1607+ class Mosek (Solver [ None ] ):
16001608 """
16011609 Solver subclass for the Mosek solver.
16021610
@@ -1926,7 +1934,7 @@ def get_solver_solution() -> Solution:
19261934 return Result (status , solution )
19271935
19281936
1929- class COPT (Solver ):
1937+ class COPT (Solver [ None ] ):
19301938 """
19311939 Solver subclass for the COPT solver.
19321940
@@ -2067,7 +2075,7 @@ def get_solver_solution() -> Solution:
20672075 return Result (status , solution , m )
20682076
20692077
2070- class MindOpt (Solver ):
2078+ class MindOpt (Solver [ None ] ):
20712079 """
20722080 Solver subclass for the MindOpt solver.
20732081
@@ -2210,7 +2218,7 @@ def get_solver_solution() -> Solution:
22102218 return Result (status , solution , m )
22112219
22122220
2213- class PIPS (Solver ):
2221+ class PIPS (Solver [ None ] ):
22142222 """
22152223 Solver subclass for the PIPS solver.
22162224 """
0 commit comments