Skip to content

Commit b58075b

Browse files
authored
Merge pull request #2450 from ERGO-Code/fix-2419
Fix 2419
2 parents 9d021c8 + 8f37327 commit b58075b

File tree

4 files changed

+37
-7
lines changed

4 files changed

+37
-7
lines changed

FEATURES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@ Forcing column reduction now checks the bound on the column dual rather than whe
66

77
Now handling correctly the case where an infeasible MIP has a feasible relaxation, so no ray is computed fixing [#2415](https://github.com/ERGO-Code/HiGHS/issues/2415)
88

9+
Fixed minor bug exposed by [#2441](https://github.com/ERGO-Code/HiGHS/issues/2441) in Highs::setSolution() for a sparse user solution when the moidel is empty, and only clearing the dual data before solving with modified objective in Highs::multiobjectiveSolve() so that user-supplied solution is not cleared.
10+
911

highs/Highs.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ class Highs {
9090
*/
9191
HighsStatus clearSolver();
9292

93+
/**
94+
* @brief Clear all dual data associated with the model
95+
*/
96+
HighsStatus clearSolverDualData();
97+
9398
/**
9499
* Methods for model input
95100
*/
@@ -1542,6 +1547,12 @@ class Highs {
15421547
// invalidateRanging(), invalidateInfo(), invalidateEkk() and
15431548
// invalidateIis()
15441549
void invalidateSolverData();
1550+
1551+
// Invalidates all solver dual data in Highs class members by calling
1552+
// invalidateModelStatus(), invalidateRanging(), and invalidateInfo()
1553+
//
1554+
// Used when only the objective changes
1555+
void invalidateSolverDualData();
15451556
//
15461557
// Invalidates the model status, solution_ and info_
15471558
void invalidateModelStatusSolutionAndInfo();

highs/lp_data/Highs.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,13 @@ HighsStatus Highs::clearSolver() {
6767
return returnFromHighs(return_status);
6868
}
6969

70+
HighsStatus Highs::clearSolverDualData() {
71+
HighsStatus return_status = HighsStatus::kOk;
72+
clearDerivedModelProperties();
73+
invalidateSolverDualData();
74+
return returnFromHighs(return_status);
75+
}
76+
7077
HighsStatus Highs::setOptionValue(const std::string& option, const bool value) {
7178
if (setLocalOptionValue(options_.log_options, option, options_.records,
7279
value) == OptionStatus::kOk)
@@ -2261,16 +2268,17 @@ HighsStatus Highs::setSolution(const HighsSolution& solution) {
22612268
HighsStatus Highs::setSolution(const HighsInt num_entries,
22622269
const HighsInt* index, const double* value) {
22632270
HighsStatus return_status = HighsStatus::kOk;
2271+
if (model_.lp_.num_col_ == 0) return return_status;
22642272
// Warn about duplicates in index
22652273
HighsInt num_duplicates = 0;
22662274
std::vector<bool> is_set;
22672275
is_set.assign(model_.lp_.num_col_, false);
22682276
for (HighsInt iX = 0; iX < num_entries; iX++) {
22692277
HighsInt iCol = index[iX];
2270-
if (iCol < 0 || iCol > model_.lp_.num_col_) {
2278+
if (iCol < 0 || iCol >= model_.lp_.num_col_) {
22712279
highsLogUser(options_.log_options, HighsLogType::kError,
22722280
"setSolution: User solution index %d has value %d out of "
2273-
"range [0, %d)",
2281+
"range [0, %d)\n",
22742282
int(iX), int(iCol), int(model_.lp_.num_col_));
22752283
return HighsStatus::kError;
22762284
} else if (value[iX] < model_.lp_.col_lower_[iCol] -
@@ -2280,7 +2288,7 @@ HighsStatus Highs::setSolution(const HighsInt num_entries,
22802288
value[iX]) {
22812289
highsLogUser(options_.log_options, HighsLogType::kError,
22822290
"setSolution: User solution value %d of %g is infeasible "
2283-
"for bounds [%g, %g]",
2291+
"for bounds [%g, %g]\n",
22842292
int(iX), value[iX], model_.lp_.col_lower_[iCol],
22852293
model_.lp_.col_upper_[iCol]);
22862294
return HighsStatus::kError;
@@ -3634,15 +3642,19 @@ void Highs::clearStandardFormLp() {
36343642
}
36353643

36363644
void Highs::invalidateSolverData() {
3637-
invalidateModelStatus();
3645+
invalidateSolverDualData();
36383646
invalidateSolution();
36393647
invalidateBasis();
3640-
invalidateRanging();
3641-
invalidateInfo();
36423648
invalidateEkk();
36433649
invalidateIis();
36443650
}
36453651

3652+
void Highs::invalidateSolverDualData() {
3653+
invalidateModelStatus();
3654+
invalidateRanging();
3655+
invalidateInfo();
3656+
}
3657+
36463658
void Highs::invalidateModelStatusSolutionAndInfo() {
36473659
invalidateModelStatus();
36483660
invalidateSolution();

highs/lp_data/HighsInterface.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3948,7 +3948,12 @@ HighsStatus Highs::multiobjectiveSolve() {
39483948
highsLogUser(options_.log_options, HighsLogType::kInfo, "%s",
39493949
multi_objective_log->str().c_str());
39503950
}
3951-
this->clearSolver();
3951+
// Solving with a different objective, but don't call
3952+
// this->clearSolver() since this loses the current solution - that
3953+
// may have been provided by the user (#2419). Just clear the dual
3954+
// data.
3955+
//
3956+
this->clearSolverDualData();
39523957
if (this->options_.blend_multi_objectives) {
39533958
// Objectives are blended by weight and minimized
39543959
lp.offset_ = 0;

0 commit comments

Comments
 (0)