diff --git a/CHANGELOG.md b/CHANGELOG.md index 342e8735b..4c0723362 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,14 @@ ## Unreleased ### Added -- Add getConshdlrName to class Constraint +- Added methods for getting the names of the current stage and of an event ### Fixed ### Changed ### Removed ## 4.4.0 - 2023-12-04 ### Added +- Add getConshdlrName to class Constraint - Added all event types and tests for checking them - Added SCIP functions SCIPconsGetNVars, SCIPconsGetVars - Added SCIP functions SCIPchgCoefLinear, SCIPaddCoefLinear and SCIPdelCoefLinear diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index 0c80107be..0b2332d88 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -110,6 +110,8 @@ cdef class PY_SCIP_STATUS: UNBOUNDED = SCIP_STATUS_UNBOUNDED INFORUNBD = SCIP_STATUS_INFORUNBD +StageNames = {} + cdef class PY_SCIP_STAGE: INIT = SCIP_STAGE_INIT PROBLEM = SCIP_STAGE_PROBLEM @@ -165,6 +167,8 @@ cdef class PY_SCIP_HEURTIMING: DURINGPRESOLLOOP = SCIP_HEURTIMING_DURINGPRESOLLOOP AFTERPROPLOOP = SCIP_HEURTIMING_AFTERPROPLOOP +EventNames = {} + cdef class PY_SCIP_EVENTTYPE: DISABLED = SCIP_EVENTTYPE_DISABLED VARADDED = SCIP_EVENTTYPE_VARADDED @@ -221,6 +225,7 @@ cdef class PY_SCIP_EVENTTYPE: ROWCHANGED = SCIP_EVENTTYPE_ROWCHANGED ROWEVENT = SCIP_EVENTTYPE_ROWEVENT + cdef class PY_SCIP_LPSOLSTAT: NOTSOLVED = SCIP_LPSOLSTAT_NOTSOLVED OPTIMAL = SCIP_LPSOLSTAT_OPTIMAL @@ -305,8 +310,24 @@ cdef class Event: """gets type of event""" return SCIPeventGetType(self.event) + def getName(self): + """gets name of event""" + if not EventNames: + self._getEventNames() + return EventNames[self.getType()] + + def _getEventNames(self): + """gets event names""" + for name in dir(PY_SCIP_EVENTTYPE): + attr = getattr(PY_SCIP_EVENTTYPE, name) + if isinstance(attr, int): + EventNames[attr] = name + def __repr__(self): - return self.getType() + return str(self.getType()) + + def __str__(self): + return self.getName() def getNewBound(self): """gets new bound for a bound change event""" @@ -4702,6 +4723,19 @@ cdef class Model: def getStage(self): """Retrieve current SCIP stage""" return SCIPgetStage(self._scip) + + def getStageName(self): + """Returns name of current stage as string""" + if not StageNames: + self._getStageNames() + return StageNames[self.getStage()] + + def _getStageNames(self): + """Gets names of stages""" + for name in dir(PY_SCIP_STAGE): + attr = getattr(PY_SCIP_STAGE, name) + if isinstance(attr, int): + StageNames[attr] = name def getStatus(self): """Retrieve solution status.""" diff --git a/tests/test_event.py b/tests/test_event.py index 92653eab4..406b6df64 100644 --- a/tests/test_event.py +++ b/tests/test_event.py @@ -14,6 +14,9 @@ def eventinit(self): # self.model.dropEvent(self.event_type, self) def eventexec(self, event): + assert str(event) == event.getName() + assert type(event.getName()) == str + calls.append('eventexec') if self.event_type == SCIP_EVENTTYPE.LPEVENT: assert event.getType() in [SCIP_EVENTTYPE.FIRSTLPSOLVED, SCIP_EVENTTYPE.LPSOLVED] @@ -61,10 +64,6 @@ def test_event(): all_events = [SCIP_EVENTTYPE.DISABLED,SCIP_EVENTTYPE.VARADDED,SCIP_EVENTTYPE.VARDELETED,SCIP_EVENTTYPE.VARFIXED,SCIP_EVENTTYPE.VARUNLOCKED,SCIP_EVENTTYPE.OBJCHANGED,SCIP_EVENTTYPE.GLBCHANGED,SCIP_EVENTTYPE.GUBCHANGED,SCIP_EVENTTYPE.LBTIGHTENED,SCIP_EVENTTYPE.LBRELAXED,SCIP_EVENTTYPE.UBTIGHTENED,SCIP_EVENTTYPE.UBRELAXED,SCIP_EVENTTYPE.GHOLEADDED,SCIP_EVENTTYPE.GHOLEREMOVED,SCIP_EVENTTYPE.LHOLEADDED,SCIP_EVENTTYPE.LHOLEREMOVED,SCIP_EVENTTYPE.IMPLADDED,SCIP_EVENTTYPE.PRESOLVEROUND,SCIP_EVENTTYPE.NODEFOCUSED,SCIP_EVENTTYPE.NODEFEASIBLE,SCIP_EVENTTYPE.NODEINFEASIBLE,SCIP_EVENTTYPE.NODEBRANCHED,SCIP_EVENTTYPE.NODEDELETE,SCIP_EVENTTYPE.FIRSTLPSOLVED,SCIP_EVENTTYPE.LPSOLVED,SCIP_EVENTTYPE.POORSOLFOUND,SCIP_EVENTTYPE.BESTSOLFOUND,SCIP_EVENTTYPE.ROWADDEDSEPA,SCIP_EVENTTYPE.ROWDELETEDSEPA,SCIP_EVENTTYPE.ROWADDEDLP,SCIP_EVENTTYPE.ROWDELETEDLP,SCIP_EVENTTYPE.ROWCOEFCHANGED,SCIP_EVENTTYPE.ROWCONSTCHANGED,SCIP_EVENTTYPE.ROWSIDECHANGED,SCIP_EVENTTYPE.SYNC,SCIP_EVENTTYPE.GBDCHANGED,SCIP_EVENTTYPE.LBCHANGED,SCIP_EVENTTYPE.UBCHANGED,SCIP_EVENTTYPE.BOUNDTIGHTENED,SCIP_EVENTTYPE.BOUNDRELAXED,SCIP_EVENTTYPE.BOUNDCHANGED,SCIP_EVENTTYPE.LHOLECHANGED,SCIP_EVENTTYPE.HOLECHANGED,SCIP_EVENTTYPE.DOMCHANGED,SCIP_EVENTTYPE.VARCHANGED,SCIP_EVENTTYPE.VAREVENT,SCIP_EVENTTYPE.NODESOLVED,SCIP_EVENTTYPE.NODEEVENT,SCIP_EVENTTYPE.LPEVENT,SCIP_EVENTTYPE.SOLFOUND,SCIP_EVENTTYPE.SOLEVENT,SCIP_EVENTTYPE.ROWCHANGED,SCIP_EVENTTYPE.ROWEVENT] - - for i in [20]: - print(SCIP_EVENTTYPE.NODEINFEASIBLE) - all_event_hdlrs = [] for event in all_events: s = Model() diff --git a/tests/test_model.py b/tests/test_model.py index 14424e108..d5016799e 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -1,6 +1,6 @@ import pytest -from pyscipopt import Model +from pyscipopt import Model, SCIP_STAGE def test_model(): # create solver instance @@ -267,4 +267,22 @@ def test_objLim(): m.setObjlimit(2) m.optimize() assert m.getNLimSolsFound() == 1 - \ No newline at end of file + +def test_getStage(): + m = Model() + + assert m.getStage() == SCIP_STAGE.PROBLEM + assert m.getStageName() == "PROBLEM" + + x = m.addVar() + m.addCons(x >= 1) + + print(m.getStage()) + assert m.getStage() == SCIP_STAGE.PROBLEM + assert m.getStageName() == "PROBLEM" + + m.optimize() + + print(m.getStage()) + assert m.getStage() == SCIP_STAGE.SOLVED + assert m.getStageName() == "SOLVED"