From 7e890c4e33464b844d46ca5f4425dc5648ed8d11 Mon Sep 17 00:00:00 2001 From: fwesselm Date: Mon, 18 Aug 2025 09:07:22 +0200 Subject: [PATCH 1/5] Remove duplicate code --- highs/mip/HighsPrimalHeuristics.cpp | 51 ++++++++++++++--------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/highs/mip/HighsPrimalHeuristics.cpp b/highs/mip/HighsPrimalHeuristics.cpp index dd393940fb8..606d82e21b1 100644 --- a/highs/mip/HighsPrimalHeuristics.cpp +++ b/highs/mip/HighsPrimalHeuristics.cpp @@ -319,7 +319,25 @@ void HighsPrimalHeuristics::rootReducedCost() { localdom.col_lower_, localdom.col_upper_, 500, // std::max(50, int(0.05 * // (mipsolver.mipdata_->num_leaves))), - 200 + mipsolver.mipdata_->num_nodes / 20, 12); + 200 + static_cast(mipsolver.mipdata_->num_nodes / 20), + 12); +} + +static double computeFixValue(double rootchange, double fracval, double cost) { + // reinforce direction of this solution away from root + // solution if the change is at least 0.4 + // otherwise take the direction where the objective gets worse + // if objective is zero round to nearest integer + if (rootchange >= 0.4) + return std::ceil(fracval); + else if (rootchange <= -0.4) + return std::floor(fracval); + else if (cost > 0.0) + return std::ceil(fracval); + else if (cost < 0.0) + return std::floor(fracval); + else + return std::floor(fracval + 0.5); } void HighsPrimalHeuristics::RENS(const std::vector& tmp) { @@ -434,25 +452,15 @@ void HighsPrimalHeuristics::RENS(const std::vector& tmp) { if (numBranched == 0) { auto getFixVal = [&](HighsInt col, double fracval) { - double fixval; - // reinforce direction of this solution away from root // solution if the change is at least 0.4 // otherwise take the direction where the objective gets worse // if objective is zero round to nearest integer - double rootchange = mipsolver.mipdata_->rootlpsol.empty() + double fixval = + computeFixValue(mipsolver.mipdata_->rootlpsol.empty() ? 0.0 - : fracval - mipsolver.mipdata_->rootlpsol[col]; - if (rootchange >= 0.4) - fixval = std::ceil(fracval); - else if (rootchange <= -0.4) - fixval = std::floor(fracval); - else if (mipsolver.model_->col_cost_[col] > 0.0) - fixval = std::ceil(fracval); - else if (mipsolver.model_->col_cost_[col] < 0.0) - fixval = std::floor(fracval); - else - fixval = std::floor(fracval + 0.5); + : fracval - mipsolver.mipdata_->rootlpsol[col], + fracval, mipsolver.model_->col_cost_[col]); // make sure we do not set an infeasible domain fixval = std::min(localdom.col_upper_[col], fixval); fixval = std::max(localdom.col_lower_[col], fixval); @@ -671,17 +679,8 @@ void HighsPrimalHeuristics::RINS(const std::vector& relaxationsol) { // solution if the change is at least 0.4 // otherwise take the direction where the objective gets worse // if objective is zero round to nearest integer - double rootchange = fracval - mipsolver.mipdata_->rootlpsol[col]; - if (rootchange >= 0.4) - fixval = std::ceil(fracval); - else if (rootchange <= -0.4) - fixval = std::floor(fracval); - else if (mipsolver.model_->col_cost_[col] > 0.0) - fixval = std::ceil(fracval); - else if (mipsolver.model_->col_cost_[col] < 0.0) - fixval = std::floor(fracval); - else - fixval = std::floor(fracval + 0.5); + fixval = computeFixValue(fracval - mipsolver.mipdata_->rootlpsol[col], + fracval, mipsolver.model_->col_cost_[col]); } // make sure we do not set an infeasible domain fixval = std::min(localdom.col_upper_[col], fixval); From 18a34979fd089ffcd1cefcabc0b80f7776a8a2bc Mon Sep 17 00:00:00 2001 From: fwesselm Date: Mon, 18 Aug 2025 09:41:13 +0200 Subject: [PATCH 2/5] Add function calcMaxVarBounds --- highs/mip/HighsImplications.cpp | 16 +++++----------- highs/mip/HighsImplications.h | 16 +++++++++++----- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/highs/mip/HighsImplications.cpp b/highs/mip/HighsImplications.cpp index 75e5d3abf80..4a4ad945051 100644 --- a/highs/mip/HighsImplications.cpp +++ b/highs/mip/HighsImplications.cpp @@ -732,13 +732,9 @@ void HighsImplications::cleanupVarbounds(HighsInt col) { if (infeasible) return; }); - if (!delVbds.empty()) { - for (HighsInt vubCol : delVbds) { - vubs[col].erase(vubCol); - numVarBounds--; - } - delVbds.clear(); - } + for (HighsInt vubCol : delVbds) vubs[col].erase(vubCol); + numVarBounds -= delVbds.size(); + delVbds.clear(); vlbs[col].for_each([&](HighsInt vlbCol, VarBound& vlb) { bool redundant = false; @@ -748,10 +744,8 @@ void HighsImplications::cleanupVarbounds(HighsInt col) { if (infeasible) return; }); - for (HighsInt vlbCol : delVbds) { - vlbs[col].erase(vlbCol); - numVarBounds--; - } + for (HighsInt vlbCol : delVbds) vlbs[col].erase(vlbCol); + numVarBounds -= delVbds.size(); } void HighsImplications::cleanupVlb(HighsInt col, HighsInt vlbCol, diff --git a/highs/mip/HighsImplications.h b/highs/mip/HighsImplications.h index ded41709f7f..7f5f1d72326 100644 --- a/highs/mip/HighsImplications.h +++ b/highs/mip/HighsImplications.h @@ -66,7 +66,7 @@ class HighsImplications { nextCleanupCall = mipsolver.numNonzero(); numImplications = 0; numVarBounds = 0; - maxVarBounds = 5000000 + 10 * numcol; + maxVarBounds = calcMaxVarBounds(numcol); } std::function @@ -89,12 +89,18 @@ class HighsImplications { vlbs.shrink_to_fit(); vlbs.resize(numcol); numVarBounds = 0; - maxVarBounds = 5000000 + 10 * numcol; + maxVarBounds = calcMaxVarBounds(numcol); nextCleanupCall = mipsolver.numNonzero(); } - HighsInt getNumImplications() const { return numImplications; } + constexpr static int64_t calcMaxVarBounds(HighsInt numcol) { + return int64_t{5000000} + 10 * static_cast(numcol); + }; + + HighsInt getNumImplications() const { + return static_cast(numImplications); + } const std::vector& getImplications(HighsInt col, bool val, bool& infeasible) { @@ -114,9 +120,9 @@ class HighsImplications { return implications[loc].computed; } - HighsInt getNumVarBounds() const { return numVarBounds; } + int64_t getNumVarBounds() const { return numVarBounds; } - HighsInt getMaxVarBounds() const { return maxVarBounds; } + int64_t getMaxVarBounds() const { return maxVarBounds; } void addVUB(HighsInt col, HighsInt vubcol, double vubcoef, double vubconstant); From d8dbbbbecff80aae49614dbc98f51091ef65d558 Mon Sep 17 00:00:00 2001 From: fwesselm Date: Mon, 18 Aug 2025 09:55:09 +0200 Subject: [PATCH 3/5] Simplify --- highs/mip/HighsCliqueTable.cpp | 2 +- highs/mip/HighsImplications.cpp | 4 ++-- highs/mip/HighsImplications.h | 4 +--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/highs/mip/HighsCliqueTable.cpp b/highs/mip/HighsCliqueTable.cpp index bc10beaa4ad..2edf934ae5f 100644 --- a/highs/mip/HighsCliqueTable.cpp +++ b/highs/mip/HighsCliqueTable.cpp @@ -861,7 +861,7 @@ void HighsCliqueTable::extractCliques( for (HighsInt i = 0; i != nbin; ++i) { HighsInt bincol = inds[perm[i]]; HighsCDouble impliedub = HighsCDouble(rhs) - vals[perm[i]]; - if (implics.getNumVarBounds() >= implics.getMaxVarBounds()) break; + if (implics.tooManyVarBounds()) break; for (HighsInt j = nbin; j != ntotal; ++j) { HighsInt col = inds[perm[j]]; if (globaldom.isFixed(col)) continue; diff --git a/highs/mip/HighsImplications.cpp b/highs/mip/HighsImplications.cpp index 4a4ad945051..405d579651b 100644 --- a/highs/mip/HighsImplications.cpp +++ b/highs/mip/HighsImplications.cpp @@ -395,7 +395,7 @@ void HighsImplications::addVUB(HighsInt col, HighsInt vubcol, double vubcoef, // assume that VUBs do not have infinite coefficients and infinite constant // terms since such VUBs effectively evaluate to NaN. assert(std::abs(vubcoef) != kHighsInf || std::abs(vubconstant) != kHighsInf); - if (numVarBounds >= maxVarBounds) return; + if (tooManyVarBounds()) return; VarBound vub{vubcoef, vubconstant}; @@ -424,7 +424,7 @@ void HighsImplications::addVLB(HighsInt col, HighsInt vlbcol, double vlbcoef, // assume that VLBs do not have infinite coefficients and infinite constant // terms since such VLBs effectively evaluate to NaN. assert(std::abs(vlbcoef) != kHighsInf || std::abs(vlbconstant) != kHighsInf); - if (numVarBounds >= maxVarBounds) return; + if (tooManyVarBounds()) return; VarBound vlb{vlbcoef, vlbconstant}; diff --git a/highs/mip/HighsImplications.h b/highs/mip/HighsImplications.h index 7f5f1d72326..e35a39880ab 100644 --- a/highs/mip/HighsImplications.h +++ b/highs/mip/HighsImplications.h @@ -120,9 +120,7 @@ class HighsImplications { return implications[loc].computed; } - int64_t getNumVarBounds() const { return numVarBounds; } - - int64_t getMaxVarBounds() const { return maxVarBounds; } + bool tooManyVarBounds() const { return numVarBounds >= maxVarBounds; } void addVUB(HighsInt col, HighsInt vubcol, double vubcoef, double vubconstant); From e79171fe7a731e016d36692451e80c0f5df7066a Mon Sep 17 00:00:00 2001 From: fwesselm Date: Mon, 18 Aug 2025 10:05:12 +0200 Subject: [PATCH 4/5] Minor things --- highs/mip/HighsPrimalHeuristics.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/highs/mip/HighsPrimalHeuristics.cpp b/highs/mip/HighsPrimalHeuristics.cpp index 606d82e21b1..c183de9492a 100644 --- a/highs/mip/HighsPrimalHeuristics.cpp +++ b/highs/mip/HighsPrimalHeuristics.cpp @@ -323,7 +323,8 @@ void HighsPrimalHeuristics::rootReducedCost() { 12); } -static double computeFixValue(double rootchange, double fracval, double cost) { +constexpr static double calcFixVal(double rootchange, double fracval, + double cost) { // reinforce direction of this solution away from root // solution if the change is at least 0.4 // otherwise take the direction where the objective gets worse @@ -457,10 +458,10 @@ void HighsPrimalHeuristics::RENS(const std::vector& tmp) { // otherwise take the direction where the objective gets worse // if objective is zero round to nearest integer double fixval = - computeFixValue(mipsolver.mipdata_->rootlpsol.empty() - ? 0.0 - : fracval - mipsolver.mipdata_->rootlpsol[col], - fracval, mipsolver.model_->col_cost_[col]); + calcFixVal(mipsolver.mipdata_->rootlpsol.empty() + ? 0.0 + : fracval - mipsolver.mipdata_->rootlpsol[col], + fracval, mipsolver.model_->col_cost_[col]); // make sure we do not set an infeasible domain fixval = std::min(localdom.col_upper_[col], fixval); fixval = std::max(localdom.col_lower_[col], fixval); @@ -679,8 +680,8 @@ void HighsPrimalHeuristics::RINS(const std::vector& relaxationsol) { // solution if the change is at least 0.4 // otherwise take the direction where the objective gets worse // if objective is zero round to nearest integer - fixval = computeFixValue(fracval - mipsolver.mipdata_->rootlpsol[col], - fracval, mipsolver.model_->col_cost_[col]); + fixval = calcFixVal(fracval - mipsolver.mipdata_->rootlpsol[col], + fracval, mipsolver.model_->col_cost_[col]); } // make sure we do not set an infeasible domain fixval = std::min(localdom.col_upper_[col], fixval); From 7e6e14bb777b93a73bc2ee0b6c820e23ec8c7d66 Mon Sep 17 00:00:00 2001 From: fwesselm Date: Mon, 18 Aug 2025 10:33:36 +0200 Subject: [PATCH 5/5] Fix issue --- highs/mip/HighsPrimalHeuristics.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/highs/mip/HighsPrimalHeuristics.cpp b/highs/mip/HighsPrimalHeuristics.cpp index c183de9492a..57dbb01ab1d 100644 --- a/highs/mip/HighsPrimalHeuristics.cpp +++ b/highs/mip/HighsPrimalHeuristics.cpp @@ -323,8 +323,7 @@ void HighsPrimalHeuristics::rootReducedCost() { 12); } -constexpr static double calcFixVal(double rootchange, double fracval, - double cost) { +static double calcFixVal(double rootchange, double fracval, double cost) { // reinforce direction of this solution away from root // solution if the change is at least 0.4 // otherwise take the direction where the objective gets worse