Skip to content

Commit d84a6b6

Browse files
committed
Now timing knapsack est/solve and (also) looking for knapsack after presolve; formatted
1 parent 671ff75 commit d84a6b6

File tree

8 files changed

+115
-30
lines changed

8 files changed

+115
-30
lines changed

highs/lp_data/HighsLp.cpp

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -85,18 +85,57 @@ bool HighsLp::equalButForNames(const HighsLp& lp) const {
8585
}
8686

8787
bool HighsLp::equalButForScalingAndNames(const HighsLp& lp) const {
88+
bool equal;
8889
bool equal_vectors = true;
89-
equal_vectors = this->num_col_ == lp.num_col_ && equal_vectors;
90-
equal_vectors = this->num_row_ == lp.num_row_ && equal_vectors;
91-
equal_vectors = this->sense_ == lp.sense_ && equal_vectors;
92-
equal_vectors = this->offset_ == lp.offset_ && equal_vectors;
93-
equal_vectors = this->model_name_ == lp.model_name_ && equal_vectors;
94-
equal_vectors = this->col_cost_ == lp.col_cost_ && equal_vectors;
95-
equal_vectors = this->col_upper_ == lp.col_upper_ && equal_vectors;
96-
equal_vectors = this->col_lower_ == lp.col_lower_ && equal_vectors;
97-
equal_vectors = this->row_upper_ == lp.row_upper_ && equal_vectors;
98-
equal_vectors = this->row_lower_ == lp.row_lower_ && equal_vectors;
90+
equal = this->num_col_ == lp.num_col_;
91+
equal_vectors = equal && equal_vectors;
9992
#ifndef NDEBUG
93+
if (!equal) printf("HighsLp::equalButForNames: unequal col dim\n");
94+
#endif
95+
equal = this->num_row_ == lp.num_row_;
96+
equal_vectors = equal && equal_vectors;
97+
#ifndef NDEBUG
98+
if (!equal) printf("HighsLp::equalButForNames: unequal row dim\n");
99+
#endif
100+
equal = this->sense_ == lp.sense_;
101+
equal_vectors = equal && equal_vectors;
102+
#ifndef NDEBUG
103+
if (!equal) printf("HighsLp::equalButForNames: unequal sense\n");
104+
#endif
105+
equal = this->offset_ == lp.offset_;
106+
equal_vectors = equal && equal_vectors;
107+
#ifndef NDEBUG
108+
if (!equal) printf("HighsLp::equalButForNames: unequal offset\n");
109+
#endif
110+
equal = this->model_name_ == lp.model_name_;
111+
equal_vectors = equal && equal_vectors;
112+
#ifndef NDEBUG
113+
if (!equal) printf("HighsLp::equalButForNames: unequal model name\n");
114+
#endif
115+
equal = this->col_cost_ == lp.col_cost_;
116+
equal_vectors = equal && equal_vectors;
117+
#ifndef NDEBUG
118+
if (!equal) printf("HighsLp::equalButForNames: unequal col cost\n");
119+
#endif
120+
equal = this->col_lower_ == lp.col_lower_;
121+
equal_vectors = equal && equal_vectors;
122+
#ifndef NDEBUG
123+
if (!equal) printf("HighsLp::equalButForNames: unequal col lower\n");
124+
#endif
125+
equal = this->col_upper_ == lp.col_upper_;
126+
equal_vectors = equal && equal_vectors;
127+
#ifndef NDEBUG
128+
if (!equal) printf("HighsLp::equalButForNames: unequal col upper\n");
129+
#endif
130+
equal = this->row_lower_ == lp.row_lower_;
131+
equal_vectors = equal && equal_vectors;
132+
#ifndef NDEBUG
133+
if (!equal) printf("HighsLp::equalButForNames: unequal row lower\n");
134+
#endif
135+
equal = this->row_upper_ == lp.row_upper_;
136+
equal_vectors = equal && equal_vectors;
137+
#ifndef NDEBUG
138+
if (!equal) printf("HighsLp::equalButForNames: unequal row upper\n");
100139
if (!equal_vectors) printf("HighsLp::equalButForNames: Unequal vectors\n");
101140
#endif
102141
const bool equal_matrix = this->a_matrix_ == lp.a_matrix_;

highs/mip/HighsMipSolver.cpp

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,22 +88,31 @@ void HighsMipSolver::run() {
8888
mipdata_->init();
8989
analysis_.mipTimerStop(kMipClockInit);
9090

91-
// Determine whether this is a knapsack problem and, if so, at least
92-
// update the data on knapsack sub-MIPs
93-
HighsInt capacity = 0;
91+
// If this is a knapsack problem, don't do MIP logging in
92+
// cleanupSolve
93+
const bool mip_logging_for_knapsack = false;
94+
95+
// Look for knapsack before presolve
96+
analysis_.mipTimerStart(kMipClockKnapsack);
9497
if (mipdata_->mipIsKnapsack()) {
95-
mipdata_->knapsack_data_.num_problem++;
96-
mipdata_->knapsack_data_.sum_variables += orig_model_->num_col_;
97-
mipdata_->knapsack_data_.sum_capacity += mipdata_->knapsack_capacity_;
9898
// Solve as a knapsack
9999
HighsStatus call_status = mipdata_->heuristics.solveMipKnapsack();
100100
assert(call_status == HighsStatus::kOk);
101-
const bool mip_logging = false;
102-
cleanupSolve(mip_logging);
101+
cleanupSolve(mip_logging_for_knapsack);
102+
analysis_.mipTimerStop(kMipClockKnapsack);
103103
return;
104104
}
105+
analysis_.mipTimerStop(kMipClockKnapsack);
105106

107+
const HighsInt num_col_before_presolve = model_->num_col_;
108+
const HighsInt num_row_before_presolve = model_->num_row_;
106109
analysis_.mipTimerStart(kMipClockRunPresolve);
110+
// Run presolve
111+
//
112+
// Note that, even with presolve=off and presolve_reduction_limit=0,
113+
// reductions can occur. This is because presolve scales the MIP -
114+
// and must do - using HighsPresolve::transformColumn. Note that
115+
// presolve is where a maximization is converted to a minimization.
107116
mipdata_->runPresolve(options_mip_->presolve_reduction_limit);
108117
analysis_.mipTimerStop(kMipClockRunPresolve);
109118
analysis_.mipTimerStop(kMipClockPresolve);
@@ -128,6 +137,21 @@ void HighsMipSolver::run() {
128137
cleanupSolve();
129138
return;
130139
}
140+
// Possibly look for knapsack after presolve
141+
const bool reduced = num_col_before_presolve > model_->num_col_ ||
142+
num_row_before_presolve > model_->num_row_;
143+
if (reduced) {
144+
analysis_.mipTimerStart(kMipClockKnapsack);
145+
if (mipdata_->mipIsKnapsack()) {
146+
// Solve as a knapsack
147+
HighsStatus call_status = mipdata_->heuristics.solveMipKnapsack();
148+
assert(call_status == HighsStatus::kOk);
149+
cleanupSolve(mip_logging_for_knapsack);
150+
analysis_.mipTimerStop(kMipClockKnapsack);
151+
return;
152+
}
153+
analysis_.mipTimerStop(kMipClockKnapsack);
154+
}
131155

132156
analysis_.mipTimerStart(kMipClockSolve);
133157

highs/mip/HighsMipSolverData.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2653,7 +2653,9 @@ void HighsMipSolverData::callbackUserSolution(
26532653
}
26542654
}
26552655

2656-
bool HighsMipSolverData::mipIsKnapsack(const bool logging) {
2656+
bool HighsMipSolverData::mipIsKnapsack(const bool silent) {
2657+
// Silent is to prevent duplicate logging and data collection when
2658+
// using assert(mipIsKnapsack(true));
26572659
const HighsLp& lp = *(mipsolver.model_);
26582660
// Has to have one constraint
26592661
if (lp.num_row_ != 1) return false;
@@ -2671,7 +2673,7 @@ bool HighsMipSolverData::mipIsKnapsack(const bool logging) {
26712673
HighsIntegers::integralScale(lp.a_matrix_.value_, 1e-6, 1e-6);
26722674
if (this->knapsack_integral_scale_ == 0) return false;
26732675
if (this->knapsack_integral_scale_ > 1000000) return false;
2674-
if (logging)
2676+
if (!silent)
26752677
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
26762678
"MIP is a knapsack problem with with scale %d\n",
26772679
int(this->knapsack_integral_scale_));
@@ -2683,6 +2685,11 @@ bool HighsMipSolverData::mipIsKnapsack(const bool logging) {
26832685
const double capacity_margin = 1e-6;
26842686
this->knapsack_capacity_ = std::floor(double_capacity + capacity_margin);
26852687
// Problem is knapsack!
2688+
if (!silent) {
2689+
this->knapsack_data_.num_problem++;
2690+
this->knapsack_data_.sum_variables += lp.num_col_;
2691+
this->knapsack_data_.sum_capacity += this->knapsack_capacity_;
2692+
}
26862693
return true;
26872694
}
26882695

highs/mip/HighsMipSolverData.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ struct HighsMipSolverData {
313313
void callbackUserSolution(
314314
const double mipsolver_objective_value,
315315
const userMipSolutionCallbackOrigin user_solution_callback_origin);
316-
bool mipIsKnapsack(const bool logging = true);
316+
bool mipIsKnapsack(const bool silent = false);
317317
};
318318

319319
#endif

highs/mip/HighsPrimalHeuristics.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1786,7 +1786,8 @@ HighsStatus HighsPrimalHeuristics::solveMipKnapsackReturn(
17861786
HighsStatus HighsPrimalHeuristics::solveMipKnapsack() {
17871787
const HighsLp& lp = *(mipsolver.model_);
17881788
const HighsLogOptions& log_options = mipsolver.options_mip_->log_options;
1789-
assert(mipsolver.mipdata_->mipIsKnapsack(false));
1789+
// Check silently that this really is a knapsack
1790+
assert(mipsolver.mipdata_->mipIsKnapsack(true));
17901791

17911792
const bool upper = lp.row_upper_[0] < kHighsInf;
17921793
const HighsInt constraint_sign = upper ? 1 : -1;

highs/mip/MipTimer.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ enum iClockMip {
1919
kMipClockPostsolve,
2020
// Level 1
2121
kMipClockInit,
22+
kMipClockKnapsack,
2223
kMipClockRunPresolve,
2324
kMipClockRunSetup,
2425
kMipClockFeasibilityJump,
@@ -134,6 +135,7 @@ class MipTimer {
134135

135136
// Level 1 - Should correspond to kMipClockTotal
136137
clock[kMipClockInit] = timer_pointer->clock_def("Initialise");
138+
clock[kMipClockKnapsack] = timer_pointer->clock_def("Knapsack test+solve");
137139
clock[kMipClockRunPresolve] = timer_pointer->clock_def("Run presolve");
138140
clock[kMipClockRunSetup] = timer_pointer->clock_def("Run setup");
139141
clock[kMipClockFeasibilityJump] =
@@ -321,6 +323,7 @@ class MipTimer {
321323

322324
void reportMipLevel1Clock(const HighsTimerClock& mip_timer_clock) {
323325
const std::vector<HighsInt> mip_clock_list{kMipClockInit,
326+
kMipClockKnapsack,
324327
kMipClockRunPresolve,
325328
kMipClockRunSetup,
326329
kMipClockFeasibilityJump,
@@ -330,7 +333,7 @@ class MipTimer {
330333
kMipClockSearch,
331334
kMipClockPostsolve};
332335
reportMipClockList("MipLevl1", mip_clock_list, mip_timer_clock,
333-
kMipClockTotal, tolerance_percent_report);
336+
kMipClockTotal); //, tolerance_percent_report);
334337
};
335338

336339
void reportMipSolveLpClock(const HighsTimerClock& mip_timer_clock) {
@@ -441,8 +444,9 @@ class MipTimer {
441444
const HighsTimerClock& mip_timer_clock, const bool header,
442445
const bool end_line) {
443446
const std::vector<HighsInt> mip_clock_list{
444-
kMipClockRunPresolve, kMipClockEvaluateRootNode,
445-
kMipClockDivePrimalHeuristics, kMipClockTheDive, kMipClockNodeSearch};
447+
kMipClockKnapsack, kMipClockRunPresolve,
448+
kMipClockEvaluateRootNode, kMipClockDivePrimalHeuristics,
449+
kMipClockTheDive, kMipClockNodeSearch};
446450
csvMipClockList("csvMIP", model_name, mip_clock_list, mip_timer_clock,
447451
kMipClockTotal, header, end_line);
448452
};

highs/presolve/HPresolve.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4339,7 +4339,7 @@ HPresolve::Result HPresolve::presolve(HighsPostsolveStack& postsolve_stack) {
43394339
analysis_.setup(this->model, this->options, this->numDeletedRows,
43404340
this->numDeletedCols);
43414341

4342-
if (options->presolve != kHighsOffString) {
4342+
if (options->presolve != kHighsOffString && reductionLimit > 0) {
43434343
if (mipsolver) mipsolver->mipdata_->cliquetable.setPresolveFlag(true);
43444344
if (!mipsolver || mipsolver->mipdata_->numRestarts == 0)
43454345
highsLogUser(options->log_options, HighsLogType::kInfo,
@@ -4529,10 +4529,18 @@ HPresolve::Result HPresolve::presolve(HighsPostsolveStack& postsolve_stack) {
45294529
report();
45304530
} else {
45314531
highsLogUser(options->log_options, HighsLogType::kInfo,
4532-
"\nPresolve is switched off\n");
4532+
"\nPresolve: Model reduction is switched off\n");
45334533
}
45344534

4535+
this->num_true_reductions_ = postsolve_stack.numReductions();
45354536
if (mipsolver != nullptr) scaleMIP(postsolve_stack);
4537+
const size_t num_scaling_reductions =
4538+
postsolve_stack.numReductions() - this->num_true_reductions_;
4539+
if (num_scaling_reductions)
4540+
highsLogUser(options->log_options, HighsLogType::kInfo,
4541+
"\nPresolve: MIP scaling requires %" PRId64
4542+
" reduction operation%s\n",
4543+
num_scaling_reductions, num_scaling_reductions > 1 ? "s" : "");
45364544

45374545
// analysePresolveRuleLog() should return true - no errors
45384546
assert(analysis_.analysePresolveRuleLog());
@@ -4680,11 +4688,12 @@ HighsModelStatus HPresolve::run(HighsPostsolveStack& postsolve_stack) {
46804688
if (options->presolve != kHighsOffString &&
46814689
reductionLimit < kHighsSize_tInf) {
46824690
highsLogUser(options->log_options, HighsLogType::kInfo,
4683-
"Presolve performed %" PRId64 " of %" PRId64
4684-
" permitted reductions\n",
4685-
postsolve_stack.numReductions(), reductionLimit);
4691+
"\nPresolve: Performed %" PRId64 " of %" PRId64
4692+
" permitted true reductions\n",
4693+
this->num_true_reductions_, reductionLimit);
46864694
}
46874695
};
4696+
this->num_true_reductions_ = 0;
46884697
switch (presolve(postsolve_stack)) {
46894698
case Result::kStopped:
46904699
case Result::kOk:

highs/presolve/HPresolve.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ class HPresolve {
132132
HighsInt oldNumCol;
133133
HighsInt oldNumRow;
134134
bool probingEarlyAbort;
135+
int64_t num_true_reductions_;
135136

136137
enum class Result {
137138
kOk,

0 commit comments

Comments
 (0)