@@ -5018,8 +5018,16 @@ HPresolve::Result HPresolve::enumerateSolutions(
50185018 numWorstCaseBounds--;
50195019 };
50205020
5021+ auto varsFormClique = [&](size_t numVars, size_t minNumActiveCols,
5022+ size_t maxNumActiveCols) {
5023+ return (maxNumActiveCols == 1 || (minNumActiveCols == numVars - 1 &&
5024+ maxNumActiveCols == numVars - 1 ));
5025+ };
5026+
50215027 auto handleSolution = [&](size_t numVars, size_t & numSolutions,
5022- size_t & numWorstCaseBounds, bool & noReductions) {
5028+ size_t & numWorstCaseBounds,
5029+ size_t & minNumActiveCols, size_t & maxNumActiveCols,
5030+ bool & noReductions) {
50235031 // propagate
50245032 domain.propagate ();
50255033 if (domain.infeasible ()) return ;
@@ -5056,14 +5064,21 @@ HPresolve::Result HPresolve::enumerateSolutions(
50565064 }
50575065 }
50585066 }
5059- // store solution
5060- for (size_t i = 0 ; i < numVars; i++)
5061- solutions[i][numSolutions] =
5062- (domain.col_lower_ [vars[i]] == 0.0 ? HighsInt{0 } : HighsInt{1 });
5067+ // store solution and compute minimum and maximum number of active variables
5068+ // (i.e. those having solution value of 1)
5069+ size_t numActiveCols = 0 ;
5070+ for (size_t i = 0 ; i < numVars; i++) {
5071+ HighsInt solValue = domain.col_lower_ [vars[i]] == 0.0 ? 0 : 1 ;
5072+ solutions[i][numSolutions] = solValue;
5073+ if (solValue != 0 ) numActiveCols++;
5074+ }
5075+ minNumActiveCols = std::min (minNumActiveCols, numActiveCols);
5076+ maxNumActiveCols = std::max (maxNumActiveCols, numActiveCols);
50635077 numSolutions++;
50645078
50655079 // if no reductions are possible, stop enumerating solutions
5066- noReductions = numWorstCaseBounds == 0 ;
5080+ noReductions = numWorstCaseBounds == 0 &&
5081+ !varsFormClique (numVars, minNumActiveCols, maxNumActiveCols);
50675082 if (noReductions) {
50685083 for (size_t i = 0 ; i < numVars - 1 ; i++) {
50695084 for (size_t ii = i + 1 ; ii < numVars; ii++) {
@@ -5078,6 +5093,7 @@ HPresolve::Result HPresolve::enumerateSolutions(
50785093
50795094 // loop over candidate rows
50805095 HighsInt numRowsChecked = 0 ;
5096+ HighsInt numCliquesFound = 0 ;
50815097 for (const auto & r : rows) {
50825098 // get row index
50835099 HighsInt row = r.row ;
@@ -5107,14 +5123,16 @@ HPresolve::Result HPresolve::enumerateSolutions(
51075123 HighsInt numBranches = -1 ;
51085124 size_t numWorstCaseBounds = 0 ;
51095125 size_t numSolutions = 0 ;
5126+ size_t minNumActiveCols = numVars;
5127+ size_t maxNumActiveCols = 0 ;
51105128 bool noReductions = false ;
51115129 while (true ) {
51125130 bool backtrack = domain.infeasible ();
51135131 if (!backtrack) {
51145132 backtrack = solutionFound (numVars);
51155133 if (backtrack) {
51165134 handleSolution (numVars, numSolutions, numWorstCaseBounds,
5117- noReductions);
5135+ minNumActiveCols, maxNumActiveCols, noReductions);
51185136 if (noReductions) break ;
51195137 }
51205138 }
@@ -5138,11 +5156,22 @@ HPresolve::Result HPresolve::enumerateSolutions(
51385156 // no solutions -> infeasible
51395157 HPRESOLVE_CHECKED_CALL (handleInfeasibility (numSolutions == 0 ));
51405158
5159+ // check if all variables form a clique
5160+ if (varsFormClique (numVars, minNumActiveCols, maxNumActiveCols)) {
5161+ numCliquesFound++;
5162+ std::vector<HighsCliqueTable::CliqueVar> clique (numVars);
5163+ for (size_t i = 0 ; i < numVars; i++)
5164+ clique[i] =
5165+ HighsCliqueTable::CliqueVar (vars[i], maxNumActiveCols == 1 ? 1 : 0 );
5166+ cliquetable.addClique (*mipsolver, clique.data (),
5167+ static_cast <HighsInt>(numVars),
5168+ minNumActiveCols == maxNumActiveCols);
5169+ HPRESOLVE_CHECKED_CALL (handleInfeasibility (domain.infeasible ()));
5170+ }
5171+
51415172 // analyse worst-case bounds
51425173 for (size_t i = 0 ; i < numWorstCaseBounds; i++) {
51435174 HighsInt col = worstCaseBounds[i];
5144- assert (worstCaseLowerBound[col] >= domain.col_lower_ [col]);
5145- assert (worstCaseUpperBound[col] <= domain.col_upper_ [col]);
51465175 if (worstCaseLowerBound[col] > domain.col_lower_ [col]) {
51475176 // tighten lower bound
51485177 col_lower[col] = worstCaseLowerBound[col];
@@ -5175,13 +5204,15 @@ HPresolve::Result HPresolve::enumerateSolutions(
51755204 // values in all feasible solutions
51765205 if (identicalVars (numSolutions, i, ii)) {
51775206 // add clique (1 - x_1) + x_2 = 1 to clique table
5207+ numCliquesFound++;
51785208 std::array<HighsCliqueTable::CliqueVar, 2 > clique;
51795209 clique[0 ] = HighsCliqueTable::CliqueVar (col, 0 );
51805210 clique[1 ] = HighsCliqueTable::CliqueVar (col2, 1 );
51815211 cliquetable.addClique (*mipsolver, clique.data (), 2 , true );
51825212 HPRESOLVE_CHECKED_CALL (handleInfeasibility (domain.infeasible ()));
51835213 } else if (complementaryVars (numSolutions, i, ii)) {
51845214 // add clique (1 - x_1) + (1 - x_2) = 1 to clique table
5215+ numCliquesFound++;
51855216 std::array<HighsCliqueTable::CliqueVar, 2 > clique;
51865217 clique[0 ] = HighsCliqueTable::CliqueVar (col, 0 );
51875218 clique[1 ] = HighsCliqueTable::CliqueVar (col2, 0 );
0 commit comments