diff --git a/CHANGELOG.md b/CHANGELOG.md index 71151df8e..b6ae25d1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Added isPositive(), isNegative(), isFeasLE(), isFeasLT(), isFeasGE(), isFeasGT(), isHugeValue(), and tests - Added SCIP_LOCKTYPE, addVarLocksType(), getNLocksDown(), getNLocksUp(), getNLocksDownType(), getNLocksUpType(), and tests - Added addMatrixConsIndicator(), and tests +- Added SCIPvarMarkRelaxationOnly, SCIPvarIsRelaxationOnly, SCIPvarMarkDeletable, SCIPvarIsDeletable, and tests ### Fixed - Raised an error when an expression is used when a variable is required ### Changed diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index b198b221d..2d20d5ff3 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -817,6 +817,10 @@ cdef extern from "scip/scip.h": void SCIPvarSetData(SCIP_VAR* var, SCIP_VARDATA* vardata) SCIP_VARDATA* SCIPvarGetData(SCIP_VAR* var) SCIP_Real SCIPvarGetAvgSol(SCIP_VAR* var) + void SCIPvarMarkRelaxationOnly(SCIP_VAR* var) + SCIP_Bool SCIPvarIsRelaxationOnly(SCIP_VAR* var) + void SCIPvarMarkDeletable(SCIP_VAR* var) + SCIP_Bool SCIPvarIsDeletable(SCIP_VAR* var) SCIP_Real SCIPgetVarPseudocost(SCIP* scip, SCIP_VAR* var, SCIP_BRANCHDIR dir) SCIP_Real SCIPvarGetCutoffSum(SCIP_VAR* var, SCIP_BRANCHDIR dir) SCIP_Longint SCIPvarGetNBranchings(SCIP_VAR* var, SCIP_BRANCHDIR dir) diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index 68f7acba1..470470f84 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -1677,6 +1677,49 @@ cdef class Variable(Expr): """ return SCIPvarGetAvgSol(self.scip_var) + def markRelaxationOnly(self): + """ + marks that this variable has only been introduced to define a relaxation + + The variable must not have a coefficient in the objective and must be deletable. + If it is not marked deletable, it will be marked as deletable, which is only possible before + the variable is added to a problem. + + Returns + ------- + None + + """ + SCIPvarMarkRelaxationOnly(self.scip_var) + + def isRelaxationOnly(self): + """ + returns whether a variable has been introduced to define a relaxation + + These variables are only valid for the current SCIP solve round, they are not contained in any (checked) + constraints, but may be used in cutting planes, for example. Relaxation-only variables are not copied + by SCIPcopyVars and cuts that contain these variables are not added as linear constraints when + restarting or transferring information from a copied SCIP to a SCIP. Also conflicts with relaxation-only + variables are not generated at the moment. Relaxation-only variables do not appear in the objective. + + Returns + ------- + bool + + """ + return SCIPvarIsRelaxationOnly(self.scip_var) + + def isDeletable(self): + """ + Returns whether variable is allowed to be deleted completely from the problem. + + Returns + ------- + bool + + """ + return SCIPvarIsDeletable(self.scip_var) + def getNLocksDown(self): """ Returns the number of locks for rounding down. @@ -3745,7 +3788,7 @@ cdef class Model: # Variable Functions - def addVar(self, name='', vtype='C', lb=0.0, ub=None, obj=0.0, pricedVar=False, pricedVarScore=1.0): + def addVar(self, name='', vtype='C', lb=0.0, ub=None, obj=0.0, pricedVar=False, pricedVarScore=1.0, deletable=False): """ Create a new variable. Default variable is non-negative and continuous. @@ -3801,6 +3844,9 @@ cdef class Model: else: raise Warning("unrecognized variable type") + if deletable: + SCIPvarMarkDeletable(scip_var) + if pricedVar: PY_SCIP_CALL(SCIPaddPricedVar(self._scip, scip_var, pricedVarScore)) else: diff --git a/tests/test_vars.py b/tests/test_vars.py index d8c92ff40..75629752a 100644 --- a/tests/test_vars.py +++ b/tests/test_vars.py @@ -64,4 +64,19 @@ def test_vtype(): assert x.vtype() == "INTEGER" m.chgVarType(y, 'M') - assert y.vtype() == "IMPLINT" \ No newline at end of file + assert y.vtype() == "IMPLINT" + +def test_markRelaxationOnly(): + m = Model() + + x = m.addVar(vtype='C', lb=-5.5, ub=8, deletable=True) + y = m.addVar(vtype='I', lb=-5.2, ub=8) + + assert not x.isRelaxationOnly() + assert not y.isRelaxationOnly() + + x.markRelaxationOnly() + assert x.isRelaxationOnly() + assert x.isDeletable() + assert not y.isRelaxationOnly() + assert not y.isDeletable() \ No newline at end of file