Skip to content

Commit bc565d3

Browse files
committed
read and write optimal LP basis in gurobi and Cbc
1 parent 210967c commit bc565d3

24 files changed

+466
-13
lines changed

mip/cbc.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,11 @@
141141
142142
void Cbc_readLp(Cbc_Model *model, const char *file);
143143
144+
int Cbc_readBasis(Cbc_Model *model, const char *filename);
145+
146+
int Cbc_writeBasis(Cbc_Model *model, const char *filename, char
147+
writeValues, int formatType);
148+
144149
void Cbc_readMps(Cbc_Model *model, const char *file);
145150
146151
char Cbc_supportsGzip();
@@ -1441,9 +1446,11 @@ def write(self, file_path: str):
14411446
cbclib.Cbc_writeMps(self._model, fpstr)
14421447
elif ".lp" in file_path.lower():
14431448
cbclib.Cbc_writeLp(self._model, fpstr)
1449+
elif ".bas" in file_path.lower():
1450+
cbclib.Cbc_writeBasis(self._model, fpstr, CHAR_ONE, 2)
14441451
else:
14451452
raise ValueError(
1446-
"Enter a valid extension (.lp or .mps) \
1453+
"Enter a valid extension (.lp, .mps or .bas) \
14471454
to indicate the file format"
14481455
)
14491456

@@ -1464,9 +1471,18 @@ def read(self, file_path: str) -> None:
14641471
cbclib.Cbc_readMps(self._model, fpstr)
14651472
elif ".lp" in file_path.lower():
14661473
cbclib.Cbc_readLp(self._model, fpstr)
1474+
elif ".bas" in file_path.lower():
1475+
status = cbclib.Cbc_readBasis(self._model, fpstr)
1476+
if status == -1:
1477+
raise IOError("Error reading %s" % file_path)
1478+
elif status == 0:
1479+
logger.warning("No values read from %s" % file_path)
1480+
elif status == 1:
1481+
logger.info("Optimal LP basis successfully loaded.")
1482+
14671483
else:
14681484
raise ValueError(
1469-
"Enter a valid extension (.lp or .mps) \
1485+
"Enter a valid extension (.lp, .mps or .bas) \
14701486
to indicate the file format"
14711487
)
14721488

mip/gurobi.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,8 @@
216216
217217
int GRBreadmodel(GRBenv *env, const char *filename, GRBmodel **modelP);
218218
219+
int GRBread(GRBmodel *model, const char *filename);
220+
219221
int GRBdelvars(GRBmodel *model, int numdel, int *ind );
220222
221223
int GRBsetcharattrlist(GRBmodel *model, const char *attrname,
@@ -258,6 +260,7 @@
258260
GRBsetdblattrlist = grblib.GRBsetdblattrlist
259261
GRBwrite = grblib.GRBwrite
260262
GRBreadmodel = grblib.GRBreadmodel
263+
GRBread = grblib.GRBread
261264
GRBgetconstrbyname = grblib.GRBgetconstrbyname
262265
GRBupdatemodel = grblib.GRBupdatemodel
263266
GRBgetcharattrelement = grblib.GRBgetcharattrelement
@@ -916,14 +919,29 @@ def write(self, file_path: str) -> None:
916919
def read(self, file_path: str) -> None:
917920
if not isfile(file_path):
918921
raise FileNotFoundError("File {} does not exist".format(file_path))
919-
GRBfreemodel(self._model)
920-
self._model = ffi.new("GRBmodel **")
921-
st = GRBreadmodel(self._env, file_path.encode("utf-8"), self._model)
922-
if st != 0:
923-
raise InterfacingError(
924-
"Could not read model {}, check contents".format(file_path)
925-
)
926-
self._model = self._model[0]
922+
923+
lfile = file_path.lower()
924+
925+
MEXTS = [".mps.gz", ".mps.bz2", ".lp.gz", ".lp.bz2", ".lp", ".mps"]
926+
is_model = False
927+
for ext in MEXTS:
928+
if lfile.endswith(ext):
929+
is_model = True
930+
break
931+
932+
if is_model:
933+
GRBfreemodel(self._model)
934+
self._model = ffi.new("GRBmodel **")
935+
st = GRBreadmodel(self._env, file_path.encode("utf-8"), self._model)
936+
if st != 0:
937+
raise InterfacingError(
938+
"Could not read model {}, check contents".format(file_path)
939+
)
940+
self._model = self._model[0]
941+
else:
942+
error = GRBread(self._model, file_path.encode("utf-8"))
943+
if error:
944+
raise IOError("Error loading %s" % file_path)
927945

928946
def num_cols(self) -> int:
929947
return self.get_int_attr("NumVars") + self.__n_cols_buffer
320 Bytes
Binary file not shown.
77 Bytes
Binary file not shown.

mip/libraries/lin64/libClp.so.0.0.0

0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.
134 Bytes
Binary file not shown.

mip/libraries/win64/libCbc-0.dll

0 Bytes
Binary file not shown.
65 Bytes
Binary file not shown.

mip/libraries/win64/libCgl-0.dll

0 Bytes
Binary file not shown.

mip/libraries/win64/libClp-0.dll

0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.
640 Bytes
Binary file not shown.

mip/libraries/win64/libOsi-0.dll

0 Bytes
Binary file not shown.

mip/libraries/win64/libOsiCbc-0.dll

0 Bytes
Binary file not shown.

mip/libraries/win64/libOsiClp-0.dll

0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.

mip/libraries/win64/libOsiGlpk-0.dll

0 Bytes
Binary file not shown.

mip/libraries/win64/libcoinasl-2.dll

0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.

mip/libraries/win64/libtermcap-0.dll

21.3 KB
Binary file not shown.

mip/model.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,10 @@ def read(self: "Model", path: str):
645645
`MPS file format <https://en.wikipedia.org/wiki/MPS_(format)>`_
646646
647647
:code:`.sol`
648-
initial feasible solution
648+
initial integer feasible solution
649+
650+
:code:`.bas`
651+
`optimal basis <http://lpsolve.sourceforge.net/5.5/bas-format.htm>`_ for the linear programming relaxation.
649652
650653
Note: if a new problem is readed, all variables, constraints
651654
and parameters from the current model will be cleared.
@@ -681,6 +684,14 @@ def read(self: "Model", path: str):
681684
self.start = var_list
682685
return
683686

687+
if path.lower().endswith(".bas"):
688+
if self.num_cols == 0:
689+
raise mip.ProgrammingError(
690+
"Cannot load optimal LP basis for empty model."
691+
)
692+
self.solver.read(path)
693+
return
694+
684695
# reading model
685696
model_ext = [".lp", ".mps", ".mps.gz"]
686697

@@ -723,6 +734,9 @@ def write(self: "Model", file_path: str):
723734
:code:`.sol`
724735
initial feasible solution
725736
737+
:code:`.bas`
738+
`optimal basis <http://lpsolve.sourceforge.net/5.5/bas-format.htm>`_ for the linear programming relaxation.
739+
726740
Args:
727741
file_path(str): file name
728742
"""
@@ -732,7 +746,11 @@ def write(self: "Model", file_path: str):
732746
else:
733747
mip_start = [(var, var.x) for var in self.vars if abs(var.x) >= 1e-8]
734748
save_mipstart(mip_start, file_path)
735-
elif file_path.lower().endswith(".lp") or file_path.lower().endswith(".mps"):
749+
elif (
750+
file_path.lower().endswith(".lp")
751+
or file_path.lower().endswith(".mps")
752+
or file_path.lower().endswith(".bas")
753+
):
736754
self.solver.write(file_path)
737755
else:
738756
raise ValueError(

0 commit comments

Comments
 (0)