Skip to content

Commit 21f9964

Browse files
committed
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into rawLoops2
2 parents f7f3824 + b58075b commit 21f9964

14 files changed

+79
-43
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;

highs/mip/HighsDomain.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,7 +1243,7 @@ void HighsDomain::ObjectivePropagation::propagate() {
12431243
void HighsDomain::computeMinActivity(HighsInt start, HighsInt end,
12441244
const HighsInt* ARindex,
12451245
const double* ARvalue, HighsInt& ninfmin,
1246-
HighsCDouble& activitymin) {
1246+
HighsCDouble& activitymin) const {
12471247
if (infeasible_) {
12481248
activitymin = 0.0;
12491249
ninfmin = 0;
@@ -1288,7 +1288,7 @@ void HighsDomain::computeMinActivity(HighsInt start, HighsInt end,
12881288
void HighsDomain::computeMaxActivity(HighsInt start, HighsInt end,
12891289
const HighsInt* ARindex,
12901290
const double* ARvalue, HighsInt& ninfmax,
1291-
HighsCDouble& activitymax) {
1291+
HighsCDouble& activitymax) const {
12921292
if (infeasible_) {
12931293
activitymax = 0.0;
12941294
ninfmax = 0;
@@ -1398,7 +1398,7 @@ HighsInt HighsDomain::propagateRowUpper(const HighsInt* Rindex,
13981398
double Rupper,
13991399
const HighsCDouble& minactivity,
14001400
HighsInt ninfmin,
1401-
HighsDomainChange* boundchgs) {
1401+
HighsDomainChange* boundchgs) const {
14021402
assert(std::isfinite(double(minactivity)));
14031403
if (ninfmin > 1) return 0;
14041404
HighsInt numchgs = 0;
@@ -1442,7 +1442,7 @@ HighsInt HighsDomain::propagateRowLower(const HighsInt* Rindex,
14421442
double Rlower,
14431443
const HighsCDouble& maxactivity,
14441444
HighsInt ninfmax,
1445-
HighsDomainChange* boundchgs) {
1445+
HighsDomainChange* boundchgs) const {
14461446
assert(std::isfinite(double(maxactivity)));
14471447
if (ninfmax > 1) return 0;
14481448
HighsInt numchgs = 0;
@@ -1481,7 +1481,7 @@ HighsInt HighsDomain::propagateRowLower(const HighsInt* Rindex,
14811481
}
14821482

14831483
void HighsDomain::updateThresholdLbChange(HighsInt col, double newbound,
1484-
double val, double& threshold) {
1484+
double val, double& threshold) const {
14851485
if (newbound != col_upper_[col]) {
14861486
double thresholdNew =
14871487
std::fabs(val) * boundRange(col_upper_[col], newbound,
@@ -1496,7 +1496,7 @@ void HighsDomain::updateThresholdLbChange(HighsInt col, double newbound,
14961496
}
14971497

14981498
void HighsDomain::updateThresholdUbChange(HighsInt col, double newbound,
1499-
double val, double& threshold) {
1499+
double val, double& threshold) const {
15001500
if (newbound != col_lower_[col]) {
15011501
double thresholdNew =
15021502
std::fabs(val) * boundRange(newbound, col_lower_[col],
@@ -3617,9 +3617,11 @@ HighsDomain::ConflictSet::popQueue() {
36173617

36183618
void HighsDomain::ConflictSet::clearQueue() { resolveQueue.clear(); }
36193619

3620-
HighsInt HighsDomain::ConflictSet::queueSize() { return resolveQueue.size(); }
3620+
HighsInt HighsDomain::ConflictSet::queueSize() const {
3621+
return resolveQueue.size();
3622+
}
36213623

3622-
bool HighsDomain::ConflictSet::resolvable(HighsInt domChgPos) {
3624+
bool HighsDomain::ConflictSet::resolvable(HighsInt domChgPos) const {
36233625
assert(domChgPos >= 0);
36243626
assert(domChgPos < (HighsInt)localdom.domchgreason_.size());
36253627
// printf("domchgPos: %d\n", domChgPos);

highs/mip/HighsDomain.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ class HighsDomain {
104104
void pushQueue(std::set<LocalDomChg>::iterator domchgPos);
105105
std::set<LocalDomChg>::iterator popQueue();
106106
void clearQueue();
107-
HighsInt queueSize();
108-
bool resolvable(HighsInt domChgPos);
107+
HighsInt queueSize() const;
108+
bool resolvable(HighsInt domChgPos) const;
109109

110110
HighsInt resolveDepth(std::set<LocalDomChg>& frontier, HighsInt depthLevel,
111111
HighsInt stopSize, HighsInt minResolve = 0,
@@ -317,10 +317,10 @@ class HighsDomain {
317317
void updateActivityUbChange(HighsInt col, double oldbound, double newbound);
318318

319319
void updateThresholdLbChange(HighsInt col, double newbound, double val,
320-
double& threshold);
320+
double& threshold) const;
321321

322322
void updateThresholdUbChange(HighsInt col, double newbound, double val,
323-
double& threshold);
323+
double& threshold) const;
324324

325325
void recomputeCapacityThreshold(HighsInt row);
326326

@@ -407,11 +407,11 @@ class HighsDomain {
407407

408408
void computeMinActivity(HighsInt start, HighsInt end, const HighsInt* ARindex,
409409
const double* ARvalue, HighsInt& ninfmin,
410-
HighsCDouble& activitymin);
410+
HighsCDouble& activitymin) const;
411411

412412
void computeMaxActivity(HighsInt start, HighsInt end, const HighsInt* ARindex,
413413
const double* ARvalue, HighsInt& ninfmax,
414-
HighsCDouble& activitymax);
414+
HighsCDouble& activitymax) const;
415415

416416
double adjustedUb(HighsInt col, HighsCDouble boundVal, bool& accept) const;
417417

@@ -420,12 +420,12 @@ class HighsDomain {
420420
HighsInt propagateRowUpper(const HighsInt* Rindex, const double* Rvalue,
421421
HighsInt Rlen, double Rupper,
422422
const HighsCDouble& minactivity, HighsInt ninfmin,
423-
HighsDomainChange* boundchgs);
423+
HighsDomainChange* boundchgs) const;
424424

425425
HighsInt propagateRowLower(const HighsInt* Rindex, const double* Rvalue,
426426
HighsInt Rlen, double Rlower,
427427
const HighsCDouble& maxactivity, HighsInt ninfmax,
428-
HighsDomainChange* boundchgs);
428+
HighsDomainChange* boundchgs) const;
429429

430430
const std::vector<HighsInt>& getChangedCols() const { return changedcols_; }
431431

highs/mip/HighsLpRelaxation.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1019,7 +1019,7 @@ bool HighsLpRelaxation::checkDualProof() const {
10191019
bool HighsLpRelaxation::computeDualInfProof(const HighsDomain& globaldomain,
10201020
std::vector<HighsInt>& inds,
10211021
std::vector<double>& vals,
1022-
double& rhs) {
1022+
double& rhs) const {
10231023
if (!hasdualproof) return false;
10241024

10251025
assert(std::isfinite(dualproofrhs));

highs/mip/HighsLpRelaxation.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ class HighsLpRelaxation {
329329

330330
bool computeDualInfProof(const HighsDomain& globaldomain,
331331
std::vector<HighsInt>& inds,
332-
std::vector<double>& vals, double& rhs);
332+
std::vector<double>& vals, double& rhs) const;
333333

334334
Status resolveLp(HighsDomain* domain = nullptr);
335335

highs/mip/HighsMipSolver.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -895,10 +895,13 @@ void HighsMipSolver::callbackGetCutPool() const {
895895
callback_->user_callback_data);
896896
}
897897

898-
bool HighsMipSolver::solutionFeasible(
899-
const HighsLp* lp, const std::vector<double>& col_value,
900-
const std::vector<double>* pass_row_value, double& bound_violation,
901-
double& row_violation, double& integrality_violation, HighsCDouble& obj) {
898+
bool HighsMipSolver::solutionFeasible(const HighsLp* lp,
899+
const std::vector<double>& col_value,
900+
const std::vector<double>* pass_row_value,
901+
double& bound_violation,
902+
double& row_violation,
903+
double& integrality_violation,
904+
HighsCDouble& obj) const {
902905
bound_violation = 0;
903906
row_violation = 0;
904907
integrality_violation = 0;

highs/mip/HighsMipSolver.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ class HighsMipSolver {
106106
bool solutionFeasible(const HighsLp* lp, const std::vector<double>& col_value,
107107
const std::vector<double>* pass_row_value,
108108
double& bound_violation, double& row_violation,
109-
double& integrality_violation, HighsCDouble& obj);
109+
double& integrality_violation, HighsCDouble& obj) const;
110110
};
111111

112112
#endif

0 commit comments

Comments
 (0)