""" See also: https://github.com/cvxopt/cvxopt/blob/master/src/C/glpk.c """ from typing import Tuple, Union, Literal, Optional, Dict, Any, Set, overload, TypedDict from cvxopt import glpk # type: ignore from . import Matrix, SparseMatrix CvxMatLike = Union[Matrix, SparseMatrix] CvxBool = Literal["GLP_ON", "GLP_OFF"] class GLPKOptions(TypedDict, total=False): # Common parameters msg_lev: Literal["GLP_MSG_OFF", "GLP_MSG_ERR", "GLP_MSG_ON", "GLP_MSG_ALL"] presolve: CvxBool tm_lim: int out_frq: int out_dly: int # LP-specific parameters meth: Literal["GLP_PRIMAL", "GLP_DUAL", "GLP_DUALP"] pricing: Literal["GLP_PT_STD", "GLP_PT_PSE"] r_test: Literal["GLP_RT_STD", "GLP_RT_HAR"] tol_bnd: float tol_dj: float tol_piv: float obj_ll: float obj_ul: float it_lim: int # MILP-specific parameters br_tech: Literal[ "GLP_BR_FFV", "GLP_BR_LFV", "GLP_BR_MFV", "GLP_BR_DTH", "GLP_BR_PCH" ] bt_tech: Literal["GLP_BT_DFS", "GLP_BT_BFS", "GLP_BT_BLB", "GLP_BT_BPH"] pp_tech: Literal["GLP_PP_NONE", "GLP_PP_ROOT", "GLP_PP_ALL"] fp_heur: CvxBool gmi_cuts: CvxBool mir_cuts: CvxBool cov_cuts: CvxBool clq_cuts: CvxBool tol_int: float tol_obj: float mip_gap: float cb_size: int binarize: CvxBool StatusLP = Literal["optimal", "primal infeasible", "dual infeasible", "unknown"] StatusILP = Literal[ "optimal", "feasible", "undefined", "invalid formulation", "infeasible problem", "LP relaxation is primal infeasible", "LP relaxation is dual infeasible", "unknown", ] @overload def lp( c: Matrix, G: CvxMatLike, h: Matrix, ) -> Tuple[StatusLP, Optional[Matrix], Optional[Matrix]]: """ (status, x, z) = lp(c, G, h) PURPOSE (status, x, z) = lp(c, G, h) solves the pair of primal and dual LPs minimize c'*x maximize -h'*z subject to G*x <= h subject to G'*z + c = 0 z >= 0. ARGUMENTS c nx1 dense 'd' matrix with n>=1 G mxn dense or sparse 'd' matrix with m>=1 h mx1 dense 'd' matrix status 'optimal', 'primal infeasible', 'dual infeasible' or 'unknown' x if status is 'optimal', a primal optimal solution; None otherwise z if status is 'optimal', the dual optimal solution; None otherwise """ @overload def lp( c: Matrix, G: CvxMatLike, h: Matrix, A: CvxMatLike, b: Matrix, ) -> Tuple[StatusLP, Optional[Matrix], Optional[Matrix], Optional[Matrix]]: """ (status, x, z, y) = lp(c, G, h, A, b) PURPOSE (status, x, z, y) = lp(c, G, h, A, b) solves the pair of primal and dual LPs minimize c'*x maximize -h'*z + b'*y subject to G*x <= h subject to G'*z + A'*y + c = 0 A*x = b z >= 0. ARGUMENTS c nx1 dense 'd' matrix with n>=1 G mxn dense or sparse 'd' matrix with m>=1 h mx1 dense 'd' matrix A pxn dense or sparse 'd' matrix with p>=0 b px1 dense 'd' matrix status 'optimal', 'primal infeasible', 'dual infeasible' or 'unknown' x if status is 'optimal', a primal optimal solution; None otherwise z,y if status is 'optimal', the dual optimal solution; None otherwise """ # https://cvxopt.org/userguide/coneprog.html#linear-programming def lp( c: Matrix, G: CvxMatLike, h: Matrix, A: Optional[CvxMatLike] = None, b: Optional[Matrix] = None, ): """ (status, x, z, y) = lp(c, G, h, A, b) (status, x, z) = lp(c, G, h) PURPOSE (status, x, z, y) = lp(c, G, h, A, b) solves the pair of primal and dual LPs minimize c'*x maximize -h'*z + b'*y subject to G*x <= h subject to G'*z + A'*y + c = 0 A*x = b z >= 0. (status, x, z) = lp(c, G, h) solves the pair of primal and dual LPs minimize c'*x maximize -h'*z subject to G*x <= h subject to G'*z + c = 0 z >= 0. ARGUMENTS c nx1 dense 'd' matrix with n>=1 G mxn dense or sparse 'd' matrix with m>=1 h mx1 dense 'd' matrix A pxn dense or sparse 'd' matrix with p>=0 b px1 dense 'd' matrix status 'optimal', 'primal infeasible', 'dual infeasible' or 'unknown' x if status is 'optimal', a primal optimal solution; None otherwise z,y if status is 'optimal', the dual optimal solution; None otherwise """ if A is None and b is None: return glpk.lp(c, G, h) return glpk.lp(c, G, h, A, b) def ilp( c: Matrix, G: CvxMatLike, h: Matrix, A: Optional[CvxMatLike] = None, b: Optional[Matrix] = None, I: Optional[Set[int]] = None, B: Optional[Set[int]] = None, ) -> Tuple[StatusILP, Optional[Matrix]]: """ Solves a mixed integer linear program using GLPK. (status, x) = ilp(c, G, h, A, b, I, B) PURPOSE Solves the mixed integer linear programming problem minimize c'*x subject to G*x <= h A*x = b x[k] is integer for k in I x[k] is binary for k in B ARGUMENTS c nx1 dense 'd' matrix with n>=1 G mxn dense or sparse 'd' matrix with m>=1 h mx1 dense 'd' matrix A pxn dense or sparse 'd' matrix with p>=0 b px1 dense 'd' matrix I set of indices of integer variables B set of indices of binary variables status if status is 'optimal', 'feasible', or 'undefined', a value of x is returned and the status string gives the status of x. Other possible values of status are: 'invalid formulation', 'infeasible problem', 'LP relaxation is primal infeasible', 'LP relaxation is dual infeasible', 'unknown'. x a (sub-)optimal solution if status is 'optimal', 'feasible', or 'undefined'. None otherwise """ return glpk.ilp(c, G, h, A, b, I, B) def set_global_options(options: GLPKOptions) -> None: glpk.options = options def get_global_options() -> GLPKOptions: return glpk.options