Skip to content

Commit 0bdaf58

Browse files
committed
Now handling user scaling in Highs::run
1 parent 2a2f242 commit 0bdaf58

File tree

6 files changed

+82
-55
lines changed

6 files changed

+82
-55
lines changed

highs/Highs.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1705,7 +1705,11 @@ class Highs {
17051705

17061706
HighsStatus handleInfCost();
17071707
void restoreInfCost(HighsStatus& return_status);
1708-
HighsStatus optionChangeAction();
1708+
// Retain trivial optionChangeAction() in case it's useful later
1709+
HighsStatus optionChangeAction() const { return HighsStatus::kOk; };
1710+
1711+
HighsStatus userScaleModel(HighsUserScaleData& data);
1712+
HighsStatus userScaleSolution(HighsUserScaleData& data, bool update_kkt = false);
17091713
HighsStatus computeIllConditioning(HighsIllConditioning& ill_conditioning,
17101714
const bool constraint,
17111715
const HighsInt method,

highs/lp_data/Highs.cpp

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -941,9 +941,23 @@ HighsStatus Highs::run() {
941941

942942
if (!options_.use_warm_start) this->clearSolver();
943943
this->reportModelStats();
944-
HighsInt num_linear_objective = this->multi_linear_objective_.size();
945-
if (num_linear_objective == 0) {
946-
HighsStatus status = this->optimizeModel();
944+
945+
// Possibly apply user-defined scaling to the incumbent model and solution
946+
HighsUserScaleData user_scale_data;
947+
initialiseUserScaleData(this->options_, user_scale_data);
948+
const bool user_scaling =
949+
user_scale_data.user_cost_scale ||
950+
user_scale_data.user_bound_scale;
951+
if (user_scaling) {
952+
if (this->userScaleModel(user_scale_data) == HighsStatus::kError) return HighsStatus::kError;
953+
this->userScaleSolution(user_scale_data);
954+
// Zero the user scale values to prevent further scaling
955+
this->options_.user_cost_scale = 0;
956+
this->options_.user_bound_scale = 0;
957+
}
958+
HighsStatus status;
959+
if (!this->multi_linear_objective_.size()) {
960+
status = this->optimizeModel();
947961
if (options_had_highs_files) {
948962
// This call to Highs::run() had HiGHS files in options, so
949963
// recover HiGHS files to options_
@@ -957,9 +971,29 @@ HighsStatus Highs::run() {
957971
if (this->options_.write_basis_file != "")
958972
status = this->writeBasis(this->options_.write_basis_file);
959973
}
960-
return status;
974+
} else {
975+
status = this->multiobjectiveSolve();
961976
}
962-
return this->multiobjectiveSolve();
977+
if (user_scaling) {
978+
// Unscale the incumbent model and solution
979+
//
980+
// Flip the scaling sign
981+
user_scale_data.user_cost_scale *= -1;
982+
user_scale_data.user_bound_scale *= -1;
983+
HighsStatus unscale_status = this->userScaleModel(user_scale_data);
984+
if (unscale_status == HighsStatus::kError) {
985+
highsLogUser(this->options_.log_options, HighsLogType::kError,
986+
"Unexpected error removing user scaling from the incumbent model\n");
987+
assert(unscale_status != HighsStatus::kError);
988+
}
989+
const bool update_kkt = true;
990+
this->userScaleSolution(user_scale_data, update_kkt);
991+
// Restore the user scale values, remembering that they've been
992+
// negated to undo user scaling
993+
this->options_.user_cost_scale = -user_scale_data.user_cost_scale;
994+
this->options_.user_bound_scale = -user_scale_data.user_bound_scale;
995+
}
996+
return status;
963997
}
964998

965999
// Checks the options calls presolve and postsolve if needed. Solvers are called

highs/lp_data/HighsInterface.cpp

Lines changed: 37 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2984,41 +2984,45 @@ void Highs::restoreInfCost(HighsStatus& return_status) {
29842984
}
29852985
}
29862986

2987-
// Update model status, data and solution with respect to non-trivial
2988-
// user bound/cost scaling
2989-
HighsStatus Highs::optionChangeAction() {
2990-
/*
2991-
HighsModel& model = this->model_;
2992-
HighsLp& lp = model.lp_;
2993-
HighsInfo& info = this->info_;
2994-
HighsOptions& options = this->options_;
2995-
HighsInt dl_user_cost_scale = options.user_cost_scale - lp.user_cost_scale_;
2996-
HighsInt dl_user_bound_scale =
2997-
options.user_bound_scale - lp.user_bound_scale_;
2998-
2999-
if (dl_user_cost_scale || dl_user_bound_scale) {
3000-
HighsUserScaleData user_scale_data;
3001-
initialiseUserScaleData(lp, options_, user_scale_data);
3002-
user_scale_data.user_cost_scale = dl_user_cost_scale;
3003-
user_scale_data.user_bound_scale = dl_user_bound_scale;
3004-
HighsStatus return_status = userScaleModel(model, user_scale_data, options.log_options);
3005-
if (return_status == HighsStatus::kError) {
3006-
options.user_cost_scale = lp.user_cost_scale_;
3007-
options.user_bound_scale = lp.user_bound_scale_;
3008-
highsLogUser(
3009-
options_.log_options, HighsLogType::kError,
3010-
"New user cost/bound scaling yields excessive costs/bounds: "
3011-
"reverting user cost scaling to %d, and user bound scaling to %d\n",
3012-
int(lp.user_cost_scale_), int(lp.user_bound_scale_));
3013-
return HighsStatus::kError;
2987+
HighsStatus Highs::userScaleModel(HighsUserScaleData& data) {
2988+
userScaleLp(this->model_.lp_, data, false);
2989+
userScaleHessian(this->model_.hessian_, data, false);
2990+
HighsStatus return_status = userScaleStatus(this->options_.log_options, data);
2991+
if (return_status == HighsStatus::kError) return HighsStatus::kError;
2992+
userScaleLp(this->model_.lp_, data);
2993+
userScaleHessian(this->model_.hessian_, data);
2994+
return return_status;
2995+
}
2996+
2997+
HighsStatus Highs::userScaleSolution(HighsUserScaleData& data, bool update_kkt) {
2998+
HighsStatus return_status = HighsStatus::kOk;
2999+
if (!data.user_cost_scale && !data.user_bound_scale) return HighsStatus::kOk;
3000+
double cost_scale_value = std::pow(2, data.user_cost_scale);
3001+
double bound_scale_value = std::pow(2, data.user_bound_scale);
3002+
const HighsLp& lp = this->model_.lp_;
3003+
const bool has_integrality = lp.integrality_.size();
3004+
if (info_.primal_solution_status != kSolutionStatusNone) {
3005+
if (data.user_bound_scale) {
3006+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
3007+
if (has_integrality && lp.integrality_[iCol] != HighsVarType::kContinuous) continue;
3008+
this->solution_.col_value[iCol] *= bound_scale_value;
3009+
}
3010+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++)
3011+
this->solution_.row_value[iRow] *= bound_scale_value;
30143012
}
3015-
this->invalidateModelStatusSolutionAndInfo();
3016-
this->invalidateSolverData();
3017-
lp.user_cost_scale_ = options.user_cost_scale;
3018-
lp.user_bound_scale_ = options.user_bound_scale;
30193013
}
3020-
*/
3021-
return HighsStatus::kOk;
3014+
if (info_.dual_solution_status != kSolutionStatusNone) {
3015+
if (data.user_cost_scale) {
3016+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++)
3017+
this->solution_.col_dual[iCol] *= cost_scale_value;
3018+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++)
3019+
this->solution_.row_dual[iRow] *= cost_scale_value;
3020+
}
3021+
}
3022+
if (!update_kkt) return return_status;
3023+
info_.objective_function_value *= (bound_scale_value*cost_scale_value);
3024+
getKktFailures(options_, model_, solution_, basis_, info_);
3025+
return return_status;
30223026
}
30233027

30243028
void HighsIllConditioning::clear() { this->record.clear(); }

highs/lp_data/HighsLpUtils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,6 @@ void getSubVectorsTranspose(const HighsIndexCollection& index_collection,
323323
HighsInt* sub_matrix_index,
324324
double* sub_matrix_value);
325325

326-
void initialiseUserScaleData(const HighsLp& lp, const HighsOptions& options,
326+
void initialiseUserScaleData(const HighsOptions& options,
327327
HighsUserScaleData& user_scale_data);
328328
#endif // LP_DATA_HIGHSLPUTILS_H_

highs/lp_data/HighsModelUtils.cpp

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1591,15 +1591,3 @@ bool repeatedNames(const std::vector<std::string> name) {
15911591
}
15921592
*/
15931593

1594-
HighsStatus userScaleModel(HighsModel& model,
1595-
HighsUserScaleData& data,
1596-
const HighsLogOptions& log_options) {
1597-
userScaleLp(model.lp_, data, false);
1598-
userScaleHessian(model.hessian_, data, false);
1599-
HighsStatus return_status = userScaleStatus(log_options, data);
1600-
if (return_status == HighsStatus::kError) return HighsStatus::kError;
1601-
userScaleLp(model.lp_, data);
1602-
userScaleHessian(model.hessian_, data);
1603-
return return_status;
1604-
}
1605-

highs/lp_data/HighsModelUtils.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,4 @@ std::string findModelObjectiveName(const HighsLp* lp,
114114

115115
// bool repeatedNames(const std::vector<std::string> name);
116116

117-
HighsStatus userScaleModel(HighsModel& model,
118-
HighsUserScaleData& data,
119-
const HighsLogOptions& log_options);
120117
#endif

0 commit comments

Comments
 (0)