From 5e5846b3f677c51a020eff1f8fab9049973556eb Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Thu, 23 Apr 2026 18:12:03 +0100 Subject: [PATCH 1/3] release v6.2.0 --- CHANGELOG.md | 6 ++++++ setup.py | 2 +- src/pyscipopt/_version.py | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d62ebcf5..8fd9bc081 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Unreleased ### Added +### Fixed +### Changed +### Removed + +## 6.2.0 - 2026.04.23 +### Added - `Expr` and `GenExpr` support NumPy unary functions (`np.sin`, `np.cos`, `np.sqrt`, `np.exp`, `np.log`, `np.absolute`, `np.negative`) - `Expr` and `GenExpr` support NumPy binary functions (`np.add`, `np.subtract`, `np.multiply`, `np.divide`, `np.true_divide`, `np.power`, `np.less_equal`, `np.greater_equal`, `np.equal`) - Added `getBase()` and `setBase()` methods to `LP` class for getting/setting basis status diff --git a/setup.py b/setup.py index 9a076a28c..4a951f60f 100644 --- a/setup.py +++ b/setup.py @@ -133,7 +133,7 @@ setup( name="PySCIPOpt", - version="6.1.0", + version="6.2.0", description="Python interface and modeling environment for SCIP", long_description=long_description, long_description_content_type="text/markdown", diff --git a/src/pyscipopt/_version.py b/src/pyscipopt/_version.py index 935ff4228..4e6275ee3 100644 --- a/src/pyscipopt/_version.py +++ b/src/pyscipopt/_version.py @@ -1 +1 @@ -__version__: str = '6.1.0' +__version__: str = '6.2.0' From 0d54453e3c6e60a0ca3d399c97f27b82d13b9601 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Fri, 8 May 2026 18:32:23 +0100 Subject: [PATCH 2/3] Wrap solveProbingLPWithPricing --- CHANGELOG.md | 1 + src/pyscipopt/scip.pxd | 1 + src/pyscipopt/scip.pxi | 29 +++++++++++++++++++ src/pyscipopt/scip.pyi | 6 ++++ tests/test_branch_probing_lp.py | 51 ++++++++++++++++++++++++++++++++- 5 files changed, 87 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fd9bc081..d8ebcd4bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ## 6.2.0 - 2026.04.23 ### Added +- Wrapped `solveProbingLPWithPricing()` and added test - `Expr` and `GenExpr` support NumPy unary functions (`np.sin`, `np.cos`, `np.sqrt`, `np.exp`, `np.log`, `np.absolute`, `np.negative`) - `Expr` and `GenExpr` support NumPy binary functions (`np.add`, `np.subtract`, `np.multiply`, `np.divide`, `np.true_divide`, `np.power`, `np.less_equal`, `np.greater_equal`, `np.equal`) - Added `getBase()` and `setBase()` methods to `LP` class for getting/setting basis status diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index b65a0c43f..af933fe19 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -651,6 +651,7 @@ cdef extern from "scip/scip.h": SCIP_RETCODE SCIPchgVarUbProbing(SCIP* scip, SCIP_VAR* var, SCIP_Real newbound) SCIP_RETCODE SCIPchgVarLbProbing(SCIP* scip, SCIP_VAR* var, SCIP_Real newbound) SCIP_RETCODE SCIPsolveProbingLP(SCIP* scip, int itlim, SCIP_Bool* lperror, SCIP_Bool* cutoff) + SCIP_RETCODE SCIPsolveProbingLPWithPricing(SCIP* scip, SCIP_Bool pretendroot, SCIP_Bool displayinfo, int maxpricerounds, SCIP_Bool* lperror, SCIP_Bool* cutoff) SCIP_RETCODE SCIPendProbing(SCIP* scip) SCIP_RETCODE SCIPfixVarProbing(SCIP* scip, SCIP_VAR* var, SCIP_Real fixedval) SCIP_Bool SCIPisObjChangedProbing(SCIP* scip) diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index b0449620b..ced5d909c 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -10407,6 +10407,35 @@ cdef class Model: PY_SCIP_CALL( SCIPsolveProbingLP(self._scip, itlim, &lperror, &cutoff) ) return lperror, cutoff + def solveProbingLPWithPricing(self, pretendroot=False, displayinfo=False, maxpricerounds=-1): + """ + Solves the LP at the current probing node (cannot be applied at preprocessing stage) and applies pricing + until the LP is solved to optimality; no separation is applied. + + Parameters + ---------- + pretendroot : bool + should the pricers be called as if we are at the root node? (Default value = False) + displayinfo : bool + should info lines be displayed after each pricing round? (Default value = False) + maxpricerounds : int + maximal number of pricing rounds (-1: no limit); a finite limit means that the LP might not be + solved to optimality! (Default value = -1) + + Returns + ------- + lperror : bool + whether an unresolved LP error occurred + cutoff : bool + whether the probing LP was infeasible or the objective limit was reached + + """ + cdef SCIP_Bool lperror + cdef SCIP_Bool cutoff + + PY_SCIP_CALL( SCIPsolveProbingLPWithPricing(self._scip, pretendroot, displayinfo, maxpricerounds, &lperror, &cutoff) ) + return lperror, cutoff + def applyCutsProbing(self): """ Applies the cuts in the separation storage to the LP and clears the storage afterwards; diff --git a/src/pyscipopt/scip.pyi b/src/pyscipopt/scip.pyi index 1b2872c0c..780bccd68 100644 --- a/src/pyscipopt/scip.pyi +++ b/src/pyscipopt/scip.pyi @@ -1557,6 +1557,12 @@ class Model: def solveConcurrent(self) -> Incomplete: ... def solveDiveLP(self, itlim: Incomplete = ...) -> Incomplete: ... def solveProbingLP(self, itlim: Incomplete = ...) -> Incomplete: ... + def solveProbingLPWithPricing( + self, + pretendroot: Incomplete = ..., + displayinfo: Incomplete = ..., + maxpricerounds: Incomplete = ..., + ) -> Incomplete: ... def sortAndCons(self, and_cons: Incomplete) -> Incomplete: ... def startDive(self) -> Incomplete: ... def startProbing(self) -> Incomplete: ... diff --git a/tests/test_branch_probing_lp.py b/tests/test_branch_probing_lp.py index fe5959190..3882cd3fe 100644 --- a/tests/test_branch_probing_lp.py +++ b/tests/test_branch_probing_lp.py @@ -91,4 +91,53 @@ def test_branching(): print("t", m.getVal(t)) assert my_branchrule.was_called_val - assert my_branchrule.was_called_int \ No newline at end of file + assert my_branchrule.was_called_int + + +class ProbingPricingBranching(Branchrule): + + def __init__(self, model): + self.model = model + self.was_called = False + + def branchexeclp(self, allowaddcons): + if self.was_called: + return {"result": SCIP_RESULT.DIDNOTRUN} + + self.model.startProbing() + self.model.constructLP() + lperror, cutoff = self.model.solveProbingLPWithPricing( + pretendroot=True, displayinfo=False, maxpricerounds=0 + ) + assert isinstance(lperror, bool) + assert isinstance(cutoff, bool) + assert not lperror + + lperror2, cutoff2 = self.model.solveProbingLPWithPricing() + assert isinstance(lperror2, bool) + assert isinstance(cutoff2, bool) + + self.model.endProbing() + self.was_called = True + return {"result": SCIP_RESULT.DIDNOTRUN} + + +def test_solve_probing_lp_with_pricing(): + m = Model() + m.setHeuristics(SCIP_PARAMSETTING.OFF) + m.setSeparating(SCIP_PARAMSETTING.OFF) + m.setIntParam("presolving/maxrounds", 0) + m.setLongintParam("limits/nodes", 1) + + y1 = m.addVar(vtype="B") + y2 = m.addVar(vtype="B") + y3 = m.addVar(vtype="B") + m.addCons(2 * y1 + 3 * y2 + y3 <= 4) + m.setObjective(5 * y1 + 4 * y2 + 3 * y3, sense="maximize") + + rule = ProbingPricingBranching(m) + m.includeBranchrule(rule, "probing-pricing-test", "exercise solveProbingLPWithPricing", + priority=10000000, maxdepth=3, maxbounddist=1) + m.optimize() + + assert rule.was_called \ No newline at end of file From 621b9692cbe1ab2cb6c3cd34be50ad997c8456a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dion=C3=ADsio?= <57299939+Joao-Dionisio@users.noreply.github.com> Date: Sat, 9 May 2026 12:26:59 +0100 Subject: [PATCH 3/3] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8d1b627d..fe6f79590 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ ## 6.2.0 - 2026.04.23 ### Added -- Wrapped `solveProbingLPWithPricing()` and added test +- Added `solveProbingLPWithPricing()` and test - `Expr` and `GenExpr` support NumPy unary functions (`np.sin`, `np.cos`, `np.sqrt`, `np.exp`, `np.log`, `np.absolute`, `np.negative`) - `Expr` and `GenExpr` support NumPy binary functions (`np.add`, `np.subtract`, `np.multiply`, `np.divide`, `np.true_divide`, `np.power`, `np.less_equal`, `np.greater_equal`, `np.equal`) - Added `getBase()` and `setBase()` methods to `LP` class for getting/setting basis status