diff --git a/highs/mip/HighsCliqueTable.cpp b/highs/mip/HighsCliqueTable.cpp index a2ccba3f2a..dcfeaad5bf 100644 --- a/highs/mip/HighsCliqueTable.cpp +++ b/highs/mip/HighsCliqueTable.cpp @@ -125,7 +125,7 @@ HighsInt HighsCliqueTable::runCliqueSubsumption( HighsInt len = cliques[cliqueid].end - cliques[cliqueid].start - cliques[cliqueid].numZeroFixed; - if (hits == (HighsInt)clique.size()) + if (hits == static_cast(clique.size())) redundant = true; else if (len == hits) { if (cliques[cliqueid].equality) { @@ -410,9 +410,11 @@ void HighsCliqueTable::doAddClique(const CliqueVar* cliquevars, // due to substitutions the clique became smaller and is now of size // two as a result we need to link it to the size two cliqueset // instead of the normal cliqueset - assert(cliqueid >= 0 && cliqueid < (HighsInt)cliques.size()); + assert(cliqueid >= 0 && + cliqueid < static_cast(cliques.size())); assert(cliques[cliqueid].start >= 0 && - cliques[cliqueid].start < (HighsInt)cliqueentries.size()); + cliques[cliqueid].start < + static_cast(cliqueentries.size())); unlink(cliques[cliqueid].start, cliqueid); unlink(cliques[cliqueid].start + 1, cliqueid); @@ -485,10 +487,10 @@ HighsInt HighsCliqueTable::partitionNeighbourhood( CliqueVar* q, HighsInt N) const { queryNeighbourhood(neighbourhoodInds, numQueries, v, q, N); - for (HighsInt i = 0; i < (HighsInt)neighbourhoodInds.size(); ++i) + for (size_t i = 0; i < neighbourhoodInds.size(); ++i) std::swap(q[i], q[neighbourhoodInds[i]]); - return neighbourhoodInds.size(); + return static_cast(neighbourhoodInds.size()); } HighsInt HighsCliqueTable::shrinkToNeighbourhood( @@ -496,23 +498,30 @@ HighsInt HighsCliqueTable::shrinkToNeighbourhood( CliqueVar* q, HighsInt N) { queryNeighbourhood(neighbourhoodInds, numQueries, v, q, N); - for (HighsInt i = 0; i < (HighsInt)neighbourhoodInds.size(); ++i) + for (size_t i = 0; i < neighbourhoodInds.size(); ++i) q[i] = q[neighbourhoodInds[i]]; - return neighbourhoodInds.size(); + return static_cast(neighbourhoodInds.size()); +} + +bool HighsCliqueTable::fixCol(HighsDomain& globaldom, CliqueVar v, + bool doProcessInfeasibleVertices) { + bool wasfixed = globaldom.isFixed(v.col); + globaldom.fixCol(v.col, static_cast(1 - v.val)); + if (globaldom.infeasible()) return false; + if (!wasfixed) { + ++nfixings; + infeasvertexstack.push_back(v); + if (doProcessInfeasibleVertices) processInfeasibleVertices(globaldom); + } + return true; } bool HighsCliqueTable::processNewEdge(HighsDomain& globaldom, CliqueVar v1, CliqueVar v2) { if (v1.col == v2.col) { if (v1.val == v2.val) { - bool wasfixed = globaldom.isFixed(v1.col); - globaldom.fixCol(v1.col, double(1 - v1.val)); - if (!wasfixed) { - ++nfixings; - infeasvertexstack.push_back(v1); - processInfeasibleVertices(globaldom); - } + fixCol(globaldom, v1, true); return false; } @@ -522,77 +531,17 @@ bool HighsCliqueTable::processNewEdge(HighsDomain& globaldom, CliqueVar v1, // invertedEdgeCache.erase(sortedEdge(v1, v2)); if (haveCommonClique(v1.complement(), v2)) { - bool wasfixed = globaldom.isFixed(v2.col); - globaldom.fixCol(v2.col, double(1 - v2.val)); - if (!wasfixed) { - ++nfixings; - infeasvertexstack.push_back(v2); - processInfeasibleVertices(globaldom); - } + fixCol(globaldom, v2, true); return false; } else if (haveCommonClique(v2.complement(), v1)) { - bool wasfixed = globaldom.isFixed(v1.col); - globaldom.fixCol(v1.col, double(1 - v1.val)); - if (!wasfixed) { - ++nfixings; - infeasvertexstack.push_back(v1); - processInfeasibleVertices(globaldom); - } + fixCol(globaldom, v1, true); return false; } else { - HighsInt commonclique = - findCommonCliqueId(v1.complement(), v2.complement()); - if (commonclique == -1) return false; - - while (commonclique != -1) { - HighsInt start = cliques[commonclique].start; - HighsInt end = cliques[commonclique].end; - - for (HighsInt i = start; i != end; ++i) { - if (cliqueentries[i] == v1.complement() || - cliqueentries[i] == v2.complement()) - continue; - - bool wasfixed = globaldom.isFixed(cliqueentries[i].col); - globaldom.fixCol(cliqueentries[i].col, 1 - cliqueentries[i].val); - if (globaldom.infeasible()) return true; - if (!wasfixed) { - ++nfixings; - infeasvertexstack.emplace_back(cliqueentries[i]); - } - } - - removeClique(commonclique); - commonclique = findCommonCliqueId(v1.complement(), v2.complement()); - } - - processInfeasibleVertices(globaldom); - if (globaldom.infeasible()) return false; - - commonclique = findCommonCliqueId(v1, v2); - - while (commonclique != -1) { - HighsInt start = cliques[commonclique].start; - HighsInt end = cliques[commonclique].end; - - for (HighsInt i = start; i != end; ++i) { - if (cliqueentries[i] == v1 || cliqueentries[i] == v2) continue; - - bool wasfixed = globaldom.isFixed(cliqueentries[i].col); - globaldom.fixCol(cliqueentries[i].col, 1 - cliqueentries[i].val); - if (globaldom.infeasible()) return true; - if (!wasfixed) { - ++nfixings; - infeasvertexstack.emplace_back(cliqueentries[i]); - } - } - - removeClique(commonclique); - commonclique = findCommonCliqueId(v1, v2); - } - - processInfeasibleVertices(globaldom); + // return if complements are not in a clique + if (!foundCover(globaldom, v1.complement(), v2.complement())) return false; + if (globaldom.infeasible()) return true; + foundCover(globaldom, v1, v2); if (globaldom.isFixed(v1.col) || globaldom.isFixed(v2.col) || globaldom.infeasible()) return true; @@ -665,39 +614,31 @@ void HighsCliqueTable::addClique(const HighsMipSolver& mipsolver, bool equality, HighsInt origin) { HighsDomain& globaldom = mipsolver.mipdata_->domain; mipsolver.mipdata_->debugSolution.checkClique(cliquevars, numcliquevars); - for (HighsInt i = 0; i != numcliquevars; ++i) { - resolveSubstitution(cliquevars[i]); - if (globaldom.isFixed(cliquevars[i].col)) { - if (cliquevars[i].val == globaldom.col_lower_[cliquevars[i].col]) { - // column is fixed to 1, every other entry can be fixed to zero - HighsInt k; - for (k = 0; k < i; ++k) { - bool wasfixed = globaldom.isFixed(cliquevars[k].col); - globaldom.fixCol(cliquevars[k].col, double(1 - cliquevars[k].val)); - if (globaldom.infeasible()) return; - if (!wasfixed) { - ++nfixings; - infeasvertexstack.push_back(cliquevars[k]); - } - } - for (k = i + 1; k < numcliquevars; ++k) { - bool wasfixed = globaldom.isFixed(cliquevars[k].col); - globaldom.fixCol(cliquevars[k].col, double(1 - cliquevars[k].val)); - if (globaldom.infeasible()) return; - if (!wasfixed) { - ++nfixings; - infeasvertexstack.push_back(cliquevars[k]); - } - } + const HighsInt maxNumCliqueVars = 100; + + // lambda for complementing clique + auto complementClique = [&]() { + for (HighsInt i = 0; i != numcliquevars; ++i) { + cliquevars[i] = cliquevars[i].complement(); + } + }; - processInfeasibleVertices(globaldom); - return; + // lambda for analysing the clique to see if all variables can be fixed + auto fixAllVarsInClique = [&](bool& hasNewEdge) { + for (HighsInt i = 0; i != numcliquevars; ++i) { + if (!globaldom.isFixed(cliquevars[i].col) || + cliquevars[i].val != globaldom.col_lower_[cliquevars[i].col]) + continue; + // column is fixed to 1, every other entry can be fixed to zero + for (HighsInt k = 0; k != numcliquevars; ++k) { + if (k == i) continue; + if (!fixCol(globaldom, cliquevars[k])) return false; } + processInfeasibleVertices(globaldom); + return true; } - } - if (numcliquevars <= 100) { - bool hasNewEdge = false; + if (numcliquevars > maxNumCliqueVars) return false; // todo, sort new clique to allow log n lookup of membership in size by // binary search @@ -714,17 +655,17 @@ void HighsCliqueTable::addClique(const HighsMipSolver& mipsolver, if (globaldom.isFixed(cliquevars[j].col)) continue; if (haveCommonClique(cliquevars[i], cliquevars[j])) continue; - // todo: Instead of haveCommonClique use findCommonClique. If the common - // clique is smaller than this clique check if it is a subset of this - // clique. If it is a subset remove the clique and iterate the process - // until either a common clique that is not a subset of this one is - // found, or no common clique exists anymore in which case we proceed - // with the code below and set hasNewEdge to true + // todo: Instead of haveCommonClique use findCommonClique. If the + // common clique is smaller than this clique check if it is a subset + // of this clique. If it is a subset remove the clique and iterate the + // process until either a common clique that is not a subset of this + // one is found, or no common clique exists anymore in which case we + // proceed with the code below and set hasNewEdge to true hasNewEdge = true; bool iscover = processNewEdge(globaldom, cliquevars[i], cliquevars[j]); - if (globaldom.infeasible()) return; + if (globaldom.infeasible()) return false; if (!mipsolver.mipdata_->nodequeue.empty()) { const auto& v1Nodes = @@ -744,20 +685,20 @@ void HighsCliqueTable::addClique(const HighsMipSolver& mipsolver, // care here, since the set of nodes branched upwards or downwards // are not necessarily containing domain changes setting the // variables to the corresponding clique value but could be - // redundant bound changes setting the upper bound to u >= 1 or the - // lower bound to l <= 0. + // redundant bound changes setting the upper bound to u >= 1 or + // the lower bound to l <= 0. // itV1 will point to the first node where v1 is fixed to val and - // endV1 to the end of the range of such nodes. Same for itV2/endV2 - // with v2. - auto itV1 = v1Nodes.lower_bound( - std::make_pair(double(cliquevars[i].val), kHighsIInf)); - auto endV1 = v1Nodes.upper_bound( - std::make_pair(double(cliquevars[i].val), kHighsIInf)); - auto itV2 = v2Nodes.lower_bound( - std::make_pair(double(cliquevars[j].val), kHighsIInf)); - auto endV2 = v2Nodes.upper_bound( - std::make_pair(double(cliquevars[j].val), kHighsIInf)); + // endV1 to the end of the range of such nodes. Same for + // itV2/endV2 with v2. + auto itV1 = v1Nodes.lower_bound(std::make_pair( + static_cast(cliquevars[i].val), kHighsIInf)); + auto endV1 = v1Nodes.upper_bound(std::make_pair( + static_cast(cliquevars[i].val), kHighsIInf)); + auto itV2 = v2Nodes.lower_bound(std::make_pair( + static_cast(cliquevars[j].val), kHighsIInf)); + auto endV2 = v2Nodes.upper_bound(std::make_pair( + static_cast(cliquevars[j].val), kHighsIInf)); if (itV1 != endV1 && itV2 != endV2 && (itV1->second <= std::prev(endV2)->second || @@ -785,23 +726,45 @@ void HighsCliqueTable::addClique(const HighsMipSolver& mipsolver, if (iscover) { for (HighsInt k = 0; k != numcliquevars; ++k) { if (k == i || k == j) continue; - - bool wasfixed = globaldom.isFixed(cliquevars[k].col); - globaldom.fixCol(cliquevars[k].col, double(1 - cliquevars[k].val)); - if (globaldom.infeasible()) return; - if (!wasfixed) { - ++nfixings; - infeasvertexstack.push_back(cliquevars[k]); - } + if (!fixCol(globaldom, cliquevars[k])) return false; } - processInfeasibleVertices(globaldom); - return; + return true; } } } - if (!hasNewEdge && origin == kHighsIInf) return; + return false; + }; + + // lambda for checking the (complemented) clique + auto checkClique = [&](bool& hasNewEdge, bool complement) { + if (complement) complementClique(); + bool done = fixAllVarsInClique(hasNewEdge); + if (complement) complementClique(); + if (done) return true; + return false; + }; + + // resolve substitutions + for (HighsInt i = 0; i != numcliquevars; ++i) { + resolveSubstitution(cliquevars[i]); } + + // initialise flag + bool hasNewEdge = false; + + // check if all variables can be fixed or infeasibility is detected + if (checkClique(hasNewEdge, false)) return; + if (globaldom.infeasible()) return; + + if (numcliquevars == 2 && equality) { + // try complemented clique + if (checkClique(hasNewEdge, true)) return; + if (globaldom.infeasible()) return; + } + + if (!hasNewEdge && origin == kHighsIInf) return; + CliqueVar* unfixedend = std::remove_if(cliquevars, cliquevars + numcliquevars, [&](CliqueVar v) { return globaldom.isFixed(v.col); }); @@ -852,7 +815,7 @@ void HighsCliqueTable::extractCliques( return globaldom.isBinary(inds[pos]); }); nbin = binaryend - perm.begin(); - HighsInt ntotal = (HighsInt)perm.size(); + HighsInt ntotal = static_cast(perm.size()); // if not all variables are binary, we extract variable upper and lower bounds // constraints on the non-binary variable for each binary variable in the @@ -860,18 +823,19 @@ void HighsCliqueTable::extractCliques( if (nbin < ntotal) { for (HighsInt i = 0; i != nbin; ++i) { HighsInt bincol = inds[perm[i]]; - HighsCDouble impliedub = HighsCDouble(rhs) - vals[perm[i]]; + HighsCDouble impliedub = static_cast(rhs) - vals[perm[i]]; if (implics.tooManyVarBounds()) break; for (HighsInt j = nbin; j != ntotal; ++j) { HighsInt col = inds[perm[j]]; if (globaldom.isFixed(col)) continue; HighsCDouble colub = - HighsCDouble(globaldom.col_upper_[col]) - globaldom.col_lower_[col]; + static_cast(globaldom.col_upper_[col]) - + globaldom.col_lower_[col]; HighsCDouble implcolub = impliedub / vals[perm[j]]; if (mipsolver.isColIntegral(col)) - implcolub = - std::floor(double(implcolub) + mipsolver.mipdata_->feastol); + implcolub = std::floor(static_cast(implcolub) + + mipsolver.mipdata_->feastol); if (implcolub < colub - feastol) { HighsCDouble coef; @@ -887,10 +851,12 @@ void HighsCliqueTable::extractCliques( if (complementation[perm[j]] == -1) { constant -= globaldom.col_upper_[col]; - implics.addVLB(col, bincol, -double(coef), -double(constant)); + implics.addVLB(col, bincol, -static_cast(coef), + -static_cast(constant)); } else { constant += globaldom.col_lower_[col]; - implics.addVUB(col, bincol, double(coef), double(constant)); + implics.addVUB(col, bincol, static_cast(coef), + static_cast(constant)); } } } @@ -1053,9 +1019,8 @@ void HighsCliqueTable::cliquePartition(const std::vector& objective, bool HighsCliqueTable::foundCover(HighsDomain& globaldom, CliqueVar v1, CliqueVar v2) { - bool equality = false; HighsInt commonclique = findCommonCliqueId(v1, v2); - if (commonclique != -1) equality = true; + if (commonclique == -1) return false; while (commonclique != -1) { HighsInt start = cliques[commonclique].start; @@ -1063,14 +1028,7 @@ bool HighsCliqueTable::foundCover(HighsDomain& globaldom, CliqueVar v1, for (HighsInt i = start; i != end; ++i) { if (cliqueentries[i] == v1 || cliqueentries[i] == v2) continue; - - bool wasfixed = globaldom.isFixed(cliqueentries[i].col); - globaldom.fixCol(cliqueentries[i].col, 1 - cliqueentries[i].val); - if (globaldom.infeasible()) return equality; - if (!wasfixed) { - ++nfixings; - infeasvertexstack.emplace_back(cliqueentries[i]); - } + if (!fixCol(globaldom, cliqueentries[i])) return true; } removeClique(commonclique); @@ -1078,8 +1036,7 @@ bool HighsCliqueTable::foundCover(HighsDomain& globaldom, CliqueVar v1, } processInfeasibleVertices(globaldom); - - return equality; + return true; } void HighsCliqueTable::extractCliquesFromCut(const HighsMipSolver& mipsolver, @@ -1114,7 +1071,7 @@ void HighsCliqueTable::extractCliquesFromCut(const HighsMipSolver& mipsolver, for (HighsInt i = 0; i != len; ++i) { if (mipsolver.isColContinuous(inds[i])) continue; - double boundVal = double((rhs - minact) / vals[i]); + double boundVal = static_cast((rhs - minact) / vals[i]); if (vals[i] > 0) { boundVal = std::floor(boundVal + globaldom.col_lower_[inds[i]] + globaldom.feastol()); @@ -1154,9 +1111,10 @@ void HighsCliqueTable::extractCliquesFromCut(const HighsMipSolver& mipsolver, if (globaldom.isFixed(col)) continue; if (vals[perm[j]] > 0) { - double implcolub = double(impliedActivity + - vals[perm[j]] * globaldom.col_lower_[col]) / - vals[perm[j]]; + double implcolub = + static_cast(impliedActivity + + vals[perm[j]] * globaldom.col_lower_[col]) / + vals[perm[j]]; if (mipsolver.isColIntegral(col)) implcolub = std::floor(implcolub + mipsolver.mipdata_->feastol); @@ -1179,9 +1137,10 @@ void HighsCliqueTable::extractCliquesFromCut(const HighsMipSolver& mipsolver, implics.addVUB(col, bincol, coef, constant); } } else { - double implcollb = double(impliedActivity + - vals[perm[j]] * globaldom.col_upper_[col]) / - vals[perm[j]]; + double implcollb = + static_cast(impliedActivity + + vals[perm[j]] * globaldom.col_upper_[col]) / + vals[perm[j]]; if (mipsolver.isColIntegral(col)) implcollb = std::ceil(implcollb - mipsolver.mipdata_->feastol); @@ -1222,7 +1181,7 @@ void HighsCliqueTable::extractCliquesFromCut(const HighsMipSolver& mipsolver, }); // check if any cliques exists if (std::abs(vals[perm[0]]) + std::abs(vals[perm[1]]) <= - double(rhs - minact + feastol)) + static_cast(rhs - minact + feastol)) return; HighsInt maxNewEntries = @@ -1232,7 +1191,7 @@ void HighsCliqueTable::extractCliquesFromCut(const HighsMipSolver& mipsolver, for (HighsInt k = nbin - 1; k != 0 && numEntries < maxNewEntries; --k) { double mincliqueval = - double(rhs - minact - std::abs(vals[perm[k]]) + feastol); + static_cast(rhs - minact - std::abs(vals[perm[k]]) + feastol); auto cliqueend = std::partition_point( perm.begin(), perm.begin() + k, [&](HighsInt p) { return std::abs(vals[p]) > mincliqueval; }); @@ -1478,12 +1437,12 @@ void HighsCliqueTable::extractObjCliques(HighsMipSolver& mipsolver) { globaldom.computeMinActivity(0, len, inds, vals, ninf, minact); const double feastol = mipsolver.mipdata_->feastol; if (std::fabs(vals[perm[0]]) + std::fabs(vals[perm[1]]) <= - double(rhs - minact + feastol)) + static_cast(rhs - minact + feastol)) return; for (HighsInt k = nbin - 1; k != 0; --k) { double mincliqueval = - double(rhs - minact - std::fabs(vals[perm[k]]) + feastol); + static_cast(rhs - minact - std::fabs(vals[perm[k]]) + feastol); auto cliqueend = std::partition_point( perm.begin(), perm.begin() + k, [&](HighsInt p) { return std::abs(vals[p]) > mincliqueval; }); @@ -1528,7 +1487,7 @@ void HighsCliqueTable::processInfeasibleVertices(HighsDomain& globaldom) { resolveSubstitution(v); bool wasfixed = globaldom.isFixed(v.col); - globaldom.fixCol(v.col, double(v.val)); + globaldom.fixCol(v.col, static_cast(v.val)); if (globaldom.infeasible()) return; if (!wasfixed) ++nfixings; if (colDeleted[v.col]) continue; @@ -1545,15 +1504,7 @@ void HighsCliqueTable::processInfeasibleVertices(HighsDomain& globaldom) { for (HighsInt i = start; i != end; ++i) { if (cliqueentries[i].col == v.col) continue; - - bool wasfixed = globaldom.isFixed(cliqueentries[i].col); - globaldom.fixCol(cliqueentries[i].col, - double(1 - cliqueentries[i].val)); - if (globaldom.infeasible()) return true; - if (!wasfixed) { - ++nfixings; - infeasvertexstack.push_back(cliqueentries[i]); - } + if (!fixCol(globaldom, cliqueentries[i])) return true; } removeClique(cliqueid); @@ -1568,15 +1519,7 @@ void HighsCliqueTable::processInfeasibleVertices(HighsDomain& globaldom) { for (HighsInt i = start; i != end; ++i) { if (cliqueentries[i].col == v.col) continue; - - bool wasfixed = globaldom.isFixed(cliqueentries[i].col); - globaldom.fixCol(cliqueentries[i].col, - double(1 - cliqueentries[i].val)); - if (globaldom.infeasible()) return true; - if (!wasfixed) { - ++nfixings; - infeasvertexstack.push_back(cliqueentries[i]); - } + if (!fixCol(globaldom, cliqueentries[i])) return true; } removeClique(cliqueid); @@ -1657,11 +1600,11 @@ void HighsCliqueTable::propagateAndCleanup(HighsDomain& globaldom) { while (!globaldom.infeasible() && start != end) { for (HighsInt k = start; k != end; ++k) { HighsInt col = domchgstack[k].column; - if (globaldom.col_lower_[col] != globaldom.col_upper_[col]) continue; + if (!globaldom.isFixed(col)) continue; if (globaldom.col_lower_[col] != 1.0 && globaldom.col_lower_[col] != 0.0) continue; - HighsInt fixval = (HighsInt)globaldom.col_lower_[col]; + HighsInt fixval = static_cast(globaldom.col_lower_[col]); CliqueVar v(col, 1 - fixval); if (numCliques(v) != 0) { vertexInfeasible(globaldom, col, 1 - fixval); @@ -1677,7 +1620,7 @@ void HighsCliqueTable::propagateAndCleanup(HighsDomain& globaldom) { void HighsCliqueTable::vertexInfeasible(HighsDomain& globaldom, HighsInt col, HighsInt val) { bool wasfixed = globaldom.isFixed(col); - globaldom.fixCol(col, double(1 - val)); + globaldom.fixCol(col, static_cast(1 - val)); if (globaldom.infeasible()) return; if (!wasfixed) ++nfixings; infeasvertexstack.emplace_back(col, val); @@ -1737,7 +1680,7 @@ void HighsCliqueTable::separateCliques(const HighsMipSolver& mipsolver, std::vector vals; for (std::vector& clique : data.cliques) { #ifdef ADD_ZERO_WEIGHT_VARS - HighsInt extensionend = (HighsInt)data.Z.size(); + HighsInt extensionend = static_cast(data.Z.size()); for (CliqueVar v : clique) { extensionend = partitionNeighbourhood(data.neighbourhoodInds, data.numNeighbourhoodQueries, v, @@ -1857,7 +1800,8 @@ void HighsCliqueTable::addImplications(HighsDomain& domain, HighsInt col, CliqueVar v(col, val); while (colsubstituted[v.col]) { - assert((HighsInt)substitutions.size() > colsubstituted[v.col] - 1); + assert(static_cast(substitutions.size()) > + colsubstituted[v.col] - 1); Substitution subst = substitutions[colsubstituted[v.col] - 1]; v = v.val == 1 ? subst.replace : subst.replace.complement(); if (v.val == 1) { @@ -1911,12 +1855,11 @@ void HighsCliqueTable::cleanupFixed(HighsDomain& globaldom) { HighsInt numcol = globaldom.col_upper_.size(); HighsInt oldnfixings = nfixings; for (HighsInt i = 0; i != numcol; ++i) { - if (colDeleted[i] || globaldom.col_lower_[i] != globaldom.col_upper_[i]) - continue; + if (colDeleted[i] || !globaldom.isFixed(i)) continue; if (globaldom.col_lower_[i] != 1.0 && globaldom.col_lower_[i] != 0.0) continue; - HighsInt fixval = (HighsInt)globaldom.col_lower_[i]; + HighsInt fixval = static_cast(globaldom.col_lower_[i]); CliqueVar v(i, 1 - fixval); vertexInfeasible(globaldom, v.col, v.val); @@ -2014,8 +1957,8 @@ void HighsCliqueTable::runCliqueMerging(HighsDomain& globaldomain, for (HighsInt i = 0; i != sizeWithCandidates; ++i) iscandidate[clique[i].index()] = false; - for (HighsInt i = 0; - i != initialCliqueSize && initialCliqueSize < (HighsInt)clique.size(); + for (HighsInt i = 0; i != initialCliqueSize && + initialCliqueSize < static_cast(clique.size()); ++i) { if (clique[i] == extensionstart) continue; @@ -2032,7 +1975,7 @@ void HighsCliqueTable::runCliqueMerging(HighsDomain& globaldomain, randgen.shuffle(clique.data() + initialCliqueSize, clique.size() - initialCliqueSize); HighsInt i = initialCliqueSize; - while (i < (HighsInt)clique.size()) { + while (i < static_cast(clique.size())) { CliqueVar extvar = clique[i]; i += 1; @@ -2044,7 +1987,8 @@ void HighsCliqueTable::runCliqueMerging(HighsDomain& globaldomain, } if (equation) { - for (HighsInt i = initialCliqueSize; i < (HighsInt)clique.size(); ++i) + for (HighsInt i = initialCliqueSize; + i < static_cast(clique.size()); ++i) vertexInfeasible(globaldomain, clique[i].col, clique[i].val); } else { runCliqueSubsumption(globaldomain, clique); @@ -2190,7 +2134,7 @@ void HighsCliqueTable::runCliqueMerging(HighsDomain& globaldomain) { HighsInt hits = cliquehits[cliqueid]; cliquehits[cliqueid] = 0; - if (hits == (HighsInt)extensionvars.size()) { + if (hits == static_cast(extensionvars.size())) { redundant = true; if (cliques[cliqueid].origin != kHighsIInf && cliques[cliqueid].origin != -1) diff --git a/highs/mip/HighsCliqueTable.h b/highs/mip/HighsCliqueTable.h index 317277054d..3777ac9e02 100644 --- a/highs/mip/HighsCliqueTable.h +++ b/highs/mip/HighsCliqueTable.h @@ -182,6 +182,9 @@ class HighsCliqueTable { int64_t& numNeighbourhoodqueries, CliqueVar v, CliqueVar* q, HighsInt N); + bool fixCol(HighsDomain& globaldom, CliqueVar v, + bool doProcessInfeasibleVertices = false); + bool processNewEdge(HighsDomain& globaldom, CliqueVar v1, CliqueVar v2); void doAddClique(const CliqueVar* cliquevars, HighsInt numcliquevars, diff --git a/highs/presolve/HPresolve.cpp b/highs/presolve/HPresolve.cpp index 5bc361f496..f0a281ab84 100644 --- a/highs/presolve/HPresolve.cpp +++ b/highs/presolve/HPresolve.cpp @@ -5168,24 +5168,20 @@ HPresolve::Result HPresolve::enumerateSolutions( for (size_t i = 0; i < numVars - 1; i++) { // get column index HighsInt col = vars[i]; - // skip already fixed columns - if (domain.isFixed(col)) continue; for (size_t ii = i + 1; ii < numVars; ii++) { // get column index HighsInt col2 = vars[ii]; - // skip already fixed columns - if (domain.isFixed(col2)) continue; // check if two binary variables take identical or complementary // values in all feasible solutions if (identicalVars(numSolutions, i, ii)) { - // add clique x_1 + (1 - x_2) = 1 to clique table + // add clique (1 - x_1) + x_2 = 1 to clique table std::array clique; clique[0] = HighsCliqueTable::CliqueVar(col, 0); clique[1] = HighsCliqueTable::CliqueVar(col2, 1); cliquetable.addClique(*mipsolver, clique.data(), 2, true); HPRESOLVE_CHECKED_CALL(handleInfeasibility(domain.infeasible())); } else if (complementaryVars(numSolutions, i, ii)) { - // add clique x_1 + x_2 = 1 to clique table + // add clique (1 - x_1) + (1 - x_2) = 1 to clique table std::array clique; clique[0] = HighsCliqueTable::CliqueVar(col, 0); clique[1] = HighsCliqueTable::CliqueVar(col2, 0);