From 3b0684822f997df353f884e425be90bdbcc7297a Mon Sep 17 00:00:00 2001 From: fwesselm Date: Thu, 9 Jul 2026 12:06:37 +0200 Subject: [PATCH 01/24] Fix accuracy of substitution --- highs/presolve/HPresolve.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/highs/presolve/HPresolve.cpp b/highs/presolve/HPresolve.cpp index 4c20fac715d..4e49070cf00 100644 --- a/highs/presolve/HPresolve.cpp +++ b/highs/presolve/HPresolve.cpp @@ -2952,7 +2952,8 @@ void HPresolve::substitute(HighsInt row, HighsInt col, double rhs) { // substitute column in the objective function if (model->col_cost_[col] != 0.0) { - HighsCDouble objscale = model->col_cost_[col] * substrowscale; + HighsCDouble objscale = + static_cast(model->col_cost_[col]) * substrowscale; model->offset_ = static_cast(model->offset_ - objscale * rhs); assert(std::isfinite(model->offset_)); for (HighsInt rowiter : rowpositions) { @@ -2967,7 +2968,7 @@ void HPresolve::substitute(HighsInt row, HighsInt col, double rhs) { } assert(std::abs(model->col_cost_[col]) <= std::max(options->dual_feasibility_tolerance, - kHighsTiny * std::abs(static_cast(objscale)))); + static_cast(kHighsTiny * abs(objscale)))); model->col_cost_[col] = 0.0; } @@ -5170,7 +5171,7 @@ HPresolve::Result HPresolve::singletonColStuffing( break; // compute delta (bound difference) HighsCDouble delta = - t.multiplier * t.val * + t.multiplier * static_cast(t.val) * (static_cast(model->col_upper_[t.col]) - static_cast(model->col_lower_[t.col])); // check if variable can be fixed @@ -7104,10 +7105,12 @@ HPresolve::Result HPresolve::strengthenInequalities( double ub = model->col_upper_[col] - model->col_lower_[col]; if (weight > 0) { comp = 1; - maxviolation += model->col_upper_[col] * weight; + maxviolation += + static_cast(model->col_upper_[col]) * weight; } else { comp = -1; - maxviolation += model->col_lower_[col] * weight; + maxviolation += + static_cast(model->col_lower_[col]) * weight; weight = -weight; } @@ -7227,16 +7230,15 @@ HPresolve::Result HPresolve::strengthenInequalities( HighsInt direction) { for (HighsInt i : indices) { assert(Arow[positions[i]] == row); - double coefdelta = - direction * static_cast(reducedcost[i] - maxviolation); + HighsCDouble coefdelta = direction * (reducedcost[i] - maxviolation); HighsInt col = Acol[positions[i]]; if (complementation[i] == -1) { rhs += coefdelta * model->col_lower_[col]; - addToMatrix(row, col, coefdelta); + addToMatrix(row, col, static_cast(coefdelta)); } else { rhs -= coefdelta * model->col_upper_[col]; - addToMatrix(row, col, -coefdelta); + addToMatrix(row, col, static_cast(-coefdelta)); } } }; From 11509e3f58d01a0f6072eeaf394cba8ef111e4c9 Mon Sep 17 00:00:00 2001 From: fwesselm Date: Thu, 9 Jul 2026 13:39:05 +0200 Subject: [PATCH 02/24] objectiveLower changes --- highs/mip/HighsDomain.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/highs/mip/HighsDomain.cpp b/highs/mip/HighsDomain.cpp index f09d0f5b817..f5e549acebc 100644 --- a/highs/mip/HighsDomain.cpp +++ b/highs/mip/HighsDomain.cpp @@ -730,12 +730,14 @@ HighsDomain::ObjectivePropagation::ObjectivePropagation(HighsDomain* domain) if (domain->col_lower_[col] == -kHighsInf) ++numInfObjLower; else - objectiveLower += domain->col_lower_[col] * cost[col]; + objectiveLower += + static_cast(domain->col_lower_[col]) * cost[col]; } else { if (domain->col_upper_[col] == kHighsInf) ++numInfObjLower; else - objectiveLower += domain->col_upper_[col] * cost[col]; + objectiveLower += + static_cast(domain->col_upper_[col]) * cost[col]; } } @@ -845,12 +847,12 @@ void HighsDomain::ObjectivePropagation::updateActivityLbChange( if (oldbound == -kHighsInf) --numInfObjLower; else - objectiveLower -= oldbound * cost[col]; + objectiveLower -= static_cast(oldbound) * cost[col]; if (newbound == -kHighsInf) ++numInfObjLower; else - objectiveLower += newbound * cost[col]; + objectiveLower += static_cast(newbound) * cost[col]; debugCheckObjectiveLower(); @@ -965,12 +967,12 @@ void HighsDomain::ObjectivePropagation::updateActivityUbChange( if (oldbound == kHighsInf) --numInfObjLower; else - objectiveLower -= oldbound * cost[col]; + objectiveLower -= static_cast(oldbound) * cost[col]; if (newbound == kHighsInf) ++numInfObjLower; else - objectiveLower += newbound * cost[col]; + objectiveLower += static_cast(newbound) * cost[col]; debugCheckObjectiveLower(); @@ -1105,18 +1107,19 @@ void HighsDomain::ObjectivePropagation::debugCheckObjectiveLower() const { HighsInt col = objNonzeros[i]; if (cost[col] > 0) { if (domain->col_lower_[col] > -kHighsInf) - lowerFromScratch += domain->col_lower_[col] * cost[col]; + lowerFromScratch += + static_cast(domain->col_lower_[col]) * cost[col]; else ++numInf; } else { if (domain->col_upper_[col] < kHighsInf) - lowerFromScratch += domain->col_upper_[col] * cost[col]; + lowerFromScratch += + static_cast(domain->col_upper_[col]) * cost[col]; else ++numInf; } } - assert(std::fabs(double(lowerFromScratch - objectiveLower)) <= - domain->feastol()); + assert(abs(lowerFromScratch - objectiveLower) <= domain->feastol()); assert(numInf == numInfObjLower); #endif } From 85e3dd6d03aa10b5dc1795150f558986541b03bb Mon Sep 17 00:00:00 2001 From: fwesselm Date: Thu, 9 Jul 2026 14:57:55 +0200 Subject: [PATCH 03/24] Compute M with quad precision --- highs/mip/HighsDomain.cpp | 48 +++++++++++++++++++++++---------------- highs/mip/HighsDomain.h | 2 +- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/highs/mip/HighsDomain.cpp b/highs/mip/HighsDomain.cpp index f5e549acebc..90710d1d596 100644 --- a/highs/mip/HighsDomain.cpp +++ b/highs/mip/HighsDomain.cpp @@ -2803,12 +2803,13 @@ bool HighsDomain::ConflictSet::explainBoundChangeGeq( if (it != currentFrontier.end()) { cand.baseBound = it->domchg.boundval; if (cand.baseBound != globaldom.col_upper_[col]) - M += vals[i] * (cand.baseBound - globaldom.col_upper_[col]); + M += vals[i] * (static_cast(cand.baseBound) - + globaldom.col_upper_[col]); if (cand.baseBound <= ub) continue; } else cand.baseBound = globaldom.col_upper_[col]; - cand.delta = vals[i] * (ub - cand.baseBound); + cand.delta = vals[i] * (static_cast(ub) - cand.baseBound); cand.prio = computePrio(vals[i], ub, globaldom.col_upper_[col], nodequeue.numNodesDown(col)); } else { @@ -2820,12 +2821,13 @@ bool HighsDomain::ConflictSet::explainBoundChangeGeq( if (it != currentFrontier.end()) { cand.baseBound = it->domchg.boundval; if (cand.baseBound != globaldom.col_lower_[col]) - M += vals[i] * (cand.baseBound - globaldom.col_lower_[col]); + M += vals[i] * (static_cast(cand.baseBound) - + globaldom.col_lower_[col]); if (cand.baseBound >= lb) continue; } else cand.baseBound = globaldom.col_lower_[col]; - cand.delta = vals[i] * (lb - cand.baseBound); + cand.delta = vals[i] * (static_cast(lb) - cand.baseBound); cand.prio = computePrio(vals[i], lb, globaldom.col_lower_[col], nodequeue.numNodesUp(col)); } @@ -2871,9 +2873,11 @@ bool HighsDomain::ConflictSet::explainBoundChangeGeq( // M is the current residual activity initially if (domchgVal < 0) - M -= domchgVal * globaldom.col_lower_[domchg.domchg.column]; + M -= static_cast(domchgVal) * + globaldom.col_lower_[domchg.domchg.column]; else - M -= domchgVal * globaldom.col_upper_[domchg.domchg.column]; + M -= static_cast(domchgVal) * + globaldom.col_upper_[domchg.domchg.column]; return resolveLinearGeq(M, Mupper, vals); } @@ -2911,12 +2915,13 @@ bool HighsDomain::ConflictSet::explainBoundChangeLeq( if (it != currentFrontier.end()) { cand.baseBound = it->domchg.boundval; if (cand.baseBound != globaldom.col_lower_[col]) - M += vals[i] * (cand.baseBound - globaldom.col_lower_[col]); + M += vals[i] * (static_cast(cand.baseBound) - + globaldom.col_lower_[col]); if (cand.baseBound >= lb) continue; } else cand.baseBound = globaldom.col_lower_[col]; - cand.delta = vals[i] * (lb - cand.baseBound); + cand.delta = vals[i] * (static_cast(lb) - cand.baseBound); cand.prio = computePrio(vals[i], lb, globaldom.col_lower_[col], nodequeue.numNodesUp(col)); } else { @@ -2927,12 +2932,13 @@ bool HighsDomain::ConflictSet::explainBoundChangeLeq( if (it != currentFrontier.end()) { cand.baseBound = it->domchg.boundval; if (cand.baseBound != globaldom.col_upper_[col]) - M += vals[i] * (cand.baseBound - globaldom.col_upper_[col]); + M += vals[i] * (static_cast(cand.baseBound) - + globaldom.col_upper_[col]); if (cand.baseBound <= ub) continue; } else cand.baseBound = globaldom.col_upper_[col]; - cand.delta = vals[i] * (ub - cand.baseBound); + cand.delta = vals[i] * (static_cast(ub) - cand.baseBound); cand.prio = computePrio(vals[i], ub, globaldom.col_upper_[col], nodequeue.numNodesDown(col)); } @@ -2980,9 +2986,11 @@ bool HighsDomain::ConflictSet::explainBoundChangeLeq( // M is the global residual activity initially if (domchgVal < 0) - M -= domchgVal * globaldom.col_upper_[domchg.domchg.column]; + M -= static_cast(domchgVal) * + globaldom.col_upper_[domchg.domchg.column]; else - M -= domchgVal * globaldom.col_lower_[domchg.domchg.column]; + M -= static_cast(domchgVal) * + globaldom.col_lower_[domchg.domchg.column]; return resolveLinearLeq(M, Mlower, vals); } @@ -3042,7 +3050,7 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, locdomchg.pos = localdom.prevboundval_[locdomchg.pos].second; // bound can be relaxed - M += vals[i] * (relaxLb - lb); + M += vals[i] * (static_cast(relaxLb) - lb); // ++numRelaxed; } @@ -3073,7 +3081,7 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, while (relaxUb >= localdom.prevboundval_[locdomchg.pos].first) locdomchg.pos = localdom.prevboundval_[locdomchg.pos].second; - M += vals[i] * (relaxUb - ub); + M += vals[i] * (static_cast(relaxUb) - ub); // ++numRelaxed; } @@ -3154,7 +3162,7 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, while (relaxLb <= localdom.prevboundval_[locdomchg.pos].first) locdomchg.pos = localdom.prevboundval_[locdomchg.pos].second; - M += vals[i] * (relaxLb - lb); + M += vals[i] * (static_cast(relaxLb) - lb); // ++numRelaxed; } @@ -3185,7 +3193,7 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, while (relaxUb >= localdom.prevboundval_[locdomchg.pos].first) locdomchg.pos = localdom.prevboundval_[locdomchg.pos].second; - M += vals[i] * (relaxUb - ub); + M += vals[i] * (static_cast(relaxUb) - ub); // ++numRelaxed; } @@ -3398,14 +3406,14 @@ bool HighsDomain::ConflictSet::explainInfeasibilityGeq(const HighsInt* inds, double ub = localdom.getColUpperPos(col, infeasible_pos, cand.boundPos); cand.baseBound = globaldom.col_upper_[col]; if (cand.baseBound <= ub || cand.boundPos == -1) continue; - cand.delta = vals[i] * (ub - cand.baseBound); + cand.delta = vals[i] * (static_cast(ub) - cand.baseBound); cand.prio = computePrio(vals[i], ub, globaldom.col_upper_[col], nodequeue.numNodesDown(col)); } else { double lb = localdom.getColLowerPos(col, infeasible_pos, cand.boundPos); cand.baseBound = globaldom.col_lower_[col]; if (cand.baseBound >= lb || cand.boundPos == -1) continue; - cand.delta = vals[i] * (lb - cand.baseBound); + cand.delta = vals[i] * (static_cast(lb) - cand.baseBound); cand.prio = computePrio(vals[i], lb, globaldom.col_lower_[col], nodequeue.numNodesUp(col)); } @@ -3445,14 +3453,14 @@ bool HighsDomain::ConflictSet::explainInfeasibilityLeq(const HighsInt* inds, double lb = localdom.getColLowerPos(col, infeasible_pos, cand.boundPos); cand.baseBound = globaldom.col_lower_[col]; if (cand.baseBound >= lb || cand.boundPos == -1) continue; - cand.delta = vals[i] * (lb - cand.baseBound); + cand.delta = vals[i] * (static_cast(lb) - cand.baseBound); cand.prio = computePrio(vals[i], lb, globaldom.col_lower_[col], nodequeue.numNodesUp(col)); } else { double ub = localdom.getColUpperPos(col, infeasible_pos, cand.boundPos); cand.baseBound = globaldom.col_upper_[col]; if (cand.baseBound <= ub || cand.boundPos == -1) continue; - cand.delta = vals[i] * (ub - cand.baseBound); + cand.delta = vals[i] * (static_cast(ub) - cand.baseBound); cand.prio = computePrio(vals[i], ub, globaldom.col_upper_[col], nodequeue.numNodesDown(col)); } diff --git a/highs/mip/HighsDomain.h b/highs/mip/HighsDomain.h index e69ab43c8c9..df255acedc4 100644 --- a/highs/mip/HighsDomain.h +++ b/highs/mip/HighsDomain.h @@ -88,7 +88,7 @@ class HighsDomain { std::vector resolvedDomainChanges; struct ResolveCandidate { - double delta; + HighsCDouble delta; double baseBound; double prio; HighsInt boundPos; From 3e26a682ba793e0771d16f488beca25d88fd1a93 Mon Sep 17 00:00:00 2001 From: fwesselm Date: Thu, 9 Jul 2026 16:11:13 +0200 Subject: [PATCH 04/24] Use feastol() --- highs/mip/HighsDomain.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/highs/mip/HighsDomain.cpp b/highs/mip/HighsDomain.cpp index 90710d1d596..9762ef99263 100644 --- a/highs/mip/HighsDomain.cpp +++ b/highs/mip/HighsDomain.cpp @@ -2852,9 +2852,9 @@ bool HighsDomain::ConflictSet::explainBoundChangeGeq( // in case of an integral variable the bound was rounded and can be // relaxed by 1-feastol. We use 1 - 10 * feastol for numerical safety. if (domchg.domchg.boundtype == HighsBoundType::kLower) - b0 -= (1.0 - 10 * localdom.mipsolver->mipdata_->feastol); + b0 -= (1.0 - 10 * localdom.feastol()); else - b0 += (1.0 - 10 * localdom.mipsolver->mipdata_->feastol); + b0 += (1.0 - 10 * localdom.feastol()); } else { // for a continuous variable we relax the bound by epsilon to // accommodate for tiny rounding errors @@ -2965,9 +2965,9 @@ bool HighsDomain::ConflictSet::explainBoundChangeLeq( // in case of an integral variable the bound was rounded and can be // relaxed by 1-feastol. We use 1 - 10 * feastol for numerical safety if (domchg.domchg.boundtype == HighsBoundType::kLower) - b0 -= (1.0 - 10 * localdom.mipsolver->mipdata_->feastol); + b0 -= (1.0 - 10 * localdom.feastol()); else - b0 += (1.0 - 10 * localdom.mipsolver->mipdata_->feastol); + b0 += (1.0 - 10 * localdom.feastol()); } else { // for a continuous variable we relax the bound by epsilon to // accommodate for tiny rounding errors @@ -3095,7 +3095,7 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, // (int)numRelaxed, (int)numDropped, // (int)resolvedDomainChanges.size()); - assert(covered <= localdom.mipsolver->mipdata_->feastol); + assert(covered <= localdom.feastol()); } } @@ -3207,7 +3207,7 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, // (int)numRelaxed, (int)numDropped, // (int)resolvedDomainChanges.size()); - assert(covered >= -localdom.mipsolver->mipdata_->feastol); + assert(covered >= -localdom.feastol()); } } return true; @@ -3232,12 +3232,12 @@ bool HighsDomain::ConflictSet::explainInfeasibility() { double ub = localdom.getColUpperPos(col, conflictingBoundPos, otherBoundPos); assert(localdom.domchgstack_[conflictingBoundPos].boundval - ub > - +localdom.mipsolver->mipdata_->feastol); + +localdom.feastol()); } else { double lb = localdom.getColLowerPos(col, conflictingBoundPos, otherBoundPos); assert(localdom.domchgstack_[conflictingBoundPos].boundval - lb < - -localdom.mipsolver->mipdata_->feastol); + -localdom.feastol()); } if (otherBoundPos != -1) resolvedDomainChanges.push_back( @@ -3424,8 +3424,7 @@ bool HighsDomain::ConflictSet::explainInfeasibilityGeq(const HighsInt* inds, pdqsort(resolveBuffer.begin(), resolveBuffer.end()); // compute the lower bound of M that is necessary - double Mupper = rhs - std::max(10.0, std::fabs(rhs)) * - localdom.mipsolver->mipdata_->feastol; + double Mupper = rhs - std::max(10.0, std::fabs(rhs)) * localdom.feastol(); assert(reasonSideFrontier.empty()); return resolveLinearGeq(maxAct, Mupper, vals); @@ -3471,8 +3470,7 @@ bool HighsDomain::ConflictSet::explainInfeasibilityLeq(const HighsInt* inds, pdqsort(resolveBuffer.begin(), resolveBuffer.end()); // compute the lower bound of M that is necessary - double Mlower = rhs + std::max(10.0, std::fabs(rhs)) * - localdom.mipsolver->mipdata_->feastol; + double Mlower = rhs + std::max(10.0, std::fabs(rhs)) * localdom.feastol(); return resolveLinearLeq(minAct, Mlower, vals); } From f93fb72f5d069c6541c3f95aeaf3086ddd5fa6ba Mon Sep 17 00:00:00 2001 From: fwesselm Date: Thu, 9 Jul 2026 16:44:31 +0200 Subject: [PATCH 05/24] WIP --- highs/mip/HighsDomain.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/highs/mip/HighsDomain.cpp b/highs/mip/HighsDomain.cpp index 9762ef99263..25b7fce8f69 100644 --- a/highs/mip/HighsDomain.cpp +++ b/highs/mip/HighsDomain.cpp @@ -3028,14 +3028,14 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, if (locdomchg.domchg.boundtype == HighsBoundType::kLower) { double lb = locdomchg.domchg.boundval; double glb = reasonDomchg.baseBound; - double relaxLb = - double(((Mupper - (M - reasonDomchg.delta)) / vals[i]) + glb); + HighsCDouble relaxLb = + ((Mupper - (M - reasonDomchg.delta)) / vals[i]) + glb; if (!localdom.mipsolver->isColContinuous(col)) - relaxLb = std::ceil(relaxLb); + relaxLb = ceil(relaxLb); if (relaxLb - lb >= -localdom.feastol()) continue; - locdomchg.domchg.boundval = relaxLb; + locdomchg.domchg.boundval = static_cast(relaxLb); if (relaxLb - glb <= localdom.mipsolver->mipdata_->epsilon) { // domain change can be fully removed from conflict @@ -3059,14 +3059,14 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, } else { double ub = locdomchg.domchg.boundval; double gub = reasonDomchg.baseBound; - double relaxUb = - double(((Mupper - (M - reasonDomchg.delta)) / vals[i]) + gub); + HighsCDouble relaxUb = + ((Mupper - (M - reasonDomchg.delta)) / vals[i]) + gub; if (!localdom.mipsolver->isColContinuous(col)) - relaxUb = std::floor(relaxUb); + relaxUb = floor(relaxUb); if (relaxUb - ub <= localdom.feastol()) continue; - locdomchg.domchg.boundval = relaxUb; + locdomchg.domchg.boundval = static_cast(relaxUb); if (relaxUb - gub >= -localdom.mipsolver->mipdata_->epsilon) { // domain change can be fully removed from conflict @@ -3140,14 +3140,14 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, if (locdomchg.domchg.boundtype == HighsBoundType::kLower) { double lb = locdomchg.domchg.boundval; double glb = reasonDomchg.baseBound; - double relaxLb = - double(((Mlower - (M - reasonDomchg.delta)) / vals[i]) + glb); + HighsCDouble relaxLb = + ((Mlower - (M - reasonDomchg.delta)) / vals[i]) + glb; if (!localdom.mipsolver->isColContinuous(col)) - relaxLb = std::ceil(relaxLb); + relaxLb = ceil(relaxLb); if (relaxLb - lb >= -localdom.feastol()) continue; - locdomchg.domchg.boundval = relaxLb; + locdomchg.domchg.boundval = static_cast(relaxLb); if (relaxLb - glb <= localdom.mipsolver->mipdata_->epsilon) { // domain change can be fully removed from conflict @@ -3171,14 +3171,14 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, } else { double ub = locdomchg.domchg.boundval; double gub = reasonDomchg.baseBound; - double relaxUb = - double(((Mlower - (M - reasonDomchg.delta)) / vals[i]) + gub); + HighsCDouble relaxUb = + ((Mlower - (M - reasonDomchg.delta)) / vals[i]) + gub; if (!localdom.mipsolver->isColContinuous(col)) - relaxUb = std::floor(relaxUb); + relaxUb = floor(relaxUb); if (relaxUb - ub <= localdom.feastol()) continue; - locdomchg.domchg.boundval = relaxUb; + locdomchg.domchg.boundval = static_cast(relaxUb); if (relaxUb - gub >= -localdom.mipsolver->mipdata_->epsilon) { // domain change can be fully removed from conflict From 4caf14b6da1f3e54a1e7791fcf80b6fe15b62c9c Mon Sep 17 00:00:00 2001 From: fwesselm Date: Fri, 10 Jul 2026 09:50:25 +0200 Subject: [PATCH 06/24] Debug --- highs/mip/HighsDomain.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/highs/mip/HighsDomain.cpp b/highs/mip/HighsDomain.cpp index 25b7fce8f69..b131d6f685f 100644 --- a/highs/mip/HighsDomain.cpp +++ b/highs/mip/HighsDomain.cpp @@ -3207,7 +3207,14 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, // (int)numRelaxed, (int)numDropped, // (int)resolvedDomainChanges.size()); - assert(covered >= -localdom.feastol()); + if (covered < -localdom.mipsolver->mipdata_->feastol) { + printf( + "resolveLinearLeq assertion: covered = %.17g, feastol = %.17g, " + "M = %.17g, Mlower = %.17g, resolvedDomainChanges.size() = %d\n", + covered, localdom.mipsolver->mipdata_->feastol, + static_cast(M), Mlower, (int)resolvedDomainChanges.size()); + } + assert(covered >= -localdom.mipsolver->mipdata_->feastol); } } return true; From 652de1ee13fc6caa1ca7a81a7a210cbce36b8795 Mon Sep 17 00:00:00 2001 From: fwesselm Date: Fri, 10 Jul 2026 10:20:17 +0200 Subject: [PATCH 07/24] Simplify --- highs/mip/HighsDomain.cpp | 143 +++++++++++++++++--------------------- highs/mip/HighsDomain.h | 2 + 2 files changed, 66 insertions(+), 79 deletions(-) diff --git a/highs/mip/HighsDomain.cpp b/highs/mip/HighsDomain.cpp index b131d6f685f..93344acbb36 100644 --- a/highs/mip/HighsDomain.cpp +++ b/highs/mip/HighsDomain.cpp @@ -537,8 +537,7 @@ void HighsDomain::CutpoolPropagation::updateActivityLbChange( } if (activitycutsinf_[row] == 0 && - activitycuts_[row] - cutpool->getRhs()[row] > - domain->mipsolver->mipdata_->feastol) { + activitycuts_[row] - cutpool->getRhs()[row] > domain->feastol()) { domain->mipsolver->mipdata_->debugSolution.nodePruned(*domain); domain->infeasible_ = true; domain->infeasible_pos = domain->domchgstack_.size(); @@ -603,8 +602,7 @@ void HighsDomain::CutpoolPropagation::updateActivityUbChange( } if (activitycutsinf_[row] == 0 && - activitycuts_[row] - cutpool->getRhs()[row] > - domain->mipsolver->mipdata_->feastol) { + activitycuts_[row] - cutpool->getRhs()[row] > domain->feastol()) { domain->mipsolver->mipdata_->debugSolution.nodePruned(*domain); domain->infeasible_ = true; domain->infeasible_pos = domain->domchgstack_.size(); @@ -1354,19 +1352,17 @@ double HighsDomain::adjustedUb(HighsInt col, HighsCDouble boundVal, double bound; if (mipsolver->isColIntegral(col)) { - bound = static_cast(floor(boundVal + mipsolver->mipdata_->feastol)); + bound = static_cast(floor(boundVal + feastol())); accept = bound < col_upper_[col] && - col_upper_[col] - bound > - 1000.0 * mipsolver->mipdata_->feastol * std::fabs(bound); + col_upper_[col] - bound > 1000.0 * feastol() * std::fabs(bound); } else { - if (std::fabs(double(boundVal) - col_lower_[col]) <= - mipsolver->mipdata_->epsilon) + if (std::fabs(double(boundVal) - col_lower_[col]) <= epsilon()) bound = col_lower_[col]; else bound = double(boundVal); if (col_upper_[col] == kHighsInf) accept = true; - else if (bound + 1000.0 * mipsolver->mipdata_->feastol < col_upper_[col]) { + else if (bound + 1000.0 * feastol() < col_upper_[col]) { double relativeImprove = col_upper_[col] - bound; if (col_lower_[col] != -kHighsInf) relativeImprove /= col_upper_[col] - col_lower_[col]; @@ -1386,19 +1382,17 @@ double HighsDomain::adjustedLb(HighsInt col, HighsCDouble boundVal, double bound; if (mipsolver->isColIntegral(col)) { - bound = static_cast(ceil(boundVal - mipsolver->mipdata_->feastol)); + bound = static_cast(ceil(boundVal - feastol())); accept = bound > col_lower_[col] && - bound - col_lower_[col] > - 1000.0 * mipsolver->mipdata_->feastol * std::fabs(bound); + bound - col_lower_[col] > 1000.0 * feastol() * std::fabs(bound); } else { - if (std::fabs(col_upper_[col] - double(boundVal)) <= - mipsolver->mipdata_->epsilon) + if (std::fabs(col_upper_[col] - double(boundVal)) <= epsilon()) bound = col_upper_[col]; else bound = double(boundVal); if (col_lower_[col] == -kHighsInf) accept = true; - else if (bound - 1000.0 * mipsolver->mipdata_->feastol > col_lower_[col]) { + else if (bound - 1000.0 * feastol() > col_lower_[col]) { double relativeImprove = bound - col_lower_[col]; if (col_upper_[col] != kHighsInf) relativeImprove /= col_upper_[col] - col_lower_[col]; @@ -1435,8 +1429,7 @@ HighsInt HighsDomain::propagateRowUpper(const HighsInt* Rindex, } HighsCDouble boundVal = (Rupper - minresact) / Rvalue[i]; - if (std::fabs(double(boundVal) * kHighsTiny) > mipsolver->mipdata_->feastol) - continue; + if (std::fabs(double(boundVal) * kHighsTiny) > feastol()) continue; if (Rvalue[i] > 0) { bool accept; @@ -1479,8 +1472,7 @@ HighsInt HighsDomain::propagateRowLower(const HighsInt* Rindex, } HighsCDouble boundVal = (Rlower - maxresact) / Rvalue[i]; - if (std::fabs(double(boundVal) * kHighsTiny) > mipsolver->mipdata_->feastol) - continue; + if (std::fabs(double(boundVal) * kHighsTiny) > feastol()) continue; if (Rvalue[i] < 0) { bool accept; @@ -1504,14 +1496,12 @@ void HighsDomain::updateThresholdLbChange(HighsInt col, double newbound, double val, double& threshold) const { if (newbound != col_upper_[col]) { double thresholdNew = - std::fabs(val) * boundRange(col_upper_[col], newbound, - mipsolver->mipdata_->feastol, - variableType(col)); + std::fabs(val) * + boundRange(col_upper_[col], newbound, feastol(), variableType(col)); // the new threshold is now the maximum of the new threshold and the current // one - threshold = - std::max({threshold, thresholdNew, mipsolver->mipdata_->feastol}); + threshold = std::max({threshold, thresholdNew, feastol()}); } } @@ -1519,14 +1509,12 @@ void HighsDomain::updateThresholdUbChange(HighsInt col, double newbound, double val, double& threshold) const { if (newbound != col_lower_[col]) { double thresholdNew = - std::fabs(val) * boundRange(newbound, col_lower_[col], - mipsolver->mipdata_->feastol, - variableType(col)); + std::fabs(val) * + boundRange(newbound, col_lower_[col], feastol(), variableType(col)); // the new threshold is now the maximum of the new threshold and the current // one - threshold = - std::max({threshold, thresholdNew, mipsolver->mipdata_->feastol}); + threshold = std::max({threshold, thresholdNew, feastol()}); } } @@ -1560,7 +1548,7 @@ void HighsDomain::updateActivityLbChange(HighsInt col, double oldbound, mipsolver->mipdata_->ARindex_.data(), mipsolver->mipdata_->ARvalue_.data(), tmpinf, tmpminact); assert(std::fabs(double(activitymin_[mip->a_matrix_.index_[i]] - - tmpminact)) <= mipsolver->mipdata_->feastol); + tmpminact)) <= feastol()); assert(tmpinf == activitymininf_[mip->a_matrix_.index_[i]]); } #endif @@ -1580,7 +1568,7 @@ void HighsDomain::updateActivityLbChange(HighsInt col, double oldbound, activitymininf_[mip->a_matrix_.index_[i]] == 0 && activitymin_[mip->a_matrix_.index_[i]] - mip->row_upper_[mip->a_matrix_.index_[i]] > - mipsolver->mipdata_->feastol) { + feastol()) { mipsolver->mipdata_->debugSolution.nodePruned(*this); infeasible_ = true; infeasible_pos = domchgstack_.size(); @@ -1609,7 +1597,7 @@ void HighsDomain::updateActivityLbChange(HighsInt col, double oldbound, mipsolver->mipdata_->ARindex_.data(), mipsolver->mipdata_->ARvalue_.data(), tmpinf, tmpmaxact); assert(std::fabs(double(activitymax_[mip->a_matrix_.index_[i]] - - tmpmaxact)) <= mipsolver->mipdata_->feastol); + tmpmaxact)) <= feastol()); assert(tmpinf == activitymaxinf_[mip->a_matrix_.index_[i]]); } #endif @@ -1629,7 +1617,7 @@ void HighsDomain::updateActivityLbChange(HighsInt col, double oldbound, activitymaxinf_[mip->a_matrix_.index_[i]] == 0 && mip->row_lower_[mip->a_matrix_.index_[i]] - activitymax_[mip->a_matrix_.index_[i]] > - mipsolver->mipdata_->feastol) { + feastol()) { mipsolver->mipdata_->debugSolution.nodePruned(*this); infeasible_ = true; infeasible_pos = domchgstack_.size(); @@ -1727,7 +1715,7 @@ void HighsDomain::updateActivityUbChange(HighsInt col, double oldbound, mipsolver->mipdata_->ARindex_.data(), mipsolver->mipdata_->ARvalue_.data(), tmpinf, tmpmaxact); assert(std::fabs(double(activitymax_[mip->a_matrix_.index_[i]] - - tmpmaxact)) <= mipsolver->mipdata_->feastol); + tmpmaxact)) <= feastol()); assert(tmpinf == activitymaxinf_[mip->a_matrix_.index_[i]]); } #endif @@ -1747,7 +1735,7 @@ void HighsDomain::updateActivityUbChange(HighsInt col, double oldbound, activitymaxinf_[mip->a_matrix_.index_[i]] == 0 && mip->row_lower_[mip->a_matrix_.index_[i]] - activitymax_[mip->a_matrix_.index_[i]] > - mipsolver->mipdata_->feastol) { + feastol()) { mipsolver->mipdata_->debugSolution.nodePruned(*this); infeasible_ = true; infeasible_pos = domchgstack_.size(); @@ -1779,7 +1767,7 @@ void HighsDomain::updateActivityUbChange(HighsInt col, double oldbound, mipsolver->mipdata_->ARindex_.data(), mipsolver->mipdata_->ARvalue_.data(), tmpinf, tmpminact); assert(std::fabs(double(activitymin_[mip->a_matrix_.index_[i]] - - tmpminact)) <= mipsolver->mipdata_->feastol); + tmpminact)) <= feastol()); assert(tmpinf == activitymininf_[mip->a_matrix_.index_[i]]); } #endif @@ -1799,7 +1787,7 @@ void HighsDomain::updateActivityUbChange(HighsInt col, double oldbound, activitymininf_[mip->a_matrix_.index_[i]] == 0 && activitymin_[mip->a_matrix_.index_[i]] - mip->row_upper_[mip->a_matrix_.index_[i]] > - mipsolver->mipdata_->feastol) { + feastol()) { mipsolver->mipdata_->debugSolution.nodePruned(*this); infeasible_ = true; infeasible_pos = domchgstack_.size(); @@ -1938,20 +1926,20 @@ void HighsDomain::markPropagateCut(Reason reason) { void HighsDomain::markPropagate(HighsInt row) { if (!propagateflags_[row]) { - bool proplower = mipsolver->rowLower(row) != -kHighsInf && - (activitymininf_[row] != 0 || - activitymin_[row] < mipsolver->rowLower(row) - - mipsolver->mipdata_->feastol) && - (activitymaxinf_[row] == 1 || - (double(activitymax_[row]) - mipsolver->rowLower(row)) <= - capacityThreshold_[row]); - bool propupper = mipsolver->rowUpper(row) != kHighsInf && - (activitymaxinf_[row] != 0 || - activitymax_[row] > mipsolver->rowUpper(row) + - mipsolver->mipdata_->feastol) && - (activitymininf_[row] == 1 || - (mipsolver->rowUpper(row) - double(activitymin_[row])) <= - capacityThreshold_[row]); + bool proplower = + mipsolver->rowLower(row) != -kHighsInf && + (activitymininf_[row] != 0 || + activitymin_[row] < mipsolver->rowLower(row) - feastol()) && + (activitymaxinf_[row] == 1 || + (double(activitymax_[row]) - mipsolver->rowLower(row)) <= + capacityThreshold_[row]); + bool propupper = + mipsolver->rowUpper(row) != kHighsInf && + (activitymaxinf_[row] != 0 || + activitymax_[row] > mipsolver->rowUpper(row) + feastol()) && + (activitymininf_[row] == 1 || + (mipsolver->rowUpper(row) - double(activitymin_[row])) <= + capacityThreshold_[row]); if (proplower || propupper) { propagateinds_.push_back(row); @@ -2041,8 +2029,7 @@ void HighsDomain::changeBound(HighsDomainChange boundchg, Reason reason) { boundchg.boundval = col_lower_[boundchg.column]; } if (boundchg.boundval > col_upper_[boundchg.column]) { - if (boundchg.boundval - col_upper_[boundchg.column] > - mipsolver->mipdata_->feastol) { + if (boundchg.boundval - col_upper_[boundchg.column] > feastol()) { mipsolver->mipdata_->debugSolution.nodePruned(*this); if (!infeasible_) { infeasible_pos = domchgstack_.size(); @@ -2063,8 +2050,7 @@ void HighsDomain::changeBound(HighsDomainChange boundchg, Reason reason) { boundchg.boundval = col_upper_[boundchg.column]; } if (boundchg.boundval < col_lower_[boundchg.column]) { - if (col_lower_[boundchg.column] - boundchg.boundval > - mipsolver->mipdata_->feastol) { + if (col_lower_[boundchg.column] - boundchg.boundval > feastol()) { mipsolver->mipdata_->debugSolution.nodePruned(*this); if (!infeasible_) { infeasible_pos = domchgstack_.size(); @@ -2438,8 +2424,7 @@ bool HighsDomain::propagate() { if (mipsolver->rowUpper(i) != kHighsInf && (activitymaxinf_[i] != 0 || - activitymax_[i] > - mipsolver->rowUpper(i) + mipsolver->mipdata_->feastol)) { + activitymax_[i] > mipsolver->rowUpper(i) + feastol())) { // computeMinActivity(start, end, mipsolver->ARstart_.data(), // mipsolver->ARvalue_.data(), activitymininf_[i], // activitymin_[i]); @@ -2453,8 +2438,7 @@ bool HighsDomain::propagate() { if (mipsolver->rowLower(i) != -kHighsInf && (activitymininf_[i] != 0 || - activitymin_[i] < - mipsolver->rowLower(i) - mipsolver->mipdata_->feastol)) { + activitymin_[i] < mipsolver->rowLower(i) - feastol())) { // computeMaxActivity(start, end, mipsolver->ARstart_.data(), // mipsolver->ARvalue_.data(), activitymaxinf_[i], // activitymax_[i]); @@ -2685,7 +2669,7 @@ void HighsDomain::tightenCoefficients(HighsInt* inds, double* vals, } HighsCDouble maxabscoef = maxactivity - rhs; - if (maxabscoef > mipsolver->mipdata_->feastol) { + if (maxabscoef > feastol()) { HighsCDouble upper = rhs; HighsInt tightened = 0; for (HighsInt i = 0; i != len; ++i) { @@ -2733,20 +2717,19 @@ bool HighsDomain::isFixing(const HighsDomainChange& domchg) const { double otherbound = domchg.boundtype == HighsBoundType::kUpper ? col_lower_[domchg.column] : col_upper_[domchg.column]; - return std::fabs(domchg.boundval - otherbound) <= - mipsolver->mipdata_->epsilon; + return std::fabs(domchg.boundval - otherbound) <= epsilon(); } HighsDomainChange HighsDomain::flip(const HighsDomainChange& domchg) const { if (domchg.boundtype == HighsBoundType::kLower) { - HighsDomainChange flipped{domchg.boundval - mipsolver->mipdata_->feastol, - domchg.column, HighsBoundType::kUpper}; + HighsDomainChange flipped{domchg.boundval - feastol(), domchg.column, + HighsBoundType::kUpper}; if (mipsolver->isColIntegral(domchg.column)) flipped.boundval = std::floor(flipped.boundval); return flipped; } else { - HighsDomainChange flipped{domchg.boundval + mipsolver->mipdata_->feastol, - domchg.column, HighsBoundType::kLower}; + HighsDomainChange flipped{domchg.boundval + feastol(), domchg.column, + HighsBoundType::kLower}; if (mipsolver->isColIntegral(domchg.column)) flipped.boundval = std::ceil(flipped.boundval); return flipped; @@ -2755,6 +2738,8 @@ HighsDomainChange HighsDomain::flip(const HighsDomainChange& domchg) const { double HighsDomain::feastol() const { return mipsolver->mipdata_->feastol; } +double HighsDomain::epsilon() const { return mipsolver->mipdata_->epsilon; } + HighsDomain::ConflictSet::ConflictSet(HighsDomain& localdom_, const HighsDomain& globaldom_) : localdom(localdom_), @@ -2859,9 +2844,9 @@ bool HighsDomain::ConflictSet::explainBoundChangeGeq( // for a continuous variable we relax the bound by epsilon to // accommodate for tiny rounding errors if (domchg.domchg.boundtype == HighsBoundType::kLower) - b0 -= localdom.mipsolver->mipdata_->epsilon; + b0 -= localdom.epsilon(); else - b0 += localdom.mipsolver->mipdata_->epsilon; + b0 += localdom.epsilon(); } // now multiply the bound constraint with the coefficient value in the @@ -2972,9 +2957,9 @@ bool HighsDomain::ConflictSet::explainBoundChangeLeq( // for a continuous variable we relax the bound by epsilon to // accommodate for tiny rounding errors if (domchg.domchg.boundtype == HighsBoundType::kLower) - b0 -= localdom.mipsolver->mipdata_->epsilon; + b0 -= localdom.epsilon(); else - b0 += localdom.mipsolver->mipdata_->epsilon; + b0 += localdom.epsilon(); } // now multiply the bound constraint with the coefficient value in the @@ -3037,7 +3022,7 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, locdomchg.domchg.boundval = static_cast(relaxLb); - if (relaxLb - glb <= localdom.mipsolver->mipdata_->epsilon) { + if (relaxLb - glb <= localdom.epsilon()) { // domain change can be fully removed from conflict HighsInt last = resolvedDomainChanges.size() - 1; std::swap(resolvedDomainChanges[last], resolvedDomainChanges[k]); @@ -3068,7 +3053,7 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, locdomchg.domchg.boundval = static_cast(relaxUb); - if (relaxUb - gub >= -localdom.mipsolver->mipdata_->epsilon) { + if (relaxUb - gub >= -localdom.epsilon()) { // domain change can be fully removed from conflict HighsInt last = resolvedDomainChanges.size() - 1; std::swap(resolvedDomainChanges[last], resolvedDomainChanges[k]); @@ -3149,7 +3134,7 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, locdomchg.domchg.boundval = static_cast(relaxLb); - if (relaxLb - glb <= localdom.mipsolver->mipdata_->epsilon) { + if (relaxLb - glb <= localdom.epsilon()) { // domain change can be fully removed from conflict HighsInt last = resolvedDomainChanges.size() - 1; std::swap(resolvedDomainChanges[last], resolvedDomainChanges[k]); @@ -3180,7 +3165,7 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, locdomchg.domchg.boundval = static_cast(relaxUb); - if (relaxUb - gub >= -localdom.mipsolver->mipdata_->epsilon) { + if (relaxUb - gub >= -localdom.epsilon()) { // domain change can be fully removed from conflict HighsInt last = resolvedDomainChanges.size() - 1; std::swap(resolvedDomainChanges[last], resolvedDomainChanges[k]); @@ -3207,14 +3192,14 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, // (int)numRelaxed, (int)numDropped, // (int)resolvedDomainChanges.size()); - if (covered < -localdom.mipsolver->mipdata_->feastol) { + if (covered < -localdom.feastol()) { printf( "resolveLinearLeq assertion: covered = %.17g, feastol = %.17g, " "M = %.17g, Mlower = %.17g, resolvedDomainChanges.size() = %d\n", - covered, localdom.mipsolver->mipdata_->feastol, - static_cast(M), Mlower, (int)resolvedDomainChanges.size()); + covered, localdom.feastol(), static_cast(M), Mlower, + (int)resolvedDomainChanges.size()); } - assert(covered >= -localdom.mipsolver->mipdata_->feastol); + assert(covered >= -localdom.feastol()); } } return true; diff --git a/highs/mip/HighsDomain.h b/highs/mip/HighsDomain.h index df255acedc4..cd92793dc2e 100644 --- a/highs/mip/HighsDomain.h +++ b/highs/mip/HighsDomain.h @@ -654,6 +654,8 @@ class HighsDomain { double feastol() const; + double epsilon() const; + HighsInt numModelNonzeros() const { return mipsolver->numNonzero(); } bool inSubmip() const { return mipsolver->submip; } From 2f5da7e77e12b6a9d124d9d4a7e7aee688e9e75f Mon Sep 17 00:00:00 2001 From: fwesselm Date: Fri, 10 Jul 2026 10:35:48 +0200 Subject: [PATCH 08/24] Fix warnings --- highs/mip/HighsDomain.cpp | 139 +++++++++++++++++++++----------------- highs/mip/HighsDomain.h | 2 +- 2 files changed, 78 insertions(+), 63 deletions(-) diff --git a/highs/mip/HighsDomain.cpp b/highs/mip/HighsDomain.cpp index 93344acbb36..53873da4248 100644 --- a/highs/mip/HighsDomain.cpp +++ b/highs/mip/HighsDomain.cpp @@ -78,12 +78,13 @@ HighsDomain::HighsDomain(HighsMipSolver& mipsolver) : mipsolver(&mipsolver) { } void HighsDomain::addCutpool(HighsCutPool& cutpool) { - HighsInt cutpoolindex = cutpoolpropagation.size(); + HighsInt cutpoolindex = static_cast(cutpoolpropagation.size()); cutpoolpropagation.emplace_back(cutpoolindex, this, cutpool); } void HighsDomain::addConflictPool(HighsConflictPool& conflictPool) { - HighsInt conflictPoolIndex = conflictPoolPropagation.size(); + HighsInt conflictPoolIndex = + static_cast(conflictPoolPropagation.size()); conflictPoolPropagation.emplace_back(conflictPoolIndex, this, conflictPool); } @@ -182,7 +183,7 @@ void HighsDomain::ConflictPoolPropagation::conflictAdded(HighsInt conflict) { const std::vector& conflictEntries = conflictpool_->getConflictEntryVector(); - if (HighsInt(conflictFlag_.size()) <= conflict) { + if (static_cast(conflictFlag_.size()) <= conflict) { watchedLiterals_.resize(2 * conflict + 2); conflictFlag_.resize(conflict + 1); } @@ -453,7 +454,7 @@ void HighsDomain::CutpoolPropagation::cutAdded(HighsInt cut, bool propagate) { const HighsInt* arindex = cutpool->getMatrix().getARindex(); const double* arvalue = cutpool->getMatrix().getARvalue(); - if (HighsInt(activitycuts_.size()) <= cut) { + if (static_cast(activitycuts_.size()) <= cut) { activitycuts_.resize(cut + 1); activitycutsinf_.resize(cut + 1); propagatecutflags_.resize(cut + 1, 2); @@ -469,7 +470,7 @@ void HighsDomain::CutpoolPropagation::cutAdded(HighsInt cut, bool propagate) { const HighsInt* arindex = cutpool->getMatrix().getARindex(); const double* arvalue = cutpool->getMatrix().getARvalue(); - if (HighsInt(activitycuts_.size()) <= cut) { + if (static_cast(activitycuts_.size()) <= cut) { activitycuts_.resize(cut + 1); activitycutsinf_.resize(cut + 1); propagatecutflags_.resize(cut + 1, 2); @@ -493,7 +494,8 @@ void HighsDomain::CutpoolPropagation::cutDeleted( return; } - if (cut < (HighsInt)propagatecutflags_.size()) propagatecutflags_[cut] |= 2; + if (cut < static_cast(propagatecutflags_.size())) + propagatecutflags_[cut] |= 2; } void HighsDomain::CutpoolPropagation::markPropagateCut(HighsInt cut) { @@ -721,7 +723,7 @@ HighsDomain::ObjectivePropagation::ObjectivePropagation(HighsDomain* domain) } // add contribution of remaining objective nonzeros - const HighsInt numObjNz = objNonzeros.size(); + const HighsInt numObjNz = static_cast(objNonzeros.size()); for (HighsInt i = partitionStarts[numPartitions]; i < numObjNz; ++i) { HighsInt col = objNonzeros[i]; if (cost[col] > 0.0) { @@ -748,7 +750,7 @@ void HighsDomain::ObjectivePropagation::getPropagationConstraint( HighsInt& len, double& rhs, HighsInt domchgCol) { const HighsInt numPartitions = objFunc->getNumCliquePartitions(); inds = objFunc->getObjectiveNonzeros().data(); - len = objFunc->getObjectiveNonzeros().size(); + len = static_cast(objFunc->getObjectiveNonzeros().size()); if (numPartitions == 0) { vals = objFunc->getObjectiveValuesPacked().data(); rhs = domain->mipsolver->mipdata_->upper_limit; @@ -811,7 +813,7 @@ void HighsDomain::ObjectivePropagation::recomputeCapacityThreshold() { } const auto& objNonzeros = objFunc->getObjectiveNonzeros(); - const HighsInt numObjNzs = objNonzeros.size(); + const HighsInt numObjNzs = static_cast(objNonzeros.size()); for (HighsInt i = partitionStarts[numPartitions]; i < numObjNzs; ++i) { HighsInt col = objNonzeros[i]; @@ -1083,7 +1085,7 @@ void HighsDomain::ObjectivePropagation::debugCheckObjectiveLower() const { const auto& partitionStarts = objFunc->getCliquePartitionStarts(); const auto& objNonzeros = objFunc->getObjectiveNonzeros(); - const HighsInt numObjNzs = objNonzeros.size(); + const HighsInt numObjNzs = static_cast(objNonzeros.size()); for (HighsInt i = 0; i < numPartitions; ++i) { HighsInt start = partitionStarts[i]; HighsInt end = partitionStarts[i + 1]; @@ -1142,7 +1144,7 @@ void HighsDomain::ObjectivePropagation::propagate() { // Scan non-binary columns for infinite bound contribution until the one // column that contributes with an infinite bound is found which is the only // column that can be propagated - HighsInt numCol = objNonzeros.size(); + HighsInt numCol = static_cast(objNonzeros.size()); for (HighsInt i = objFunc->getNumBinariesInObjective(); i < numCol; ++i) { HighsInt col = objNonzeros[i]; if ((cost[col] > 0 && domain->col_lower_[col] != -kHighsInf) || @@ -1227,7 +1229,7 @@ void HighsDomain::ObjectivePropagation::propagate() { if (domain->infeasible_) break; - const HighsInt numObjNzs = objNonzeros.size(); + const HighsInt numObjNzs = static_cast(objNonzeros.size()); for (HighsInt i = objFunc->getCliquePartitionStarts()[numPartitions]; i < numObjNzs; ++i) { HighsInt col = objNonzeros[i]; @@ -1269,7 +1271,7 @@ void HighsDomain::computeMinActivity(HighsInt start, HighsInt end, HighsInt col = ARindex[j]; double val = ARvalue[j]; - assert(col < int(col_lower_.size())); + assert(col < static_cast(col_lower_.size())); HighsInt tmp; double lb = getColLowerPos(col, infeasible_pos - 1, tmp); @@ -1289,7 +1291,7 @@ void HighsDomain::computeMinActivity(HighsInt start, HighsInt end, HighsInt col = ARindex[j]; double val = ARvalue[j]; - assert(col < int(col_lower_.size())); + assert(col < static_cast(col_lower_.size())); double contributionmin = activityContributionMin(val, col_lower_[col], col_upper_[col]); @@ -1314,7 +1316,7 @@ void HighsDomain::computeMaxActivity(HighsInt start, HighsInt end, HighsInt col = ARindex[j]; double val = ARvalue[j]; - assert(col < int(col_lower_.size())); + assert(col < static_cast(col_lower_.size())); HighsInt tmp; double lb = getColLowerPos(col, infeasible_pos - 1, tmp); @@ -1333,7 +1335,7 @@ void HighsDomain::computeMaxActivity(HighsInt start, HighsInt end, HighsInt col = ARindex[j]; double val = ARvalue[j]; - assert(col < int(col_lower_.size())); + assert(col < static_cast(col_lower_.size())); double contributionmin = activityContributionMax(val, col_lower_[col], col_upper_[col]); @@ -1914,9 +1916,10 @@ void HighsDomain::markPropagateCut(Reason reason) { break; default: assert(reason.type >= 0 && - reason.type < HighsInt(cutpoolpropagation.size() + - conflictPoolPropagation.size())); - if (reason.type < (HighsInt)cutpoolpropagation.size()) + reason.type < + static_cast(cutpoolpropagation.size() + + conflictPoolPropagation.size())); + if (reason.type < static_cast(cutpoolpropagation.size())) cutpoolpropagation[reason.type].markPropagateCut(reason.index); else conflictPoolPropagation[reason.type - cutpoolpropagation.size()] @@ -2013,7 +2016,7 @@ double HighsDomain::doChangeBound(const HighsDomainChange& boundchg) { void HighsDomain::changeBound(HighsDomainChange boundchg, Reason reason) { assert(boundchg.column >= 0); - assert(boundchg.column < (HighsInt)col_upper_.size()); + assert(boundchg.column < static_cast(col_upper_.size())); // assert(infeasible_ == 0); // if (reason.type == Reason::kObjective) { // if (!mipsolver->submip) @@ -2073,7 +2076,7 @@ void HighsDomain::changeBound(HighsDomainChange boundchg, Reason reason) { if (reason.type == Reason::kBranching) branchPos_.push_back(domchgstack_.size()); - assert(prevPos < (HighsInt)domchgstack_.size()); + assert(prevPos < static_cast(domchgstack_.size())); bool binary = isBinary(boundchg.column); @@ -2124,7 +2127,7 @@ void HighsDomain::setDomainChangeStack( domchgstack_.clear(); domchgreason_.clear(); branchPos_.clear(); - HighsInt stacksize = domchgstack.size(); + HighsInt stacksize = static_cast(domchgstack.size()); for (HighsInt k = 0; k != stacksize; ++k) { if (domchgstack[k].boundtype == HighsBoundType::kLower && domchgstack[k].boundval <= col_lower_[domchgstack[k].column]) @@ -2158,7 +2161,7 @@ void HighsDomain::setDomainChangeStack( domchgstack_.clear(); domchgreason_.clear(); branchPos_.clear(); - HighsInt stacksize = domchgstack.size(); + HighsInt stacksize = static_cast(domchgstack.size()); HighsInt k = 0; for (HighsInt branchPos : branchingPositions) { for (; k < branchPos; ++k) { @@ -2221,13 +2224,14 @@ void HighsDomain::setDomainChangeStack( } void HighsDomain::backtrackToGlobal() { - HighsInt k = HighsInt(domchgstack_.size()) - 1; + HighsInt k = static_cast(domchgstack_.size()) - 1; bool old_infeasible = infeasible_; Reason old_reason = infeasible_reason; - if (infeasible_ && infeasible_pos == HighsInt(domchgstack_.size())) { + if (infeasible_ && + infeasible_pos == static_cast(domchgstack_.size())) { assert(old_infeasible); - assert(k == HighsInt(domchgstack_.size()) - 1); + assert(k == static_cast(domchgstack_.size()) - 1); infeasible_ = false; infeasible_reason = Reason::unspecified(); } @@ -2256,7 +2260,7 @@ void HighsDomain::backtrackToGlobal() { if (infeasible_ && infeasible_pos == k) { assert(old_infeasible); - assert(k == HighsInt(domchgstack_.size()) - 1); + assert(k == static_cast(domchgstack_.size()) - 1); infeasible_ = false; infeasible_reason = Reason::unspecified(); } @@ -2270,7 +2274,7 @@ void HighsDomain::backtrackToGlobal() { infeasible_ = false; } - HighsInt numreason = domchgreason_.size(); + HighsInt numreason = static_cast(domchgreason_.size()); for (HighsInt i = k + 1; i < numreason; ++i) markPropagateCut(domchgreason_[i]); @@ -2281,13 +2285,14 @@ void HighsDomain::backtrackToGlobal() { } HighsDomainChange HighsDomain::backtrack() { - HighsInt k = HighsInt(domchgstack_.size()) - 1; + HighsInt k = static_cast(domchgstack_.size()) - 1; bool old_infeasible = infeasible_; Reason old_reason = infeasible_reason; - if (infeasible_ && infeasible_pos == HighsInt(domchgstack_.size())) { + if (infeasible_ && + infeasible_pos == static_cast(domchgstack_.size())) { assert(old_infeasible); - assert(k == HighsInt(domchgstack_.size()) - 1); + assert(k == static_cast(domchgstack_.size()) - 1); infeasible_ = false; infeasible_reason = Reason::unspecified(); } @@ -2313,7 +2318,7 @@ HighsDomainChange HighsDomain::backtrack() { if (infeasible_ && infeasible_pos == k) { assert(old_infeasible); - assert(k == HighsInt(domchgstack_.size()) - 1); + assert(k == static_cast(domchgstack_.size()) - 1); infeasible_ = false; infeasible_reason = Reason::unspecified(); } @@ -2332,7 +2337,7 @@ HighsDomainChange HighsDomain::backtrack() { infeasible_ = false; } - HighsInt numreason = domchgreason_.size(); + HighsInt numreason = static_cast(domchgreason_.size()); for (HighsInt i = k + 1; i < numreason; ++i) markPropagateCut(domchgreason_[i]); @@ -2385,7 +2390,8 @@ bool HighsDomain::propagate() { while (havePropagationRows()) { if (objProp_.isActive()) objProp_.propagate(); - const HighsInt numConflictPools = conflictPoolPropagation.size(); + const HighsInt numConflictPools = + static_cast(conflictPoolPropagation.size()); for (HighsInt conflictPool = 0; conflictPool < numConflictPools; ++conflictPool) { auto& conflictprop = conflictPoolPropagation[conflictPool]; @@ -2402,7 +2408,7 @@ bool HighsDomain::propagate() { if (!propagateinds_.empty()) { propagateinds.swap(propagateinds_); - HighsInt numproprows = propagateinds.size(); + HighsInt numproprows = static_cast(propagateinds.size()); for (HighsInt i = 0; i != numproprows; ++i) { HighsInt row = propagateinds[i]; propagateflags_[row] = 0; @@ -2484,13 +2490,13 @@ bool HighsDomain::propagate() { propagateinds.clear(); } - const HighsInt numpools = cutpoolpropagation.size(); + const HighsInt numpools = static_cast(cutpoolpropagation.size()); for (HighsInt cutpool = 0; cutpool != numpools; ++cutpool) { auto& cutpoolprop = cutpoolpropagation[cutpool]; if (!cutpoolprop.propagatecutinds_.empty()) { propagateinds.swap(cutpoolprop.propagatecutinds_); - HighsInt numproprows = propagateinds.size(); + HighsInt numproprows = static_cast(propagateinds.size()); for (HighsInt i = 0; i != numproprows; ++i) { HighsInt cut = propagateinds[i]; cutpoolprop.propagatecutflags_[cut] &= 2; @@ -2624,7 +2630,8 @@ void HighsDomain::conflictAnalyzeReconvergence( if (!conflictSet.explainBoundChangeLeq( conflictSet.reconvergenceFrontier, - ConflictSet::LocalDomChg{HighsInt(domchgstack_.size()), domchg}, + ConflictSet::LocalDomChg{static_cast(domchgstack_.size()), + domchg}, proofinds, proofvals, prooflen, proofrhs, double(activitymin))) return; @@ -2636,7 +2643,7 @@ void HighsDomain::conflictAnalyzeReconvergence( conflictSet.resolvedDomainChanges.begin(), conflictSet.resolvedDomainChanges.end()); - HighsInt depth = branchPos_.size(); + HighsInt depth = static_cast(branchPos_.size()); while (depth > 0) { HighsInt branchPos = branchPos_[depth - 1]; @@ -2702,7 +2709,8 @@ double HighsDomain::getMinCutActivity(const HighsCutPool& cutpool, if (cutpoolprop.cutpool == &cutpool) { // assert((cutpoolprop.propagatecutflags_[cut] & 2) == 0); - return cut < (HighsInt)cutpoolprop.propagatecutflags_.size() && + return cut < static_cast( + cutpoolprop.propagatecutflags_.size()) && (cutpoolprop.propagatecutflags_[cut] & 2) == 0 && cutpoolprop.activitycutsinf_[cut] == 0 ? double(cutpoolprop.activitycuts_[cut]) @@ -2993,7 +3001,7 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, resolvedDomainChanges.push_back(locdomchg); assert(resolvedDomainChanges.back().pos >= 0); assert(resolvedDomainChanges.back().pos < - (HighsInt)localdom.domchgstack_.size()); + static_cast(localdom.domchgstack_.size())); covered = double(M - Mupper); if (covered <= 0) break; } @@ -3005,7 +3013,8 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, // from the explanation // HighsInt numRelaxed = 0; // HighsInt numDropped = 0; - for (HighsInt k = resolvedDomainChanges.size() - 1; k >= 0; --k) { + for (HighsInt k = static_cast(resolvedDomainChanges.size()) - 1; + k >= 0; --k) { ResolveCandidate& reasonDomchg = resolveBuffer[k]; LocalDomChg& locdomchg = resolvedDomainChanges[k]; HighsInt i = reasonDomchg.valuePos; @@ -3024,7 +3033,8 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, if (relaxLb - glb <= localdom.epsilon()) { // domain change can be fully removed from conflict - HighsInt last = resolvedDomainChanges.size() - 1; + HighsInt last = + static_cast(resolvedDomainChanges.size()) - 1; std::swap(resolvedDomainChanges[last], resolvedDomainChanges[k]); resolvedDomainChanges.resize(last); @@ -3055,7 +3065,8 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, if (relaxUb - gub >= -localdom.epsilon()) { // domain change can be fully removed from conflict - HighsInt last = resolvedDomainChanges.size() - 1; + HighsInt last = + static_cast(resolvedDomainChanges.size()) - 1; std::swap(resolvedDomainChanges[last], resolvedDomainChanges[k]); resolvedDomainChanges.resize(last); @@ -3100,7 +3111,7 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, resolvedDomainChanges.push_back(locdomchg); assert(resolvedDomainChanges.back().pos >= 0); assert(resolvedDomainChanges.back().pos < - (HighsInt)localdom.domchgstack_.size()); + static_cast(localdom.domchgstack_.size())); covered = double(M - Mlower); if (covered >= 0) break; } @@ -3117,7 +3128,8 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, // from the explanation // HighsInt numRelaxed = 0; // HighsInt numDropped = 0; - for (HighsInt k = resolvedDomainChanges.size() - 1; k >= 0; --k) { + for (HighsInt k = static_cast(resolvedDomainChanges.size()) - 1; + k >= 0; --k) { ResolveCandidate& reasonDomchg = resolveBuffer[k]; LocalDomChg& locdomchg = resolvedDomainChanges[k]; HighsInt i = reasonDomchg.valuePos; @@ -3136,7 +3148,8 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, if (relaxLb - glb <= localdom.epsilon()) { // domain change can be fully removed from conflict - HighsInt last = resolvedDomainChanges.size() - 1; + HighsInt last = + static_cast(resolvedDomainChanges.size()) - 1; std::swap(resolvedDomainChanges[last], resolvedDomainChanges[k]); resolvedDomainChanges.resize(last); @@ -3167,7 +3180,8 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, if (relaxUb - gub >= -localdom.epsilon()) { // domain change can be fully removed from conflict - HighsInt last = resolvedDomainChanges.size() - 1; + HighsInt last = + static_cast(resolvedDomainChanges.size()) - 1; std::swap(resolvedDomainChanges[last], resolvedDomainChanges[k]); resolvedDomainChanges.resize(last); @@ -3289,11 +3303,11 @@ bool HighsDomain::ConflictSet::explainInfeasibility() { default: assert(localdom.infeasible_reason.type >= 0); assert(localdom.infeasible_reason.type < - HighsInt(localdom.cutpoolpropagation.size() + - localdom.conflictPoolPropagation.size())); + static_cast(localdom.cutpoolpropagation.size() + + localdom.conflictPoolPropagation.size())); if (localdom.infeasible_reason.type < - (HighsInt)localdom.cutpoolpropagation.size()) { + static_cast(localdom.cutpoolpropagation.size())) { HighsInt cutpoolIndex = localdom.infeasible_reason.type; HighsInt cutIndex = localdom.infeasible_reason.index; @@ -3482,13 +3496,13 @@ bool HighsDomain::ConflictSet::explainBoundChange( if (val) { assert(localdom.colLowerPos_[col] >= 0); assert(localdom.colLowerPos_[col] < - (HighsInt)localdom.domchgstack_.size()); + static_cast(localdom.domchgstack_.size())); localdom.getColLowerPos(col, domchg.pos, boundPos); } else { assert(localdom.colUpperPos_[col] >= 0); assert(localdom.colUpperPos_[col] < - (HighsInt)localdom.domchgstack_.size()); + static_cast(localdom.domchgstack_.size())); localdom.getColUpperPos(col, domchg.pos, boundPos); } @@ -3552,10 +3566,10 @@ bool HighsDomain::ConflictSet::explainBoundChange( default: assert(localdom.domchgreason_[domchg.pos].type >= 0); assert(localdom.domchgreason_[domchg.pos].type < - (HighsInt)(localdom.cutpoolpropagation.size() + - localdom.conflictPoolPropagation.size())); + static_cast(localdom.cutpoolpropagation.size() + + localdom.conflictPoolPropagation.size())); if (localdom.domchgreason_[domchg.pos].type < - (HighsInt)localdom.cutpoolpropagation.size()) { + static_cast(localdom.cutpoolpropagation.size())) { HighsInt cutpoolIndex = localdom.domchgreason_[domchg.pos].type; HighsInt cutIndex = localdom.domchgreason_[domchg.pos].index; @@ -3688,7 +3702,7 @@ HighsInt HighsDomain::ConflictSet::queueSize() const { bool HighsDomain::ConflictSet::resolvable(HighsInt domChgPos) const { assert(domChgPos >= 0); - assert(domChgPos < (HighsInt)localdom.domchgreason_.size()); + assert(domChgPos < static_cast(localdom.domchgreason_.size())); // printf("domchgPos: %d\n", domChgPos); // printf("stacksize: %ld\n", localdom.domchgreason_.size()); switch (localdom.domchgreason_[domChgPos].type) { @@ -3710,7 +3724,7 @@ HighsInt HighsDomain::ConflictSet::resolveDepth(std::set& frontier, LocalDomChg startPos = LocalDomChg{depthLevel == 0 ? 0 : localdom.branchPos_[depthLevel - 1] + 1, HighsDomainChange()}; - while (depthLevel < (HighsInt)localdom.branchPos_.size()) { + while (depthLevel < static_cast(localdom.branchPos_.size())) { HighsInt branchPos = localdom.branchPos_[depthLevel]; if (localdom.domchgstack_[branchPos].boundval != localdom.prevboundval_[branchPos].first) @@ -3720,7 +3734,7 @@ HighsInt HighsDomain::ConflictSet::resolveDepth(std::set& frontier, } auto iterEnd = - depthLevel == (HighsInt)localdom.branchPos_.size() + depthLevel == static_cast(localdom.branchPos_.size()) ? frontier.end() : frontier.upper_bound(LocalDomChg{localdom.branchPos_[depthLevel], HighsDomainChange()}); @@ -3788,7 +3802,8 @@ HighsInt HighsDomain::ConflictSet::computeCuts(HighsInt depthLevel, HighsPseudocost& pseudocost) { HighsInt numResolved = resolveDepth( reasonSideFrontier, depthLevel, 1, pseudocost, - depthLevel == (HighsInt)localdom.branchPos_.size() ? 1 : 0, true); + depthLevel == static_cast(localdom.branchPos_.size()) ? 1 : 0, + true); if (numResolved == -1) return -1; HighsInt numConflicts = 0; if (numResolved > 0) { @@ -3852,7 +3867,7 @@ void HighsDomain::ConflictSet::conflictAnalysis(HighsConflictPool& conflictPool, reasonSideFrontier, localdom.domchgstack_); HighsInt numConflicts = 0; - HighsInt lastDepth = localdom.branchPos_.size(); + HighsInt lastDepth = static_cast(localdom.branchPos_.size()); // printf("start conflict analysis\n"); HighsInt currDepth; for (currDepth = lastDepth; currDepth >= 0; --currDepth) { @@ -3929,7 +3944,7 @@ void HighsDomain::ConflictSet::conflictAnalysis(const HighsInt* proofinds, reasonSideFrontier, localdom.domchgstack_); HighsInt numConflicts = 0; - HighsInt lastDepth = localdom.branchPos_.size(); + HighsInt lastDepth = static_cast(localdom.branchPos_.size()); HighsInt currDepth; for (currDepth = lastDepth; currDepth >= 0; --currDepth) { if (currDepth > 0) { diff --git a/highs/mip/HighsDomain.h b/highs/mip/HighsDomain.h index cd92793dc2e..4f32596ab08 100644 --- a/highs/mip/HighsDomain.h +++ b/highs/mip/HighsDomain.h @@ -561,7 +561,7 @@ class HighsDomain { std::vector reducedstack; reducedstack.reserve(domchgstack_.size()); branchingPositions.reserve(branchPos_.size()); - for (HighsInt i = 0; i < (HighsInt)domchgstack_.size(); ++i) { + for (HighsInt i = 0; i < static_cast(domchgstack_.size()); ++i) { // keep only the tightest bound change for each variable if ((domchgstack_[i].boundtype == HighsBoundType::kLower && colLowerPos_[domchgstack_[i].column] != i) || From 1728aee9e65a0247fb9958969a915f80e097dbb7 Mon Sep 17 00:00:00 2001 From: fwesselm Date: Fri, 10 Jul 2026 10:50:01 +0200 Subject: [PATCH 09/24] Simplify --- highs/mip/HighsDomain.cpp | 122 ++++++++++++++++++++------------------ highs/mip/HighsDomain.h | 8 ++- 2 files changed, 70 insertions(+), 60 deletions(-) diff --git a/highs/mip/HighsDomain.cpp b/highs/mip/HighsDomain.cpp index 53873da4248..58262332459 100644 --- a/highs/mip/HighsDomain.cpp +++ b/highs/mip/HighsDomain.cpp @@ -501,7 +501,7 @@ void HighsDomain::CutpoolPropagation::cutDeleted( void HighsDomain::CutpoolPropagation::markPropagateCut(HighsInt cut) { if (!propagatecutflags_[cut] && (activitycutsinf_[cut] == 1 || - (cutpool->getRhs()[cut] - double(activitycuts_[cut]) <= + (cutpool->getRhs()[cut] - static_cast(activitycuts_[cut]) <= capacityThreshold_[cut]))) { propagatecutinds_.push_back(cut); propagatecutflags_[cut] |= 1; @@ -789,7 +789,7 @@ void HighsDomain::ObjectivePropagation::getPropagationConstraint( } vals = propagationConsBuffer.data(); - rhs = double(tmpRhs); + rhs = static_cast(tmpRhs); } void HighsDomain::ObjectivePropagation::recomputeCapacityThreshold() { @@ -1071,7 +1071,8 @@ bool HighsDomain::ObjectivePropagation::shouldBePropagated() const { if (domain->infeasible_) return false; double upperLimit = domain->mipsolver->mipdata_->upper_limit; if (upperLimit == kHighsInf) return false; - if (upperLimit - double(objectiveLower) > capacityThreshold) return false; + if (upperLimit - static_cast(objectiveLower) > capacityThreshold) + return false; return true; } @@ -1358,10 +1359,10 @@ double HighsDomain::adjustedUb(HighsInt col, HighsCDouble boundVal, accept = bound < col_upper_[col] && col_upper_[col] - bound > 1000.0 * feastol() * std::fabs(bound); } else { - if (std::fabs(double(boundVal) - col_lower_[col]) <= epsilon()) + if (abs(boundVal - col_lower_[col]) <= epsilon()) bound = col_lower_[col]; else - bound = double(boundVal); + bound = static_cast(boundVal); if (col_upper_[col] == kHighsInf) accept = true; else if (bound + 1000.0 * feastol() < col_upper_[col]) { @@ -1388,10 +1389,10 @@ double HighsDomain::adjustedLb(HighsInt col, HighsCDouble boundVal, accept = bound > col_lower_[col] && bound - col_lower_[col] > 1000.0 * feastol() * std::fabs(bound); } else { - if (std::fabs(col_upper_[col] - double(boundVal)) <= epsilon()) + if (abs(col_upper_[col] - boundVal) <= epsilon()) bound = col_upper_[col]; else - bound = double(boundVal); + bound = static_cast(boundVal); if (col_lower_[col] == -kHighsInf) accept = true; else if (bound - 1000.0 * feastol() > col_lower_[col]) { @@ -1415,7 +1416,7 @@ HighsInt HighsDomain::propagateRowUpper(const HighsInt* Rindex, const HighsCDouble& minactivity, HighsInt ninfmin, HighsDomainChange* boundchgs) const { - assert(std::isfinite(double(minactivity))); + assert(std::isfinite(static_cast(minactivity))); if (ninfmin > 1) return 0; HighsInt numchgs = 0; for (HighsInt i = 0; i != Rlen; ++i) { @@ -1431,7 +1432,7 @@ HighsInt HighsDomain::propagateRowUpper(const HighsInt* Rindex, } HighsCDouble boundVal = (Rupper - minresact) / Rvalue[i]; - if (std::fabs(double(boundVal) * kHighsTiny) > feastol()) continue; + if (abs(boundVal) * kHighsTiny > feastol()) continue; if (Rvalue[i] > 0) { bool accept; @@ -1458,7 +1459,7 @@ HighsInt HighsDomain::propagateRowLower(const HighsInt* Rindex, const HighsCDouble& maxactivity, HighsInt ninfmax, HighsDomainChange* boundchgs) const { - assert(std::isfinite(double(maxactivity))); + assert(std::isfinite(static_cast(maxactivity))); if (ninfmax > 1) return 0; HighsInt numchgs = 0; for (HighsInt i = 0; i != Rlen; ++i) { @@ -1474,7 +1475,7 @@ HighsInt HighsDomain::propagateRowLower(const HighsInt* Rindex, } HighsCDouble boundVal = (Rlower - maxresact) / Rvalue[i]; - if (std::fabs(double(boundVal) * kHighsTiny) > feastol()) continue; + if (abs(boundVal) * kHighsTiny > feastol()) continue; if (Rvalue[i] < 0) { bool accept; @@ -1549,8 +1550,8 @@ void HighsDomain::updateActivityLbChange(HighsInt col, double oldbound, mipsolver->mipdata_->ARstart_[mip->a_matrix_.index_[i] + 1], mipsolver->mipdata_->ARindex_.data(), mipsolver->mipdata_->ARvalue_.data(), tmpinf, tmpminact); - assert(std::fabs(double(activitymin_[mip->a_matrix_.index_[i]] - - tmpminact)) <= feastol()); + assert(abs(activitymin_[mip->a_matrix_.index_[i]] - tmpminact) <= + feastol()); assert(tmpinf == activitymininf_[mip->a_matrix_.index_[i]]); } #endif @@ -1598,8 +1599,8 @@ void HighsDomain::updateActivityLbChange(HighsInt col, double oldbound, mipsolver->mipdata_->ARstart_[mip->a_matrix_.index_[i] + 1], mipsolver->mipdata_->ARindex_.data(), mipsolver->mipdata_->ARvalue_.data(), tmpinf, tmpmaxact); - assert(std::fabs(double(activitymax_[mip->a_matrix_.index_[i]] - - tmpmaxact)) <= feastol()); + assert(abs(activitymax_[mip->a_matrix_.index_[i]] - tmpmaxact) <= + feastol()); assert(tmpinf == activitymaxinf_[mip->a_matrix_.index_[i]]); } #endif @@ -1716,8 +1717,8 @@ void HighsDomain::updateActivityUbChange(HighsInt col, double oldbound, mipsolver->mipdata_->ARstart_[mip->a_matrix_.index_[i] + 1], mipsolver->mipdata_->ARindex_.data(), mipsolver->mipdata_->ARvalue_.data(), tmpinf, tmpmaxact); - assert(std::fabs(double(activitymax_[mip->a_matrix_.index_[i]] - - tmpmaxact)) <= feastol()); + assert(abs(activitymax_[mip->a_matrix_.index_[i]] - tmpmaxact) <= + feastol()); assert(tmpinf == activitymaxinf_[mip->a_matrix_.index_[i]]); } #endif @@ -1768,8 +1769,8 @@ void HighsDomain::updateActivityUbChange(HighsInt col, double oldbound, mipsolver->mipdata_->ARstart_[mip->a_matrix_.index_[i] + 1], mipsolver->mipdata_->ARindex_.data(), mipsolver->mipdata_->ARvalue_.data(), tmpinf, tmpminact); - assert(std::fabs(double(activitymin_[mip->a_matrix_.index_[i]] - - tmpminact)) <= feastol()); + assert(abs(activitymin_[mip->a_matrix_.index_[i]] - tmpminact) <= + feastol()); assert(tmpinf == activitymininf_[mip->a_matrix_.index_[i]]); } #endif @@ -1934,14 +1935,14 @@ void HighsDomain::markPropagate(HighsInt row) { (activitymininf_[row] != 0 || activitymin_[row] < mipsolver->rowLower(row) - feastol()) && (activitymaxinf_[row] == 1 || - (double(activitymax_[row]) - mipsolver->rowLower(row)) <= + (static_cast(activitymax_[row]) - mipsolver->rowLower(row)) <= capacityThreshold_[row]); bool propupper = mipsolver->rowUpper(row) != kHighsInf && (activitymaxinf_[row] != 0 || activitymax_[row] > mipsolver->rowUpper(row) + feastol()) && (activitymininf_[row] == 1 || - (mipsolver->rowUpper(row) - double(activitymin_[row])) <= + (mipsolver->rowUpper(row) - static_cast(activitymin_[row])) <= capacityThreshold_[row]); if (proplower || propupper) { @@ -2098,8 +2099,7 @@ void HighsDomain::changeBound(HighsDomainChange boundchg, Reason reason) { bool HighsDomain::checkChangeBound(HighsBoundType boundtype, HighsInt col, HighsCDouble boundval, Reason reason) { - if (std::abs(static_cast(boundval * kHighsTiny)) > feastol()) - return false; + if (abs(boundval) * kHighsTiny > feastol()) return false; bool accept; double bound = boundtype == HighsBoundType::kLower ? adjustedLb(col, boundval, accept) @@ -2632,7 +2632,8 @@ void HighsDomain::conflictAnalyzeReconvergence( conflictSet.reconvergenceFrontier, ConflictSet::LocalDomChg{static_cast(domchgstack_.size()), domchg}, - proofinds, proofvals, prooflen, proofrhs, double(activitymin))) + proofinds, proofvals, prooflen, proofrhs, + static_cast(activitymin))) return; if (10 * conflictSet.resolvedDomainChanges.size() > @@ -2684,12 +2685,12 @@ void HighsDomain::tightenCoefficients(HighsInt* inds, double* vals, if (vals[i] > maxabscoef) { HighsCDouble delta = vals[i] - maxabscoef; upper -= delta * col_upper_[inds[i]]; - vals[i] = double(maxabscoef); + vals[i] = static_cast(maxabscoef); ++tightened; } else if (vals[i] < -maxabscoef) { HighsCDouble delta = -vals[i] - maxabscoef; upper += delta * col_lower_[inds[i]]; - vals[i] = -double(maxabscoef); + vals[i] = -static_cast(maxabscoef); ++tightened; } } @@ -2697,8 +2698,8 @@ void HighsDomain::tightenCoefficients(HighsInt* inds, double* vals, if (tightened != 0) { // printf("tightened %" HIGHSINT_FORMAT " coefficients, rhs changed from // %g to %g\n", - // tightened, rhs, double(upper)); - rhs = double(upper); + // tightened, rhs, static_cast(upper)); + rhs = static_cast(upper); } } } @@ -2713,7 +2714,7 @@ double HighsDomain::getMinCutActivity(const HighsCutPool& cutpool, cutpoolprop.propagatecutflags_.size()) && (cutpoolprop.propagatecutflags_[cut] & 2) == 0 && cutpoolprop.activitycutsinf_[cut] == 0 - ? double(cutpoolprop.activitycuts_[cut]) + ? static_cast(cutpoolprop.activitycuts_[cut]) : -kHighsInf; } } @@ -2991,7 +2992,7 @@ bool HighsDomain::ConflictSet::explainBoundChangeLeq( bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, const double* vals) { resolvedDomainChanges.clear(); - double covered = double(M - Mupper); + double covered = static_cast(M - Mupper); if (covered > 0) { for (const auto& reasonDomchg : resolveBuffer) { LocalDomChg locdomchg; @@ -3002,7 +3003,7 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, assert(resolvedDomainChanges.back().pos >= 0); assert(resolvedDomainChanges.back().pos < static_cast(localdom.domchgstack_.size())); - covered = double(M - Mupper); + covered = static_cast(M - Mupper); if (covered <= 0) break; } @@ -3049,7 +3050,7 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, // ++numRelaxed; } - covered = double(M - Mupper); + covered = static_cast(M - Mupper); if (covered >= -localdom.feastol()) break; } else { double ub = locdomchg.domchg.boundval; @@ -3081,7 +3082,7 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, // ++numRelaxed; } - covered = double(M - Mupper); + covered = static_cast(M - Mupper); if (covered >= -localdom.feastol()) break; } } @@ -3101,7 +3102,7 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, const double* vals) { resolvedDomainChanges.clear(); - double covered = double(M - Mlower); + double covered = static_cast(M - Mlower); if (covered < 0) { for (const auto& reasonDomchg : resolveBuffer) { LocalDomChg locdomchg; @@ -3112,7 +3113,7 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, assert(resolvedDomainChanges.back().pos >= 0); assert(resolvedDomainChanges.back().pos < static_cast(localdom.domchgstack_.size())); - covered = double(M - Mlower); + covered = static_cast(M - Mlower); if (covered >= 0) break; } @@ -3126,8 +3127,10 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, if (covered > localdom.feastol()) { // there is room for relaxing bounds / dropping unneeded bound changes // from the explanation - // HighsInt numRelaxed = 0; - // HighsInt numDropped = 0; + HighsInt numRelaxed = 0; + HighsInt numDropped = 0; + HighsInt numSkipped = 0; + HighsCDouble M_entry = M; for (HighsInt k = static_cast(resolvedDomainChanges.size()) - 1; k >= 0; --k) { ResolveCandidate& reasonDomchg = resolveBuffer[k]; @@ -3142,7 +3145,10 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, if (!localdom.mipsolver->isColContinuous(col)) relaxLb = ceil(relaxLb); - if (relaxLb - lb >= -localdom.feastol()) continue; + if (relaxLb - lb >= -localdom.feastol()) { + ++numSkipped; + continue; + } locdomchg.domchg.boundval = static_cast(relaxLb); @@ -3154,17 +3160,17 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, resolvedDomainChanges.resize(last); M -= reasonDomchg.delta; - // ++numDropped; + ++numDropped; } else { // bound can be relaxed while (relaxLb <= localdom.prevboundval_[locdomchg.pos].first) locdomchg.pos = localdom.prevboundval_[locdomchg.pos].second; M += vals[i] * (static_cast(relaxLb) - lb); - // ++numRelaxed; + ++numRelaxed; } - covered = double(M - Mlower); + covered = static_cast(M - Mlower); if (covered <= localdom.feastol()) break; } else { double ub = locdomchg.domchg.boundval; @@ -3174,7 +3180,10 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, if (!localdom.mipsolver->isColContinuous(col)) relaxUb = floor(relaxUb); - if (relaxUb - ub <= localdom.feastol()) continue; + if (relaxUb - ub <= localdom.feastol()) { + ++numSkipped; + continue; + } locdomchg.domchg.boundval = static_cast(relaxUb); @@ -3186,32 +3195,30 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, resolvedDomainChanges.resize(last); M -= reasonDomchg.delta; - // ++numDropped; + ++numDropped; } else { // bound can be relaxed while (relaxUb >= localdom.prevboundval_[locdomchg.pos].first) locdomchg.pos = localdom.prevboundval_[locdomchg.pos].second; M += vals[i] * (static_cast(relaxUb) - ub); - // ++numRelaxed; + ++numRelaxed; } - covered = double(M - Mlower); + covered = static_cast(M - Mlower); if (covered <= localdom.feastol()) break; } } - // if (numRelaxed + numDropped) - // printf("relaxed %d and dropped %d of %d resolved domain changes\n", - // (int)numRelaxed, (int)numDropped, - // (int)resolvedDomainChanges.size()); - if (covered < -localdom.feastol()) { printf( - "resolveLinearLeq assertion: covered = %.17g, feastol = %.17g, " - "M = %.17g, Mlower = %.17g, resolvedDomainChanges.size() = %d\n", - covered, localdom.feastol(), static_cast(M), Mlower, - (int)resolvedDomainChanges.size()); + "resolveLinearLeq FAIL: covered=%.17g feastol=%.17g\n" + " M_entry=%.17g M_final=%.17g Mlower=%.17g\n" + " numDropped=%d numRelaxed=%d numSkipped=%d " + "remaining_size=%d\n", + covered, localdom.feastol(), static_cast(M_entry), + static_cast(M), Mlower, (int)numDropped, (int)numRelaxed, + (int)numSkipped, (int)resolvedDomainChanges.size()); } assert(covered >= -localdom.feastol()); } @@ -3298,7 +3305,8 @@ bool HighsDomain::ConflictSet::explainInfeasibility() { // heuristic. if (ninfmin > 0) return false; - return explainInfeasibilityLeq(inds, vals, len, rhs, double(minAct)); + return explainInfeasibilityLeq(inds, vals, len, rhs, + static_cast(minAct)); } default: assert(localdom.infeasible_reason.type >= 0); @@ -3561,7 +3569,7 @@ bool HighsDomain::ConflictSet::explainBoundChange( if (ninfmin == 1) return false; return explainBoundChangeLeq(currentFrontier, domchg, inds, vals, len, - rhs, double(minAct)); + rhs, static_cast(minAct)); } default: assert(localdom.domchgreason_[domchg.pos].type >= 0); @@ -3920,7 +3928,7 @@ void HighsDomain::ConflictSet::conflictAnalysis(const HighsInt* proofinds, if (ninfmin != 0) return; if (!explainInfeasibilityLeq(proofinds, proofvals, prooflen, proofrhs, - double(activitymin))) + static_cast(activitymin))) return; pseudocost.increaseConflictWeight(); diff --git a/highs/mip/HighsDomain.h b/highs/mip/HighsDomain.h index 4f32596ab08..ce2d6ce900c 100644 --- a/highs/mip/HighsDomain.h +++ b/highs/mip/HighsDomain.h @@ -537,7 +537,7 @@ class HighsDomain { double getObjectiveLowerBound() const { if (objProp_.isActive() && objProp_.numInfObjLower == 0) - return double(objProp_.objectiveLower); + return static_cast(objProp_.objectiveLower); return -kHighsInf; } @@ -620,11 +620,13 @@ class HighsDomain { double& rhs) const; double getMinActivity(HighsInt row) const { - return activitymininf_[row] == 0 ? double(activitymin_[row]) : -kHighsInf; + return activitymininf_[row] == 0 ? static_cast(activitymin_[row]) + : -kHighsInf; } double getMaxActivity(HighsInt row) const { - return activitymaxinf_[row] == 0 ? double(activitymax_[row]) : kHighsInf; + return activitymaxinf_[row] == 0 ? static_cast(activitymax_[row]) + : kHighsInf; } double getMinCutActivity(const HighsCutPool& cutpool, HighsInt cut) const; From 38c5b90726d10170a4e3d8e4a61a4bd095d1ff1f Mon Sep 17 00:00:00 2001 From: fwesselm Date: Fri, 10 Jul 2026 11:02:20 +0200 Subject: [PATCH 10/24] Debug code --- highs/mip/HighsDomain.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/highs/mip/HighsDomain.cpp b/highs/mip/HighsDomain.cpp index 58262332459..ac3732612c0 100644 --- a/highs/mip/HighsDomain.cpp +++ b/highs/mip/HighsDomain.cpp @@ -3131,6 +3131,10 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, HighsInt numDropped = 0; HighsInt numSkipped = 0; HighsCDouble M_entry = M; + HighsInt dbg_col = -1; + double dbg_val = 0, dbg_lb = 0, dbg_glb = 0; + HighsCDouble dbg_delta = 0, dbg_relaxLb = 0, dbg_M_before = 0; + int dbg_continuous = 0; for (HighsInt k = static_cast(resolvedDomainChanges.size()) - 1; k >= 0; --k) { ResolveCandidate& reasonDomchg = resolveBuffer[k]; @@ -3154,6 +3158,14 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, if (relaxLb - glb <= localdom.epsilon()) { // domain change can be fully removed from conflict + dbg_col = col; + dbg_val = vals[i]; + dbg_lb = lb; + dbg_glb = glb; + dbg_delta = reasonDomchg.delta; + dbg_relaxLb = relaxLb; + dbg_M_before = M; + dbg_continuous = localdom.mipsolver->isColContinuous(col); HighsInt last = static_cast(resolvedDomainChanges.size()) - 1; std::swap(resolvedDomainChanges[last], resolvedDomainChanges[k]); @@ -3189,6 +3201,14 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, if (relaxUb - gub >= -localdom.epsilon()) { // domain change can be fully removed from conflict + dbg_col = col; + dbg_val = vals[i]; + dbg_lb = ub; + dbg_glb = gub; + dbg_delta = reasonDomchg.delta; + dbg_relaxLb = relaxUb; + dbg_M_before = M; + dbg_continuous = localdom.mipsolver->isColContinuous(col); HighsInt last = static_cast(resolvedDomainChanges.size()) - 1; std::swap(resolvedDomainChanges[last], resolvedDomainChanges[k]); @@ -3219,6 +3239,16 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, covered, localdom.feastol(), static_cast(M_entry), static_cast(M), Mlower, (int)numDropped, (int)numRelaxed, (int)numSkipped, (int)resolvedDomainChanges.size()); + printf(" last_drop: col=%d vals[i]=%.17g lb=%.17g glb=%.17g\n" + " delta=%.17g relaxLb=%.17g relaxLb-glb=%.17g eps=%.17g\n" + " M_before_drop=%.17g M-delta-Mlower=%.17g\n" + " continuous=%d\n", + (int)dbg_col, dbg_val, dbg_lb, dbg_glb, + static_cast(dbg_delta), static_cast(dbg_relaxLb), + static_cast(dbg_relaxLb - dbg_glb), localdom.epsilon(), + static_cast(dbg_M_before), + static_cast(dbg_M_before - dbg_delta - Mlower), + (int)dbg_continuous); } assert(covered >= -localdom.feastol()); } From 4070b83b3afeb36e5bef616387ce7ab4aca45f0a Mon Sep 17 00:00:00 2001 From: fwesselm Date: Fri, 10 Jul 2026 11:32:27 +0200 Subject: [PATCH 11/24] delta is double --- highs/mip/HighsDomain.cpp | 37 +++++++++++++++++++------------------ highs/mip/HighsDomain.h | 2 +- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/highs/mip/HighsDomain.cpp b/highs/mip/HighsDomain.cpp index ac3732612c0..e84c7d7bf86 100644 --- a/highs/mip/HighsDomain.cpp +++ b/highs/mip/HighsDomain.cpp @@ -2803,7 +2803,7 @@ bool HighsDomain::ConflictSet::explainBoundChangeGeq( } else cand.baseBound = globaldom.col_upper_[col]; - cand.delta = vals[i] * (static_cast(ub) - cand.baseBound); + cand.delta = vals[i] * (ub - cand.baseBound); cand.prio = computePrio(vals[i], ub, globaldom.col_upper_[col], nodequeue.numNodesDown(col)); } else { @@ -2821,7 +2821,7 @@ bool HighsDomain::ConflictSet::explainBoundChangeGeq( } else cand.baseBound = globaldom.col_lower_[col]; - cand.delta = vals[i] * (static_cast(lb) - cand.baseBound); + cand.delta = vals[i] * (lb - cand.baseBound); cand.prio = computePrio(vals[i], lb, globaldom.col_lower_[col], nodequeue.numNodesUp(col)); } @@ -2915,7 +2915,7 @@ bool HighsDomain::ConflictSet::explainBoundChangeLeq( } else cand.baseBound = globaldom.col_lower_[col]; - cand.delta = vals[i] * (static_cast(lb) - cand.baseBound); + cand.delta = vals[i] * (lb - cand.baseBound); cand.prio = computePrio(vals[i], lb, globaldom.col_lower_[col], nodequeue.numNodesUp(col)); } else { @@ -2932,7 +2932,7 @@ bool HighsDomain::ConflictSet::explainBoundChangeLeq( } else cand.baseBound = globaldom.col_upper_[col]; - cand.delta = vals[i] * (static_cast(ub) - cand.baseBound); + cand.delta = vals[i] * (ub - cand.baseBound); cand.prio = computePrio(vals[i], ub, globaldom.col_upper_[col], nodequeue.numNodesDown(col)); } @@ -3239,16 +3239,17 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, covered, localdom.feastol(), static_cast(M_entry), static_cast(M), Mlower, (int)numDropped, (int)numRelaxed, (int)numSkipped, (int)resolvedDomainChanges.size()); - printf(" last_drop: col=%d vals[i]=%.17g lb=%.17g glb=%.17g\n" - " delta=%.17g relaxLb=%.17g relaxLb-glb=%.17g eps=%.17g\n" - " M_before_drop=%.17g M-delta-Mlower=%.17g\n" - " continuous=%d\n", - (int)dbg_col, dbg_val, dbg_lb, dbg_glb, - static_cast(dbg_delta), static_cast(dbg_relaxLb), - static_cast(dbg_relaxLb - dbg_glb), localdom.epsilon(), - static_cast(dbg_M_before), - static_cast(dbg_M_before - dbg_delta - Mlower), - (int)dbg_continuous); + printf( + " last_drop: col=%d vals[i]=%.17g lb=%.17g glb=%.17g\n" + " delta=%.17g relaxLb=%.17g relaxLb-glb=%.17g eps=%.17g\n" + " M_before_drop=%.17g M-delta-Mlower=%.17g\n" + " continuous=%d\n", + (int)dbg_col, dbg_val, dbg_lb, dbg_glb, + static_cast(dbg_delta), static_cast(dbg_relaxLb), + static_cast(dbg_relaxLb - dbg_glb), localdom.epsilon(), + static_cast(dbg_M_before), + static_cast(dbg_M_before - dbg_delta - Mlower), + (int)dbg_continuous); } assert(covered >= -localdom.feastol()); } @@ -3450,14 +3451,14 @@ bool HighsDomain::ConflictSet::explainInfeasibilityGeq(const HighsInt* inds, double ub = localdom.getColUpperPos(col, infeasible_pos, cand.boundPos); cand.baseBound = globaldom.col_upper_[col]; if (cand.baseBound <= ub || cand.boundPos == -1) continue; - cand.delta = vals[i] * (static_cast(ub) - cand.baseBound); + cand.delta = vals[i] * (ub - cand.baseBound); cand.prio = computePrio(vals[i], ub, globaldom.col_upper_[col], nodequeue.numNodesDown(col)); } else { double lb = localdom.getColLowerPos(col, infeasible_pos, cand.boundPos); cand.baseBound = globaldom.col_lower_[col]; if (cand.baseBound >= lb || cand.boundPos == -1) continue; - cand.delta = vals[i] * (static_cast(lb) - cand.baseBound); + cand.delta = vals[i] * (lb - cand.baseBound); cand.prio = computePrio(vals[i], lb, globaldom.col_lower_[col], nodequeue.numNodesUp(col)); } @@ -3496,14 +3497,14 @@ bool HighsDomain::ConflictSet::explainInfeasibilityLeq(const HighsInt* inds, double lb = localdom.getColLowerPos(col, infeasible_pos, cand.boundPos); cand.baseBound = globaldom.col_lower_[col]; if (cand.baseBound >= lb || cand.boundPos == -1) continue; - cand.delta = vals[i] * (static_cast(lb) - cand.baseBound); + cand.delta = vals[i] * (lb - cand.baseBound); cand.prio = computePrio(vals[i], lb, globaldom.col_lower_[col], nodequeue.numNodesUp(col)); } else { double ub = localdom.getColUpperPos(col, infeasible_pos, cand.boundPos); cand.baseBound = globaldom.col_upper_[col]; if (cand.baseBound <= ub || cand.boundPos == -1) continue; - cand.delta = vals[i] * (static_cast(ub) - cand.baseBound); + cand.delta = vals[i] * (ub - cand.baseBound); cand.prio = computePrio(vals[i], ub, globaldom.col_upper_[col], nodequeue.numNodesDown(col)); } diff --git a/highs/mip/HighsDomain.h b/highs/mip/HighsDomain.h index ce2d6ce900c..95c742eb6e9 100644 --- a/highs/mip/HighsDomain.h +++ b/highs/mip/HighsDomain.h @@ -88,7 +88,7 @@ class HighsDomain { std::vector resolvedDomainChanges; struct ResolveCandidate { - HighsCDouble delta; + double delta; double baseBound; double prio; HighsInt boundPos; From 8653bf269579591c23c02d5ad14be94d4404e093 Mon Sep 17 00:00:00 2001 From: fwesselm Date: Fri, 10 Jul 2026 11:46:55 +0200 Subject: [PATCH 12/24] Fix assertion failure --- highs/mip/HighsDomain.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/highs/mip/HighsDomain.cpp b/highs/mip/HighsDomain.cpp index e84c7d7bf86..6df3b038630 100644 --- a/highs/mip/HighsDomain.cpp +++ b/highs/mip/HighsDomain.cpp @@ -3032,7 +3032,9 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, locdomchg.domchg.boundval = static_cast(relaxLb); - if (relaxLb - glb <= localdom.epsilon()) { + if (relaxLb - glb <= localdom.epsilon() && + static_cast(M - reasonDomchg.delta - Mupper) <= + localdom.feastol()) { // domain change can be fully removed from conflict HighsInt last = static_cast(resolvedDomainChanges.size()) - 1; @@ -3064,7 +3066,9 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, locdomchg.domchg.boundval = static_cast(relaxUb); - if (relaxUb - gub >= -localdom.epsilon()) { + if (relaxUb - gub >= -localdom.epsilon() && + static_cast(M - reasonDomchg.delta - Mupper) <= + localdom.feastol()) { // domain change can be fully removed from conflict HighsInt last = static_cast(resolvedDomainChanges.size()) - 1; @@ -3156,7 +3160,9 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, locdomchg.domchg.boundval = static_cast(relaxLb); - if (relaxLb - glb <= localdom.epsilon()) { + if (relaxLb - glb <= localdom.epsilon() && + static_cast(M - reasonDomchg.delta - Mlower) >= + -localdom.feastol()) { // domain change can be fully removed from conflict dbg_col = col; dbg_val = vals[i]; @@ -3199,7 +3205,9 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, locdomchg.domchg.boundval = static_cast(relaxUb); - if (relaxUb - gub >= -localdom.epsilon()) { + if (relaxUb - gub >= -localdom.epsilon() && + static_cast(M - reasonDomchg.delta - Mlower) >= + -localdom.feastol()) { // domain change can be fully removed from conflict dbg_col = col; dbg_val = vals[i]; From e21afae8bbd9c4707a5cac982c8d9a0ad93f86b2 Mon Sep 17 00:00:00 2001 From: fwesselm Date: Fri, 10 Jul 2026 12:10:24 +0200 Subject: [PATCH 13/24] Simplify --- highs/mip/HighsDomain.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/highs/mip/HighsDomain.cpp b/highs/mip/HighsDomain.cpp index 6df3b038630..f8b7cd91f90 100644 --- a/highs/mip/HighsDomain.cpp +++ b/highs/mip/HighsDomain.cpp @@ -501,7 +501,7 @@ void HighsDomain::CutpoolPropagation::cutDeleted( void HighsDomain::CutpoolPropagation::markPropagateCut(HighsInt cut) { if (!propagatecutflags_[cut] && (activitycutsinf_[cut] == 1 || - (cutpool->getRhs()[cut] - static_cast(activitycuts_[cut]) <= + (cutpool->getRhs()[cut] - activitycuts_[cut] <= capacityThreshold_[cut]))) { propagatecutinds_.push_back(cut); propagatecutflags_[cut] |= 1; @@ -1935,14 +1935,14 @@ void HighsDomain::markPropagate(HighsInt row) { (activitymininf_[row] != 0 || activitymin_[row] < mipsolver->rowLower(row) - feastol()) && (activitymaxinf_[row] == 1 || - (static_cast(activitymax_[row]) - mipsolver->rowLower(row)) <= + activitymax_[row] - mipsolver->rowLower(row) <= capacityThreshold_[row]); bool propupper = mipsolver->rowUpper(row) != kHighsInf && (activitymaxinf_[row] != 0 || activitymax_[row] > mipsolver->rowUpper(row) + feastol()) && (activitymininf_[row] == 1 || - (mipsolver->rowUpper(row) - static_cast(activitymin_[row])) <= + mipsolver->rowUpper(row) - activitymin_[row] <= capacityThreshold_[row]); if (proplower || propupper) { From 16b4f6e9a15a4723dbcbde8d6b0a59374700839f Mon Sep 17 00:00:00 2001 From: fwesselm Date: Fri, 10 Jul 2026 15:01:14 +0200 Subject: [PATCH 14/24] Check estimate --- highs/mip/HighsLpRelaxation.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/highs/mip/HighsLpRelaxation.cpp b/highs/mip/HighsLpRelaxation.cpp index 77b2b0f98f1..bbba949b577 100644 --- a/highs/mip/HighsLpRelaxation.cpp +++ b/highs/mip/HighsLpRelaxation.cpp @@ -439,14 +439,31 @@ double HighsLpRelaxation::computeBestEstimate(const HighsPseudocost& ps) const { static_cast(mipsolver.mipdata_->integral_cols.size()); for (const std::pair& f : fractionalints) { - increase += std::min(ps.getPseudocostUp(f.first, f.second, offset), - ps.getPseudocostDown(f.first, f.second, offset)); + double up = ps.getPseudocostUp(f.first, f.second, offset); + double down = ps.getPseudocostDown(f.first, f.second, offset); + double contrib = std::min(up, down); + if (!std::isfinite(contrib)) { + printf( + "computeBestEstimate: infinite pseudocost for col %d frac=%.17g\n" + " up=%.17g down=%.17g offset=%.17g objective=%.17g\n", + (int)f.first, f.second, up, down, offset, objective); + assert(std::isfinite(contrib)); + } + increase += contrib; } estimate += double(increase); } - return double(estimate); + double result = static_cast(estimate); + if (!std::isfinite(result)) { + printf( + "computeBestEstimate: infinite estimate=%.17g objective=%.17g " + "nfrac=%d\n", + result, objective, (int)fractionalints.size()); + assert(std::isfinite(result)); + } + return result; } double HighsLpRelaxation::computeLPDegneracy( From 205fe81f26350c19f5bc451bcc3e58839915ed1b Mon Sep 17 00:00:00 2001 From: fwesselm Date: Mon, 13 Jul 2026 08:43:57 +0200 Subject: [PATCH 15/24] Add more diagnostics --- highs/mip/HighsLpRelaxation.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/highs/mip/HighsLpRelaxation.cpp b/highs/mip/HighsLpRelaxation.cpp index bbba949b577..52d69866995 100644 --- a/highs/mip/HighsLpRelaxation.cpp +++ b/highs/mip/HighsLpRelaxation.cpp @@ -1641,8 +1641,17 @@ HighsLpRelaxation::Status HighsLpRelaxation::resolveLp(HighsDomain* domain) { objsum = 0; } - for (HighsInt i = 0; i != mipsolver.numCol(); ++i) + for (HighsInt i = 0; i != mipsolver.numCol(); ++i) { objsum += sol.col_value[i] * mipsolver.colCost(i); + if (!std::isfinite(static_cast(objsum))) { + printf( + "resolveLp objsum overflow: col=%d val=%.17g cost=%.17g " + "objsum=%.17g status=%d\n", + (int)i, sol.col_value[i], mipsolver.colCost(i), + static_cast(objsum), (int)status); + assert(std::isfinite(static_cast(objsum))); + } + } if (fractionalints.empty() && !unscaledPrimalFeasible(status)) { std::vector fixSol = sol.col_value; From e788a96fba95a60706920476967325c23456d0dd Mon Sep 17 00:00:00 2001 From: fwesselm Date: Mon, 13 Jul 2026 08:51:03 +0200 Subject: [PATCH 16/24] WIP --- highs/mip/HighsLpRelaxation.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/highs/mip/HighsLpRelaxation.cpp b/highs/mip/HighsLpRelaxation.cpp index 52d69866995..0f97c66c5eb 100644 --- a/highs/mip/HighsLpRelaxation.cpp +++ b/highs/mip/HighsLpRelaxation.cpp @@ -456,12 +456,12 @@ double HighsLpRelaxation::computeBestEstimate(const HighsPseudocost& ps) const { } double result = static_cast(estimate); - if (!std::isfinite(result)) { + if (result == kHighsInf) { printf( - "computeBestEstimate: infinite estimate=%.17g objective=%.17g " + "computeBestEstimate: +inf estimate objective=%.17g " "nfrac=%d\n", - result, objective, (int)fractionalints.size()); - assert(std::isfinite(result)); + objective, (int)fractionalints.size()); + assert(result != kHighsInf); } return result; } From 75cd593b7b34028a52894e3a4d79e6e4ebd54e40 Mon Sep 17 00:00:00 2001 From: fwesselm Date: Mon, 13 Jul 2026 09:33:56 +0200 Subject: [PATCH 17/24] Add more diagnostics --- highs/mip/HighsLpRelaxation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/highs/mip/HighsLpRelaxation.cpp b/highs/mip/HighsLpRelaxation.cpp index 0f97c66c5eb..bab5a525829 100644 --- a/highs/mip/HighsLpRelaxation.cpp +++ b/highs/mip/HighsLpRelaxation.cpp @@ -459,8 +459,8 @@ double HighsLpRelaxation::computeBestEstimate(const HighsPseudocost& ps) const { if (result == kHighsInf) { printf( "computeBestEstimate: +inf estimate objective=%.17g " - "nfrac=%d\n", - objective, (int)fractionalints.size()); + "nfrac=%d status=%d\n", + objective, (int)fractionalints.size(), (int)status); assert(result != kHighsInf); } return result; From 1ade3398d052ab6216437842562d4d406750139c Mon Sep 17 00:00:00 2001 From: fwesselm Date: Mon, 13 Jul 2026 10:22:04 +0200 Subject: [PATCH 18/24] Compute objective using HighsCDouble --- highs/mip/HighsDebugSol.cpp | 13 ++++++++----- highs/mip/HighsLpRelaxation.cpp | 8 +++++--- highs/mip/HighsMipSolver.cpp | 2 +- highs/mip/HighsMipSolverData.cpp | 11 ++++++----- highs/mip/HighsMipWorker.cpp | 2 +- highs/mip/HighsSearch.cpp | 2 +- 6 files changed, 22 insertions(+), 16 deletions(-) diff --git a/highs/mip/HighsDebugSol.cpp b/highs/mip/HighsDebugSol.cpp index f9d84325478..02dfa212426 100644 --- a/highs/mip/HighsDebugSol.cpp +++ b/highs/mip/HighsDebugSol.cpp @@ -68,10 +68,12 @@ void HighsDebugSol::activate() { HighsCDouble debugsolobj = 0.0; for (HighsInt i = 0; i != mipsolver->orig_model_->num_col_; ++i) - debugsolobj += mipsolver->orig_model_->col_cost_[i] * - HighsCDouble(debugOrigSolution[i]); + debugsolobj += + static_cast(mipsolver->orig_model_->col_cost_[i]) * + debugOrigSolution[i]; - debugSolObjective = double(debugsolobj + mipsolver->orig_model_->offset_); + debugSolObjective = + static_cast(debugsolobj + mipsolver->orig_model_->offset_); debugSolActive = true; printf("debug sol active\n"); registerDomain(mipsolver->mipdata_->getDomain()); @@ -101,9 +103,10 @@ void HighsDebugSol::shrink(const std::vector& newColIndex) { debugSolution.resize(mipsolver->model_->num_col_); HighsCDouble debugsolobj = 0.0; for (HighsInt i = 0; i != mipsolver->model_->num_col_; ++i) - debugsolobj += mipsolver->model_->col_cost_[i] * debugSolution[i]; + debugsolobj += static_cast(mipsolver->model_->col_cost_[i]) * + debugSolution[i]; - debugSolObjective = double(debugsolobj); + debugSolObjective = static_cast(debugsolobj); conflictingBounds.clear(); } diff --git a/highs/mip/HighsLpRelaxation.cpp b/highs/mip/HighsLpRelaxation.cpp index bab5a525829..3b9e8163e1b 100644 --- a/highs/mip/HighsLpRelaxation.cpp +++ b/highs/mip/HighsLpRelaxation.cpp @@ -1629,7 +1629,8 @@ HighsLpRelaxation::Status HighsLpRelaxation::resolveLp(HighsDomain* domain) { } for (HighsInt i = 0; i != mipsolver.numCol(); ++i) - objsum += roundsol[i] * mipsolver.colCost(i); + objsum += + static_cast(roundsol[i]) * mipsolver.colCost(i); if (!mipsolver.mipdata_->parallelLockActive() || !worker_) { mipsolver.mipdata_->addIncumbent( @@ -1642,7 +1643,8 @@ HighsLpRelaxation::Status HighsLpRelaxation::resolveLp(HighsDomain* domain) { } for (HighsInt i = 0; i != mipsolver.numCol(); ++i) { - objsum += sol.col_value[i] * mipsolver.colCost(i); + objsum += static_cast(sol.col_value[i]) * + mipsolver.colCost(i); if (!std::isfinite(static_cast(objsum))) { printf( "resolveLp objsum overflow: col=%d val=%.17g cost=%.17g " @@ -1673,7 +1675,7 @@ HighsLpRelaxation::Status HighsLpRelaxation::resolveLp(HighsDomain* domain) { } } - objective = double(objsum); + objective = static_cast(objsum); break; } case Status::kInfeasible: diff --git a/highs/mip/HighsMipSolver.cpp b/highs/mip/HighsMipSolver.cpp index 1742cc730d1..2044074f486 100644 --- a/highs/mip/HighsMipSolver.cpp +++ b/highs/mip/HighsMipSolver.cpp @@ -1365,7 +1365,7 @@ bool HighsMipSolver::solutionFeasible(const HighsLp* lp, assert(col_value.size() == static_cast(lp->num_col_)); for (HighsInt i = 0; i != lp->num_col_; ++i) { const double value = col_value[i]; - obj += lp->col_cost_[i] * value; + obj += static_cast(lp->col_cost_[i]) * value; if (lp->integrality_[i] == HighsVarType::kInteger) { integrality_violation = diff --git a/highs/mip/HighsMipSolverData.cpp b/highs/mip/HighsMipSolverData.cpp index cabbdb8070b..2b7bd3184e3 100644 --- a/highs/mip/HighsMipSolverData.cpp +++ b/highs/mip/HighsMipSolverData.cpp @@ -226,7 +226,7 @@ bool HighsMipSolverData::trySolution(const std::vector& solution, if (mipsolver.isColInteger(i) && fractionality(solution[i]) > feastol) return false; - obj += mipsolver.colCost(i) * solution[i]; + obj += static_cast(mipsolver.colCost(i)) * solution[i]; } for (HighsInt i = 0; i != mipsolver.numRow(); ++i) { @@ -389,8 +389,9 @@ HighsModelStatus HighsMipSolverData::trivialHeuristics() { HighsCDouble cdouble_obj = 0.0; for (HighsInt iCol = 0; iCol < mipsolver.numCol(); iCol++) - cdouble_obj += mipsolver.colCost(iCol) * solution[iCol]; - double obj = double(cdouble_obj); + cdouble_obj += + static_cast(mipsolver.colCost(iCol)) * solution[iCol]; + double obj = static_cast(cdouble_obj); const double save_upper_bound = upper_bound; const bool new_incumbent = addIncumbent(solution, obj, heuristic_source[try_heuristic]); @@ -1145,8 +1146,8 @@ void HighsMipSolverData::runSetup() { debugSolution.debugSolObjective = 0; HighsCDouble debugsolobj = 0.0; for (HighsInt i = 0; i != mipsolver.numCol(); ++i) - debugsolobj += - mipsolver.colCost(i) * HighsCDouble(debugSolution.debugSolution[i]); + debugsolobj += static_cast(mipsolver.colCost(i)) * + debugSolution.debugSolution[i]; debugSolution.debugSolObjective = static_cast(debugsolobj); debugSolution.registerDomain(getDomain()); assert(checkSolution(debugSolution.debugSolution)); diff --git a/highs/mip/HighsMipWorker.cpp b/highs/mip/HighsMipWorker.cpp index 1fcba775737..7c7f2cd6a1d 100644 --- a/highs/mip/HighsMipWorker.cpp +++ b/highs/mip/HighsMipWorker.cpp @@ -127,7 +127,7 @@ bool HighsMipWorker::trySolution(const std::vector& solution, fractionality(solution[i]) > mipdata_.feastol) return false; - obj += mipsolver_.colCost(i) * solution[i]; + obj += static_cast(mipsolver_.colCost(i)) * solution[i]; } for (HighsInt i = 0; i != mipsolver_.model_->num_row_; ++i) { diff --git a/highs/mip/HighsSearch.cpp b/highs/mip/HighsSearch.cpp index 5149c2f6f28..2ab00508239 100644 --- a/highs/mip/HighsSearch.cpp +++ b/highs/mip/HighsSearch.cpp @@ -44,7 +44,7 @@ double HighsSearch::checkSol(const std::vector& sol, HighsCDouble objval = 0.0; integerfeasible = true; for (HighsInt i = 0; i != mipsolver.numCol(); ++i) { - objval += sol[i] * mipsolver.colCost(i); + objval += static_cast(sol[i]) * mipsolver.colCost(i); assert(std::isfinite(sol[i])); if (!integerfeasible || !mipsolver.isColInteger(i)) continue; From f9b34024f4da4946208c05642a9f5a013ffabdde Mon Sep 17 00:00:00 2001 From: fwesselm Date: Mon, 13 Jul 2026 11:17:18 +0200 Subject: [PATCH 19/24] Add more diagnostics --- highs/mip/HighsLpRelaxation.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/highs/mip/HighsLpRelaxation.cpp b/highs/mip/HighsLpRelaxation.cpp index 3b9e8163e1b..337099e60c3 100644 --- a/highs/mip/HighsLpRelaxation.cpp +++ b/highs/mip/HighsLpRelaxation.cpp @@ -1272,6 +1272,8 @@ HighsLpRelaxation::Status HighsLpRelaxation::run(bool resolve_on_error) { recoverBasis(); + printf( + "resolveLp: kError from LP solver (HighsStatus::kError after retry)\n"); return Status::kError; } @@ -1325,6 +1327,7 @@ HighsLpRelaxation::Status HighsLpRelaxation::run(bool resolve_on_error) { // %" HIGHSINT_FORMAT ")\n", // (HighsInt)lpsolver.getModelStatus(), // (HighsInt)lpsolver.getModelStatus(true)); + printf("resolveLp: kError from unreliable infeasibility proof\n"); return Status::kError; } case HighsModelStatus::kUnbounded: @@ -1349,7 +1352,10 @@ HighsLpRelaxation::Status HighsLpRelaxation::run(bool resolve_on_error) { return Status::kUnbounded; case HighsModelStatus::kUnknown: - if (info.basis_validity == kBasisValidityInvalid) return Status::kError; + if (info.basis_validity == kBasisValidityInvalid) { + printf("resolveLp: kError from kUnknown with invalid basis\n"); + return Status::kError; + } // fall through case HighsModelStatus::kOptimal: assert(info.max_primal_infeasibility >= 0); @@ -1371,6 +1377,10 @@ HighsLpRelaxation::Status HighsLpRelaxation::run(bool resolve_on_error) { if (model_status == HighsModelStatus::kOptimal) return Status::kUnscaledInfeasible; + printf( + "resolveLp: kError from kUnknown with large infeasibilities " + "(primal=%.4g dual=%.4g)\n", + info.max_primal_infeasibility, info.max_dual_infeasibility); return Status::kError; case HighsModelStatus::kIterationLimit: { if (!mipsolver.submip && resolve_on_error) { @@ -1439,10 +1449,11 @@ HighsLpRelaxation::Status HighsLpRelaxation::run(bool resolve_on_error) { return run(false); } - // printf("error: lpsolver reached iteration limit\n"); + printf("resolveLp: kError from iteration limit\n"); return Status::kError; } case HighsModelStatus::kTimeLimit: + printf("resolveLp: kError from time limit\n"); return Status::kError; default: // printf("error: lpsolver stopped with unexpected status %" @@ -1451,6 +1462,8 @@ HighsLpRelaxation::Status HighsLpRelaxation::run(bool resolve_on_error) { highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kWarning, "LP solved to unexpected status: %s\n", lpsolver.modelStatusToString(model_status).c_str()); + printf("resolveLp: kError from unexpected model status %d\n", + (int)model_status); return Status::kError; } } From 23437c8e85cb9e4f46d05cb18b7201a982587bae Mon Sep 17 00:00:00 2001 From: fwesselm Date: Wed, 15 Jul 2026 10:45:49 +0200 Subject: [PATCH 20/24] Clean up --- highs/mip/HighsDomain.cpp | 59 ++------------------------------- highs/mip/HighsLpRelaxation.cpp | 51 ++++------------------------ 2 files changed, 8 insertions(+), 102 deletions(-) diff --git a/highs/mip/HighsDomain.cpp b/highs/mip/HighsDomain.cpp index f8b7cd91f90..5950198c084 100644 --- a/highs/mip/HighsDomain.cpp +++ b/highs/mip/HighsDomain.cpp @@ -3131,14 +3131,6 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, if (covered > localdom.feastol()) { // there is room for relaxing bounds / dropping unneeded bound changes // from the explanation - HighsInt numRelaxed = 0; - HighsInt numDropped = 0; - HighsInt numSkipped = 0; - HighsCDouble M_entry = M; - HighsInt dbg_col = -1; - double dbg_val = 0, dbg_lb = 0, dbg_glb = 0; - HighsCDouble dbg_delta = 0, dbg_relaxLb = 0, dbg_M_before = 0; - int dbg_continuous = 0; for (HighsInt k = static_cast(resolvedDomainChanges.size()) - 1; k >= 0; --k) { ResolveCandidate& reasonDomchg = resolveBuffer[k]; @@ -3153,10 +3145,7 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, if (!localdom.mipsolver->isColContinuous(col)) relaxLb = ceil(relaxLb); - if (relaxLb - lb >= -localdom.feastol()) { - ++numSkipped; - continue; - } + if (relaxLb - lb >= -localdom.feastol()) continue; locdomchg.domchg.boundval = static_cast(relaxLb); @@ -3164,28 +3153,18 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, static_cast(M - reasonDomchg.delta - Mlower) >= -localdom.feastol()) { // domain change can be fully removed from conflict - dbg_col = col; - dbg_val = vals[i]; - dbg_lb = lb; - dbg_glb = glb; - dbg_delta = reasonDomchg.delta; - dbg_relaxLb = relaxLb; - dbg_M_before = M; - dbg_continuous = localdom.mipsolver->isColContinuous(col); HighsInt last = static_cast(resolvedDomainChanges.size()) - 1; std::swap(resolvedDomainChanges[last], resolvedDomainChanges[k]); resolvedDomainChanges.resize(last); M -= reasonDomchg.delta; - ++numDropped; } else { // bound can be relaxed while (relaxLb <= localdom.prevboundval_[locdomchg.pos].first) locdomchg.pos = localdom.prevboundval_[locdomchg.pos].second; M += vals[i] * (static_cast(relaxLb) - lb); - ++numRelaxed; } covered = static_cast(M - Mlower); @@ -3198,10 +3177,7 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, if (!localdom.mipsolver->isColContinuous(col)) relaxUb = floor(relaxUb); - if (relaxUb - ub <= localdom.feastol()) { - ++numSkipped; - continue; - } + if (relaxUb - ub <= localdom.feastol()) continue; locdomchg.domchg.boundval = static_cast(relaxUb); @@ -3209,28 +3185,18 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, static_cast(M - reasonDomchg.delta - Mlower) >= -localdom.feastol()) { // domain change can be fully removed from conflict - dbg_col = col; - dbg_val = vals[i]; - dbg_lb = ub; - dbg_glb = gub; - dbg_delta = reasonDomchg.delta; - dbg_relaxLb = relaxUb; - dbg_M_before = M; - dbg_continuous = localdom.mipsolver->isColContinuous(col); HighsInt last = static_cast(resolvedDomainChanges.size()) - 1; std::swap(resolvedDomainChanges[last], resolvedDomainChanges[k]); resolvedDomainChanges.resize(last); M -= reasonDomchg.delta; - ++numDropped; } else { // bound can be relaxed while (relaxUb >= localdom.prevboundval_[locdomchg.pos].first) locdomchg.pos = localdom.prevboundval_[locdomchg.pos].second; M += vals[i] * (static_cast(relaxUb) - ub); - ++numRelaxed; } covered = static_cast(M - Mlower); @@ -3238,27 +3204,6 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, } } - if (covered < -localdom.feastol()) { - printf( - "resolveLinearLeq FAIL: covered=%.17g feastol=%.17g\n" - " M_entry=%.17g M_final=%.17g Mlower=%.17g\n" - " numDropped=%d numRelaxed=%d numSkipped=%d " - "remaining_size=%d\n", - covered, localdom.feastol(), static_cast(M_entry), - static_cast(M), Mlower, (int)numDropped, (int)numRelaxed, - (int)numSkipped, (int)resolvedDomainChanges.size()); - printf( - " last_drop: col=%d vals[i]=%.17g lb=%.17g glb=%.17g\n" - " delta=%.17g relaxLb=%.17g relaxLb-glb=%.17g eps=%.17g\n" - " M_before_drop=%.17g M-delta-Mlower=%.17g\n" - " continuous=%d\n", - (int)dbg_col, dbg_val, dbg_lb, dbg_glb, - static_cast(dbg_delta), static_cast(dbg_relaxLb), - static_cast(dbg_relaxLb - dbg_glb), localdom.epsilon(), - static_cast(dbg_M_before), - static_cast(dbg_M_before - dbg_delta - Mlower), - (int)dbg_continuous); - } assert(covered >= -localdom.feastol()); } } diff --git a/highs/mip/HighsLpRelaxation.cpp b/highs/mip/HighsLpRelaxation.cpp index 337099e60c3..843b27849b8 100644 --- a/highs/mip/HighsLpRelaxation.cpp +++ b/highs/mip/HighsLpRelaxation.cpp @@ -439,31 +439,14 @@ double HighsLpRelaxation::computeBestEstimate(const HighsPseudocost& ps) const { static_cast(mipsolver.mipdata_->integral_cols.size()); for (const std::pair& f : fractionalints) { - double up = ps.getPseudocostUp(f.first, f.second, offset); - double down = ps.getPseudocostDown(f.first, f.second, offset); - double contrib = std::min(up, down); - if (!std::isfinite(contrib)) { - printf( - "computeBestEstimate: infinite pseudocost for col %d frac=%.17g\n" - " up=%.17g down=%.17g offset=%.17g objective=%.17g\n", - (int)f.first, f.second, up, down, offset, objective); - assert(std::isfinite(contrib)); - } - increase += contrib; + increase += std::min(ps.getPseudocostUp(f.first, f.second, offset), + ps.getPseudocostDown(f.first, f.second, offset)); } estimate += double(increase); } - double result = static_cast(estimate); - if (result == kHighsInf) { - printf( - "computeBestEstimate: +inf estimate objective=%.17g " - "nfrac=%d status=%d\n", - objective, (int)fractionalints.size(), (int)status); - assert(result != kHighsInf); - } - return result; + return static_cast(estimate); } double HighsLpRelaxation::computeLPDegneracy( @@ -1272,8 +1255,6 @@ HighsLpRelaxation::Status HighsLpRelaxation::run(bool resolve_on_error) { recoverBasis(); - printf( - "resolveLp: kError from LP solver (HighsStatus::kError after retry)\n"); return Status::kError; } @@ -1327,7 +1308,6 @@ HighsLpRelaxation::Status HighsLpRelaxation::run(bool resolve_on_error) { // %" HIGHSINT_FORMAT ")\n", // (HighsInt)lpsolver.getModelStatus(), // (HighsInt)lpsolver.getModelStatus(true)); - printf("resolveLp: kError from unreliable infeasibility proof\n"); return Status::kError; } case HighsModelStatus::kUnbounded: @@ -1352,10 +1332,7 @@ HighsLpRelaxation::Status HighsLpRelaxation::run(bool resolve_on_error) { return Status::kUnbounded; case HighsModelStatus::kUnknown: - if (info.basis_validity == kBasisValidityInvalid) { - printf("resolveLp: kError from kUnknown with invalid basis\n"); - return Status::kError; - } + if (info.basis_validity == kBasisValidityInvalid) return Status::kError; // fall through case HighsModelStatus::kOptimal: assert(info.max_primal_infeasibility >= 0); @@ -1377,10 +1354,6 @@ HighsLpRelaxation::Status HighsLpRelaxation::run(bool resolve_on_error) { if (model_status == HighsModelStatus::kOptimal) return Status::kUnscaledInfeasible; - printf( - "resolveLp: kError from kUnknown with large infeasibilities " - "(primal=%.4g dual=%.4g)\n", - info.max_primal_infeasibility, info.max_dual_infeasibility); return Status::kError; case HighsModelStatus::kIterationLimit: { if (!mipsolver.submip && resolve_on_error) { @@ -1449,11 +1422,10 @@ HighsLpRelaxation::Status HighsLpRelaxation::run(bool resolve_on_error) { return run(false); } - printf("resolveLp: kError from iteration limit\n"); + // printf("error: lpsolver reached iteration limit\n"); return Status::kError; } case HighsModelStatus::kTimeLimit: - printf("resolveLp: kError from time limit\n"); return Status::kError; default: // printf("error: lpsolver stopped with unexpected status %" @@ -1462,8 +1434,6 @@ HighsLpRelaxation::Status HighsLpRelaxation::run(bool resolve_on_error) { highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kWarning, "LP solved to unexpected status: %s\n", lpsolver.modelStatusToString(model_status).c_str()); - printf("resolveLp: kError from unexpected model status %d\n", - (int)model_status); return Status::kError; } } @@ -1655,18 +1625,9 @@ HighsLpRelaxation::Status HighsLpRelaxation::resolveLp(HighsDomain* domain) { objsum = 0; } - for (HighsInt i = 0; i != mipsolver.numCol(); ++i) { + for (HighsInt i = 0; i != mipsolver.numCol(); ++i) objsum += static_cast(sol.col_value[i]) * mipsolver.colCost(i); - if (!std::isfinite(static_cast(objsum))) { - printf( - "resolveLp objsum overflow: col=%d val=%.17g cost=%.17g " - "objsum=%.17g status=%d\n", - (int)i, sol.col_value[i], mipsolver.colCost(i), - static_cast(objsum), (int)status); - assert(std::isfinite(static_cast(objsum))); - } - } if (fractionalints.empty() && !unscaledPrimalFeasible(status)) { std::vector fixSol = sol.col_value; From bce30f036e11a2f10e332179273f8e4bd6e5be79 Mon Sep 17 00:00:00 2001 From: fwesselm Date: Wed, 15 Jul 2026 10:57:59 +0200 Subject: [PATCH 21/24] Clean up --- highs/mip/HighsDomain.cpp | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/highs/mip/HighsDomain.cpp b/highs/mip/HighsDomain.cpp index 5950198c084..c34ac6dc1f2 100644 --- a/highs/mip/HighsDomain.cpp +++ b/highs/mip/HighsDomain.cpp @@ -1071,8 +1071,7 @@ bool HighsDomain::ObjectivePropagation::shouldBePropagated() const { if (domain->infeasible_) return false; double upperLimit = domain->mipsolver->mipdata_->upper_limit; if (upperLimit == kHighsInf) return false; - if (upperLimit - static_cast(objectiveLower) > capacityThreshold) - return false; + if (upperLimit - objectiveLower > capacityThreshold) return false; return true; } @@ -3023,14 +3022,14 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, if (locdomchg.domchg.boundtype == HighsBoundType::kLower) { double lb = locdomchg.domchg.boundval; double glb = reasonDomchg.baseBound; - HighsCDouble relaxLb = - ((Mupper - (M - reasonDomchg.delta)) / vals[i]) + glb; + double relaxLb = static_cast( + ((Mupper - (M - reasonDomchg.delta)) / vals[i]) + glb); if (!localdom.mipsolver->isColContinuous(col)) - relaxLb = ceil(relaxLb); + relaxLb = std::ceil(relaxLb); if (relaxLb - lb >= -localdom.feastol()) continue; - locdomchg.domchg.boundval = static_cast(relaxLb); + locdomchg.domchg.boundval = relaxLb; if (relaxLb - glb <= localdom.epsilon() && static_cast(M - reasonDomchg.delta - Mupper) <= @@ -3057,14 +3056,14 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, } else { double ub = locdomchg.domchg.boundval; double gub = reasonDomchg.baseBound; - HighsCDouble relaxUb = - ((Mupper - (M - reasonDomchg.delta)) / vals[i]) + gub; + double relaxUb = static_cast( + ((Mupper - (M - reasonDomchg.delta)) / vals[i]) + gub); if (!localdom.mipsolver->isColContinuous(col)) - relaxUb = floor(relaxUb); + relaxUb = std::floor(relaxUb); if (relaxUb - ub <= localdom.feastol()) continue; - locdomchg.domchg.boundval = static_cast(relaxUb); + locdomchg.domchg.boundval = relaxUb; if (relaxUb - gub >= -localdom.epsilon() && static_cast(M - reasonDomchg.delta - Mupper) <= @@ -3140,14 +3139,14 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, if (locdomchg.domchg.boundtype == HighsBoundType::kLower) { double lb = locdomchg.domchg.boundval; double glb = reasonDomchg.baseBound; - HighsCDouble relaxLb = - ((Mlower - (M - reasonDomchg.delta)) / vals[i]) + glb; + double relaxLb = static_cast( + ((Mlower - (M - reasonDomchg.delta)) / vals[i]) + glb); if (!localdom.mipsolver->isColContinuous(col)) - relaxLb = ceil(relaxLb); + relaxLb = std::ceil(relaxLb); if (relaxLb - lb >= -localdom.feastol()) continue; - locdomchg.domchg.boundval = static_cast(relaxLb); + locdomchg.domchg.boundval = relaxLb; if (relaxLb - glb <= localdom.epsilon() && static_cast(M - reasonDomchg.delta - Mlower) >= @@ -3172,14 +3171,14 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, } else { double ub = locdomchg.domchg.boundval; double gub = reasonDomchg.baseBound; - HighsCDouble relaxUb = - ((Mlower - (M - reasonDomchg.delta)) / vals[i]) + gub; + double relaxUb = static_cast( + ((Mlower - (M - reasonDomchg.delta)) / vals[i]) + gub); if (!localdom.mipsolver->isColContinuous(col)) - relaxUb = floor(relaxUb); + relaxUb = std::floor(relaxUb); if (relaxUb - ub <= localdom.feastol()) continue; - locdomchg.domchg.boundval = static_cast(relaxUb); + locdomchg.domchg.boundval = relaxUb; if (relaxUb - gub >= -localdom.epsilon() && static_cast(M - reasonDomchg.delta - Mlower) >= From 5475af41cdcf560efdeef58169535c4e4c5c9b71 Mon Sep 17 00:00:00 2001 From: fwesselm Date: Wed, 15 Jul 2026 11:02:35 +0200 Subject: [PATCH 22/24] Remove cast --- highs/mip/HighsDomain.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/highs/mip/HighsDomain.cpp b/highs/mip/HighsDomain.cpp index c34ac6dc1f2..168a3b675ce 100644 --- a/highs/mip/HighsDomain.cpp +++ b/highs/mip/HighsDomain.cpp @@ -3032,8 +3032,7 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, locdomchg.domchg.boundval = relaxLb; if (relaxLb - glb <= localdom.epsilon() && - static_cast(M - reasonDomchg.delta - Mupper) <= - localdom.feastol()) { + M - reasonDomchg.delta - Mupper <= localdom.feastol()) { // domain change can be fully removed from conflict HighsInt last = static_cast(resolvedDomainChanges.size()) - 1; @@ -3066,8 +3065,7 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, locdomchg.domchg.boundval = relaxUb; if (relaxUb - gub >= -localdom.epsilon() && - static_cast(M - reasonDomchg.delta - Mupper) <= - localdom.feastol()) { + M - reasonDomchg.delta - Mupper <= localdom.feastol()) { // domain change can be fully removed from conflict HighsInt last = static_cast(resolvedDomainChanges.size()) - 1; @@ -3149,8 +3147,7 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, locdomchg.domchg.boundval = relaxLb; if (relaxLb - glb <= localdom.epsilon() && - static_cast(M - reasonDomchg.delta - Mlower) >= - -localdom.feastol()) { + M - reasonDomchg.delta - Mlower >= -localdom.feastol()) { // domain change can be fully removed from conflict HighsInt last = static_cast(resolvedDomainChanges.size()) - 1; @@ -3181,8 +3178,7 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, locdomchg.domchg.boundval = relaxUb; if (relaxUb - gub >= -localdom.epsilon() && - static_cast(M - reasonDomchg.delta - Mlower) >= - -localdom.feastol()) { + M - reasonDomchg.delta - Mlower >= -localdom.feastol()) { // domain change can be fully removed from conflict HighsInt last = static_cast(resolvedDomainChanges.size()) - 1; From 14168cc277ded9cb3c89f9992847bf7080a6a31a Mon Sep 17 00:00:00 2001 From: fwesselm Date: Wed, 15 Jul 2026 11:10:56 +0200 Subject: [PATCH 23/24] Restore commented out printfs --- highs/mip/HighsDomain.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/highs/mip/HighsDomain.cpp b/highs/mip/HighsDomain.cpp index 168a3b675ce..c8ee9539e1b 100644 --- a/highs/mip/HighsDomain.cpp +++ b/highs/mip/HighsDomain.cpp @@ -3031,6 +3031,7 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, locdomchg.domchg.boundval = relaxLb; + // only drop if explanation stays valid without this entry if (relaxLb - glb <= localdom.epsilon() && M - reasonDomchg.delta - Mupper <= localdom.feastol()) { // domain change can be fully removed from conflict @@ -3064,6 +3065,7 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, locdomchg.domchg.boundval = relaxUb; + // only drop if explanation stays valid without this entry if (relaxUb - gub >= -localdom.epsilon() && M - reasonDomchg.delta - Mupper <= localdom.feastol()) { // domain change can be fully removed from conflict @@ -3128,6 +3130,8 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, if (covered > localdom.feastol()) { // there is room for relaxing bounds / dropping unneeded bound changes // from the explanation + // HighsInt numRelaxed = 0; + // HighsInt numDropped = 0; for (HighsInt k = static_cast(resolvedDomainChanges.size()) - 1; k >= 0; --k) { ResolveCandidate& reasonDomchg = resolveBuffer[k]; @@ -3146,6 +3150,7 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, locdomchg.domchg.boundval = relaxLb; + // only drop if explanation stays valid without this entry if (relaxLb - glb <= localdom.epsilon() && M - reasonDomchg.delta - Mlower >= -localdom.feastol()) { // domain change can be fully removed from conflict @@ -3155,12 +3160,14 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, resolvedDomainChanges.resize(last); M -= reasonDomchg.delta; + // ++numDropped; } else { // bound can be relaxed while (relaxLb <= localdom.prevboundval_[locdomchg.pos].first) locdomchg.pos = localdom.prevboundval_[locdomchg.pos].second; M += vals[i] * (static_cast(relaxLb) - lb); + // ++numRelaxed; } covered = static_cast(M - Mlower); @@ -3177,6 +3184,7 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, locdomchg.domchg.boundval = relaxUb; + // only drop if explanation stays valid without this entry if (relaxUb - gub >= -localdom.epsilon() && M - reasonDomchg.delta - Mlower >= -localdom.feastol()) { // domain change can be fully removed from conflict @@ -3186,12 +3194,14 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, resolvedDomainChanges.resize(last); M -= reasonDomchg.delta; + // ++numDropped; } else { // bound can be relaxed while (relaxUb >= localdom.prevboundval_[locdomchg.pos].first) locdomchg.pos = localdom.prevboundval_[locdomchg.pos].second; M += vals[i] * (static_cast(relaxUb) - ub); + // ++numRelaxed; } covered = static_cast(M - Mlower); @@ -3199,6 +3209,11 @@ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower, } } + // if (numRelaxed + numDropped) + // printf("relaxed %d and dropped %d of %d resolved domain changes\n", + // (int)numRelaxed, (int)numDropped, + // (int)resolvedDomainChanges.size()); + assert(covered >= -localdom.feastol()); } } From 7a2af0f8393d34f172b2f1aadc43b7dd93b07134 Mon Sep 17 00:00:00 2001 From: fwesselm Date: Wed, 15 Jul 2026 12:02:22 +0200 Subject: [PATCH 24/24] Undo change --- highs/presolve/HPresolve.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/highs/presolve/HPresolve.cpp b/highs/presolve/HPresolve.cpp index 79f0ea06eec..954e432d2f0 100644 --- a/highs/presolve/HPresolve.cpp +++ b/highs/presolve/HPresolve.cpp @@ -5171,7 +5171,7 @@ HPresolve::Result HPresolve::singletonColStuffing( break; // compute delta (bound difference) HighsCDouble delta = - t.multiplier * static_cast(t.val) * + t.multiplier * t.val * (static_cast(model->col_upper_[t.col]) - static_cast(model->col_lower_[t.col])); // check if variable can be fixed