Skip to content

Commit

Permalink
Merge pull request #1844 from ERGO-Code/fix-1808
Browse files Browse the repository at this point in the history
Added mip_max_start_nodes` to avoid excessive cost when a MIP is solved to complete a partial solution.
  • Loading branch information
jajhall authored Jul 15, 2024
2 parents 08646bc + 49f320a commit b73d4e8
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 12 deletions.
3 changes: 2 additions & 1 deletion FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Added `int64_t mip_total_lp_iterations` to `HighsCallbackDataOut` and modified a

Introduced `const double kHighsUndefined` as value of undefined values in a user solution. It's equal to `kHighsInf`

Added `Highs::setSolution(const HighsInt num_entries, const HighsInt* index, const double* value);` to allow a sparse primal solution to be defined.
Added `Highs::setSolution(const HighsInt num_entries, const HighsInt* index, const double* value);` to allow a sparse primal solution to be defined. When a MIP is solved to do this, the value of (new) option `mip_max_start_nodes` is used for `mip_max_nodes` to avoid excessive cost



24 changes: 16 additions & 8 deletions src/lp_data/Highs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3465,6 +3465,8 @@ HighsStatus Highs::completeSolutionFromDiscreteAssignment() {
const HighsInt num_continuous_variable = lp.num_col_ - num_discrete_variable;
assert(num_continuous_variable >= 0);
bool call_run = true;
const bool few_fixed_discrete_variables =
10 * num_fixed_discrete_variable < num_discrete_variable;
if (num_unfixed_discrete_variable == 0) {
// Solution is integer valued
if (num_continuous_variable == 0) {
Expand All @@ -3484,14 +3486,14 @@ HighsStatus Highs::completeSolutionFromDiscreteAssignment() {
}
} else {
// There are unfixed discrete variables
if (10 * num_fixed_discrete_variable < num_discrete_variable) {
// Too few discrete variables are fixed
highsLogUser(options_.log_options, HighsLogType::kInfo,
"User-supplied values fix only %d / %d discrete variables, "
"so not attempting to complete a feasible solution\n",
int(num_fixed_discrete_variable),
int(num_discrete_variable));
call_run = false;
if (few_fixed_discrete_variables) {
// Too few discrete variables are fixed so warn, but still
// attempt to complete a feasible solution
highsLogUser(
options_.log_options, HighsLogType::kWarning,
"User-supplied values fix only %d / %d discrete variables, "
"so attempt to complete a feasible solution may be expensive\n",
int(num_fixed_discrete_variable), int(num_discrete_variable));
} else {
highsLogUser(options_.log_options, HighsLogType::kInfo,
"Attempting to find feasible solution "
Expand All @@ -3508,9 +3510,15 @@ HighsStatus Highs::completeSolutionFromDiscreteAssignment() {
// feasible - or it's not worth using the user solution
solution_.clear();
if (call_run) {
// Solve the model, using mip_max_start_nodes for
// mip_max_nodes...
const HighsInt mip_max_nodes = options_.mip_max_nodes;
options_.mip_max_nodes = options_.mip_max_start_nodes;
// Solve the model
basis_.clear();
return_status = this->run();
// ... remembering to recover the original value of mip_max_nodes
options_.mip_max_nodes = mip_max_nodes;
}
// Recover the column bounds and integrality
lp.col_lower_ = save_col_lower;
Expand Down
11 changes: 10 additions & 1 deletion src/lp_data/HighsOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ struct HighsOptionsStruct {
bool mip_allow_restart;
HighsInt mip_max_nodes;
HighsInt mip_max_stall_nodes;
HighsInt mip_max_start_nodes;
HighsInt mip_max_leaves;
HighsInt mip_max_improving_sols;
HighsInt mip_lp_age_limit;
Expand Down Expand Up @@ -527,6 +528,7 @@ struct HighsOptionsStruct {
mip_allow_restart(false),
mip_max_nodes(0),
mip_max_stall_nodes(0),
mip_max_start_nodes(0),
mip_max_leaves(0),
mip_max_improving_sols(0),
mip_lp_age_limit(0),
Expand Down Expand Up @@ -916,6 +918,13 @@ class HighsOptions : public HighsOptionsStruct {
"MIP solver max number of nodes where estimate is above cutoff bound",
advanced, &mip_max_stall_nodes, 0, kHighsIInf, kHighsIInf);
records.push_back(record_int);

record_int = new OptionRecordInt(
"mip_max_start_nodes",
"MIP solver max number of nodes when completing a partial MIP start",
advanced, &mip_max_start_nodes, 0, 500, kHighsIInf);
records.push_back(record_int);

#ifdef HIGHS_DEBUGSOL
record_string = new OptionRecordString(
"mip_debug_solution_file",
Expand Down Expand Up @@ -944,7 +953,7 @@ class HighsOptions : public HighsOptionsStruct {
records.push_back(record_string);

record_int = new OptionRecordInt(
"mip_max_leaves", "MIP solver max number of leave nodes", advanced,
"mip_max_leaves", "MIP solver max number of leaf nodes", advanced,
&mip_max_leaves, 0, kHighsIInf, kHighsIInf);
records.push_back(record_int);

Expand Down
4 changes: 2 additions & 2 deletions src/presolve/HighsSymmetry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1078,7 +1078,7 @@ bool HighsSymmetryDetection::distinguishVertex(HighsInt targetCell) {

void HighsSymmetryDetection::backtrack(HighsInt backtrackStackNewEnd,
HighsInt backtrackStackEnd) {
// we assume that we always backtrack from a leave node, i.e. a discrete
// we assume that we always backtrack from a leaf node, i.e. a discrete
// partition therefore we do not need to remember the values of the hash
// contributions as it is the indentity for each position and all new cells
// are on the cell creation stack.
Expand Down Expand Up @@ -1805,7 +1805,7 @@ void HighsSymmetryDetection::run(HighsSymmetries& symmetries) {
// than the current best leave, because its prefix length is smaller
// than the best leaves and it would have been already pruned if
// it's certificate value was larger unless it is equal to the first
// leave nodes certificate value which is caught by the first case
// leaf nodes certificate value which is caught by the first case
// of the if condition. Hence, having a lexicographically smaller
// certificate value than the best leave is the only way to get
// here.
Expand Down

0 comments on commit b73d4e8

Please sign in to comment.