Skip to content

Commit

Permalink
P-D integral now correct for 100 MIP
Browse files Browse the repository at this point in the history
  • Loading branch information
jajhall committed Nov 2, 2024
1 parent e1c5a46 commit 4003eb2
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 68 deletions.
5 changes: 4 additions & 1 deletion check/TestLpSolvers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,9 @@ TEST_CASE("standard-form-lp", "[highs_lp_solver]") {
REQUIRE(highs.addRow(1.0, 1.0, 4, index.data(), value.data()) ==
HighsStatus::kOk);
REQUIRE(highs.changeObjectiveSense(ObjSense::kMaximize) == HighsStatus::kOk);
if (dev_run) printf("\nNow test by adding a fixed column and a fixed row, and maximizing\n");
if (dev_run)
printf(
"\nNow test by adding a fixed column and a fixed row, and "
"maximizing\n");
testStandardForm(highs.getLp());
}
2 changes: 0 additions & 2 deletions src/mip/HighsMipSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,7 @@ void HighsMipSolver::run() {
mipdata_->cutpool.performAging();
mipdata_->cutpool.performAging();
}
printf("HighsMipSolver::run() bounds are [%g, %g]: nodequeue.empty() = %d; checkLimits() = %d\n", mipdata_->lower_bound, mipdata_->upper_bound, mipdata_->nodequeue.empty(), mipdata_->checkLimits());
if (mipdata_->nodequeue.empty() || mipdata_->checkLimits()) {
printf("HighsMipSolver::run() calling cleanupSolve();\n");
cleanupSolve();
return;
}
Expand Down
140 changes: 76 additions & 64 deletions src/mip/HighsMipSolverData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1069,6 +1069,12 @@ void HighsMipSolverData::performRestart() {
runPresolve(further_presolve_reduction_limit);

if (mipsolver.modelstatus_ != HighsModelStatus::kNotset) {
// if (!mipsolver.submip) {
// printf(
// "HighsMipSolverData::performRestart() After runPresolve(), "
// "mipsolver.modelstatus_ = %s\n",
// utilModelStatusToString(mipsolver.modelstatus_).c_str());
// }
// transform the objective limit to the current model
upper_limit -= mipsolver.model_->offset_;
optimality_limit -= mipsolver.model_->offset_;
Expand All @@ -1081,21 +1087,23 @@ void HighsMipSolverData::performRestart() {
upper_bound -= mipsolver.model_->offset_;
}

double prev_lower_bound = lower_bound;
// lower_bound still relates to the original model, and the offset
// is never applied, since MIP solving is complete, and
// lower_bound is set to upper_bound, so apply the offset now, so
// that housekeeping in updatePrimaDualIntegral is correct
double prev_lower_bound = lower_bound - mipsolver.model_->offset_;

lower_bound = upper_bound;

if (!mipsolver.submip) {
printf(
"HighsMipSolverData::performRestart() After mipsolver.modelstatus_ "
"!= HighsModelStatus::kNotset\n");
// assert(333 == 999);
}
// There must be a gap change, since it's now zero, so always call
// updatePrimaDualIntegral (unless solving a sub-MIP)
//
// Surely there must be a lower bound change
bool bound_change = lower_bound != prev_lower_bound;
assert(bound_change);
if (!mipsolver.submip && bound_change)
updatePrimaDualIntegral(prev_lower_bound, lower_bound, upper_bound,
upper_bound);

if (mipsolver.solution_objective_ != kHighsInf &&
mipsolver.modelstatus_ == HighsModelStatus::kInfeasible)
mipsolver.modelstatus_ = HighsModelStatus::kOptimal;
Expand Down Expand Up @@ -1689,7 +1697,6 @@ void HighsMipSolverData::evaluateRootNode() {
fixingRate);
tg.taskWait();
performRestart();
printf("HighsMipSolverData::evaluateRootNode() return 0 from performRestart();\n");
++numRestartsRoot;
if (mipsolver.modelstatus_ == HighsModelStatus::kNotset) goto restart;

Expand Down Expand Up @@ -1921,7 +1928,6 @@ void HighsMipSolverData::evaluateRootNode() {
if (stall != -1) maxSepaRounds = std::min(maxSepaRounds, nseparounds);
tg.taskWait();
performRestart();
printf("HighsMipSolverData::evaluateRootNode() return 1 from performRestart() bounds are [%g, %g]\n", lower_bound, upper_bound);
++numRestartsRoot;
if (mipsolver.modelstatus_ == HighsModelStatus::kNotset) goto restart;

Expand Down Expand Up @@ -2183,11 +2189,12 @@ double possInfRelDiff(const double v0, const double v1, const double den) {
return rel_diff;
}

void HighsMipSolverData::updatePrimaDualIntegral(
const double from_lower_bound, const double to_lower_bound,
const double from_upper_bound, const double to_upper_bound,
const bool check_bound_change) {
//
void HighsMipSolverData::updatePrimaDualIntegral(const double from_lower_bound,
const double to_lower_bound,
const double from_upper_bound,
const double to_upper_bound,
const bool check_bound_change,
const bool check_prev_data) {
// Parameters to updatePrimaDualIntegral are lower and upper bounds
// before/after a change
//
Expand All @@ -2206,12 +2213,12 @@ void HighsMipSolverData::updatePrimaDualIntegral(
// the previous call. Used as a check that the value of lb
// computed from from_lower_bound in this call is equal - to
// within bound_change_tolerance. If not true, then a change in lb
// has been missed. Only for checking/debugging
//
// * prev_ub: Ditto for upper_bound. Only for checking/debugging
//
// * prev_gap: Ditto for gap. Only for checking/debugging
//
// has been missed. Only for checking/debugging
//
// * prev_ub: Ditto for upper_bound. Only for checking/debugging
//
// * prev_gap: Ditto for gap. Only for checking/debugging
//
// * prev_time: Used to determine the time spent at the previous gap

double from_lb;
Expand All @@ -2238,8 +2245,8 @@ void HighsMipSolverData::updatePrimaDualIntegral(
if (!bound_change) {
// printf(
// "HighsMipSolverData::updatePrimaDualIntegral\n"
// "Expected original lower/upper bound change not observed:\n"
// "lower = [%16.10g, %16.10g] change = %16.10g\n"
// "Expected original lower/upper bound change not
// observed:\n" "lower = [%16.10g, %16.10g] change = %16.10g\n"
// "upper = [%16.10g, %16.10g] change = %16.10g\n",
// from_lb, to_lb, lb_difference, from_ub, to_ub, ub_difference);
if (from_lower_bound == to_lower_bound &&
Expand All @@ -2262,8 +2269,8 @@ void HighsMipSolverData::updatePrimaDualIntegral(
if (bound_change) {
// printf(
// "HighsMipSolverData::updatePrimaDualIntegral\n"
// "Expected original lower/upper bound no-change not observed:\\"
// "lower = [%16.10g, %16.10g] change = %16.10g\n"
// "Expected original lower/upper bound no-change not
// observed:\\" "lower = [%16.10g, %16.10g] change = %16.10g\n"
// "upper = [%16.10g, %16.10g] change = %16.10g\n",
// from_lb, to_lb, lb_difference, from_ub, to_ub, ub_difference);
if (from_lower_bound != to_lower_bound ||
Expand All @@ -2284,46 +2291,52 @@ void HighsMipSolverData::updatePrimaDualIntegral(
}
}
if (pdi.value > -kHighsInf) {
// updatePrimaDualIntegral has been called previously, so can test
// housekeeping, even if gap is still inf
// updatePrimaDualIntegral has been called previously, so can
// usually test housekeeping, even if gap is still inf
//
// These housekeeping tests check that the previous saved
// lower/upper bounds and gap are very close to the "from"
// lower/upper bounds and corresponding gap. They are usually
// identical, but rounding error can occur when passing through
// reset, when the old/new offsets are added/subtracted from the
// bounds due to changes in offset during presolve.
const double lb_inconsistency =
possInfRelDiff(from_lb, pdi.prev_lb, pdi.prev_lb);
const bool lb_consistent = lb_inconsistency < 1e-12;
if (!lb_consistent) {
printf(
"HighsMipSolverData::updatePrimaDualIntegral (prev_lb) from_lb of "
"(%16.10g) %16.10g: relative inconsistency of %16.10g\n",
pdi.prev_lb, from_lb, lb_inconsistency);
}
const double ub_inconsistency =
possInfRelDiff(from_ub, pdi.prev_ub, pdi.prev_ub);
const bool ub_consistent = ub_inconsistency < 1e-12;
if (!ub_consistent) {
printf(
"HighsMipSolverData::updatePrimaDualIntegral (prev_ub) from_ub of "
"(%16.10g) %16.10g: relative inconsistency of %16.10g\n",
pdi.prev_ub, from_ub, ub_inconsistency);
}
const double gap_inconsistency =
possInfRelDiff(from_gap, pdi.prev_gap, 1.0);
const bool gap_consistent = gap_inconsistency < 1e-12;
if (!gap_consistent) {
printf(
"HighsMipSolverData::updatePrimaDualIntegral (prev_gap) from_gap "
"of (%16.10g) %16.10g: relative inconsistency of %16.10g\n",
pdi.prev_gap, from_gap, gap_inconsistency);
// The one case where the checking can't be done comes after restart, where
// the
//
if (check_prev_data) {
// These housekeeping tests check that the previous saved
// lower/upper bounds and gap are very close to the "from"
// lower/upper bounds and corresponding gap. They are usually
// identical, but rounding error can occur when passing through
// reset, when the old/new offsets are added/subtracted from the
// bounds due to changes in offset during presolve.
const double lb_inconsistency =
possInfRelDiff(from_lb, pdi.prev_lb, pdi.prev_lb);
const bool lb_consistent = lb_inconsistency < 1e-12;
if (!lb_consistent) {
printf(
"HighsMipSolverData::updatePrimaDualIntegral (prev_lb) from_lb "
"of "
"(%16.10g) %16.10g: relative inconsistency of %16.10g\n",
pdi.prev_lb, from_lb, lb_inconsistency);
}
const double ub_inconsistency =
possInfRelDiff(from_ub, pdi.prev_ub, pdi.prev_ub);
const bool ub_consistent = ub_inconsistency < 1e-12;
if (!ub_consistent) {
printf(
"HighsMipSolverData::updatePrimaDualIntegral (prev_ub) from_ub "
"of "
"(%16.10g) %16.10g: relative inconsistency of %16.10g\n",
pdi.prev_ub, from_ub, ub_inconsistency);
}
const double gap_inconsistency =
possInfRelDiff(from_gap, pdi.prev_gap, 1.0);
const bool gap_consistent = gap_inconsistency < 1e-12;
if (!gap_consistent) {
printf(
"HighsMipSolverData::updatePrimaDualIntegral (prev_gap) from_gap "
"of (%16.10g) %16.10g: relative inconsistency of %16.10g\n",
pdi.prev_gap, from_gap, gap_inconsistency);
}
assert(lb_consistent);
assert(ub_consistent);
assert(gap_consistent);
}
assert(lb_consistent);
assert(ub_consistent);
assert(gap_consistent);

if (to_gap < kHighsInf) {
double time = mipsolver.timer_.read(mipsolver.timer_.solve_clock);
if (from_gap < kHighsInf) {
Expand All @@ -2344,4 +2357,3 @@ void HighsMipSolverData::updatePrimaDualIntegral(
}

void HighsPrimaDualIntegral::initialise() { this->value = -kHighsInf; }

3 changes: 2 additions & 1 deletion src/mip/HighsMipSolverData.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@ struct HighsMipSolverData {
const double to_lower_bound,
const double from_upper_bound,
const double to_upper_bound,
const bool check_bound_change = true);
const bool check_bound_change = true,
const bool check_prev_data = true);
double gapFromBounds(const double use_lower_bound,
const double use_upper_bound, double& lb, double& ub);

Expand Down

0 comments on commit 4003eb2

Please sign in to comment.