@@ -4988,8 +4988,7 @@ HPresolve::Result HPresolve::singletonColStuffing(
49884988
49894989 // count number of fixed columns
49904990 HighsInt numFixedCols = 0 ;
4991- // Temporary for fix-col-stuffing
4992- bool report_stuffing = true ;
4991+
49934992 struct candidate {
49944993 HighsInt col;
49954994 double val;
@@ -5028,8 +5027,7 @@ HPresolve::Result HPresolve::singletonColStuffing(
50285027 double & maxWeight, size_t & numIntegerCandidates) {
50295028 if (model->integrality_ [col] == HighsVarType::kInteger )
50305029 numIntegerCandidates++;
5031- // Temporary for fix-col-stuffing
5032- assert (direction * val > 0 );
5030+
50335031 minWeight = std::min (minWeight, direction * val);
50345032 maxWeight = std::max (maxWeight, direction * val);
50355033 candidates.push_back (candidate{col, val, direction});
@@ -5071,54 +5069,6 @@ HPresolve::Result HPresolve::singletonColStuffing(
50715069 double sumUpperBound = model->col_upper_ [j];
50725070 bool isCandidate = allowIntegerCandidates ||
50735071 model->integrality_ [j] != HighsVarType::kInteger ;
5074- // Considering row as a knapsack
5075- //
5076- // minimize c^Tx st a^Tx <= W; l <= x <= u
5077- //
5078- // NB minimize
5079- //
5080- // If cj/aj >= 0, then dual fixing means that xj can _probably_
5081- // be fixed
5082- //
5083- // If aj > 0, then xj is contributing positively to the
5084- // knapsack, but if cj >=0 its optimal value would appear to be
5085- // lj, and it must be if cj > 0, in which case lj = -inf implies
5086- // dual infeasibility.
5087- //
5088- // However, if cj = 0 and lj = -inf, then it is not logically
5089- // correct to fix it to its lower bound and claim dual
5090- // infeasibility. The row is redundant since, whatever values
5091- // are assigned to the other variables, xj can be made
5092- // sufficiently negative so that a^Tx <= W.
5093- //
5094- // If lj is finite, then it is fair to fix xj = lj
5095- //
5096- // If aj < 0 then then xj is contributing negatively to the
5097- // knapsack, and if cj < 0 its optimal value is uj, in which
5098- // case uj = inf implies dual infeasibility. If cj = 0 then, as
5099- // above, if uj is finite fix xj = uj, otherwise the row is
5100- // redundant.
5101- //
5102- // If cj/aj < 0, then xj is a candidate to have its value
5103- // assigned optimally. This is done greedily according to the
5104- // sorted values of cj/aj, over all such candidates
5105- //
5106- // Perhaps the cj = 0 issue is moot, since fixing to an infinte
5107- // bound leads to at least one of sumLowerFinite and
5108- // sumUpperFinite being false, so set of candidates is
5109- // abandoned.
5110- //
5111- // Question: The greedy algorithm is only guaranteed to assign
5112- // values optimally if the variables are continuous. The
5113- // criterion minWeight != maxWeight (ie not all |aj| values
5114- // being equal) leading to abandonment of stuffing if there are
5115- // only integer columns overcomes this. However, is it
5116- // guaranteed that with those continuous decisions the knapsack
5117- // is solved optimally?
5118- //
5119- // Question: Is there value in solving the knapsack problem by
5120- // DP if all variables are integer, and not all |aj| values are
5121- // equal?
51225072 if (isSingleton (j)) {
51235073 // check singleton
51245074 if (aj > 0 ) {
@@ -5209,12 +5159,6 @@ HPresolve::Result HPresolve::singletonColStuffing(
52095159 sortCols (candidates);
52105160
52115161 // check candidates
5212- // Temporary for fix-col-stuffing
5213- if (report_stuffing)
5214- printf (
5215- " ColStuffing: num candidates = %d; sumLower = %g; sumUpper = %g; rhs "
5216- " = %g\n " ,
5217- int (candidates.size ()), double (sumLower), double (sumUpper), rhs);
52185162 for (const auto & t : candidates) {
52195163 // both bounds have to be finite
52205164 if (model->col_lower_ [t.col ] == -kHighsInf ||
@@ -5228,38 +5172,20 @@ HPresolve::Result HPresolve::singletonColStuffing(
52285172 // check if variable can be fixed
52295173 if (sumUpperFinite &&
52305174 delta <= direction * rhs - sumUpper + primal_feastol) {
5231- if (report_stuffing)
5232- printf (
5233- " ColStuffing:0 (%2d) fix %6d to %s: cost = %11.4g; delta = "
5234- " %11.4g | "
5235- " Logic: delta = %11.4g <= %11.4g = direction * rhs - sumUpper + "
5236- " primal_feastol\n " ,
5237- int (t.multiplier ), int (t.col ),
5238- t.multiplier < 0 ? " lower" : " upper" , model->col_cost_ [t.col ],
5239- double (delta), double (delta),
5240- double (direction * rhs - sumUpper + primal_feastol));
52415175 numFixedCols++;
52425176 HPRESOLVE_CHECKED_CALL (fixCol (t.col , t.multiplier ));
52435177 } else if (sumLowerFinite &&
5244- direction * rhs <= sumLower + primal_feastol) {
5245- // Only allow fixing if there is no degeneracy
5246- const bool allow_fixing =
5247- direction * rhs + delta <= sumLower + primal_feastol;
5248- if (report_stuffing) {
5249- printf (
5250- " ColStuffing:1 (%2d) fix %6d to %s: cost = %11.4g; delta = "
5251- " %11.4g | "
5252- " Logic: direction * rhs = %11.4g <= %11.4g = sumLower + "
5253- " primal_feastol: %s fixing\n " ,
5254- int (-t.multiplier ), int (t.col ),
5255- -t.multiplier < 0 ? " lower" : " upper" , model->col_cost_ [t.col ],
5256- double (delta), double (direction * rhs),
5257- double (sumLower + primal_feastol), allow_fixing ? " allow" : " no" );
5258- }
5259- if (allow_fixing) {
5260- numFixedCols++;
5261- HPRESOLVE_CHECKED_CALL (fixCol (t.col , -t.multiplier ));
5262- }
5178+ delta <= sumLower - direction * rhs + primal_feastol) {
5179+ // Previously
5180+ //
5181+ // direction * rhs <= sumLower + primal_feastol
5182+ //
5183+ // But this led to fixing at -t.multiplier until row activity
5184+ // was at its bound, which is primal optmal but degenerate,
5185+ // and does not yield an optimal basis if column costs are
5186+ // positive
5187+ numFixedCols++;
5188+ HPRESOLVE_CHECKED_CALL (fixCol (t.col , -t.multiplier ));
52635189 }
52645190 // update row activities
52655191 if (sumLowerFinite) sumLower += delta;
@@ -5842,9 +5768,6 @@ HPresolve::Result HPresolve::fastPresolveLoop(
58425768
58435769 HPRESOLVE_CHECKED_CALL (presolveChangedCols (postsolve_stack));
58445770
5845- // Temporary for fix-col-stuffing
5846- HPRESOLVE_CHECKED_CALL (checkLimits (postsolve_stack));
5847-
58485771 } while (problemSizeReduction () > 0.01 );
58495772
58505773 return Result::kOk ;
@@ -6220,12 +6143,7 @@ HPresolve::Result HPresolve::checkLimits(HighsPostsolveStack& postsolve_stack) {
62206143
62216144 if ((numreductions & 1023u ) == 0 ) HPRESOLVE_CHECKED_CALL (checkTimeLimit ());
62226145
6223- // Temporary for fix-col-stuffing
6224- const bool limit_reached = numreductions >= reductionLimit;
6225- if (limit_reached) {
6226- printf (" HPresolve::checkLimits Reduction limit reached\n " );
6227- }
6228- return limit_reached ? Result::kStopped : Result::kOk ;
6146+ return numreductions >= reductionLimit ? Result::kStopped : Result::kOk ;
62296147}
62306148
62316149void HPresolve::storeCurrentProblemSize () {
@@ -7040,8 +6958,6 @@ HPresolve::Result HPresolve::presolveColSingletons(
70406958 HighsInt col = singletonColumns[i];
70416959 if (colDeleted[col]) continue ;
70426960 HPRESOLVE_CHECKED_CALL (colPresolve (postsolve_stack, col));
7043- // Temporary for fix-col-stuffing
7044- HPRESOLVE_CHECKED_CALL (checkLimits (postsolve_stack));
70456961 }
70466962 singletonColumns.erase (
70476963 std::remove_if (
0 commit comments