Skip to content

Commit

Permalink
Add more config parameters to HiGHS python API + set up logging (#606)
Browse files Browse the repository at this point in the history
* Add callback tuple + recognise common options

* Simplify options handling

* last touch-ups
  • Loading branch information
siwy authored Jul 15, 2023
1 parent d479cea commit 6a8e463
Showing 1 changed file with 45 additions and 6 deletions.
51 changes: 45 additions & 6 deletions pulp/apis/highs_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,29 +248,66 @@ def actualSolve(self, lp, callback=None):
raise PulpSolverError("HiGHS: Not Available")

else:
# Note(maciej): It was surprising to me that higshpy wasn't logging out of the box,
# even with the different logging options set. This callback seems to work, but there
# are probably better ways of doing this ¯\_(ツ)_/¯
DEFAULT_CALLBACK = lambda logType, logMsg, callbackValue: print(
f"[{logType.name}] {logMsg}"
)
DEFAULT_CALLBACK_VALUE = ""

def __init__(
self,
mip=True,
msg=True,
callbackTuple=None,
gapAbs=None,
gapRel=None,
threads=None,
timeLimit=None,
warmStart=False,
logPath=None,
**solverParams,
):
super().__init__(mip, msg, timeLimit=timeLimit, **solverParams)
"""
:param bool mip: if False, assume LP even if integer variables
:param bool msg: if False, no log is shown
:param tuple callbackTuple: Tuple of log callback function (see DEFAULT_CALLBACK above for definition)
and callbackValue (tag embedded in every callback)
:param float gapRel: relative gap tolerance for the solver to stop (in fraction)
:param float gapAbs: absolute gap tolerance for the solver to stop
:param int threads: sets the maximum number of threads
:param float timeLimit: maximum time for solver (in seconds)
:param dict solverParams: list of named options to pass directly to the HiGHS solver
"""
super().__init__(mip=mip, msg=msg, timeLimit=timeLimit, **solverParams)
self.callbackTuple = callbackTuple
self.gapAbs = gapAbs
self.gapRel = gapRel
self.threads = threads

def available(self):
return True

def callSolver(self, lp):
lp.solverModel.run()

def buildSolverModel(self, lp):
def createAndConfigureSolver(self, lp):
lp.solverModel = highspy.Highs()

gapRel = self.optionsDict.get("gapRel", 0)
lp.solverModel.setOptionValue("mip_rel_gap", gapRel)
if self.msg or self.callbackTuple:
callbackTuple = self.callbackTuple or (
HiGHS.DEFAULT_CALLBACK,
HiGHS.DEFAULT_CALLBACK_VALUE,
)
lp.solverModel.setLogCallback(*callbackTuple)

if self.gapRel is not None:
lp.solverModel.setOptionValue("mip_rel_gap", self.gapRel)

if self.gapAbs is not None:
lp.solverModel.setOptionValue("mip_abs_gap", self.gapAbs)

if self.threads is not None:
lp.solverModel.setOptionValue("threads", self.threads)

if self.timeLimit is not None:
lp.solverModel.setOptionValue("time_limit", float(self.timeLimit))
Expand All @@ -279,6 +316,7 @@ def buildSolverModel(self, lp):
for key, value in self.optionsDict.items():
lp.solverModel.setOptionValue(key, value)

def buildSolverModel(self, lp):
inf = highspy.kHighsInf

obj_mult = -1 if lp.sense == constants.LpMaximize else 1
Expand Down Expand Up @@ -353,6 +391,7 @@ def findSolutionValues(self, lp):
return status_dict[status]

def actualSolve(self, lp):
self.createAndConfigureSolver(lp)
self.buildSolverModel(lp)
self.callSolver(lp)

Expand Down

0 comments on commit 6a8e463

Please sign in to comment.