Skip to content
Merged
Show file tree
Hide file tree
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
4 changes: 4 additions & 0 deletions .github/workflows/github-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ name: CI

on: [push, pull_request]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:

pre-commit:
Expand Down
54 changes: 19 additions & 35 deletions mip/cbc.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,36 +70,20 @@
cbclib = ffi.dlopen(libfile)
os.chdir(old_dir)
else:
import cbcbox as _cbcbox

_lib_dir = _cbcbox.cbc_lib_dir()
if "linux" in platform.lower():
if not os_is_64_bit:
raise NotImplementedError("Linux 32 bits platform not supported.")
libfile = os.path.join(_lib_dir, "libCbc.so")
elif platform.lower().startswith("win"):
if not os_is_64_bit:
raise NotImplementedError("Win32 platform not supported.")
# autotools/MinGW places DLLs under bin/, not lib/
_bin_dir = os.path.join(_cbcbox.cbc_dist_dir(), "bin")
libfile = os.path.join(_bin_dir, "libCbc-0.dll")
if not os.path.exists(libfile):
raise FileNotFoundError(
"libCbc-0.dll not found in cbcbox Windows distribution at"
" {}. The cbcbox Windows wheel may only contain a static"
" libCbc.a. A shared libCbc-0.dll is required.".format(_bin_dir)
)
# Python 3.8+ ignores PATH for DLL resolution; use add_dll_directory
import mipster as _mipster

if not os_is_64_bit:
raise NotImplementedError("32-bit platforms are not supported.")
libfile = _mipster.lib_path()
if platform.lower().startswith("win"):
# Python 3.8+ ignores PATH for DLL resolution; let Windows find
# any sibling DLLs (libgcc, libstdc++, libwinpthread) via
# add_dll_directory on the directory holding libmipster-N.dll.
_bin_dir = os.path.dirname(libfile)
if hasattr(os, "add_dll_directory"):
os.add_dll_directory(_bin_dir)
elif _bin_dir not in os.environ.get("PATH", ""):
os.environ["PATH"] = _bin_dir + ";" + os.environ["PATH"]
elif platform.lower().startswith("darwin") or platform.lower().startswith(
"macos"
):
libfile = os.path.join(_lib_dir, "libCbc.dylib")
else:
raise NotImplementedError("Your operating system/platform is not supported")
cbclib = ffi.dlopen(libfile)
has_cbc = True
except Exception as e:
Expand Down Expand Up @@ -317,11 +301,6 @@
void Cbc_setAllowableFractionGap(Cbc_Model *model,
double allowedFracionGap);

double Cbc_getAllowablePercentageGap(Cbc_Model *model);

void Cbc_setAllowablePercentageGap(Cbc_Model *model,
double allowedPercentageGap);

double Cbc_getMaximumSeconds(Cbc_Model *model);

void Cbc_setMaximumSeconds(Cbc_Model *model, double maxSeconds);
Expand Down Expand Up @@ -1022,7 +1001,9 @@ def clique_merge(self, constrs: Optional[List["mip.Constr"]] = None):
strengthenPacking = cbclib.Cbc_strengthenPackingRows
strengthenPacking(self._model, nr, idxr)

def optimize(self, relax: bool = False, lp_preprocess: bool = False) -> OptimizationStatus:
def optimize(
self, relax: bool = False, lp_preprocess: bool = False
) -> OptimizationStatus:
# get name indexes from an osi problem
def cbc_get_osi_name_indexes(osi_solver) -> Dict[str, int]:
nameIdx = {}
Expand Down Expand Up @@ -1203,7 +1184,9 @@ def cbc_cut_callback(osi_solver, osi_cuts, app_data, depth, npass):

# user-specified cut passes override the cuts-level default
if self.model.cut_passes != -1:
cbclib.Cbc_setIntParam(self._model, INT_PARAM_CUT_PASS, self.model.cut_passes)
cbclib.Cbc_setIntParam(
self._model, INT_PARAM_CUT_PASS, self.model.cut_passes
)

if self.model.clique == 0:
cbc_set_parameter(self, "clique", "off")
Expand Down Expand Up @@ -1662,7 +1645,8 @@ def remove_vars(self, varsList: List[int]):
cbclib.Cbc_deleteCols(self._model, len(varsList), idx)

def __del__(self):
cbclib.Cbc_deleteModel(self._model)
if getattr(self, "_model", None) is not None:
cbclib.Cbc_deleteModel(self._model)

def get_problem_name(self) -> str:
namep = self.__name_space
Expand Down Expand Up @@ -1793,7 +1777,7 @@ def __clear_sol(self: "SolverOsi"):
self.__obj_val = None

def __del__(self):
if self.owns_solver:
if getattr(self, "owns_solver", False):
cbclib.Osi_deleteSolver(self.osi)

def add_var(
Expand Down
15 changes: 8 additions & 7 deletions mip/gurobi.py
Original file line number Diff line number Diff line change
Expand Up @@ -428,11 +428,12 @@ def __clear_sol(self):
self.__obj_val = None

def __del__(self):
# freeing Gurobi model and environment
if self._ownsModel:
# Guard against partially-constructed objects (e.g. PyPy GC may call
# __del__ even if __init__ raised before setting these attributes).
if getattr(self, "_ownsModel", False):
if self._model:
GRBfreemodel(self._model)
if self._env and self._venv_loaded:
if self._env and getattr(self, "_venv_loaded", False):
GRBfreeenv(self._env)

def add_var(
Expand Down Expand Up @@ -589,7 +590,9 @@ def set_max_iter(self, max_iter: int):
def set_num_threads(self, threads: int):
self.__threads = threads

def optimize(self, relax: bool = False, lp_preprocess: bool = False) -> OptimizationStatus:
def optimize(
self, relax: bool = False, lp_preprocess: bool = False
) -> OptimizationStatus:

# todo add branch_selector and incumbent_updater callbacks
@ffi.callback(
Expand Down Expand Up @@ -802,9 +805,7 @@ def callback(
self.__obj_val = self.get_dbl_attr("ObjVal")
self.__x = ffi.new("double[{}]".format(self.num_cols()))
attr = "X".encode("utf-8")
st = GRBgetdblattrarray(
self._model, attr, 0, self.num_cols(), self.__x
)
st = GRBgetdblattrarray(self._model, attr, 0, self.num_cols(), self.__x)
if st:
raise ParameterNotAvailable("Error querying Gurobi solution")
# duals are only valid at optimality for Gurobi, skip Pi/RC
Expand Down
Loading
Loading