Path: blob/master/src/sage/numerical/backends/glpk_backend.pyx
8817 views
"""1GLPK Backend23AUTHORS:45- Nathann Cohen (2010-10): initial implementation6- John Perry (2012-01): glp_simplex preprocessing7- John Perry and Raniere Gaia Silva (2012-03): solver parameters8- Christian Kuper (2012-10): Additions for sensitivity analysis9"""1011##############################################################################12# Copyright (C) 2010 Nathann Cohen <[email protected]>13# Distributed under the terms of the GNU General Public License (GPL)14# The full text of the GPL is available at:15# http://www.gnu.org/licenses/16##############################################################################1718from sage.numerical.mip import MIPSolverException1920include "sage/ext/interrupt.pxi"2122cdef class GLPKBackend(GenericBackend):2324def __cinit__(self, maximization = True):25"""26Constructor2728EXAMPLE::2930sage: p = MixedIntegerLinearProgram(solver="GLPK")31"""32self.lp = glp_create_prob()33self.simplex_or_intopt = glp_intopt_only34self.smcp = <c_glp_smcp* > sage_malloc(sizeof(c_glp_smcp))35glp_init_smcp(self.smcp)36self.iocp = <c_glp_iocp* > sage_malloc(sizeof(c_glp_iocp))37glp_init_iocp(self.iocp)38self.iocp.presolve = GLP_ON39self.set_verbosity(0)40self.obj_constant_term = 0.04142if maximization:43self.set_sense(+1)44else:45self.set_sense(-1)4647cpdef int add_variable(self, lower_bound=0.0, upper_bound=None, binary=False, continuous=False, integer=False, obj=0.0, name=None) except -1:48"""49Add a variable.5051This amounts to adding a new column to the matrix. By default,52the variable is both positive, real and the coefficient in the53objective function is 0.0.5455INPUT:5657- ``lower_bound`` - the lower bound of the variable (default: 0)5859- ``upper_bound`` - the upper bound of the variable (default: ``None``)6061- ``binary`` - ``True`` if the variable is binary (default: ``False``).6263- ``continuous`` - ``True`` if the variable is binary (default: ``True``).6465- ``integer`` - ``True`` if the variable is binary (default: ``False``).6667- ``obj`` - (optional) coefficient of this variable in the objective function (default: 0.0)6869- ``name`` - an optional name for the newly added variable (default: ``None``).7071OUTPUT: The index of the newly created variable7273EXAMPLE::7475sage: from sage.numerical.backends.generic_backend import get_solver76sage: p = get_solver(solver = "GLPK")77sage: p.ncols()78079sage: p.add_variable()80081sage: p.ncols()82183sage: p.add_variable(binary=True)84185sage: p.add_variable(lower_bound=-2.0, integer=True)86287sage: p.add_variable(continuous=True, integer=True)88Traceback (most recent call last):89...90ValueError: ...91sage: p.add_variable(name='x',obj=1.0)92393sage: p.col_name(3)94'x'95sage: p.objective_coefficient(3)961.097"""98cdef int vtype = int(bool(binary)) + int(bool(continuous)) + int(bool(integer))99if vtype == 0:100continuous = True101elif vtype != 1:102raise ValueError("Exactly one parameter of 'binary', 'integer' and 'continuous' must be 'True'.")103104glp_add_cols(self.lp, 1)105cdef int n_var = glp_get_num_cols(self.lp)106107self.variable_lower_bound(n_var - 1, lower_bound)108self.variable_upper_bound(n_var - 1, upper_bound)109110if continuous:111glp_set_col_kind(self.lp, n_var, GLP_CV)112elif binary:113glp_set_col_kind(self.lp, n_var, GLP_BV)114elif integer:115glp_set_col_kind(self.lp, n_var, GLP_IV)116117if name is not None:118glp_set_col_name(self.lp, n_var, name)119120if obj:121self.objective_coefficient(n_var - 1, obj)122123return n_var - 1124125cpdef int add_variables(self, int number, lower_bound=0.0, upper_bound=None, binary=False, continuous=False, integer=False, obj=0.0, names=None) except -1:126"""127Add ``number`` new variables.128129This amounts to adding new columns to the matrix. By default,130the variables are both positive, real and theor coefficient in131the objective function is 0.0.132133INPUT:134135- ``n`` - the number of new variables (must be > 0)136137- ``lower_bound`` - the lower bound of the variable (default: 0)138139- ``upper_bound`` - the upper bound of the variable (default: ``None``)140141- ``binary`` - ``True`` if the variable is binary (default: ``False``).142143- ``continuous`` - ``True`` if the variable is binary (default: ``True``).144145- ``integer`` - ``True`` if the variable is binary (default: ``False``).146147- ``obj`` - (optional) coefficient of all variables in the objective function (default: 0.0)148149- ``names`` - optional list of names (default: ``None``)150151OUTPUT: The index of the variable created last.152153EXAMPLE::154155sage: from sage.numerical.backends.generic_backend import get_solver156sage: p = get_solver(solver = "GLPK")157sage: p.ncols()1580159sage: p.add_variables(5)1604161sage: p.ncols()1625163sage: p.add_variables(2, lower_bound=-2.0, integer=True, names=['a','b'])1646165"""166cdef int vtype = int(bool(binary)) + int(bool(continuous)) + int(bool(integer))167if vtype == 0:168continuous = True169elif vtype != 1:170raise ValueError("Exactly one parameter of 'binary', 'integer' and 'continuous' must be 'True'.")171172glp_add_cols(self.lp, number)173174cdef int n_var175n_var = glp_get_num_cols(self.lp)176177cdef int i178179for 0<= i < number:180self.variable_lower_bound(n_var - i - 1, lower_bound)181self.variable_upper_bound(n_var - i - 1, upper_bound)182if continuous:183glp_set_col_kind(self.lp, n_var - i, GLP_CV)184elif binary:185glp_set_col_kind(self.lp, n_var - i, GLP_BV)186elif integer:187glp_set_col_kind(self.lp, n_var - i, GLP_IV)188189if obj:190self.objective_coefficient(n_var - i - 1, obj)191192if names is not None:193glp_set_col_name(self.lp, n_var, names[number - i - 1])194195return n_var - 1196197cpdef set_variable_type(self, int variable, int vtype):198"""199Set the type of a variable200201INPUT:202203- ``variable`` (integer) -- the variable's id204205- ``vtype`` (integer) :206207* 1 Integer208* 0 Binary209* -1 Real210211EXAMPLE::212213sage: from sage.numerical.backends.generic_backend import get_solver214sage: p = get_solver(solver = "GLPK")215sage: p.ncols()2160217sage: p.add_variable()2180219sage: p.set_variable_type(0,1)220sage: p.is_variable_integer(0)221True222"""223224if vtype==1:225glp_set_col_kind(self.lp, variable+1, GLP_IV)226227elif vtype==0:228glp_set_col_kind(self.lp, variable+1, GLP_BV)229230else:231glp_set_col_kind(self.lp, variable+1, GLP_CV)232233cpdef set_sense(self, int sense):234"""235Set the direction (maximization/minimization).236237INPUT:238239- ``sense`` (integer) :240241* +1 => Maximization242* -1 => Minimization243244EXAMPLE::245246sage: from sage.numerical.backends.generic_backend import get_solver247sage: p = get_solver(solver = "GLPK")248sage: p.is_maximization()249True250sage: p.set_sense(-1)251sage: p.is_maximization()252False253"""254if sense == 1:255glp_set_obj_dir(self.lp, GLP_MAX)256else:257glp_set_obj_dir(self.lp, GLP_MIN)258259cpdef objective_coefficient(self, int variable, coeff=None):260"""261Set or get the coefficient of a variable in the objective function262263INPUT:264265- ``variable`` (integer) -- the variable's id266267- ``coeff`` (double) -- its coefficient or ``None`` for268reading (default: ``None``)269270EXAMPLE::271272sage: from sage.numerical.backends.generic_backend import get_solver273sage: p = get_solver(solver = "GLPK")274sage: p.add_variable()2750276sage: p.objective_coefficient(0)2770.0278sage: p.objective_coefficient(0,2)279sage: p.objective_coefficient(0)2802.0281"""282if coeff is None:283return glp_get_obj_coef(self.lp, variable + 1)284else:285glp_set_obj_coef(self.lp, variable + 1, coeff)286287cpdef problem_name(self, char * name = NULL):288"""289Return or define the problem's name290291INPUT:292293- ``name`` (``char *``) -- the problem's name. When set to294``NULL`` (default), the method returns the problem's name.295296EXAMPLE::297298sage: from sage.numerical.backends.generic_backend import get_solver299sage: p = get_solver(solver = "GLPK")300sage: p.problem_name("There once was a french fry")301sage: print p.problem_name()302There once was a french fry303"""304cdef char * n305306if name == NULL:307n = <char *> glp_get_prob_name(self.lp)308if n == NULL:309return ""310else:311return n312313else:314if len(name) > 255:315raise ValueError("Problem name for GLPK must not be longer than 255 characters.")316glp_set_prob_name(self.lp, name)317318cpdef set_objective(self, list coeff, d = 0.0):319"""320Set the objective function.321322INPUT:323324- ``coeff`` - a list of real values, whose ith element is the325coefficient of the ith variable in the objective function.326327- ``d`` (double) -- the constant term in the linear function (set to `0` by default)328329EXAMPLE::330331sage: from sage.numerical.backends.generic_backend import get_solver332sage: p = get_solver(solver = "GLPK")333sage: p.add_variables(5)3344335sage: p.set_objective([1, 1, 2, 1, 3])336sage: map(lambda x :p.objective_coefficient(x), range(5))337[1.0, 1.0, 2.0, 1.0, 3.0]338"""339cdef int i340341for i,v in enumerate(coeff):342glp_set_obj_coef(self.lp, i+1, v)343344glp_set_obj_coef(self.lp, 0, d)345346self.obj_constant_term = d347348cpdef set_verbosity(self, int level):349"""350Set the verbosity level351352INPUT:353354- ``level`` (integer) -- From 0 (no verbosity) to 3.355356EXAMPLE::357358sage: from sage.numerical.backends.generic_backend import get_solver359sage: p = get_solver(solver = "GLPK")360sage: p.set_verbosity(2)361362"""363if level == 0:364self.iocp.msg_lev = GLP_MSG_OFF365self.smcp.msg_lev = GLP_MSG_OFF366elif level == 1:367self.iocp.msg_lev = GLP_MSG_ERR368self.smcp.msg_lev = GLP_MSG_ERR369elif level == 2:370self.iocp.msg_lev = GLP_MSG_ON371self.smcp.msg_lev = GLP_MSG_ON372else:373self.iocp.msg_lev = GLP_MSG_ALL374self.smcp.msg_lev = GLP_MSG_ALL375376cpdef remove_constraint(self, int i):377r"""378Remove a constraint from self.379380INPUT:381382- ``i`` -- index of the constraint to remove383384EXAMPLE::385386sage: p = MixedIntegerLinearProgram(solver='GLPK')387sage: x,y = p[0], p[1]388sage: p.add_constraint(2*x + 3*y, max = 6)389sage: p.add_constraint(3*x + 2*y, max = 6)390sage: p.set_objective(x + y + 7)391sage: p.set_integer(x); p.set_integer(y)392sage: p.solve()3939.0394sage: p.remove_constraint(0)395sage: p.solve()39610.0397398Removing fancy constraints does not make Sage crash::399400sage: MixedIntegerLinearProgram(solver = "GLPK").remove_constraint(-2)401Traceback (most recent call last):402...403ValueError: The constraint's index i must satisfy 0 <= i < number_of_constraints404"""405cdef int rows[2]406407if i < 0 or i >= glp_get_num_rows(self.lp):408raise ValueError("The constraint's index i must satisfy 0 <= i < number_of_constraints")409410rows[1] = i + 1411glp_del_rows(self.lp, 1, rows)412glp_std_basis(self.lp)413414cpdef remove_constraints(self, constraints):415r"""416Remove several constraints.417418INPUT:419420- ``constraints`` -- an iterable containing the indices of the rows to remove.421422EXAMPLE::423424sage: p = MixedIntegerLinearProgram(solver='GLPK')425sage: x,y = p[0], p[1]426sage: p.add_constraint(2*x + 3*y, max = 6)427sage: p.add_constraint(3*x + 2*y, max = 6)428sage: p.set_objective(x + y + 7)429sage: p.set_integer(x); p.set_integer(y)430sage: p.solve()4319.0432sage: p.remove_constraints([1])433sage: p.solve()43410.0435sage: p.get_values([x,y])436[3.0, 0.0]437438TESTS:439440Removing fancy constraints does not make Sage crash::441442sage: MixedIntegerLinearProgram(solver= "GLPK").remove_constraints([0, -2])443Traceback (most recent call last):444...445ValueError: The constraint's index i must satisfy 0 <= i < number_of_constraints446"""447cdef int i, c448cdef int m = len(constraints)449cdef int * rows = <int *>sage_malloc((m + 1) * sizeof(int *))450cdef int nrows = glp_get_num_rows(self.lp)451452for i in xrange(m):453454c = constraints[i]455if c < 0 or c >= nrows:456sage_free(rows)457raise ValueError("The constraint's index i must satisfy 0 <= i < number_of_constraints")458459rows[i+1] = c + 1460461glp_del_rows(self.lp, m, rows)462sage_free(rows)463glp_std_basis(self.lp)464465cpdef add_linear_constraint(self, coefficients, lower_bound, upper_bound, name=None):466"""467Add a linear constraint.468469INPUT:470471- ``coefficients`` an iterable with ``(c,v)`` pairs where ``c``472is a variable index (integer) and ``v`` is a value (real473value).474475- ``lower_bound`` - a lower bound, either a real value or ``None``476477- ``upper_bound`` - an upper bound, either a real value or ``None``478479- ``name`` - an optional name for this row (default: ``None``)480481EXAMPLE::482483sage: from sage.numerical.backends.generic_backend import get_solver484sage: p = get_solver(solver = "GLPK")485sage: p.add_variables(5)4864487sage: p.add_linear_constraint( zip(range(5), range(5)), 2.0, 2.0)488sage: p.row(0)489([4, 3, 2, 1], [4.0, 3.0, 2.0, 1.0])490sage: p.row_bounds(0)491(2.0, 2.0)492sage: p.add_linear_constraint( zip(range(5), range(5)), 1.0, 1.0, name='foo')493sage: p.row_name(1)494'foo'495"""496if lower_bound is None and upper_bound is None:497raise ValueError("At least one of 'upper_bound' or 'lower_bound' must be set.")498499glp_add_rows(self.lp, 1)500cdef int n = glp_get_num_rows(self.lp)501502cdef int * row_i503cdef double * row_values504505row_i = <int *> sage_malloc((len(coefficients)+1) * sizeof(int))506row_values = <double *> sage_malloc((len(coefficients)+1) * sizeof(double))507508for i,(c,v) in enumerate(coefficients):509row_i[i+1] = c+1510row_values[i+1] = v511512glp_set_mat_row(self.lp, n, len(coefficients), row_i, row_values)513514if upper_bound is not None and lower_bound is None:515glp_set_row_bnds(self.lp, n, GLP_UP, upper_bound, upper_bound)516elif lower_bound is not None and upper_bound is None:517glp_set_row_bnds(self.lp, n, GLP_LO, lower_bound, lower_bound)518elif upper_bound is not None and lower_bound is not None:519if lower_bound == upper_bound:520glp_set_row_bnds(self.lp, n, GLP_FX, lower_bound, upper_bound)521else:522glp_set_row_bnds(self.lp, n, GLP_DB, lower_bound, upper_bound)523524if name is not None:525glp_set_row_name(self.lp, n, name)526527sage_free(row_i)528sage_free(row_values)529530cpdef add_linear_constraints(self, int number, lower_bound, upper_bound, names=None):531"""532Add ``'number`` linear constraints.533534INPUT:535536- ``number`` (integer) -- the number of constraints to add.537538- ``lower_bound`` - a lower bound, either a real value or ``None``539540- ``upper_bound`` - an upper bound, either a real value or ``None``541542- ``names`` - an optional list of names (default: ``None``)543544EXAMPLE::545546sage: from sage.numerical.backends.generic_backend import get_solver547sage: p = get_solver(solver = "GLPK")548sage: p.add_variables(5)5494550sage: p.add_linear_constraints(5, None, 2)551sage: p.row(4)552([], [])553sage: p.row_bounds(4)554(None, 2.0)555sage: p.add_linear_constraints(2, None, 2, names=['foo','bar'])556"""557if lower_bound is None and upper_bound is None:558raise ValueError("At least one of 'upper_bound' or 'lower_bound' must be set.")559560glp_add_rows(self.lp, number)561cdef int n = glp_get_num_rows(self.lp)562563cdef int i564for 0<= i < number:565if upper_bound is not None and lower_bound is None:566glp_set_row_bnds(self.lp, n-i, GLP_UP, upper_bound, upper_bound)567elif lower_bound is not None and upper_bound is None:568glp_set_row_bnds(self.lp, n-i, GLP_LO, lower_bound, lower_bound)569elif upper_bound is not None and lower_bound is not None:570if lower_bound == upper_bound:571glp_set_row_bnds(self.lp, n-i, GLP_FX, lower_bound, upper_bound)572else:573glp_set_row_bnds(self.lp, n-i, GLP_DB, lower_bound, upper_bound)574if names is not None:575glp_set_row_name(self.lp, n-i, names[number-i-1])576577cpdef row(self, int index):578r"""579Return a row580581INPUT:582583- ``index`` (integer) -- the constraint's id.584585OUTPUT:586587A pair ``(indices, coeffs)`` where ``indices`` lists the588entries whose coefficient is nonzero, and to which ``coeffs``589associates their coefficient on the model of the590``add_linear_constraint`` method.591592EXAMPLE::593594sage: from sage.numerical.backends.generic_backend import get_solver595sage: p = get_solver(solver = "GLPK")596sage: p.add_variables(5)5974598sage: p.add_linear_constraint(zip(range(5), range(5)), 2, 2)599sage: p.row(0)600([4, 3, 2, 1], [4.0, 3.0, 2.0, 1.0])601sage: p.row_bounds(0)602(2.0, 2.0)603"""604cdef int n = glp_get_num_cols(self.lp)605cdef int * c_indices = <int*> sage_malloc((n+1)*sizeof(int))606cdef double * c_values = <double*> sage_malloc((n+1)*sizeof(double))607cdef list indices = []608cdef list values = []609cdef int i,j610611i = glp_get_mat_row(self.lp, index + 1, c_indices, c_values)612for 0 < j <= i:613indices.append(c_indices[j]-1)614values.append(c_values[j])615616sage_free(c_indices)617sage_free(c_values)618619return (indices, values)620621cpdef row_bounds(self, int index):622"""623Return the bounds of a specific constraint.624625INPUT:626627- ``index`` (integer) -- the constraint's id.628629OUTPUT:630631A pair ``(lower_bound, upper_bound)``. Each of them can be set632to ``None`` if the constraint is not bounded in the633corresponding direction, and is a real value otherwise.634635EXAMPLE::636637sage: from sage.numerical.backends.generic_backend import get_solver638sage: p = get_solver(solver = "GLPK")639sage: p.add_variables(5)6404641sage: p.add_linear_constraint(zip(range(5), range(5)), 2, 2)642sage: p.row(0)643([4, 3, 2, 1], [4.0, 3.0, 2.0, 1.0])644sage: p.row_bounds(0)645(2.0, 2.0)646"""647cdef double ub648cdef double lb649650ub = glp_get_row_ub(self.lp, index + 1)651lb = glp_get_row_lb(self.lp, index +1)652653return (654(lb if lb != -DBL_MAX else None),655(ub if ub != +DBL_MAX else None)656)657658cpdef col_bounds(self, int index):659"""660Return the bounds of a specific variable.661662INPUT:663664- ``index`` (integer) -- the variable's id.665666OUTPUT:667668A pair ``(lower_bound, upper_bound)``. Each of them can be set669to ``None`` if the variable is not bounded in the670corresponding direction, and is a real value otherwise.671672EXAMPLE::673674sage: from sage.numerical.backends.generic_backend import get_solver675sage: p = get_solver(solver = "GLPK")676sage: p.add_variable()6770678sage: p.col_bounds(0)679(0.0, None)680sage: p.variable_upper_bound(0, 5)681sage: p.col_bounds(0)682(0.0, 5.0)683"""684685cdef double ub686cdef double lb687688ub = glp_get_col_ub(self.lp, index +1)689lb = glp_get_col_lb(self.lp, index +1)690691return (692(lb if lb != -DBL_MAX else None),693(ub if ub != +DBL_MAX else None)694)695696cpdef add_col(self, list indices, list coeffs):697"""698Add a column.699700INPUT:701702- ``indices`` (list of integers) -- this list constains the703indices of the constraints in which the variable's704coefficient is nonzero705706- ``coeffs`` (list of real values) -- associates a coefficient707to the variable in each of the constraints in which it708appears. Namely, the ith entry of ``coeffs`` corresponds to709the coefficient of the variable in the constraint710represented by the ith entry in ``indices``.711712.. NOTE::713714``indices`` and ``coeffs`` are expected to be of the same715length.716717EXAMPLE::718719sage: from sage.numerical.backends.generic_backend import get_solver720sage: p = get_solver(solver = "GLPK")721sage: p.ncols()7220723sage: p.nrows()7240725sage: p.add_linear_constraints(5, 0, None)726sage: p.add_col(range(5), range(5))727sage: p.nrows()7285729"""730731glp_add_cols(self.lp, 1)732cdef int n = glp_get_num_cols(self.lp)733734cdef int * col_i735cdef double * col_values736737col_i = <int *> sage_malloc((len(indices)+1) * sizeof(int))738col_values = <double *> sage_malloc((len(indices)+1) * sizeof(double))739740for i,v in enumerate(indices):741col_i[i+1] = v+1742for i,v in enumerate(coeffs):743col_values[i+1] = v744745glp_set_mat_col(self.lp, n, len(indices), col_i, col_values)746glp_set_col_bnds(self.lp, n, GLP_LO, 0,0)747748749cpdef int solve(self) except -1:750"""751Solve the problem.752753.. NOTE::754755This method raises ``MIPSolverException`` exceptions when756the solution can not be computed for any reason (none757exists, or the LP solver was not able to find it, etc...)758759EXAMPLE::760761sage: from sage.numerical.backends.generic_backend import get_solver762sage: p = get_solver(solver = "GLPK")763sage: p.add_linear_constraints(5, 0, None)764sage: p.add_col(range(5), range(5))765sage: p.solve()7660767sage: p.objective_coefficient(0,1)768sage: p.solve()769Traceback (most recent call last):770...771MIPSolverException: ...772773.. WARNING::774775Sage uses GLPK's ``glp_intopt`` to find solutions.776This routine sometimes FAILS CATASTROPHICALLY777when given a system it cannot solve. (Ticket #12309.)778Here, "catastrophic" can mean either "infinite loop" or779segmentation fault. Upstream considers this behavior780"essentially innate" to their design, and suggests781preprocessing it with ``glpk_simplex`` first.782Thus, if you suspect that your system is infeasible,783set the ``preprocessing`` option first.784785EXAMPLE::786787sage: lp = MixedIntegerLinearProgram(solver = "GLPK")788sage: lp.add_constraint( lp[1] +lp[2] -2.0 *lp[3] , max =-1.0)789sage: lp.add_constraint( lp[0] -4.0/3 *lp[1] +1.0/3 *lp[2] , max =-1.0/3)790sage: lp.add_constraint( lp[0] +0.5 *lp[1] -0.5 *lp[2] +0.25 *lp[3] , max =-0.25)791sage: lp.solve()7920.0793sage: lp.add_constraint( lp[0] +4.0 *lp[1] -lp[2] +lp[3] , max =-1.0)794sage: lp.solve()795Traceback (most recent call last):796...797RuntimeError: GLPK : Signal sent, try preprocessing option798sage: lp.solver_parameter("simplex_or_intopt", "simplex_then_intopt")799sage: lp.solve()800Traceback (most recent call last):801...802MIPSolverException: 'GLPK : Simplex cannot find a feasible solution'803804The user can ask sage to solve via ``simplex`` or ``intopt``.805The default solver is ``intopt``, so we get integer solutions.806807sage: lp = MixedIntegerLinearProgram(solver = 'GLPK', maximization = False)808sage: x, y = lp[0], lp[1]809sage: lp.add_constraint(-2*x + y <= 1)810sage: lp.add_constraint(x - y <= 1)811sage: lp.add_constraint(x + y >= 2)812sage: lp.set_objective(x + y)813sage: lp.set_integer(x)814sage: lp.set_integer(y)815sage: lp.solve()8162.0817sage: lp.get_values([x, y])818[1.0, 1.0]819820If we switch to ``simplex``, we get continuous solutions.821822sage: lp.solver_parameter("simplex_or_intopt", "simplex_only") # use simplex only823sage: lp.solve()8242.0825sage: lp.get_values([x, y])826[1.5, 0.5]827"""828829cdef int status830if self.simplex_or_intopt == glp_simplex_only or self.simplex_or_intopt == glp_simplex_then_intopt:831status = glp_simplex(self.lp, self.smcp)832status = glp_get_prim_stat(self.lp)833if status == GLP_OPT or status == GLP_FEAS:834pass835elif status == GLP_UNDEF or status == GLP_NOFEAS:836raise MIPSolverException("GLPK : Simplex cannot find a feasible solution")837838if self.simplex_or_intopt != glp_simplex_only:839sig_str('GLPK : Signal sent, try preprocessing option')840status = glp_intopt(self.lp, self.iocp)841sig_off()842# this is necessary to catch errors when certain options are enabled, e.g. tm_lim843if status == GLP_ETMLIM: raise MIPSolverException("GLPK : The time limit was reached")844elif status == GLP_EITLIM: raise MIPSolverException("GLPK : The iteration limit was reached")845846status = glp_mip_status(self.lp)847if status == GLP_OPT:848pass849elif status == GLP_UNDEF:850raise MIPSolverException("GLPK : Solution is undefined")851elif status == GLP_FEAS:852raise MIPSolverException("GLPK : Feasible solution found, while optimality has not been proven")853elif status == GLP_INFEAS:854raise MIPSolverException("GLPK : Solution is infeasible")855elif status == GLP_UNBND:856raise MIPSolverException("GLPK : Problem has unbounded solution")857elif status == GLP_NOFEAS:858raise MIPSolverException("GLPK : There is no feasible integer solution to this Linear Program")859860return 0861862cpdef get_objective_value(self):863"""864Returns the value of the objective function.865866.. NOTE::867868Behaviour is undefined unless ``solve`` has been called before.869870EXAMPLE::871872sage: from sage.numerical.backends.generic_backend import get_solver873sage: p = get_solver(solver = "GLPK")874sage: p.add_variables(2)8751876sage: p.add_linear_constraint([[0, 1], [1, 2]], None, 3)877sage: p.set_objective([2, 5])878sage: p.solve()8790880sage: p.get_objective_value()8817.5882sage: p.get_variable_value(0)8830.0884sage: p.get_variable_value(1)8851.5886"""887if self.simplex_or_intopt != glp_simplex_only:888return glp_mip_obj_val(self.lp)889else:890return glp_get_obj_val(self.lp)891892cpdef get_variable_value(self, int variable):893"""894Returns the value of a variable given by the solver.895896.. NOTE::897898Behaviour is undefined unless ``solve`` has been called before.899900EXAMPLE::901902sage: from sage.numerical.backends.generic_backend import get_solver903sage: p = get_solver(solver = "GLPK")904sage: p.add_variables(2)9051906sage: p.add_linear_constraint([[0, 1], [1, 2]], None, 3)907sage: p.set_objective([2, 5])908sage: p.solve()9090910sage: p.get_objective_value()9117.5912sage: p.get_variable_value(0)9130.0914sage: p.get_variable_value(1)9151.5916"""917if self.simplex_or_intopt != glp_simplex_only:918return glp_mip_col_val(self.lp, variable+1)919else:920return glp_get_col_prim(self.lp, variable+1)921922cpdef int ncols(self):923"""924Return the number of columns/variables.925926EXAMPLE::927928sage: from sage.numerical.backends.generic_backend import get_solver929sage: p = get_solver(solver = "GLPK")930sage: p.ncols()9310932sage: p.add_variables(2)9331934sage: p.ncols()9352936"""937return glp_get_num_cols(self.lp)938939cpdef int nrows(self):940"""941Return the number of rows/constraints.942943EXAMPLE::944945sage: from sage.numerical.backends.generic_backend import get_solver946sage: p = get_solver(solver = "GLPK")947sage: p.nrows()9480949sage: p.add_linear_constraints(2, 2, None)950sage: p.nrows()9512952"""953954return glp_get_num_rows(self.lp)955956cpdef col_name(self, int index):957"""958Return the ``index`` th col name959960INPUT:961962- ``index`` (integer) -- the col's id963964EXAMPLE::965966sage: from sage.numerical.backends.generic_backend import get_solver967sage: p = get_solver(solver = "GLPK")968sage: p.add_variable(name='I am a variable')9690970sage: p.col_name(0)971'I am a variable'972"""973cdef char * s974975glp_create_index(self.lp)976s = <char*> glp_get_col_name(self.lp, index + 1)977978if s != NULL:979return s980else:981return ""982983cpdef row_name(self, int index):984"""985Return the ``index`` th row name986987INPUT:988989- ``index`` (integer) -- the row's id990991EXAMPLE::992993sage: from sage.numerical.backends.generic_backend import get_solver994sage: p = get_solver(solver = "GLPK")995sage: p.add_linear_constraints(1, 2, None, names=['Empty constraint 1'])996sage: p.row_name(0)997'Empty constraint 1'998"""999cdef char * s10001001glp_create_index(self.lp)1002s = <char*> glp_get_row_name(self.lp, index + 1)10031004if s != NULL:1005return s1006else:1007return ""10081009cpdef bint is_variable_binary(self, int index):1010"""1011Test whether the given variable is of binary type.10121013INPUT:10141015- ``index`` (integer) -- the variable's id10161017EXAMPLE::10181019sage: from sage.numerical.backends.generic_backend import get_solver1020sage: p = get_solver(solver = "GLPK")1021sage: p.ncols()102201023sage: p.add_variable()102401025sage: p.set_variable_type(0,0)1026sage: p.is_variable_binary(0)1027True10281029"""1030return glp_get_col_kind(self.lp, index + 1) == GLP_BV10311032cpdef bint is_variable_integer(self, int index):1033"""1034Test whether the given variable is of integer type.10351036INPUT:10371038- ``index`` (integer) -- the variable's id10391040EXAMPLE::10411042sage: from sage.numerical.backends.generic_backend import get_solver1043sage: p = get_solver(solver = "GLPK")1044sage: p.ncols()104501046sage: p.add_variable()104701048sage: p.set_variable_type(0,1)1049sage: p.is_variable_integer(0)1050True1051"""1052return glp_get_col_kind(self.lp, index + 1) == GLP_IV10531054cpdef bint is_variable_continuous(self, int index):1055"""1056Test whether the given variable is of continuous/real type.10571058INPUT:10591060- ``index`` (integer) -- the variable's id10611062EXAMPLE::10631064sage: from sage.numerical.backends.generic_backend import get_solver1065sage: p = get_solver(solver = "GLPK")1066sage: p.ncols()106701068sage: p.add_variable()106901070sage: p.is_variable_continuous(0)1071True1072sage: p.set_variable_type(0,1)1073sage: p.is_variable_continuous(0)1074False10751076"""1077return glp_get_col_kind(self.lp, index + 1) == GLP_CV10781079cpdef bint is_maximization(self):1080"""1081Test whether the problem is a maximization10821083EXAMPLE::10841085sage: from sage.numerical.backends.generic_backend import get_solver1086sage: p = get_solver(solver = "GLPK")1087sage: p.is_maximization()1088True1089sage: p.set_sense(-1)1090sage: p.is_maximization()1091False1092"""10931094return glp_get_obj_dir(self.lp) == GLP_MAX10951096cpdef variable_upper_bound(self, int index, value = False):1097"""1098Return or define the upper bound on a variable10991100INPUT:11011102- ``index`` (integer) -- the variable's id11031104- ``value`` -- real value, or ``None`` to mean that the1105variable has not upper bound. When set to ``False``1106(default), the method returns the current value.11071108EXAMPLE::11091110sage: from sage.numerical.backends.generic_backend import get_solver1111sage: p = get_solver(solver = "GLPK")1112sage: p.add_variable()111301114sage: p.col_bounds(0)1115(0.0, None)1116sage: p.variable_upper_bound(0, 5)1117sage: p.col_bounds(0)1118(0.0, 5.0)11191120TESTS:11211122:trac:`14581`::11231124sage: P = MixedIntegerLinearProgram(solver="GLPK")1125sage: x = P["x"]1126sage: P.set_max(x, 0)1127sage: P.get_max(x)11280.01129"""1130cdef double x1131cdef double min11321133if value is False:1134x = glp_get_col_ub(self.lp, index +1)1135if x == DBL_MAX:1136return None1137else:1138return x1139else:1140min = glp_get_col_lb(self.lp, index + 1)11411142if value is None and min == -DBL_MAX:1143glp_set_col_bnds(self.lp, index + 1, GLP_FR, 0, 0)11441145elif value is None:1146glp_set_col_bnds(self.lp, index + 1, GLP_LO, min, 0)11471148elif min == -DBL_MAX:1149glp_set_col_bnds(self.lp, index + 1, GLP_UP, 0, value)11501151elif min == value:1152glp_set_col_bnds(self.lp, index + 1, GLP_FX, value, value)11531154else:1155glp_set_col_bnds(self.lp, index + 1, GLP_DB, min, value)11561157cpdef variable_lower_bound(self, int index, value = False):1158"""1159Return or define the lower bound on a variable11601161INPUT:11621163- ``index`` (integer) -- the variable's id11641165- ``value`` -- real value, or ``None`` to mean that the1166variable has not lower bound. When set to ``False``1167(default), the method returns the current value.11681169EXAMPLE::11701171sage: from sage.numerical.backends.generic_backend import get_solver1172sage: p = get_solver(solver = "GLPK")1173sage: p.add_variable()117401175sage: p.col_bounds(0)1176(0.0, None)1177sage: p.variable_lower_bound(0, 5)1178sage: p.col_bounds(0)1179(5.0, None)11801181TESTS:11821183:trac:`14581`::11841185sage: P = MixedIntegerLinearProgram(solver="GLPK")1186sage: x = P["x"]1187sage: P.set_min(x, 5)1188sage: P.set_min(x, 0)1189sage: P.get_min(x)11900.01191"""1192cdef double x1193cdef double max11941195if value is False:1196x = glp_get_col_lb(self.lp, index +1)1197if x == -DBL_MAX:1198return None1199else:1200return x1201else:1202max = glp_get_col_ub(self.lp, index + 1)12031204if value is None and max == DBL_MAX:1205glp_set_col_bnds(self.lp, index + 1, GLP_FR, 0.0, 0.0)12061207elif value is None:1208glp_set_col_bnds(self.lp, index + 1, GLP_UP, 0.0, max)12091210elif max == DBL_MAX:1211glp_set_col_bnds(self.lp, index + 1, GLP_LO, value, 0.0)12121213elif max == value:1214glp_set_col_bnds(self.lp, index + 1, GLP_FX, value, value)12151216else:1217glp_set_col_bnds(self.lp, index + 1, GLP_DB, value, max)12181219cpdef write_lp(self, char * filename):1220"""1221Write the problem to a .lp file12221223INPUT:12241225- ``filename`` (string)12261227EXAMPLE::12281229sage: from sage.numerical.backends.generic_backend import get_solver1230sage: p = get_solver(solver = "GLPK")1231sage: p.add_variables(2)123211233sage: p.add_linear_constraint([[0, 1], [1, 2]], None, 3)1234sage: p.set_objective([2, 5])1235sage: p.write_lp(os.path.join(SAGE_TMP, "lp_problem.lp"))1236Writing problem data to ...12379 lines were written1238"""1239glp_write_lp(self.lp, NULL, filename)12401241cpdef write_mps(self, char * filename, int modern):1242"""1243Write the problem to a .mps file12441245INPUT:12461247- ``filename`` (string)12481249EXAMPLE::12501251sage: from sage.numerical.backends.generic_backend import get_solver1252sage: p = get_solver(solver = "GLPK")1253sage: p.add_variables(2)125411255sage: p.add_linear_constraint([[0, 1], [1, 2]], None, 3)1256sage: p.set_objective([2, 5])1257sage: p.write_mps(os.path.join(SAGE_TMP, "lp_problem.mps"), 2)1258Writing problem data to...125917 records were written1260"""1261glp_write_mps(self.lp, modern, NULL, filename)12621263cpdef GLPKBackend copy(self):1264"""1265Returns a copy of self.12661267EXAMPLE::12681269sage: from sage.numerical.backends.generic_backend import get_solver1270sage: p = MixedIntegerLinearProgram(solver = "GLPK")1271sage: b = p.new_variable()1272sage: p.add_constraint(b[1] + b[2] <= 6)1273sage: p.set_objective(b[1] + b[2])1274sage: copy(p).solve()12756.01276"""1277cdef GLPKBackend p = GLPKBackend(maximization = (1 if self.is_maximization() else -1))1278p.simplex_or_intopt = self.simplex_or_intopt1279p.iocp.tm_lim = self.iocp.tm_lim1280glp_copy_prob(p.lp, self.lp, 1)1281return p128212831284cpdef solver_parameter(self, name, value = None):1285"""1286Return or define a solver parameter12871288INPUT:12891290- ``name`` (string) -- the parameter12911292- ``value`` -- the parameter's value if it is to be defined,1293or ``None`` (default) to obtain its current value.12941295You can supply the name of a parameter and its value using either a1296string or a ``glp_`` constant (which are defined as Cython variables of1297this module).12981299In most cases, you can use the same name for a parameter as that given1300in the GLPK documentation, which is available by downloading GLPK from1301<http://www.gnu.org/software/glpk/>. The exceptions relate to parameters1302common to both methods; these require you to append ``_simplex`` or1303``_intopt`` to the name to resolve ambiguity, since the interface allows1304access to both.13051306We have also provided more meaningful names, to assist readability.13071308Parameter **names** are specified in lower case.1309To use a constant instead of a string, prepend ``glp_`` to the name.1310For example, both ``glp_gmi_cuts`` or ``"gmi_cuts"`` control whether1311to solve using Gomory cuts.13121313Parameter **values** are specificed as strings in upper case,1314or as constants in lower case. For example, both ``glp_on`` and ``"GLP_ON"``1315specify the same thing.13161317Naturally, you can use ``True`` and ``False`` in cases where ``glp_on`` and ``glp_off``1318would be used.13191320A list of parameter names, with their possible values:13211322**General-purpose parameters:**13231324.. list-table::1325:widths: 30 7013261327* - ``timelimit``13281329- specify the time limit IN SECONDS. This affects both simplex1330and intopt.13311332* - ``timelimit_simplex`` and ``timelimit_intopt``13331334- specify the time limit IN MILLISECONDS. (This is glpk's1335default.)13361337* - ``simplex_or_intopt``13381339- whether to use the ``simplex`` or ``intopt`` routines in1340GLPK. This is controlled by using ``glp_simplex_only``,1341``glp_intopt_only``, and ``glp_simplex_then_intopt``. The latter1342is useful to deal with a problem in GLPK where problems with no1343solution hang when using integer optimization; if you specify1344``glp_simplex_then_intopt``, sage will try simplex first, then1345perform integer optimization only if a solution of the LP1346relaxation exists.13471348* - ``verbosity_intopt`` and ``verbosity_simplex``13491350- one of ``GLP_MSG_OFF``, ``GLP_MSG_ERR``, ``GLP_MSG_ON``, or1351``GLP_MSG_ALL``. The default is ``GLP_MSG_OFF``.13521353* - ``output_frequency_intopt`` and ``output_frequency_simplex``13541355- the output frequency, in milliseconds. Default is 5000.13561357* - ``output_delay_intopt`` and ``output_delay_simplex``13581359- the output delay, in milliseconds, regarding the use of the1360simplex method on the LP relaxation. Default is 10000.136113621363**intopt-specific parameters:**13641365.. list-table::1366:widths: 30 7013671368* - ``branching``1369- - ``GLP_BR_FFV`` first fractional variable1370- ``GLP_BR_LFV`` last fractional variable1371- ``GLP_BR_MFV`` most fractional variable1372- ``GLP_BR_DTH`` Driebeck-Tomlin heuristic (default)1373- ``GLP_BR_PCH`` hybrid pseudocost heuristic13741375* - ``backtracking``1376- - ``GLP_BT_DFS`` depth first search1377- ``GLP_BT_BFS`` breadth first search1378- ``GLP_BT_BLB`` best local bound (default)1379- ``GLP_BT_BPH`` best projection heuristic13801381* - ``preprocessing``1382- - ``GLP_PP_NONE``1383- ``GLP_PP_ROOT`` preprocessing only at root level1384- ``GLP_PP_ALL`` (default)138513861387* - ``feasibility_pump``13881389- ``GLP_ON`` or ``GLP_OFF`` (default)13901391* - ``gomory_cuts``13921393- ``GLP_ON`` or ``GLP_OFF`` (default)13941395* - ``mixed_int_rounding_cuts``13961397- ``GLP_ON`` or ``GLP_OFF`` (default)13981399* - ``mixed_cover_cuts``14001401- ``GLP_ON`` or ``GLP_OFF`` (default)14021403* - ``clique_cuts``14041405- ``GLP_ON`` or ``GLP_OFF`` (default)14061407* - ``absolute_tolerance``14081409- (double) used to check if optimal solution to LP relaxation is1410integer feasible. GLPK manual advises, "do not change... without1411detailed understanding of its purpose."14121413* - ``relative_tolerance``14141415- (double) used to check if objective value in LP relaxation is not1416better than best known integer solution. GLPK manual advises, "do1417not change... without detailed understanding of its purpose."14181419* - ``mip_gap_tolerance``14201421- (double) relative mip gap tolerance. Default is 0.0.14221423* - ``presolve_intopt``14241425- ``GLP_ON`` (default) or ``GLP_OFF``.14261427* - ``binarize``14281429- ``GLP_ON`` or ``GLP_OFF`` (default)143014311432**simplex-specific parameters:**14331434.. list-table::1435:widths: 30 7014361437* - ``primal_v_dual``14381439- - ``GLP_PRIMAL`` (default)1440- ``GLP_DUAL``1441- ``GLP_DUALP``14421443* - ``pricing``14441445- - ``GLP_PT_STD`` standard (textbook)1446- ``GLP_PT_PSE`` projected steepest edge (default)14471448* - ``ratio_test``14491450- - ``GLP_RT_STD`` standard (textbook)1451- ``GLP_RT_HAR`` Harris' two-pass ratio test (default)14521453* - ``tolerance_primal``14541455- (double) tolerance used to check if basic solution is primal1456feasible. GLPK manual advises, "do not change... without1457detailed understanding of its purpose."14581459* - ``tolerance_dual``14601461- (double) tolerance used to check if basic solution is dual1462feasible. GLPK manual advises, "do not change... without1463detailed understanding of its purpose."14641465* - ``tolerance_pivot``14661467- (double) tolerance used to choose pivot. GLPK manual advises,1468"do not change... without detailed understanding of its1469purpose."14701471* - ``obj_lower_limit``14721473- (double) lower limit of the objective function. The default is1474``-DBL_MAX``.14751476* - ``obj_upper_limit``14771478- (double) upper limit of the objective function. The default is1479``DBL_MAX``.14801481* - ``iteration_limit``14821483- (int) iteration limit of the simplex algorithm. The default is1484``INT_MAX``.14851486* - ``presolve_simplex``14871488- ``GLP_ON`` or ``GLP_OFF`` (default).14891490.. NOTE::14911492The coverage for GLPK's control parameters for simplex and integer optimization1493is nearly complete. The only thing lacking is a wrapper for callback routines.14941495To date, no attempt has been made to expose the interior point methods.14961497EXAMPLE::14981499sage: from sage.numerical.backends.generic_backend import get_solver1500sage: p = get_solver(solver = "GLPK")1501sage: p.solver_parameter("timelimit", 60)1502sage: p.solver_parameter("timelimit")150360.015041505- Don't forget the difference between ``timelimit`` and ``timelimit_intopt``15061507::15081509sage: p.solver_parameter("timelimit_intopt")15106000015111512If you don't care for an integer answer, you can ask for an lp1513relaxation instead. The default solver performs integer optimization,1514but you can switch to the standard simplex algorithm through the1515``glp_simplex_or_intopt`` parameter.15161517EXAMPLE::15181519sage: lp = MixedIntegerLinearProgram(solver = 'GLPK', maximization = False)1520sage: x, y = lp[0], lp[1]1521sage: lp.add_constraint(-2*x + y <= 1)1522sage: lp.add_constraint(x - y <= 1)1523sage: lp.add_constraint(x + y >= 2)1524sage: lp.set_integer(x); lp.set_integer(y)1525sage: lp.set_objective(x + y)1526sage: lp.solve()15272.01528sage: lp.get_values([x,y])1529[1.0, 1.0]1530sage: import sage.numerical.backends.glpk_backend as backend1531sage: lp.solver_parameter(backend.glp_simplex_or_intopt, backend.glp_simplex_only)1532sage: lp.solve()15332.01534sage: lp.get_values([x,y])1535[1.5, 0.5]15361537You can get glpk to spout all sorts of information at you.1538The default is to turn this off, but sometimes (debugging) it's very useful::15391540sage: lp.solver_parameter(backend.glp_simplex_or_intopt, backend.glp_simplex_then_intopt)1541sage: lp.solver_parameter(backend.glp_mir_cuts, backend.glp_on)1542sage: lp.solver_parameter(backend.glp_msg_lev_intopt, backend.glp_msg_all)1543sage: lp.solver_parameter(backend.glp_mir_cuts)1544115451546If you actually try to solve ``lp``, you will get a lot of detailed information.1547"""15481549if type(name) == str:1550if name == "out_frq" or name == "out_dly" or name == "tm_lim" or name == "msg_lev":1551raise ValueError("To set parameter " + name + " you must specify the solver. Append either _simplex or _intopt.")1552name = solver_parameter_names_dict[name]15531554if type(value) == str: value = solver_parameter_values[value]15551556if name == timelimit_intopt:1557if value is None: return self.iocp.tm_lim1558else: self.iocp.tm_lim = value15591560if name == timelimit_seconds:1561if value is None: return self.iocp.tm_lim / 1000.01562else:1563self.iocp.tm_lim = value * 1000.01564self.smcp.tm_lim = value * 1000.015651566elif name == timelimit_simplex:1567if value is None: return self.smcp.tm_lim1568else: self.smcp.tm_lim = value15691570elif name == simplex_or_intopt:1571if value is None: return self.simplex_or_intopt1572if not value in (simplex_only,intopt_only,simplex_then_intopt):1573raise MIPSolverException, "GLPK: invalid value for simplex_or_intopt; see documentation"1574self.simplex_or_intopt = value15751576elif name == msg_lev_simplex:1577if value is None: return self.smcp.msg_lev1578else: self.smcp.msg_lev = value15791580elif name == msg_lev_intopt:1581if value is None: return self.iocp.msg_lev1582else: self.iocp.msg_lev = value15831584elif name == br_tech:1585if value is None: return self.iocp.br_tech1586else: self.iocp.br_tech = value15871588elif name == bt_tech:1589if value is None: return self.iocp.bt_tech1590else: self.iocp.bt_tech = value15911592elif name == pp_tech:1593if value is None: return self.iocp.pp_tech1594else: self.iocp.pp_tech = value15951596elif name == fp_heur:1597if value is None: return self.iocp.fp_heur1598else:1599if value: value = GLP_ON1600else: value = GLP_OFF1601self.iocp.fp_heur = value16021603elif name == gmi_cuts:1604if value is None: return self.iocp.gmi_cuts1605else:1606if value: value = GLP_ON1607else: value = GLP_OFF1608self.iocp.gmi_cuts = value16091610elif name == mir_cuts:1611if value is None: return self.iocp.mir_cuts1612else:1613if value: value = GLP_ON1614else: value = GLP_OFF1615self.iocp.mir_cuts = value16161617elif name == cov_cuts:1618if value is None: return self.iocp.cov_cuts1619else:1620if value: value = GLP_ON1621else: value = GLP_OFF1622self.iocp.cov_cuts = value16231624elif name == clq_cuts:1625if value is None: return self.iocp.clq_cuts1626else:1627if value: value = GLP_ON1628else: value = GLP_OFF1629self.iocp.clq_cuts = value16301631elif name == tol_int:1632if value is None: return self.iocp.tol_int1633else: self.iocp.tol_int = value16341635elif name == tol_obj:1636if value is None: return self.iocp.tol_obj1637else: self.iocp.tol_obj = value16381639elif name == mip_gap:1640if value is None: return self.iocp.mip_gap1641else: self.iocp.mip_gap = value16421643elif name == tm_lim_intopt:1644if value is None: return self.iocp.tm_lim1645else: self.iocp.tm_lim = value16461647elif name == out_frq_intopt:1648if value is None: return self.iocp.out_frq1649else: self.iocp.out_frq = value16501651elif name == out_dly_intopt:1652if value is None: return self.iocp.out_dly1653else: self.iocp.out_dly = value16541655elif name == presolve_intopt:1656if value is None: return self.iocp.presolve1657else:1658if value: value = GLP_ON1659else: value = GLP_OFF1660self.iocp.presolve = value16611662elif name == binarize:1663if value is None: return self.iocp.binarize1664else:1665if value: value = GLP_ON1666else: value = GLP_OFF1667self.iocp.binarize = value16681669elif name == msg_lev_simplex:1670if value is None: return self.smcp.msg_lev1671else: self.smcp.msg_lev = value16721673elif name == meth:1674if value is None: return self.smcp.meth1675else: self.smcp.meth = value16761677elif name == pricing:1678if value is None: return self.smcp.pricing1679else: self.smcp.pricing = value16801681elif name == r_test:1682if value is None: return self.smcp.r_test1683else: self.smcp.r_test = value16841685elif name == tol_bnd:1686if value is None: return self.smcp.tol_bnd1687else: self.smcp.tol_bnd = value16881689elif name == tol_dj:1690if value is None: return self.smcp.tol_dj1691else: self.smcp.tol_dj = value16921693elif name == tol_piv:1694if value is None: return self.smcp.tol_piv1695else: self.smcp.tol_piv = value16961697elif name == obj_ll:1698if value is None: return self.smcp.obj_ll1699else: self.smcp.obj_ll = value17001701elif name == obj_ul:1702if value is None: return self.smcp.obj_ul1703else: self.smcp.obj_ul = value17041705elif name == it_lim:1706if value is None: return self.smcp.it_lim1707else: self.smcp.it_lim = value17081709elif name == tm_lim_simplex:1710if value is None: return self.smcp.tm_lim1711else: self.smcp.tm_lim = value17121713elif name == out_frq_simplex:1714if value is None: return self.smcp.out_frq1715else: self.smcp.out_frq = value17161717elif name == out_dly_simplex:1718if value is None: return self.smcp.out_dly1719else: self.smcp.out_dly = value17201721elif name == presolve_simplex:1722if value is None: return self.smcp.presolve1723else:1724if value: value = GLP_ON1725else: value = GLP_OFF1726self.smcp.presolve = value17271728else:1729raise ValueError("This parameter is not available.")173017311732cpdef int print_ranges(self, char * filename = NULL) except -1:1733r"""1734Print results of a sensitivity analysis17351736If no filename is given as an input the results of the1737sensitivity analysis are displayed on the screen. If a1738filename is given they are written to a file.17391740INPUT:17411742- ``filename`` -- (optional) name of the file17431744OUTPUT:17451746Zero if the operations was successful otherwise nonzero.17471748.. NOTE::17491750This method is only effective if an optimal solution has been found1751for the lp using the simplex algorithm. In all other cases an error1752message is printed.17531754EXAMPLE::17551756sage: from sage.numerical.backends.generic_backend import get_solver1757sage: p = get_solver(solver = "GLPK")1758sage: p.add_variables(2)175911760sage: p.add_linear_constraint(zip([0, 1], [1, 2]), None, 3)1761sage: p.set_objective([2, 5])1762sage: import sage.numerical.backends.glpk_backend as backend1763sage: p.solver_parameter(backend.glp_simplex_or_intopt, backend.glp_simplex_only)1764sage: p.print_ranges()1765glp_print_ranges: optimal basic solution required176611767sage: p.solve()176801769sage: p.print_ranges()1770Write sensitivity analysis report to...1771GLPK ... - SENSITIVITY ANALYSIS REPORT Page 11772<BLANKLINE>1773Problem:1774Objective: 7.5 (MAXimum)1775<BLANKLINE>1776No. Row name St Activity Slack Lower bound Activity Obj coef Obj value at Limiting1777Marginal Upper bound range range break point variable1778------ ------------ -- ------------- ------------- ------------- ------------- ------------- ------------- ------------17791 NU 3.00000 . -Inf . -2.50000 .17802.50000 3.00000 +Inf +Inf +Inf1781<BLANKLINE>1782GLPK ... - SENSITIVITY ANALYSIS REPORT Page 21783<BLANKLINE>1784Problem:1785Objective: 7.5 (MAXimum)1786<BLANKLINE>1787No. Column name St Activity Obj coef Lower bound Activity Obj coef Obj value at Limiting1788Marginal Upper bound range range break point variable1789------ ------------ -- ------------- ------------- ------------- ------------- ------------- ------------- ------------17901 NL . 2.00000 . -Inf -Inf +Inf1791-.50000 +Inf 3.00000 2.50000 6.000001792<BLANKLINE>17932 BS 1.50000 5.00000 . -Inf 4.00000 6.000001794. +Inf 1.50000 +Inf +Inf1795<BLANKLINE>1796End of report1797<BLANKLINE>179801799"""18001801from sage.misc.all import SAGE_TMP18021803if filename == NULL:1804fname = SAGE_TMP+"/ranges.tmp"1805else:1806fname = filename18071808res = glp_print_ranges(self.lp, 0, 0, 0, fname)18091810if filename == NULL:1811if res == 0:1812with open(fname) as f:1813for line in f:1814print line,181518161817return res18181819cpdef double get_row_dual(self, int variable):1820r"""1821Returns the dual value of a constraint.18221823The dual value of the ith row is also the value of the ith variable1824of the dual problem.18251826The dual value of a constraint is the shadow price of the constraint.1827The shadow price is the amount by which the objective value will change1828if the constraints bounds change by one unit under the precondition1829that the basis remains the same.18301831INPUT:18321833- ``variable`` -- The number of the constraint18341835.. NOTE::18361837Behaviour is undefined unless ``solve`` has been called before.1838If the simplex algorithm has not been used for solving 0.0 will1839be returned.18401841EXAMPLE::18421843sage: from sage.numerical.backends.generic_backend import get_solver1844sage: lp = get_solver(solver = "GLPK")1845sage: lp.add_variables(3)184621847sage: lp.add_linear_constraint(zip([0, 1, 2], [8, 6, 1]), None, 48)1848sage: lp.add_linear_constraint(zip([0, 1, 2], [4, 2, 1.5]), None, 20)1849sage: lp.add_linear_constraint(zip([0, 1, 2], [2, 1.5, 0.5]), None, 8)1850sage: lp.set_objective([60, 30, 20])1851sage: import sage.numerical.backends.glpk_backend as backend1852sage: lp.solver_parameter(backend.glp_simplex_or_intopt, backend.glp_simplex_only)1853sage: lp.solve()185401855sage: lp.get_row_dual(0) # tolerance 0.0000118560.01857sage: lp.get_row_dual(1) # tolerance 0.00001185810.0185918601861"""18621863if self.simplex_or_intopt == simplex_only:1864return glp_get_row_dual(self.lp, variable+1)1865else:1866return 0.018671868cpdef double get_col_dual(self, int variable):1869"""1870Returns the dual value (reduced cost) of a variable18711872The dual value is the reduced cost of a variable.1873The reduced cost is the amount by which the objective coefficient1874of a non basic variable has to change to become a basic variable.18751876INPUT:18771878- ``variable`` -- The number of the variable18791880.. NOTE::18811882Behaviour is undefined unless ``solve`` has been called before.1883If the simplex algorithm has not been used for solving just a18840.0 will be returned.188518861887EXAMPLE::18881889sage: from sage.numerical.backends.generic_backend import get_solver1890sage: p = get_solver(solver = "GLPK")1891sage: p.add_variables(3)189221893sage: p.add_linear_constraint(zip([0, 1, 2], [8, 6, 1]), None, 48)1894sage: p.add_linear_constraint(zip([0, 1, 2], [4, 2, 1.5]), None, 20)1895sage: p.add_linear_constraint(zip([0, 1, 2], [2, 1.5, 0.5]), None, 8)1896sage: p.set_objective([60, 30, 20])1897sage: import sage.numerical.backends.glpk_backend as backend1898sage: p.solver_parameter(backend.glp_simplex_or_intopt, backend.glp_simplex_only)1899sage: p.solve()190001901sage: p.get_col_dual(1)1902-5.019031904"""1905if self.simplex_or_intopt == simplex_only:1906return glp_get_col_dual(self.lp, variable+1)1907else:1908return 0.0190919101911def __dealloc__(self):1912"""1913Destructor1914"""1915glp_delete_prob(self.lp)1916sage_free(self.iocp)1917sage_free(self.smcp)19181919# parameter names19201921cdef enum solver_parameter_names:1922timelimit_seconds, timelimit_simplex, timelimit_intopt, simplex_or_intopt, msg_lev_simplex,1923msg_lev_intopt, br_tech, bt_tech, pp_tech, fp_heur, gmi_cuts,1924mir_cuts, cov_cuts, clq_cuts, tol_int, tol_obj, mip_gap,1925tm_lim_intopt, out_frq_intopt, out_dly_intopt, presolve_intopt,1926binarize, meth, pricing, r_test, tol_bnd, tol_dj, tol_piv, obj_ll,1927obj_ul, it_lim, tm_lim_simplex, out_frq_simplex, out_dly_simplex,1928presolve_simplex19291930glp_tm_lim_simplex = timelimit_simplex1931glp_tm_lim_intopt = timelimit_intopt1932glp_simplex_or_intopt = simplex_or_intopt1933glp_msg_lev_intopt = glp_verbosity_intopt = msg_lev_intopt1934glp_msg_lev_simplex = glp_verbosity_simplex = msg_lev_simplex1935glp_br_tech = glp_branching = br_tech1936glp_bt_tech = glp_backtracking = bt_tech1937glp_pp_tech = glp_preprocessing = pp_tech1938glp_fp_heur = glp_feasibility_pump = fp_heur1939glp_gmi_cuts = glp_gomory_cuts = gmi_cuts1940glp_mir_cuts = glp_mixed_int_rounding_cuts = mir_cuts1941glp_cov_cuts = glp_mixed_cover_cuts = cov_cuts1942glp_clq_cuts = glp_clique_cuts = clq_cuts1943glp_tol_int = glp_absolute_tolerance = tol_int1944glp_tol_obj = glp_relative_tolerance = tol_obj1945glp_mip_gap = glp_mip_gap_tolerance = mip_gap1946glp_out_frq_intopt = glp_output_frequency_intopt = out_frq_intopt1947glp_out_dly_intopt = glp_output_delay_intopt = out_dly_intopt1948glp_presolve_intopt = presolve_intopt1949glp_binarize = binarize1950glp_meth = glp_primal_v_dual = meth1951glp_pricing = pricing1952glp_r_test = glp_ratio_test = r_test1953glp_tol_bnd = glp_tolerance_primal = tol_bnd1954glp_tol_dj = glp_tolerance_dual = tol_dj1955glp_tol_piv = glp_tolerance_pivot = tol_piv1956glp_obj_ll = glp_obj_lower_limit = obj_ll1957glp_obj_ul = glp_obj_upper_limit = obj_ul1958glp_it_lim = glp_iteration_limit = it_lim1959glp_out_frq_simplex = glp_output_frequency_intopt = out_frq_simplex1960glp_out_dly_simplex = glp_output_delay_simplex = out_dly_simplex1961glp_presolve_simplex = presolve_simplex19621963solver_parameter_names_dict = {1964'timelimit': timelimit_seconds,1965'timelimit_intopt': timelimit_intopt,1966'tm_lim_intopt': timelimit_intopt,1967'timelimit_simplex': timelimit_simplex,1968'tm_lim_simplex': timelimit_simplex,1969'simplex_or_intopt': simplex_or_intopt,1970'msg_lev_simplex': msg_lev_simplex, 'verbosity_simplex': msg_lev_simplex,1971'msg_lev_intopt': msg_lev_intopt, 'verbosity_intopt': msg_lev_intopt,1972'br_tech': br_tech, 'branching': br_tech,1973'bt_tech': bt_tech, 'backtracking': bt_tech,1974'pp_tech': pp_tech, 'preprocessing': pp_tech,1975'fp_heur': fp_heur, 'feasibility_pump': fp_heur,1976'gmi_cuts': gmi_cuts, 'gomory_cuts': gmi_cuts,1977'mir_cuts': mir_cuts, 'mixed_int_rounding_cuts': mir_cuts,1978'cov_cuts': cov_cuts, 'mixed_cover_cuts': cov_cuts,1979'clq_cuts': clq_cuts, 'clique_cuts': clq_cuts,1980'tol_int': tol_int, 'absolute_tolerance': tol_int,1981'tol_obj': tol_obj, 'relative_tolerance': tol_obj,1982'mip_gap': mip_gap, 'mip_gap_tolerance': mip_gap,1983'out_frq_intopt': out_frq_intopt, 'output_frequency_intopt': out_frq_intopt,1984'out_dly_intopt': out_dly_intopt, 'output_delay_intopt': out_dly_intopt,1985'presolve_intopt': presolve_intopt, 'binarize': binarize,1986'meth': meth, 'primal_v_dual': meth,1987'pricing': pricing,1988'r_test': r_test, 'ratio_test': r_test,1989'tol_bnd': tol_bnd, 'tolerance_primal': tol_bnd,1990'tol_dj': tol_dj, 'tolerance_dual': tol_dj,1991'tol_piv': tol_piv, 'tolerance_pivot': tol_piv,1992'obj_ll': obj_ll, 'obj_lower_limit': obj_ll,1993'obj_ul': obj_ul, 'obj_upper_limit': obj_ul,1994'it_lim': it_lim, 'iteration_limit': it_lim,1995'out_frq_simplex': out_frq_simplex, 'output_frequency_intopt': out_frq_simplex,1996'out_dly_simplex': out_dly_simplex, 'output_delay_simplex': out_dly_simplex,1997'presolve_simplex': presolve_simplex1998}19992000# parameter values20012002glp_msg_off = GLP_MSG_OFF2003glp_msg_on = GLP_MSG_ON2004glp_msg_err = GLP_MSG_ERR2005glp_msg_all = GLP_MSG_ALL2006glp_msg_dbg = GLP_MSG_DBG20072008glp_primal = GLP_PRIMAL2009glp_dual = GLP_DUAL2010glp_dualp = GLP_DUALP20112012glp_pt_std = GLP_PT_STD2013glp_pt_pse = GLP_PT_PSE20142015glp_rt_std = GLP_RT_STD2016glp_rt_har = GLP_RT_HAR20172018dbl_max = DBL_MAX2019int_max = INT_MAX20202021glp_on = GLP_ON2022glp_off = GLP_OFF20232024glp_br_ffv = GLP_BR_FFV2025glp_br_lfv = GLP_BR_LFV2026glp_br_mfv = GLP_BR_MFV2027glp_br_dth = GLP_BR_DTH2028glp_br_pch = GLP_BR_PCH20292030glp_bt_dfs = GLP_BT_DFS2031glp_bt_bfs = GLP_BT_BFS2032glp_bt_blb = GLP_BT_BLB2033glp_bt_bph = GLP_BT_BPH20342035glp_pp_none = GLP_PP_NONE2036glp_pp_root = GLP_PP_ROOT2037glp_pp_all = GLP_PP_ALL20382039glp_max = GLP_MAX2040glp_min = GLP_MIN2041glp_up = GLP_UP2042glp_fr = GLP_FR2043glp_db = GLP_DB2044glp_fx = GLP_FX2045glp_lo = GLP_LO2046glp_cv = GLP_CV2047glp_iv = GLP_IV2048glp_bv = GLP_BV2049glp_mps_deck = GLP_MPS_DECK2050glp_mps_file = GLP_MPS_FILE20512052glp_undef = GLP_UNDEF2053glp_opt = GLP_OPT2054glp_feas = GLP_FEAS2055glp_nofeas = GLP_NOFEAS20562057cdef enum more_parameter_values:2058simplex_only, simplex_then_intopt, intopt_only20592060glp_simplex_only = simplex_only2061glp_simplex_then_intopt = simplex_then_intopt2062glp_intopt_only = intopt_only20632064# dictionaries for those who prefer to use strings20652066solver_parameter_values = {20672068'simplex_only': simplex_only,2069'simplex_then_intopt': simplex_then_intopt,2070'intopt_only': intopt_only,20712072'GLP_MSG_OFF' : GLP_MSG_OFF,2073'GLP_MSG_ON' : GLP_MSG_ON,2074'GLP_MSG_ERR' : GLP_MSG_ERR,2075'GLP_MSG_ALL' : GLP_MSG_ALL,2076'GLP_MSG_DBG' : GLP_MSG_DBG,20772078'GLP_PRIMAL' : GLP_PRIMAL,2079'GLP_DUAL' : GLP_DUAL,2080'GLP_DUALP' : GLP_DUALP,20812082'GLP_PT_STD' : GLP_PT_STD,2083'GLP_PT_PSE' : GLP_PT_PSE,20842085'GLP_RT_STD' : GLP_RT_STD,2086'GLP_RT_HAR' : GLP_RT_HAR,20872088'DBL_MAX' : DBL_MAX,2089'INT_MAX' : INT_MAX,20902091'GLP_ON' : GLP_ON,2092'GLP_OFF' : GLP_OFF,20932094'GLP_BR_FFV' : GLP_BR_FFV,2095'GLP_BR_LFV' : GLP_BR_LFV,2096'GLP_BR_MFV' : GLP_BR_MFV,2097'GLP_BR_DTH' : GLP_BR_DTH,2098'GLP_BR_PCH' : GLP_BR_PCH,20992100'GLP_BT_DFS' : GLP_BT_DFS,2101'GLP_BT_BFS' : GLP_BT_BFS,2102'GLP_BT_BLB' : GLP_BT_BLB,2103'GLP_BT_BPH' : GLP_BT_BPH,21042105'GLP_PP_NONE' : GLP_PP_NONE,2106'GLP_PP_ROOT' : GLP_PP_ROOT,2107'GLP_PP_ALL' : GLP_PP_ALL,21082109'GLP_MAX' : GLP_MAX,2110'GLP_MIN' : GLP_MIN,2111'GLP_UP' : GLP_UP,2112'GLP_FR' : GLP_FR,2113'GLP_DB' : GLP_DB,2114'GLP_FX' : GLP_FX,2115'GLP_LO' : GLP_LO,2116'GLP_CV' : GLP_CV,2117'GLP_IV' : GLP_IV,2118'GLP_BV' : GLP_BV,2119'GLP_MPS_DECK' : GLP_MPS_DECK,2120'GLP_MPS_FILE' : GLP_MPS_FILE,21212122'GLP_UNDEF' : GLP_UNDEF,2123'GLP_OPT' : GLP_OPT,2124'GLP_FEAS' : GLP_FEAS,2125'GLP_NOFEAS' : GLP_NOFEAS21262127}212821292130