Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gurobi FLK compatibility #387

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 73 additions & 6 deletions mip/gurobi.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@

int GRBloadenv(GRBenv **envP, const char *logfilename);

int GRBemptyenv (GRBenv **envP);

int GRBstartenv (GRBenv *env);

int GRBnewmodel(GRBenv *env, GRBmodel **modelP,
const char *Pname, int numvars,
double *obj, double *lb, double *ub, char *vtype,
Expand Down Expand Up @@ -180,6 +184,8 @@

int GRBsetdblparam(GRBenv *env, const char *paramname, double value);

int GRBsetstrparam(GRBenv *env, const char *paramname, const char *newvalue);

int GRBsetobjectiven(GRBmodel *model, int index,
int priority, double weight,
double abstol, double reltol, const char *name,
Expand Down Expand Up @@ -243,10 +249,14 @@
int GRBdelconstrs (GRBmodel *model, int numdel, int *ind);

int GRBreset (GRBmodel *model, int clearall);

char * GRBgeterrormsg (GRBenv *env);
"""
)

GRBloadenv = grblib.GRBloadenv
GRBemptyenv = grblib.GRBemptyenv
GRBstartenv = grblib.GRBstartenv
GRBnewmodel = grblib.GRBnewmodel
GRBfreeenv = grblib.GRBfreeenv
GRBfreemodel = grblib.GRBfreemodel
Expand Down Expand Up @@ -279,6 +289,7 @@
GRBgetdblattr = grblib.GRBgetdblattr
GRBsetdblparam = grblib.GRBsetdblparam
GRBgetdblparam = grblib.GRBgetdblparam
GRBsetstrparam = grblib.GRBsetstrparam
GRBgetstrattrelement = grblib.GRBgetstrattrelement
GRBcbget = grblib.GRBcbget
GRBcbsetparam = grblib.GRBcbsetparam
Expand All @@ -293,6 +304,7 @@
GRBsetstrattr = grblib.GRBsetstrattr
GRBgetdblattrarray = grblib.GRBgetdblattrarray
GRBreset = grblib.GRBreset
GRBgeterrormsg = grblib.GRBgeterrormsg

GRB_CB_MIPSOL = 4
GRB_CB_MIPNODE = 5
Expand Down Expand Up @@ -337,6 +349,11 @@


class SolverGurobi(Solver):

# class dictionary to facilitate setting of Gurobi's Flexible Licensing Key parameters
# which are used in the __init__ method.
_env_params = {}

def __init__(self, model: Model, name: str, sense: str, modelp: CData = ffi.NULL):
"""modelp should be informed if a model should not be created,
but only allow access to an existing one"""
Expand Down Expand Up @@ -364,12 +381,53 @@ def __init__(self, model: Model, name: str, sense: str, modelp: CData = ffi.NULL
self._ownsModel = True
self._env = ffi.new("GRBenv **")

# creating Gurobi environment
st = GRBloadenv(self._env, "".encode("utf-8"))
if st != 0:
raise InterfacingError(
"Gurobi environment could not be loaded, check your license."
)
if self._env_params:
# The following is the only way in which environments relying on FLK licenses
# can be created.

st = GRBemptyenv(self._env)
if st != 0:
raise InterfacingError(
"Could not start (empty) Gurobi environment."
)

def _gurobi_param_error(param_type, key):
gurobi_err_msg = ffi.string(GRBgeterrormsg(self._env[0])).decode("utf-8")
return ParameterNotAvailable(
f"GurobiError: {gurobi_err_msg}.\nCould not set {param_type} parameter: {key}. Check parameter name. Check value type."
)

for key, val in self._env_params.items():
if isinstance(val, str):
st = GRBsetstrparam(self._env[0], key.encode("utf-8"), val.encode("utf-8"))
if st != 0:
raise _gurobi_param_error("str", key)
elif isinstance(val, int):
st = GRBsetintparam(self._env[0], key.encode("utf-8"), val)
if st != 0:
raise _gurobi_param_error("int", key)
elif isinstance(val, float):
st = GRBsetintparam(self._env[0], key.encode("utf-8"), val)
if st != 0:
raise _gurobi_param_error("float", key)
else:
raise ParameterNotAvailable(
f"Unrecognized type ({type(val)}) for parameter value {key}. Supported types: str, int, float."
)

st = GRBstartenv(self._env[0])
if st != 0:
gurobi_err_msg = ffi.string(GRBgeterrormsg(self._env[0])).decode("utf-8")
raise InterfacingError(
f"GurobiError: {gurobi_err_msg}.\nGurobi environment could not be started"
)
else:
# creating Gurobi environment
st = GRBloadenv(self._env, "".encode("utf-8"))
if st != 0:
raise InterfacingError(
"Gurobi environment could not be loaded, check your license."
)
self._env = self._env[0]

# creating Gurobi model
Expand Down Expand Up @@ -1540,6 +1598,15 @@ def var_get_x(self, var: Var):

def __del__(self):
return


def set_env_params(**kwargs):
# Gurobi offers a licensing method called FLK (Flexible Licensing Key)
# Previously this was known as ISV. This license requires parameters
# to be set on an empty Gurobi environment. Gurobi users with FLK
# licenses will be instructed to use this method in order to be able
# to use their license.
SolverGurobi._env_params = kwargs


class ModelGurobiCB(Model):
Expand Down