From d938ef9591961a3ea31d9ba0aeb896a7a0a76100 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Sat, 12 Jul 2025 11:45:47 +0100 Subject: [PATCH 1/4] Add SCIPvarMarkRelaxationOnly --- CHANGELOG.md | 1 + src/pyscipopt/scip.pxd | 1 + src/pyscipopt/scip.pxi | 15 +++++++++++++++ 3 files changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f917ec92..288a33c7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Added support for knapsack constraints - Added isPositive(), isNegative(), isFeasLE(), isFeasLT(), isFeasGE(), isFeasGT(), isHugeValue(), and tests - Added SCIP_LOCKTYPE, addVarLocksType(), getNLocksDown(), getNLocksUp(), getNLocksDownType(), getNLocksUpType(), and tests +- Added SCIPvarMarkRelaxationOnly ### 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..a620db624 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -817,6 +817,7 @@ 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_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 7c7216c83..11c3f3a2f 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -1676,6 +1676,21 @@ 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 + + """ + PY_SCIP_CALL(SCIPvarMarkRelaxationOnly(self.scip_var)) def getNLocksDown(self): """ From e7026d3d960d6a92f22bea3106094a4d6e528df5 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Tue, 15 Jul 2025 08:44:58 +0100 Subject: [PATCH 2/4] Fix and add isRelaxationOnly --- CHANGELOG.md | 2 +- src/pyscipopt/scip.pxd | 1 + src/pyscipopt/scip.pxi | 19 ++++++++++++++++++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 288a33c7d..d24ac9508 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ - Added support for knapsack constraints - Added isPositive(), isNegative(), isFeasLE(), isFeasLT(), isFeasGE(), isFeasGT(), isHugeValue(), and tests - Added SCIP_LOCKTYPE, addVarLocksType(), getNLocksDown(), getNLocksUp(), getNLocksDownType(), getNLocksUpType(), and tests -- Added SCIPvarMarkRelaxationOnly +- Added SCIPvarMarkRelaxationOnly, SCIPvarIsRelaxationOnly ### 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 a620db624..0d3a22657 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -818,6 +818,7 @@ cdef extern from "scip/scip.h": SCIP_VARDATA* SCIPvarGetData(SCIP_VAR* var) SCIP_Real SCIPvarGetAvgSol(SCIP_VAR* var) void SCIPvarMarkRelaxationOnly(SCIP_VAR* var) + SCIP_Bool SCIPvarIsRelaxationOnly(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 11c3f3a2f..98b8a408d 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -1690,7 +1690,24 @@ cdef class Variable(Expr): None """ - PY_SCIP_CALL(SCIPvarMarkRelaxationOnly(self.scip_var)) + 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 getNLocksDown(self): """ From bbd7e5da98489db28097f2e1011bb4a91bc6fd2e Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Thu, 17 Jul 2025 15:35:49 +0100 Subject: [PATCH 3/4] remove debug flag --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 90ec9cba3..abebcc5d4 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ # look for environment variable that specifies path to SCIP scipoptdir = os.environ.get("SCIPOPTDIR", "").strip('"') -extra_compile_args = ["-UNDEBUG"] +extra_compile_args = [] extra_link_args = [] # if SCIPOPTDIR is not set, we assume that SCIP is installed globally From 841114a99ec64aec3e495f014167f2e8f4a83825 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Fri, 18 Jul 2025 11:55:50 +0100 Subject: [PATCH 4/4] varDeletable functions --- CHANGELOG.md | 2 +- src/pyscipopt/scip.pxd | 2 ++ src/pyscipopt/scip.pxi | 16 +++++++++++++++- tests/test_vars.py | 6 ++++-- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1790c0023..b7dbefbb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +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, 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 0d3a22657..2d20d5ff3 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -819,6 +819,8 @@ cdef extern from "scip/scip.h": 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 86a7ba883..470470f84 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -1708,6 +1708,17 @@ cdef class Variable(Expr): """ 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): """ @@ -3777,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. @@ -3833,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 48cbe061c..75629752a 100644 --- a/tests/test_vars.py +++ b/tests/test_vars.py @@ -69,7 +69,7 @@ def test_vtype(): def test_markRelaxationOnly(): m = Model() - x = m.addVar(vtype='C', lb=-5.5, ub=8) + 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() @@ -77,4 +77,6 @@ def test_markRelaxationOnly(): x.markRelaxationOnly() assert x.isRelaxationOnly() - assert not y.isRelaxationOnly() \ No newline at end of file + assert x.isDeletable() + assert not y.isRelaxationOnly() + assert not y.isDeletable() \ No newline at end of file