Path: blob/master/src/sage/numerical/backends/gurobi_backend.pyx
8815 views
"""1Gurobi Backend23AUTHORS:45- Nathann Cohen (2011-10): initial implementation67TESTS:89Bug from :trac:`12833`::1011sage: g = DiGraph('IESK@XgAbCgH??KG??')12sage: g.feedback_edge_set(value_only = True, constraint_generation = False)13714sage: g.feedback_edge_set(value_only = True, constraint_generation = False, solver = "Gurobi") # optional - Gurobi1571617Methods18-------19"""2021##############################################################################22# Copyright (C) 2010 Nathann Cohen <[email protected]>23# Distributed under the terms of the GNU General Public License (GPL)24# The full text of the GPL is available at:25# http://www.gnu.org/licenses/26##############################################################################2728from sage.numerical.mip import MIPSolverException2930cdef class GurobiBackend(GenericBackend):31def __init__(self, maximization = True):32"""33Constructor3435EXAMPLE::3637sage: p = MixedIntegerLinearProgram(solver="Gurobi") # optional - Gurobi38"""39cdef int error4041# Initializing the master Environment. This one is kept to be42# deallocated on __dealloc__43error = GRBloadenv(&self.env_master, NULL)4445if self.env_master == NULL:46raise RuntimeError("Could not initialize Gurobi environment")4748check(self.env_master, error)4950# Initializing the model51error = GRBnewmodel(self.env_master, &self.model, NULL, 0, NULL, NULL, NULL, NULL, NULL)5253self.env = GRBgetenv (self.model)5455if error:56raise RuntimeError("Could not initialize Gurobi model")5758if maximization:59error = GRBsetintattr(self.model, "ModelSense", -1)60else:61error = GRBsetintattr(self.model, "ModelSense", +1)6263check(self.env, error)6465self.set_sense(1 if maximization else -1)6667self.set_verbosity(0)68self.obj_constant_term = 0.06970cpdef int add_variable(self, lower_bound=0.0, upper_bound=None, binary=False, continuous=False, integer=False, obj=0.0, name=None) except -1:71"""72Add a variable.7374This amounts to adding a new column to the matrix. By default,75the variable is both positive, real and the coefficient in the76objective function is 0.0.7778INPUT:7980- ``lower_bound`` - the lower bound of the variable (default: 0)8182- ``upper_bound`` - the upper bound of the variable (default: ``None``)8384- ``binary`` - ``True`` if the variable is binary (default: ``False``).8586- ``continuous`` - ``True`` if the variable is binary (default: ``True``).8788- ``integer`` - ``True`` if the variable is binary (default: ``False``).8990- ``obj`` - (optional) coefficient of this variable in the objective function (default: 0.0)9192- ``name`` - an optional name for the newly added variable (default: ``None``).9394OUTPUT: The index of the newly created variable9596EXAMPLE::9798sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi99sage: p = get_solver(solver = "Gurobi") # optional - Gurobi100sage: p.ncols() # optional - Gurobi1010102sage: p.add_variable() # optional - Gurobi1030104sage: p.ncols() # optional - Gurobi1051106sage: p.add_variable(binary=True) # optional - Gurobi1071108sage: p.add_variable(lower_bound=-2.0, integer=True) # optional - Gurobi1092110sage: p.add_variable(continuous=True, integer=True) # optional - Gurobi111Traceback (most recent call last):112...113ValueError: ...114sage: p.add_variable(name='x',obj=1.0) # optional - Gurobi1153116sage: p.col_name(3) # optional - Gurobi117'x'118sage: p.objective_coefficient(3) # optional - Gurobi1191.0120"""121# Checking the input122cdef char vtype = int(bool(binary)) + int(bool(continuous)) + int(bool(integer))123if vtype == 0:124continuous = True125elif vtype != 1:126raise ValueError("Exactly one parameter of 'binary', 'integer' and 'continuous' must be 'True'.")127128cdef int error129130if binary:131vtype = GRB_BINARY132elif continuous:133vtype = GRB_CONTINUOUS134elif integer:135vtype = GRB_INTEGER136137cdef char * c_name = ""138139if name is None:140name = "x_"+str(self.ncols())141142c_name = name143144if upper_bound is None:145upper_bound = GRB_INFINITY146if lower_bound is None:147lower_bound = -GRB_INFINITY148149150error = GRBaddvar(self.model, 0, NULL, NULL, obj, <double> lower_bound, <double> upper_bound, vtype, c_name)151152check(self.env,error)153154check(self.env,GRBupdatemodel(self.model))155156return self.ncols()-1157158cpdef 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:159"""160Add ``number`` new variables.161162This amounts to adding new columns to the matrix. By default,163the variables are both positive, real and theor coefficient in164the objective function is 0.0.165166INPUT:167168- ``n`` - the number of new variables (must be > 0)169170- ``lower_bound`` - the lower bound of the variable (default: 0)171172- ``upper_bound`` - the upper bound of the variable (default: ``None``)173174- ``binary`` - ``True`` if the variable is binary (default: ``False``).175176- ``continuous`` - ``True`` if the variable is binary (default: ``True``).177178- ``integer`` - ``True`` if the variable is binary (default: ``False``).179180- ``obj`` - (optional) coefficient of all variables in the objective function (default: 0.0)181182- ``names`` - optional list of names (default: ``None``)183184OUTPUT: The index of the variable created last.185186EXAMPLE::187188sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi189sage: p = get_solver(solver = "Gurobi") # optional - Gurobi190sage: p.ncols() # optional - Gurobi1910192sage: p.add_variables(5) # optional - Gurobi1934194sage: p.ncols() # optional - Gurobi1955196sage: p.add_variables(2, lower_bound=-2.0, integer=True, names=['a','b']) # optional - Gurobi1976198"""199cdef int i200cdef int value201for i in range(number):202value = self.add_variable(lower_bound = lower_bound,203upper_bound = upper_bound,204binary = binary,205continuous = continuous,206integer = integer,207obj = obj,208name = None if names is None else names[i])209return value210211cpdef set_variable_type(self, int variable, int vtype):212"""213Set the type of a variable214215INPUT:216217- ``variable`` (integer) -- the variable's id218219- ``vtype`` (integer) :220221* 1 Integer222* 0 Binary223* -1 Real224225EXAMPLE::226227sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi228sage: p = get_solver(solver = "Gurobi") # optional - Gurobi229sage: p.ncols() # optional - Gurobi2300231sage: p.add_variable() # optional - Gurobi2320233sage: p.set_variable_type(0,1) # optional - Gurobi234sage: p.is_variable_integer(0) # optional - Gurobi235True236"""237cdef int error238239if vtype == 1:240error = GRBsetcharattrelement(self.model, "VType", variable, 'I')241elif vtype == 0:242error = GRBsetcharattrelement(self.model, "VType", variable, 'B')243else:244error = GRBsetcharattrelement(self.model, "VType", variable, 'C')245check(self.env, error)246247check(self.env,GRBupdatemodel(self.model))248249cpdef set_sense(self, int sense):250"""251Set the direction (maximization/minimization).252253INPUT:254255- ``sense`` (integer) :256257* +1 => Maximization258* -1 => Minimization259260EXAMPLE::261262sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi263sage: p = get_solver(solver = "Gurobi") # optional - Gurobi264sage: p.is_maximization() # optional - Gurobi265True266sage: p.set_sense(-1) # optional - Gurobi267sage: p.is_maximization() # optional - Gurobi268False269"""270cdef int error271272if sense == 1:273error = GRBsetintattr(self.model, "ModelSense", -1)274else:275error = GRBsetintattr(self.model, "ModelSense", +1)276277check(self.env, error)278check(self.env,GRBupdatemodel(self.model))279280cpdef objective_coefficient(self, int variable, coeff=None):281"""282Set or get the coefficient of a variable in the objective function283284INPUT:285286- ``variable`` (integer) -- the variable's id287288- ``coeff`` (double) -- its coefficient or ``None`` for289reading (default: ``None``)290291EXAMPLE::292293sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi294sage: p = get_solver(solver = "Gurobi") # optional - Gurobi295sage: p.add_variable() # optional - Gurobi2960297sage: p.objective_coefficient(0) == 0 # optional - Gurobi298True299sage: p.objective_coefficient(0,2) # optional - Gurobi300sage: p.objective_coefficient(0) # optional - Gurobi3012.0302"""303cdef int error304cdef double value[1]305306if coeff:307error = GRBsetdblattrelement(self.model, "Obj", variable, coeff)308check(self.env, error)309check(self.env,GRBupdatemodel(self.model))310else:311error = GRBgetdblattrelement(self.model, "Obj", variable, value)312check(self.env, error)313return value[0]314315cpdef problem_name(self, char * name = NULL):316"""317Return or define the problem's name318319INPUT:320321- ``name`` (``char *``) -- the problem's name. When set to322``NULL`` (default), the method returns the problem's name.323324EXAMPLE::325326sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi327sage: p = get_solver(solver = "Gurobi") # optional - Gurobi328sage: p.problem_name("There once was a french fry") # optional - Gurobi329sage: print p.problem_name() # optional - Gurobi330There once was a french fry331332TESTS::333334sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi335sage: p = get_solver(solver = "Gurobi") # optional - Gurobi336sage: print p.problem_name() # optional - Gurobi337"""338cdef int error339cdef char * pp_name[1]340341if name:342error = GRBsetstrattr(self.model, "ModelName", name)343check(self.env, error)344check(self.env,GRBupdatemodel(self.model))345346else:347check(self.env,GRBgetstrattr(self.model, "ModelName", <char **> pp_name))348if pp_name[0] == NULL:349value = ""350else:351value = str(pp_name[0])352353return value354355cpdef set_objective(self, list coeff, d = 0.0):356"""357Set the objective function.358359INPUT:360361- ``coeff`` - a list of real values, whose ith element is the362coefficient of the ith variable in the objective function.363364- ``d`` (double) -- the constant term in the linear function (set to `0` by default)365366EXAMPLE::367368sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi369sage: p = get_solver(solver = "Gurobi") # optional - Gurobi370sage: p.add_variables(5) # optional - Gurobi3714372sage: p.set_objective([1, 1, 2, 1, 3]) # optional - Gurobi373sage: map(lambda x :p.objective_coefficient(x), range(5)) # optional - Gurobi374[1.0, 1.0, 2.0, 1.0, 3.0]375376Constants in the objective function are respected::377378sage: p = MixedIntegerLinearProgram(solver='Gurobi')# optional - Gurobi379sage: x,y = p[0], p[1] # optional - Gurobi380sage: p.add_constraint(2*x + 3*y, max = 6) # optional - Gurobi381sage: p.add_constraint(3*x + 2*y, max = 6) # optional - Gurobi382sage: p.set_objective(x + y + 7) # optional - Gurobi383sage: p.set_integer(x); p.set_integer(y) # optional - Gurobi384sage: p.solve() # optional - Gurobi3859.0386"""387cdef int i = 0388cdef double value389cdef int error390391for value in coeff:392error = GRBsetdblattrelement (self.model, "Obj", i, value)393check(self.env,error)394i += 1395396check(self.env,GRBupdatemodel(self.model))397398self.obj_constant_term = d399400cpdef set_verbosity(self, int level):401"""402Set the verbosity level403404INPUT:405406- ``level`` (integer) -- From 0 (no verbosity) to 3.407408EXAMPLE::409410sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi411sage: p = get_solver(solver = "Gurobi") # optional - Gurobi412sage: p.set_verbosity(2) # optional - Gurobi413414"""415cdef int error416if level:417error = GRBsetintparam(self.env, "OutputFlag", 1)418else:419error = GRBsetintparam(self.env, "OutputFlag", 0)420421check(self.env, error)422423cpdef remove_constraint(self, int i):424r"""425Remove a constraint from self.426427INPUT:428429- ``i`` -- index of the constraint to remove430431EXAMPLE::432433sage: p = MixedIntegerLinearProgram(solver='Gurobi')# optional - Gurobi434sage: x,y = p[0], p[1] # optional - Gurobi435sage: p.add_constraint(2*x + 3*y, max = 6) # optional - Gurobi436sage: p.add_constraint(3*x + 2*y, max = 6) # optional - Gurobi437sage: p.set_objective(x + y + 7) # optional - Gurobi438sage: p.set_integer(x); p.set_integer(y) # optional - Gurobi439sage: p.solve() # optional - Gurobi4409.0441sage: p.remove_constraint(0) # optional - Gurobi442sage: p.solve() # optional - Gurobi44310.0444sage: p.get_values([x,y]) # optional - Gurobi445[0.0, 3.0]446"""447cdef int ind[1]448ind[0] = i449cdef int error450error = GRBdelconstrs (self.model, 1, ind )451check(self.env, error)452453error = GRBupdatemodel(self.model)454check(self.env,error)455456cpdef add_linear_constraint(self, coefficients, lower_bound, upper_bound, name=None):457"""458Add a linear constraint.459460INPUT:461462- ``coefficients`` an iterable with ``(c,v)`` pairs where ``c``463is a variable index (integer) and ``v`` is a value (real464value).465466- ``lower_bound`` - a lower bound, either a real value or ``None``467468- ``upper_bound`` - an upper bound, either a real value or ``None``469470- ``name`` - an optional name for this row (default: ``None``)471472EXAMPLE::473474sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi475sage: p = get_solver(solver = "Gurobi") # optional - Gurobi476sage: p.add_variables(5) # optional - Gurobi4774478sage: p.add_linear_constraint( zip(range(5), range(5)), 2.0, 2.0) # optional - Gurobi479sage: p.row(0) # optional - Gurobi480([0, 1, 2, 3, 4], [0.0, 1.0, 2.0, 3.0, 4.0])481sage: p.row_bounds(0) # optional - Gurobi482(2.0, 2.0)483sage: p.add_linear_constraint( zip(range(5), range(5)), 1.0, 1.0, name='foo') # optional - Gurobi484sage: p.row_name(1) # optional - Gurobi485'foo'486"""487488if lower_bound is None and upper_bound is None:489raise ValueError("At least one of 'upper_bound' or 'lower_bound' must be set.")490491cdef int * row_i492cdef double * row_values493494row_i = <int *> sage_malloc((len(coefficients)) * sizeof(int))495row_values = <double *> sage_malloc((len(coefficients)) * sizeof(double))496497498for i,(c,v) in enumerate(coefficients):499row_i[i] = c500row_values[i] = v501502if name is None:503name = ""504505if upper_bound is not None and lower_bound is None:506error = GRBaddconstr(self.model, len(coefficients), row_i, row_values, GRB_LESS_EQUAL, <double> upper_bound, name)507508elif lower_bound is not None and upper_bound is None:509error = GRBaddconstr(self.model, len(coefficients), row_i, row_values, GRB_GREATER_EQUAL, <double> lower_bound, name)510511elif upper_bound is not None and lower_bound is not None:512if lower_bound == upper_bound:513error = GRBaddconstr(self.model, len(coefficients), row_i, row_values, GRB_EQUAL, <double> lower_bound, name)514515else:516error = GRBaddrangeconstr(self.model, len(coefficients), row_i, row_values, <double> lower_bound, <double> upper_bound, name)517518check(self.env,error)519520error = GRBupdatemodel(self.model)521522check(self.env,error)523524sage_free(row_i)525sage_free(row_values)526527cpdef row(self, int index):528r"""529Return a row530531INPUT:532533- ``index`` (integer) -- the constraint's id.534535OUTPUT:536537A pair ``(indices, coeffs)`` where ``indices`` lists the538entries whose coefficient is nonzero, and to which ``coeffs``539associates their coefficient on the model of the540``add_linear_constraint`` method.541542EXAMPLE::543544sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi545sage: p = get_solver(solver = "Gurobi") # optional - Gurobi546sage: p.add_variables(5) # optional - Gurobi5474548sage: p.add_linear_constraint(zip(range(5), range(5)), 2, 2) # optional - Gurobi549sage: p.row(0) # optional - Gurobi550([0, 1, 2, 3, 4], [0.0, 1.0, 2.0, 3.0, 4.0])551sage: p.row_bounds(0) # optional - Gurobi552(2.0, 2.0)553"""554cdef int error555cdef int fake[1]556557cdef int length[1]558error = GRBgetconstrs(self.model, length, NULL, NULL, NULL, index, 1 )559check(self.env,error)560561cdef int * p_indices = <int *> sage_malloc(length[0] * sizeof(int))562cdef double * p_values = <double *> sage_malloc(length[0] * sizeof(double))563564error = GRBgetconstrs(self.model, length, <int *> fake, p_indices, p_values, index, 1 )565check(self.env,error)566567cdef list indices = []568cdef list values = []569570cdef int i571for i in range(length[0]):572indices.append(p_indices[i])573values.append(p_values[i])574575sage_free(p_indices)576sage_free(p_values)577578return indices, values579580581cpdef row_bounds(self, int index):582"""583Return the bounds of a specific constraint.584585INPUT:586587- ``index`` (integer) -- the constraint's id.588589OUTPUT:590591A pair ``(lower_bound, upper_bound)``. Each of them can be set592to ``None`` if the constraint is not bounded in the593corresponding direction, and is a real value otherwise.594595EXAMPLE::596597sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi598sage: p = get_solver(solver = "Gurobi") # optional - Gurobi599sage: p.add_variables(5) # optional - Gurobi6004601sage: p.add_linear_constraint(zip(range(5), range(5)), 2, 2) # optional - Gurobi602sage: p.row(0) # optional - Gurobi603([0, 1, 2, 3, 4], [0.0, 1.0, 2.0, 3.0, 4.0])604sage: p.row_bounds(0) # optional - Gurobi605(2.0, 2.0)606"""607cdef double d[1]608cdef char sense[1]609cdef int error610611error = GRBgetcharattrelement(self.model, "Sense", index, <char *> sense)612check(self.env, error)613614error = GRBgetdblattrelement(self.model, "RHS", index, <double *> d)615check(self.env, error)616617if sense[0] == '>':618return (d[0], None)619elif sense[0] == '<':620return (None, d[0])621else:622return (d[0],d[0])623624cpdef col_bounds(self, int index):625"""626Return the bounds of a specific variable.627628INPUT:629630- ``index`` (integer) -- the variable's id.631632OUTPUT:633634A pair ``(lower_bound, upper_bound)``. Each of them can be set635to ``None`` if the variable is not bounded in the636corresponding direction, and is a real value otherwise.637638EXAMPLE::639640sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi641sage: p = get_solver(solver = "Gurobi") # optional - Gurobi642sage: p.add_variable() # optional - Gurobi6430644sage: p.col_bounds(0) # optional - Gurobi645(0.0, None)646sage: p.variable_upper_bound(0, 5) # optional - Gurobi647sage: p.col_bounds(0) # optional - Gurobi648(0.0, 5.0)649"""650651cdef double lb[1], ub[1]652653error = GRBgetdblattrelement(self.model, "LB", index, <double *> lb)654check(self.env, error)655656error = GRBgetdblattrelement(self.model, "UB", index, <double *> ub)657check(self.env, error)658659return (None if lb[0] <= -2147483647 else lb[0],660None if ub[0] >= 2147483647 else ub[0])661662cpdef int solve(self) except -1:663"""664Solve the problem.665666.. NOTE::667668This method raises ``MIPSolverException`` exceptions when669the solution can not be computed for any reason (none670exists, or the LP solver was not able to find it, etc...)671672EXAMPLE::673674sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi675sage: p = get_solver(solver = "Gurobi") # optional - Gurobi676sage: p.add_variables(5) # optional - Gurobi6774678sage: p.add_linear_constraint([(0,1), (1, 1)], 1.2, 1.7) # optional - Gurobi679sage: p.set_variable_type(0, 1) # optional - Gurobi680sage: p.set_variable_type(1, 1) # optional - Gurobi681sage: p.solve() # optional - Gurobi682Traceback (most recent call last):683...684MIPSolverException: 'Gurobi: The problem is infeasible'685"""686cdef int error687global mip_status688689check(self.env, GRBoptimize(self.model))690691cdef int status[1]692check(self.env, GRBgetintattr(self.model, "Status", <int *> status))693694# Has there been a problem ?695if status[0] != GRB_OPTIMAL:696raise MIPSolverException("Gurobi: "+mip_status.get(status[0], "unknown error during call to GRBoptimize : "+str(status[0])))697698699cpdef get_objective_value(self):700"""701Returns the value of the objective function.702703.. NOTE::704705Behaviour is undefined unless ``solve`` has been called before.706707EXAMPLE::708709sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi710sage: p = get_solver(solver = "Gurobi") # optional - Gurobi711sage: p.add_variables(2) # optional - Gurobi7121713sage: p.add_linear_constraint([[0, 1], [1, 2]], None, 3) # optional - Gurobi714sage: p.set_objective([2, 5]) # optional - Gurobi715sage: p.solve() # optional - Gurobi7160717sage: p.get_objective_value() # optional - Gurobi7187.5719sage: p.get_variable_value(0) # optional - Gurobi7200.0721sage: p.get_variable_value(1) # optional - Gurobi7221.5723"""724cdef double p_value[1]725726check(self.env,GRBgetdblattr(self.model, "ObjVal", <double* >p_value))727728return p_value[0] + self.obj_constant_term729730cpdef get_variable_value(self, int variable):731"""732Returns the value of a variable given by the solver.733734.. NOTE::735736Behaviour is undefined unless ``solve`` has been called before.737738EXAMPLE::739740sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi741sage: p = get_solver(solver = "Gurobi") # optional - Gurobi742sage: p.add_variables(2) # optional - Gurobi7431744sage: p.add_linear_constraint([[0, 1], [1, 2]], None, 3) # optional - Gurobi745sage: p.set_objective([2, 5]) # optional - Gurobi746sage: p.solve() # optional - Gurobi7470748sage: p.get_objective_value() # optional - Gurobi7497.5750sage: p.get_variable_value(0) # optional - Gurobi7510.0752sage: p.get_variable_value(1) # optional - Gurobi7531.5754"""755756cdef double value[1]757check(self.env,GRBgetdblattrelement(self.model, "X", variable, value))758return round(value[0]) if self.is_variable_binary(variable) else value[0]759760cpdef int ncols(self):761"""762Return the number of columns/variables.763764EXAMPLE::765766sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi767sage: p = get_solver(solver = "Gurobi") # optional - Gurobi768sage: p.ncols() # optional - Gurobi7690770sage: p.add_variables(2) # optional - Gurobi7711772sage: p.ncols() # optional - Gurobi7732774"""775cdef int i[1]776check(self.env,GRBgetintattr(self.model, "NumVars", i))777return i[0]778779cpdef int nrows(self):780"""781Return the number of rows/constraints.782783EXAMPLE::784785sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi786sage: p = get_solver(solver = "Gurobi") # optional - Gurobi787sage: p.nrows() # optional - Gurobi7880789sage: p.add_linear_constraint([], 2, None) # optional - Gurobi790sage: p.add_linear_constraint([], 2, None) # optional - Gurobi791sage: p.nrows() # optional - Gurobi7922793"""794cdef int i[1]795check(self.env,GRBgetintattr(self.model, "NumConstrs", i))796return i[0]797798cpdef col_name(self, int index):799"""800Return the ``index`` th col name801802INPUT:803804- ``index`` (integer) -- the col's id805806EXAMPLE::807808sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi809sage: p = get_solver(solver = "Gurobi") # optional - Gurobi810sage: p.add_variable(name='I am a variable') # optional - Gurobi8110812sage: p.col_name(0) # optional - Gurobi813'I am a variable'814"""815cdef char * name[1]816check(self.env,GRBgetstrattrelement(self.model, "VarName", index, <char **> name))817if name[0] == NULL:818value = ""819else:820value = str(name[0])821return value822823cpdef row_name(self, int index):824"""825Return the ``index`` th row name826827INPUT:828829- ``index`` (integer) -- the row's id830831EXAMPLE::832833sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi834sage: p = get_solver(solver = "Gurobi") # optional - Gurobi835sage: p.add_linear_constraint([], 2, None, name='Empty constraint 1') # optional - Gurobi836sage: p.row_name(0) # optional - Gurobi837'Empty constraint 1'838"""839cdef char * name[1]840check(self.env,GRBgetstrattrelement(self.model, "ConstrName", index, <char **> name))841if name[0] == NULL:842value = ""843else:844value = str(name[0])845return value846847cpdef bint is_variable_binary(self, int index):848"""849Test whether the given variable is of binary type.850851INPUT:852853- ``index`` (integer) -- the variable's id854855EXAMPLE::856857sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi858sage: p = get_solver(solver = "Gurobi") # optional - Gurobi859sage: p.ncols() # optional - Gurobi8600861sage: p.add_variable() # optional - Gurobi8620863sage: p.set_variable_type(0,0) # optional - Gurobi864sage: p.is_variable_binary(0) # optional - Gurobi865True866"""867cdef char vtype[1]868check(self.env, GRBgetcharattrelement(self.model, "VType", index, <char *> vtype))869return vtype[0] == 'B'870871872cpdef bint is_variable_integer(self, int index):873"""874Test whether the given variable is of integer type.875876INPUT:877878- ``index`` (integer) -- the variable's id879880EXAMPLE::881882sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi883sage: p = get_solver(solver = "Gurobi") # optional - Gurobi884sage: p.ncols() # optional - Gurobi8850886sage: p.add_variable() # optional - Gurobi8870888sage: p.set_variable_type(0,1) # optional - Gurobi889sage: p.is_variable_integer(0) # optional - Gurobi890True891"""892cdef char vtype[1]893check(self.env, GRBgetcharattrelement(self.model, "VType", index, <char *> vtype))894return vtype[0] == 'I'895896cpdef bint is_variable_continuous(self, int index):897"""898Test whether the given variable is of continuous/real type.899900INPUT:901902- ``index`` (integer) -- the variable's id903904EXAMPLE::905906sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi907sage: p = get_solver(solver = "Gurobi") # optional - Gurobi908sage: p.ncols() # optional - Gurobi9090910sage: p.add_variable() # optional - Gurobi9110912sage: p.is_variable_continuous(0) # optional - Gurobi913True914sage: p.set_variable_type(0,1) # optional - Gurobi915sage: p.is_variable_continuous(0) # optional - Gurobi916False917918"""919cdef char vtype[1]920check(self.env, GRBgetcharattrelement(self.model, "VType", index, <char *> vtype))921return vtype[0] == 'C'922923cpdef bint is_maximization(self):924"""925Test whether the problem is a maximization926927EXAMPLE::928929sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi930sage: p = get_solver(solver = "Gurobi") # optional - Gurobi931sage: p.is_maximization() # optional - Gurobi932True933sage: p.set_sense(-1) # optional - Gurobi934sage: p.is_maximization() # optional - Gurobi935False936"""937cdef int sense[1]938check(self.env,GRBgetintattr(self.model, "ModelSense", <int *> sense))939return sense[0] == -1940941cpdef variable_upper_bound(self, int index, value = False):942"""943Return or define the upper bound on a variable944945INPUT:946947- ``index`` (integer) -- the variable's id948949- ``value`` -- real value, or ``None`` to mean that the950variable has not upper bound. When set to ``False``951(default), the method returns the current value.952953EXAMPLE::954955sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi956sage: p = get_solver(solver = "Gurobi") # optional - Gurobi957sage: p.add_variable() # optional - Gurobi9580959sage: p.col_bounds(0) # optional - Gurobi960(0.0, None)961sage: p.variable_upper_bound(0, 5) # optional - Gurobi962sage: p.col_bounds(0) # optional - Gurobi963(0.0, 5.0)964"""965cdef double b[1]966967if not value is False:968check(self.env, GRBsetdblattrelement(969self.model, "UB",970index,971value if value is not None else GRB_INFINITY))972973check(self.env,GRBupdatemodel(self.model))974else:975error = GRBgetdblattrelement(self.model, "UB", index, <double *> b)976check(self.env, error)977return None if b[0] >= 2147483647 else b[0]978979cpdef variable_lower_bound(self, int index, value = False):980"""981Return or define the lower bound on a variable982983INPUT:984985- ``index`` (integer) -- the variable's id986987- ``value`` -- real value, or ``None`` to mean that the988variable has not lower bound. When set to ``False``989(default), the method returns the current value.990991EXAMPLE::992993sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi994sage: p = get_solver(solver = "Gurobi") # optional - Gurobi995sage: p.add_variable() # optional - Gurobi9960997sage: p.col_bounds(0) # optional - Gurobi998(0.0, None)999sage: p.variable_lower_bound(0, 5) # optional - Gurobi1000sage: p.col_bounds(0) # optional - Gurobi1001(5.0, None)1002"""1003cdef double b[1]100410051006if not value is False:1007check(self.env, GRBsetdblattrelement(1008self.model, "LB",1009index,1010value if value is not None else -GRB_INFINITY))10111012check(self.env,GRBupdatemodel(self.model))10131014else:1015error = GRBgetdblattrelement(self.model, "LB", index, <double *> b)1016check(self.env, error)1017return None if b[0] <= -2147483647 else b[0]10181019cpdef write_lp(self, char * filename):1020"""1021Write the problem to a .lp file10221023INPUT:10241025- ``filename`` (string)10261027EXAMPLE::10281029sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi1030sage: p = get_solver(solver = "Gurobi") # optional - Gurobi1031sage: p.add_variables(2) # optional - Gurobi103211033sage: p.add_linear_constraint([[0, 1], [1, 2]], None, 3) # optional - Gurobi1034sage: p.set_objective([2, 5]) # optional - Gurobi1035sage: p.write_lp(os.path.join(SAGE_TMP, "lp_problem.lp")) # optional - Gurobi1036"""1037check(self.env, GRBwrite(self.model, filename))10381039cpdef write_mps(self, char * filename, int modern):1040"""1041Write the problem to a .mps file10421043INPUT:10441045- ``filename`` (string)10461047EXAMPLE::10481049sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi1050sage: p = get_solver(solver = "Gurobi") # optional - Gurobi1051sage: p.add_variables(2) # optional - Gurobi105211053sage: p.add_linear_constraint([[0, 1], [1, 2]], None, 3) # optional - Gurobi1054sage: p.set_objective([2, 5]) # optional - Gurobi1055sage: p.write_lp(os.path.join(SAGE_TMP, "lp_problem.lp")) # optional - Gurobi1056"""1057check(self.env, GRBwrite(self.model, filename))10581059cpdef solver_parameter(self, name, value = None):1060"""1061Returns or defines a solver parameter.10621063For a list of parameters and associated values, please refer to Gurobi's1064reference manual1065`<http://www.gurobi.com/documentation/5.5/reference-manual/node798>`_.10661067INPUT:10681069- ``name`` (string) -- the parameter10701071- ``value`` -- the parameter's value if it is to be defined,1072or ``None`` (default) to obtain its current value.10731074EXAMPLES::10751076sage: p = MixedIntegerLinearProgram(solver="Gurobi") # optional - Gurobi10771078An integer parameter::10791080sage: p.solver_parameter("VarBranch") # optional - Gurobi1081-11082sage: p.solver_parameter("VarBranch", 1) # optional - Gurobi1083sage: p.solver_parameter("VarBranch") # optional - Gurobi1084110851086A double parameter::10871088sage: p.solver_parameter("TimeLimit") # optional - Gurobi10891e+1001090sage: p.solver_parameter("TimeLimit", 10) # optional - Gurobi1091sage: p.solver_parameter("TimeLimit") # optional - Gurobi109210.010931094A string parameter::10951096sage: p.solver_parameter("LogFile") # optional - Gurobi1097''1098sage: p.solver_parameter("LogFile", "/dev/null") # optional - Gurobi1099sage: p.solver_parameter("LogFile") # optional - Gurobi1100'/dev/null'11011102"""1103cdef int tmp_int[1]1104cdef double tmp_dbl[1]1105cdef char tmp_str[25500]1106cdef char * c_name1107c_name = tmp_str11081109if name == "timelimit":1110name = "TimeLimit"11111112try:1113t = parameters_type[name]1114except KeyError:1115raise ValueError("This parameter is not available. "+1116"Enabling it may not be so hard, though.")11171118if t == "int":1119if value is None:1120check(self.env, GRBgetintparam(self.env, name, tmp_int))1121return tmp_int[0]1122else:1123check(self.env, GRBsetintparam(self.env, name, value))1124elif t == "double":1125if value is None:1126check(self.env, GRBgetdblparam(self.env, name, tmp_dbl))1127return tmp_dbl[0]1128else:1129check(self.env, GRBsetdblparam(self.env, name, value))1130elif t == "string":1131if value is None:1132check(self.env, GRBgetstrparam(self.env, name, c_name))1133return str(c_name)1134else:1135check(self.env, GRBsetstrparam(self.env, name, value))1136else:1137raise RuntimeError("This should not happen.")11381139cpdef GurobiBackend copy(self):1140"""1141Returns a copy of self.11421143EXAMPLE::11441145sage: from sage.numerical.backends.generic_backend import get_solver # optional - GUROBI1146sage: p = MixedIntegerLinearProgram(solver = "GUROBI") # optional - GUROBI1147sage: b = p.new_variable() # optional - GUROBI1148sage: p.add_constraint(b[1] + b[2] <= 6) # optional - GUROBI1149sage: p.set_objective(b[1] + b[2]) # optional - GUROBI1150sage: copy(p).solve() # optional - GUROBI11516.01152"""1153cdef GurobiBackend p = GurobiBackend(maximization = self.is_maximization())1154p.model = GRBcopymodel(self.model)1155p.env = GRBgetenv(p.model)1156return p11571158def __dealloc__(self):1159"""1160Destructor1161"""1162GRBfreeenv(self.env)1163GRBfreeenv(self.env_master)1164GRBfreemodel(self.model)11651166cdef dict errors = {116710001 : "GRB_ERROR_OUT_OF_MEMORY",116810002 : "GRB_ERROR_NULL_ARGUMENT",116910003 : "GRB_ERROR_INVALID_ARGUMENT",117010004 : "GRB_ERROR_UNKNOWN_ATTRIBUTE",117110005 : "GRB_ERROR_DATA_NOT_AVAILABLE",117210006 : "GRB_ERROR_INDEX_OUT_OF_RANGE",117310007 : "GRB_ERROR_UNKNOWN_PARAMETER",117410008 : "GRB_ERROR_VALUE_OUT_OF_RANGE",117510009 : "GRB_ERROR_NO_LICENSE",117610010 : "GRB_ERROR_SIZE_LIMIT_EXCEEDED",117710011 : "GRB_ERROR_CALLBACK",117810012 : "GRB_ERROR_FILE_READ",117910013 : "GRB_ERROR_FILE_WRITE",118010014 : "GRB_ERROR_NUMERIC",118110015 : "GRB_ERROR_IIS_NOT_INFEASIBLE",118210016 : "GRB_ERROR_NOT_FOR_MIP",118310017 : "GRB_ERROR_OPTIMIZATION_IN_PROGRESS",118410018 : "GRB_ERROR_DUPLICATES",118510019 : "GRB_ERROR_NODEFILE",118610020 : "GRB_ERROR_Q_NOT_PSD",1187}11881189cdef dict mip_status = {1190GRB_INFEASIBLE: "The problem is infeasible",1191GRB_INF_OR_UNBD: "The problem is infeasible or unbounded",1192GRB_UNBOUNDED: "The problem is unbounded",1193GRB_ITERATION_LIMIT: "The iteration limit has been reached",1194GRB_NODE_LIMIT: "The node limit has been reached",1195GRB_TIME_LIMIT: "The time limit has been reached",1196GRB_SOLUTION_LIMIT: "The solution limit has been reached",1197}11981199cdef dict parameters_type = {1200"AggFill" : "int",1201"Aggregate" : "int",1202"BarConvTol" : "double",1203"BarCorrectors" : "int",1204"BarHomogeneous" : "int",1205"BarOrder" : "int",1206"BarQCPConvTol" : "double",1207"BarIterLimit" : "int",1208"BranchDir" : "int",1209"CliqueCuts" : "int",1210"CoverCuts" : "int",1211"Crossover" : "int",1212"CrossoverBasis" : "int",1213"Cutoff" : "double",1214"CutAggPasses" : "int",1215"CutPasses" : "int",1216"Cuts" : "int",1217"DisplayInterval" : "int",1218"DualReductions" : "int",1219"FeasibilityTol" : "double",1220"FeasRelaxBigM" : "double",1221"FlowCoverCuts" : "int",1222"FlowPathCuts" : "int",1223"GomoryPasses" : "int",1224"GUBCoverCuts" : "int",1225"Heuristics" : "double",1226"IISMethod" : "int",1227"ImpliedCuts" : "int",1228"ImproveStartGap" : "double",1229"ImproveStartNodes" : "double",1230"ImproveStartTime" : "double",1231"InfUnbdInfo" : "int",1232"InputFile" : "string",1233"IntFeasTol" : "double",1234"IterationLimit" : "double",1235"LogFile" : "string",1236"LogToConsole" : "int",1237"MarkowitzTol" : "double",1238"Method" : "int",1239"MinRelNodes" : "int",1240"MIPFocus" : "int",1241"MIPGap" : "double",1242"MIPGapAbs" : "double",1243"MIPSepCuts" : "int",1244"MIQCPMethod" : "int",1245"MIRCuts" : "int",1246"ModKCuts" : "int",1247"NetworkCuts" : "int",1248"NodefileDir" : "string",1249"NodefileStart" : "double",1250"NodeLimit" : "double",1251"NodeMethod" : "int",1252"NormAdjust" : "int",1253"ObjScale" : "double",1254"OptimalityTol" : "double",1255"OutputFlag" : "int",1256"PerturbValue" : "double",1257"PreCrush" : "int",1258"PreDepRow" : "int",1259"PreDual" : "int",1260"PrePasses" : "int",1261"PreQLinearize" : "int",1262"Presolve" : "int",1263"PreSparsify" : "int",1264"PSDTol" : "double",1265"PumpPasses" : "int",1266"QCPDual" : "int",1267"Quad" : "int",1268"ResultFile" : "string",1269"RINS" : "int",1270"ScaleFlag" : "int",1271"Seed" : "int",1272"Sifting" : "int",1273"SiftMethod" : "int",1274"SimplexPricing" : "int",1275"SolutionLimit" : "int",1276"SolutionNumber" : "int",1277"SubMIPCuts" : "int",1278"SubMIPNodes" : "int",1279"Symmetry" : "int",1280"Threads" : "int",1281"TimeLimit" : "double",1282"VarBranch" : "int",1283"ZeroHalfCuts" : "int",1284"ZeroObjNodes" : "int"1285}12861287cdef check(GRBenv * env, int error):1288if error:1289raise MIPSolverException("Gurobi: "+str(GRBgeterrormsg(env))+" ("+errors[error]+")")129012911292