Skip to content

Commit 29c52db

Browse files
committed
Add non working version
1 parent 8b8a3f7 commit 29c52db

File tree

3 files changed

+213
-38
lines changed

3 files changed

+213
-38
lines changed

highs/mip/HighsImplications.cpp

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,195 @@ std::pair<HighsInt, HighsImplications::VarBound> HighsImplications::getBestVlb(
295295
return bestVlb;
296296
}
297297

298+
std::pair<HighsInt, HighsImplications::VarBound> HighsImplications::getBestVub(
299+
HighsInt col, const double lb, const double ub, const double coef,
300+
const HighsSolution& lpSolution, const HighsSparseVectorSum& bincoef,
301+
bool& complementvub, bool& inclbincolvub) const {
302+
std::pair<HighsInt, VarBound> bestVub =
303+
std::make_pair(-1, VarBound{0.0, kHighsInf});
304+
double minbestUb = ub;
305+
double bestUbDist = kHighsInf;
306+
int64_t bestvubnodes = 0;
307+
308+
auto isVubBetter = [&](double ubDist, int64_t vubNodes, double minVubVal) {
309+
if (ubDist < bestUbDist - mipsolver.mipdata_->feastol) return true;
310+
if (vubNodes > bestvubnodes) return true;
311+
if (vubNodes < bestvubnodes) return false;
312+
if (minVubVal < minbestUb - mipsolver.mipdata_->feastol) return true;
313+
314+
return false;
315+
};
316+
317+
double scale = mipsolver.mipdata_->domain.col_upper_[col] -
318+
mipsolver.mipdata_->domain.col_lower_[col];
319+
if (scale == kHighsInf)
320+
scale = 1.0;
321+
else
322+
scale = 1.0 / scale;
323+
324+
vubs[col].for_each([&](HighsInt vubCol, const VarBound& vub) {
325+
if (vub.coef == kHighsInf) return;
326+
if (mipsolver.mipdata_->domain.isFixed(vubCol)) return;
327+
assert(mipsolver.mipdata_->domain.isBinary(vubCol));
328+
double vubval = lpSolution.col_value[vubCol] * vub.coef + vub.constant;
329+
double ubDist = std::max(0.0, vubval - lpSolution.col_value[col]);
330+
331+
double yDist = mipsolver.mipdata_->feastol +
332+
(vub.coef > 0 ? 1 - lpSolution.col_value[vubCol]
333+
: lpSolution.col_value[vubCol]);
334+
double norm2 = 1.0 + vub.coef * vub.coef;
335+
if (ubDist * ubDist > yDist * yDist * norm2) return;
336+
337+
assert(vubCol >= 0 && vubCol < mipsolver.numCol());
338+
ubDist *= scale;
339+
if (ubDist <= bestUbDist + mipsolver.mipdata_->feastol) {
340+
bool complement = false;
341+
bool inclbincol = true;
342+
if (lb < vub.constant) {
343+
if (lb >= vub.constant + vub.coef) {
344+
complement = true;
345+
} else {
346+
return;
347+
}
348+
}
349+
const double sign = coef >= 0 ? 1 : -1;
350+
double complorigbincoef = complement ? -bincoef.getValue(vubCol) : bincoef.getValue(vubCol);
351+
double vbconstant = complement ? vub.constant + vub.coef : vub.constant;
352+
double vbcoef = complement ? -vub.coef : vub.coef;
353+
double val;
354+
val = sign * (coef * vbcoef + complorigbincoef);
355+
if (val > kHighsInf) return;
356+
if (val < 0) {
357+
val = sign * (coef * vbcoef);
358+
if (val < 0) return;
359+
inclbincol = false;
360+
}
361+
if (inclbincol) {
362+
val = sign * (coef * (lb - vbconstant) + complorigbincoef);
363+
if (val < 0) {
364+
val = sign * (coef * (lb - vbconstant));
365+
if (val < 0) return;
366+
inclbincol = false;
367+
val = sign * (coef * vbcoef);
368+
if (val < 0) return;
369+
}
370+
} else {
371+
val = sign * (coef * (lb - vbconstant));
372+
if (val < 0) return;
373+
}
374+
double minvubval = vub.minValue();
375+
int64_t vubnodes =
376+
vub.coef > 0 ? mipsolver.mipdata_->nodequeue.numNodesDown(vubCol)
377+
: mipsolver.mipdata_->nodequeue.numNodesUp(vubCol);
378+
379+
if (isVubBetter(ubDist, vubnodes, minvubval)) {
380+
minbestUb = minvubval;
381+
bestVub = std::make_pair(vubCol, vub);
382+
bestvubnodes = vubnodes;
383+
bestUbDist = ubDist;
384+
complementvub = complement;
385+
inclbincolvub = inclbincol;
386+
}
387+
}
388+
});
389+
390+
return bestVub;
391+
}
392+
393+
std::pair<HighsInt, HighsImplications::VarBound> HighsImplications::getBestVlb(
394+
HighsInt col, const double lb, const double ub, const double coef,
395+
const HighsSolution& lpSolution, const HighsSparseVectorSum& bincoef,
396+
bool& complementvlb, bool& inclbincolvlb) const {
397+
std::pair<HighsInt, VarBound> bestVlb =
398+
std::make_pair(-1, VarBound{0.0, -kHighsInf});
399+
double maxbestlb = lb;
400+
double bestLbDist = kHighsInf;
401+
int64_t bestvlbnodes = 0;
402+
403+
auto isVlbBetter = [&](double lbDist, int64_t vlbNodes, double maxVlbVal) {
404+
if (lbDist < bestLbDist - mipsolver.mipdata_->feastol) return true;
405+
if (vlbNodes > bestvlbnodes) return true;
406+
if (vlbNodes < bestvlbnodes) return false;
407+
if (maxVlbVal > maxbestlb + mipsolver.mipdata_->feastol) return true;
408+
return false;
409+
};
410+
411+
double scale = mipsolver.mipdata_->domain.col_upper_[col] -
412+
mipsolver.mipdata_->domain.col_lower_[col];
413+
if (scale == kHighsInf)
414+
scale = 1.0;
415+
else
416+
scale = 1.0 / scale;
417+
418+
vlbs[col].for_each([&](HighsInt vlbCol, const VarBound& vlb) {
419+
if (vlb.coef == -kHighsInf) return;
420+
if (mipsolver.mipdata_->domain.isFixed(vlbCol)) return;
421+
assert(mipsolver.mipdata_->domain.isBinary(vlbCol));
422+
assert(vlbCol >= 0 && vlbCol < mipsolver.numCol());
423+
double vlbval = lpSolution.col_value[vlbCol] * vlb.coef + vlb.constant;
424+
double lbDist = std::max(0.0, lpSolution.col_value[col] - vlbval);
425+
426+
double yDist = mipsolver.mipdata_->feastol +
427+
(vlb.coef > 0 ? lpSolution.col_value[vlbCol]
428+
: 1 - lpSolution.col_value[vlbCol]);
429+
430+
double norm2 = 1.0 + vlb.coef * vlb.coef;
431+
if (lbDist * lbDist > yDist * yDist * norm2) return;
432+
lbDist *= scale;
433+
if (lbDist <= bestLbDist + mipsolver.mipdata_->feastol) {
434+
bool complement = false;
435+
bool inclbincol = true;
436+
if (ub > vlb.constant) {
437+
if (ub <= vlb.constant + vlb.coef) {
438+
complement = true;
439+
} else {
440+
return;
441+
}
442+
}
443+
const double sign = coef >= 0 ? 1 : -1;
444+
double complorigbincoef = complement ? -bincoef.getValue(vlbCol) : bincoef.getValue(vlbCol);
445+
double vbconstant = complement ? vlb.constant + vlb.coef : vlb.constant;
446+
double vbcoef = complement ? -vlb.coef : vlb.coef;
447+
double val;
448+
val = sign * (coef * vbcoef + complorigbincoef);
449+
if (-val > kHighsInf) return;
450+
if (val > 0) {
451+
val = sign * (coef * vbcoef);
452+
if (val > 0) return;
453+
inclbincol = false;
454+
}
455+
if (inclbincol) {
456+
val = sign * (coef * (ub - vbconstant) + complorigbincoef);
457+
if (val > 0) {
458+
val = sign * (coef * (ub - vbconstant));
459+
if (val > 0) return;
460+
inclbincol = false;
461+
val = sign * (coef * vbcoef);
462+
if (val > 0) return;
463+
}
464+
} else {
465+
val = sign * (coef * (ub - vbconstant));
466+
if (val > 0) return;
467+
}
468+
double maxvlbval = vlb.maxValue();
469+
int64_t vlbnodes =
470+
vlb.coef > 0 ? mipsolver.mipdata_->nodequeue.numNodesUp(vlbCol)
471+
: mipsolver.mipdata_->nodequeue.numNodesDown(vlbCol);
472+
473+
if (isVlbBetter(lbDist, vlbnodes, maxvlbval)) {
474+
maxbestlb = maxvlbval;
475+
bestVlb = std::make_pair(vlbCol, vlb);
476+
bestvlbnodes = vlbnodes;
477+
bestLbDist = lbDist;
478+
inclbincolvlb = inclbincol;
479+
complementvlb = complement;
480+
}
481+
}
482+
});
483+
484+
return bestVlb;
485+
}
486+
298487
bool HighsImplications::runProbing(HighsInt col, HighsInt& numReductions) {
299488
HighsDomain& globaldomain = mipsolver.mipdata_->domain;
300489
if (globaldomain.isBinary(col) && !implicationsCached(col, 1) &&

highs/mip/HighsImplications.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,14 @@ class HighsImplications {
155155
const HighsSolution& lpSolution,
156156
double& bestLb) const;
157157

158+
std::pair<HighsInt, VarBound> getBestVub(HighsInt col, double lb, double ub, double coef,
159+
const HighsSolution& lpSolution, const HighsSparseVectorSum& bincoef,
160+
bool& complementvub, bool& inclbincolvub) const;
161+
162+
std::pair<HighsInt, VarBound> getBestVlb(HighsInt col, double lb, double ub, double coef,
163+
const HighsSolution& lpSolution, const HighsSparseVectorSum& bincoef,
164+
bool& complementvlb, bool& inclbincolvlb) const;
165+
158166
bool runProbing(HighsInt col, HighsInt& numReductions);
159167

160168
void rebuild(HighsInt ncols, const std::vector<HighsInt>& cIndex,

highs/mip/HighsTransformedLp.cpp

Lines changed: 16 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -782,36 +782,6 @@ bool HighsTransformedLp::transformSNFRelaxation(
782782
return false;
783783
}
784784

785-
// the code below uses the difference between the column upper and lower
786-
// bounds as the upper bound for the slack from the variable upper bound
787-
// constraint (upper[j] = ub - lb) and thus assumes that the variable upper
788-
// bound constraints are tight. this assumption may not be satisfied when
789-
// new bound changes were derived during cut generation and, therefore, we
790-
// tighten the best variable upper bound.
791-
if (bestVub[col].first != -1 &&
792-
bestVub[col].second.maxValue() > ub + mip.mipdata_->feastol) {
793-
bool redundant = false;
794-
bool infeasible = false;
795-
mip.mipdata_->implications.cleanupVub(col, bestVub[col].first,
796-
bestVub[col].second, ub, redundant,
797-
infeasible, false);
798-
}
799-
800-
// the code below uses the difference between the column upper and lower
801-
// bounds as the upper bound for the slack from the variable lower bound
802-
// constraint (upper[j] = ub - lb) and thus assumes that the variable lower
803-
// bound constraints are tight. this assumption may not be satisfied when
804-
// new bound changes were derived during cut generation and, therefore, we
805-
// tighten the best variable lower bound.
806-
if (bestVlb[col].first != -1 &&
807-
bestVlb[col].second.minValue() < lb - mip.mipdata_->feastol) {
808-
bool redundant = false;
809-
bool infeasible = false;
810-
mip.mipdata_->implications.cleanupVlb(col, bestVlb[col].first,
811-
bestVlb[col].second, lb, redundant,
812-
infeasible, false);
813-
}
814-
815785
// Transform entry into the SNFR
816786
if (i >= numNz - numBinCols) {
817787
// Binary columns can be added directly to the SNFR
@@ -826,16 +796,24 @@ bool HighsTransformedLp::transformSNFRelaxation(
826796
// Decide whether to use {simple, variable} {lower, upper} bound
827797
bool complementvlb = false;
828798
bool inclbincolvlb = true;
829-
bool vlbValid = checkValidityVB(
830-
bestVlb[col].first, bestVlb[col].second, vals[i],
831-
bestVlb[col].first == -1 ? 0 : vectorsum.getValue(bestVlb[col].first),
832-
lb, ub, false, complementvlb, inclbincolvlb);
799+
std::pair<HighsInt, HighsImplications::VarBound> vlb =
800+
std::make_pair(-1, HighsImplications::VarBound{0.0, -kHighsInf});
801+
if (col < slackOffset) {
802+
vlb = HighsImplications::getBestVlb(col, lb, ub,
803+
vals[i], lpSolution, vectorsum,
804+
complementvlb, inclbincolvlb);
805+
}
806+
bool vlbValid = (vlb.first != -1);
833807
bool complementvub = false;
834808
bool inclbincolvub = true;
835-
bool vubValid = checkValidityVB(
836-
bestVub[col].first, bestVub[col].second, vals[i],
837-
bestVub[col].first == -1 ? 0 : vectorsum.getValue(bestVub[col].first),
838-
lb, ub, true, complementvub, inclbincolvub);
809+
std::pair<HighsInt, HighsImplications::VarBound> vub =
810+
std::make_pair(-1, HighsImplications::VarBound{0.0, -kHighsInf});
811+
if (col < slackOffset) {
812+
vlb = HighsImplications::getBestVub(col, lb, ub,
813+
vals[i], lpSolution, vectorsum,
814+
complementvub, inclbincolvub);
815+
}
816+
bool vubValid = (vub.first != -1);
839817
auto boundType = BoundType::kSimpleLb;
840818
if (lbDist[col] < ubDist[col] - mip.mipdata_->feastol && vlbValid) {
841819
boundType = BoundType::kVariableLb;

0 commit comments

Comments
 (0)