Skip to content

Commit a8a840d

Browse files
committed
Now applying user scaling to incumbent solution before/after solve
1 parent 0bdaf58 commit a8a840d

File tree

9 files changed

+72
-169
lines changed

9 files changed

+72
-169
lines changed

check/TestUserScale.cpp

Lines changed: 19 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -7,71 +7,51 @@
77
const bool dev_run = true; // false;
88
const double inf = kHighsInf;
99

10-
void checkModelScaling(const HighsInt user_bound_scale,
11-
const HighsInt user_cost_scale,
12-
const HighsModel& unscaled_model,
13-
const HighsModel& scaled_model);
14-
15-
void checkLpScaling(const HighsInt user_bound_scale,
16-
const HighsInt user_cost_scale, const HighsLp& unscaled_lp,
17-
const HighsLp& scaled_lp);
18-
1910
bool doubleEqual0(const double v0, const double v1) {
20-
return std::fabs(v0 - v1)/std::max(1.0, std::fabs(v0)) < 1e-12;
11+
double rel_difference = std::fabs(v0 - v1) / std::max(1.0, std::fabs(v0));
12+
bool ok = rel_difference < 1e-12;
13+
if (dev_run && !ok)
14+
printf("UserScaleDoubleEqual: %g and %g have relative difference = %g\n",
15+
v0, v1, rel_difference);
16+
return ok;
2117
}
2218

2319
TEST_CASE("user-scale-after-run", "[highs_user_scale]") {
24-
const std::string mip_model = "flugpl";//"rgn";//
20+
const std::string mip_model = "flugpl"; //"rgn";//
2521
std::string model = "avgas";
2622
Highs highs;
2723
const HighsInfo& info = highs.getInfo();
2824
highs.setOptionValue("output_flag", dev_run);
29-
// REQUIRE(highs.setOptionValue("presolve", kHighsOffString) == HighsStatus::kOk);
30-
HighsInt num_k = 1;
25+
// REQUIRE(highs.setOptionValue("presolve", kHighsOffString) ==
26+
// HighsStatus::kOk);
27+
HighsInt num_k = 2;
3128
if (num_k == 1) model = mip_model;
3229
for (HighsInt k = 0; k < num_k; k++) {
3330
std::string filename =
34-
std::string(HIGHS_DIR) + "/check/instances/" + model + ".mps";
31+
std::string(HIGHS_DIR) + "/check/instances/" + model + ".mps";
3532
highs.readModel(filename);
3633
HighsLp unscaled_lp = highs.getLp();
3734
const bool is_lp = !unscaled_lp.isMip();
38-
highs.writeModel("unscaled.mps");
35+
// highs.writeModel("unscaled.mps");
3936

4037
highs.run();
4138
double unscaled_objective = highs.getInfo().objective_function_value;
4239

4340
HighsInt user_bound_scale = 1;
4441
double user_bound_scale_value = std::pow(2, user_bound_scale);
45-
46-
REQUIRE(highs.setOptionValue("user_bound_scale", user_bound_scale) == HighsStatus::kOk);
47-
48-
HighsLp bound_scaled_lp = highs.getLp();
49-
checkLpScaling(user_bound_scale, 0, unscaled_lp, bound_scaled_lp);
42+
REQUIRE(highs.setOptionValue("user_bound_scale", user_bound_scale) ==
43+
HighsStatus::kOk);
5044

5145
HighsInt user_cost_scale = 4;
5246
double user_cost_scale_value = std::pow(2, user_cost_scale);
53-
REQUIRE(highs.setOptionValue("user_cost_scale", user_cost_scale) == HighsStatus::kOk);
54-
55-
HighsLp scaled_lp = highs.getLp();
56-
checkLpScaling(user_bound_scale, user_cost_scale, unscaled_lp, scaled_lp);
57-
58-
REQUIRE(highs.getModelStatus() == HighsModelStatus::kNotset);
59-
REQUIRE(info.primal_solution_status == kSolutionStatusNone);
60-
REQUIRE(info.dual_solution_status == kSolutionStatusNone);
61-
REQUIRE(info.num_primal_infeasibilities == kHighsIllegalInfeasibilityCount);
62-
REQUIRE(info.max_primal_infeasibility == kHighsIllegalInfeasibilityMeasure);
63-
REQUIRE(info.sum_primal_infeasibilities == kHighsIllegalInfeasibilityMeasure);
64-
REQUIRE(info.num_dual_infeasibilities == kHighsIllegalInfeasibilityCount);
65-
REQUIRE(info.max_dual_infeasibility == kHighsIllegalInfeasibilityMeasure);
66-
REQUIRE(info.sum_dual_infeasibilities == kHighsIllegalInfeasibilityMeasure);
67-
68-
highs.writeModel("scaled0.mps");
69-
highs.passModel(scaled_lp);
47+
REQUIRE(highs.setOptionValue("user_cost_scale", user_cost_scale) ==
48+
HighsStatus::kOk);
49+
7050
highs.run();
71-
51+
7252
REQUIRE(highs.getModelStatus() == HighsModelStatus::kOptimal);
7353
REQUIRE(doubleEqual0(highs.getInfo().objective_function_value,
74-
user_bound_scale_value*user_cost_scale_value*unscaled_objective));
54+
unscaled_objective));
7555

7656
model = mip_model;
7757
REQUIRE(highs.setOptionValue("user_bound_scale", 0) == HighsStatus::kOk);
@@ -81,38 +61,6 @@ TEST_CASE("user-scale-after-run", "[highs_user_scale]") {
8161
highs.resetGlobalScheduler(true);
8262
}
8363

84-
TEST_CASE("user-scale-after-load", "[highs_user_scale]") {
85-
std::string filename =
86-
std::string(HIGHS_DIR) + "/check/instances/adlittle.mps";
87-
Highs highs;
88-
const HighsInfo& info = highs.getInfo();
89-
highs.setOptionValue("output_flag", dev_run);
90-
91-
for (HighsInt k = 0; k < 2; k++) {
92-
highs.readModel(filename);
93-
HighsLp unscaled_lp = highs.getLp();
94-
95-
HighsInt user_bound_scale = 10;
96-
REQUIRE(highs.setOptionValue("user_bound_scale", user_bound_scale) == HighsStatus::kOk);
97-
98-
HighsInt user_cost_scale = 30;
99-
REQUIRE(highs.setOptionValue("user_cost_scale", user_cost_scale) == HighsStatus::kOk);
100-
101-
REQUIRE(highs.readModel(filename) == HighsStatus::kOk);
102-
HighsLp scaled_lp = highs.getLp();
103-
104-
checkLpScaling(user_bound_scale, user_cost_scale, unscaled_lp, scaled_lp);
105-
106-
filename =
107-
std::string(HIGHS_DIR) + "/check/instances/flugpl.mps";
108-
REQUIRE(highs.setOptionValue("user_bound_scale", 0) == HighsStatus::kOk);
109-
REQUIRE(highs.setOptionValue("user_cost_scale", 0) == HighsStatus::kOk);
110-
111-
}
112-
113-
highs.resetGlobalScheduler(true);
114-
}
115-
11664
TEST_CASE("user-small-cost-scale", "[highs_user_scale]") {
11765
Highs highs;
11866
const HighsInfo& info = highs.getInfo();
@@ -151,53 +99,3 @@ TEST_CASE("user-small-cost-scale", "[highs_user_scale]") {
15199

152100
highs.resetGlobalScheduler(true);
153101
}
154-
155-
void checkModelScaling(const HighsInt user_bound_scale,
156-
const HighsInt user_cost_scale,
157-
const HighsModel& unscaled_model,
158-
const HighsModel& scaled_model) {
159-
checkLpScaling(user_bound_scale, user_cost_scale, unscaled_model.lp_,
160-
scaled_model.lp_);
161-
}
162-
163-
void checkLpScaling(const HighsInt user_bound_scale,
164-
const HighsInt user_cost_scale, const HighsLp& unscaled_lp,
165-
const HighsLp& scaled_lp) {
166-
const double user_bound_scale_value = std::pow(2, user_bound_scale);
167-
const double user_cost_scale_value = std::pow(2, user_cost_scale);
168-
REQUIRE(unscaled_lp.num_col_ == scaled_lp.num_col_);
169-
REQUIRE(unscaled_lp.num_row_ == scaled_lp.num_row_);
170-
const bool has_integrality = scaled_lp.integrality_.size() > 0;
171-
const HighsSparseMatrix& unscaled_matrix = unscaled_lp.a_matrix_;
172-
REQUIRE(unscaled_matrix.isColwise());
173-
for (HighsInt iCol = 0; iCol < unscaled_lp.num_col_; iCol++) {
174-
bool continuous = !has_integrality || scaled_lp.integrality_[iCol] == HighsVarType::kContinuous;
175-
double value = unscaled_lp.col_cost_[iCol] * user_cost_scale_value;
176-
if (!continuous) value *= user_bound_scale_value;
177-
REQUIRE(scaled_lp.col_cost_[iCol] == value);
178-
if (unscaled_lp.col_lower_[iCol] > -inf) {
179-
value = unscaled_lp.col_lower_[iCol];
180-
if (continuous) value *= user_bound_scale_value;
181-
REQUIRE(scaled_lp.col_lower_[iCol] == value);
182-
}
183-
if (unscaled_lp.col_upper_[iCol] < inf) {
184-
value = unscaled_lp.col_upper_[iCol];
185-
if (continuous) value *= user_bound_scale_value;
186-
REQUIRE(scaled_lp.col_upper_[iCol] == value);
187-
}
188-
for (HighsInt iEl = unscaled_matrix.start_[iCol]; iEl < unscaled_matrix.start_[iCol+1]; iEl++) {
189-
value = unscaled_matrix.value_[iEl];
190-
if (!continuous) value *= user_bound_scale_value;
191-
REQUIRE(scaled_lp.a_matrix_.value_[iEl] == value);
192-
}
193-
}
194-
for (HighsInt iRow = 0; iRow < unscaled_lp.num_row_; iRow++) {
195-
if (unscaled_lp.row_lower_[iRow] > -inf)
196-
REQUIRE(scaled_lp.row_lower_[iRow] ==
197-
unscaled_lp.row_lower_[iRow] * user_bound_scale_value);
198-
if (unscaled_lp.row_upper_[iRow] < inf)
199-
REQUIRE(scaled_lp.row_upper_[iRow] ==
200-
unscaled_lp.row_upper_[iRow] * user_bound_scale_value);
201-
}
202-
}
203-

highs/Highs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1709,7 +1709,8 @@ class Highs {
17091709
HighsStatus optionChangeAction() const { return HighsStatus::kOk; };
17101710

17111711
HighsStatus userScaleModel(HighsUserScaleData& data);
1712-
HighsStatus userScaleSolution(HighsUserScaleData& data, bool update_kkt = false);
1712+
HighsStatus userScaleSolution(HighsUserScaleData& data,
1713+
bool update_kkt = false);
17131714
HighsStatus computeIllConditioning(HighsIllConditioning& ill_conditioning,
17141715
const bool constraint,
17151716
const HighsInt method,

highs/lp_data/Highs.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -946,10 +946,10 @@ HighsStatus Highs::run() {
946946
HighsUserScaleData user_scale_data;
947947
initialiseUserScaleData(this->options_, user_scale_data);
948948
const bool user_scaling =
949-
user_scale_data.user_cost_scale ||
950-
user_scale_data.user_bound_scale;
949+
user_scale_data.user_cost_scale || user_scale_data.user_bound_scale;
951950
if (user_scaling) {
952-
if (this->userScaleModel(user_scale_data) == HighsStatus::kError) return HighsStatus::kError;
951+
if (this->userScaleModel(user_scale_data) == HighsStatus::kError)
952+
return HighsStatus::kError;
953953
this->userScaleSolution(user_scale_data);
954954
// Zero the user scale values to prevent further scaling
955955
this->options_.user_cost_scale = 0;
@@ -977,13 +977,14 @@ HighsStatus Highs::run() {
977977
if (user_scaling) {
978978
// Unscale the incumbent model and solution
979979
//
980-
// Flip the scaling sign
980+
// Flip the scaling sign
981981
user_scale_data.user_cost_scale *= -1;
982982
user_scale_data.user_bound_scale *= -1;
983983
HighsStatus unscale_status = this->userScaleModel(user_scale_data);
984984
if (unscale_status == HighsStatus::kError) {
985-
highsLogUser(this->options_.log_options, HighsLogType::kError,
986-
"Unexpected error removing user scaling from the incumbent model\n");
985+
highsLogUser(
986+
this->options_.log_options, HighsLogType::kError,
987+
"Unexpected error removing user scaling from the incumbent model\n");
987988
assert(unscale_status != HighsStatus::kError);
988989
}
989990
const bool update_kkt = true;
@@ -992,6 +993,10 @@ HighsStatus Highs::run() {
992993
// negated to undo user scaling
993994
this->options_.user_cost_scale = -user_scale_data.user_cost_scale;
994995
this->options_.user_bound_scale = -user_scale_data.user_bound_scale;
996+
highsLogUser(this->options_.log_options, HighsLogType::kInfo,
997+
"After solving the user-scaled model the unscaled solution "
998+
"has objective value %.12g\n",
999+
this->info_.objective_function_value);
9951000
}
9961001
return status;
9971002
}

highs/lp_data/HighsInterface.cpp

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2994,7 +2994,8 @@ HighsStatus Highs::userScaleModel(HighsUserScaleData& data) {
29942994
return return_status;
29952995
}
29962996

2997-
HighsStatus Highs::userScaleSolution(HighsUserScaleData& data, bool update_kkt) {
2997+
HighsStatus Highs::userScaleSolution(HighsUserScaleData& data,
2998+
bool update_kkt) {
29982999
HighsStatus return_status = HighsStatus::kOk;
29993000
if (!data.user_cost_scale && !data.user_bound_scale) return HighsStatus::kOk;
30003001
double cost_scale_value = std::pow(2, data.user_cost_scale);
@@ -3004,23 +3005,25 @@ HighsStatus Highs::userScaleSolution(HighsUserScaleData& data, bool update_kkt)
30043005
if (info_.primal_solution_status != kSolutionStatusNone) {
30053006
if (data.user_bound_scale) {
30063007
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;
3008+
if (has_integrality &&
3009+
lp.integrality_[iCol] != HighsVarType::kContinuous)
3010+
continue;
3011+
this->solution_.col_value[iCol] *= bound_scale_value;
30093012
}
3010-
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++)
3011-
this->solution_.row_value[iRow] *= bound_scale_value;
3013+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++)
3014+
this->solution_.row_value[iRow] *= bound_scale_value;
30123015
}
30133016
}
30143017
if (info_.dual_solution_status != kSolutionStatusNone) {
30153018
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;
3019+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++)
3020+
this->solution_.col_dual[iCol] *= cost_scale_value;
3021+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++)
3022+
this->solution_.row_dual[iRow] *= cost_scale_value;
30203023
}
30213024
}
30223025
if (!update_kkt) return return_status;
3023-
info_.objective_function_value *= (bound_scale_value*cost_scale_value);
3026+
info_.objective_function_value *= (bound_scale_value * cost_scale_value);
30243027
getKktFailures(options_, model_, solution_, basis_, info_);
30253028
return return_status;
30263029
}

highs/lp_data/HighsLpUtils.cpp

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -769,8 +769,7 @@ HighsStatus cleanBounds(const HighsOptions& options, HighsLp& lp) {
769769
return HighsStatus::kOk;
770770
}
771771

772-
HighsStatus userScaleLp(HighsLp& lp,
773-
HighsUserScaleData& data,
772+
HighsStatus userScaleLp(HighsLp& lp, HighsUserScaleData& data,
774773
const HighsLogOptions& log_options) {
775774
userScaleLp(lp, data, false);
776775
HighsStatus return_status = userScaleStatus(log_options, data);
@@ -779,10 +778,10 @@ HighsStatus userScaleLp(HighsLp& lp,
779778
return return_status;
780779
}
781780

782-
void userScaleLp(HighsLp& lp, HighsUserScaleData& data,
783-
const bool apply) {
781+
void userScaleLp(HighsLp& lp, HighsUserScaleData& data, const bool apply) {
784782
userScaleCosts(lp.integrality_, lp.col_cost_, data, apply);
785-
userScaleColBounds(lp.integrality_, lp.col_lower_, lp.col_upper_, data, apply);
783+
userScaleColBounds(lp.integrality_, lp.col_lower_, lp.col_upper_, data,
784+
apply);
786785
userScaleMatrix(lp.integrality_, lp.a_matrix_, data, apply);
787786
userScaleRowBounds(lp.row_lower_, lp.row_upper_, data, apply);
788787
}
@@ -1734,10 +1733,10 @@ HighsStatus changeLpIntegrality(HighsLp& lp,
17341733
HighsInt lp_col;
17351734
HighsInt usr_col = -1;
17361735

1737-
// If changing integrality for a problem without an integrality
1738-
// vector (ie an LP), have to create it for the incumbent columns -
1739-
// which are naturally continuous
1740-
if (lp.integrality_.size() == 0)
1736+
// If changing integrality for a problem without an integrality
1737+
// vector (ie an LP), have to create it for the incumbent columns -
1738+
// which are naturally continuous
1739+
if (lp.integrality_.size() == 0)
17411740
lp.integrality_.assign(lp.num_col_, HighsVarType::kContinuous);
17421741

17431742
assert(HighsInt(lp.integrality_.size()) == lp.num_col_);
@@ -3688,8 +3687,9 @@ void HighsUserScaleData::initialise(const HighsInt& user_cost_scale_,
36883687
}
36893688

36903689
bool HighsUserScaleData::scaleError(std::string& message) const {
3691-
if (this->num_infinite_costs + this->num_infinite_hessian_values + this->num_infinite_col_bounds +
3692-
this->num_infinite_row_bounds + this->num_large_matrix_values ==
3690+
if (this->num_infinite_costs + this->num_infinite_hessian_values +
3691+
this->num_infinite_col_bounds + this->num_infinite_row_bounds +
3692+
this->num_large_matrix_values ==
36933693
0)
36943694
return false;
36953695
assert(this->user_cost_scale != 0 || this->user_bound_scale != 0);
@@ -3710,19 +3710,18 @@ bool HighsUserScaleData::scaleError(std::string& message) const {
37103710
}
37113711
if (this->num_infinite_hessian_values) {
37123712
if (this->num_infinite_costs) {
3713-
if (this->num_infinite_col_bounds ||
3714-
this->num_infinite_row_bounds) {
3713+
if (this->num_infinite_col_bounds || this->num_infinite_row_bounds) {
37153714
ss << ",";
37163715
} else {
37173716
ss << " and";
37183717
}
37193718
}
3720-
ss << " " << this->num_infinite_hessian_values << " infinite Hessian values";
3719+
ss << " " << this->num_infinite_hessian_values
3720+
<< " infinite Hessian values";
37213721
if (this->num_infinite_hessian_values > 1) ss << "s";
37223722
}
37233723
if (this->num_infinite_col_bounds) {
3724-
if (this->num_infinite_costs ||
3725-
this->num_infinite_hessian_values) {
3724+
if (this->num_infinite_costs || this->num_infinite_hessian_values) {
37263725
if (this->num_infinite_row_bounds) {
37273726
ss << ",";
37283727
} else {
@@ -3733,17 +3732,15 @@ bool HighsUserScaleData::scaleError(std::string& message) const {
37333732
if (this->num_infinite_col_bounds > 1) ss << "s";
37343733
}
37353734
if (this->num_infinite_row_bounds) {
3736-
if (this->num_infinite_costs ||
3737-
this->num_infinite_hessian_values ||
3738-
this->num_infinite_col_bounds) ss << " and";
3735+
if (this->num_infinite_costs || this->num_infinite_hessian_values ||
3736+
this->num_infinite_col_bounds)
3737+
ss << " and";
37393738
ss << " " << this->num_infinite_row_bounds << " infinite row bound";
37403739
if (this->num_infinite_row_bounds > 1) ss << "s";
37413740
}
37423741
if (this->num_large_matrix_values) {
3743-
if (this->num_infinite_costs +
3744-
this->num_infinite_hessian_values +
3745-
this->num_infinite_col_bounds +
3746-
this->num_infinite_row_bounds >
3742+
if (this->num_infinite_costs + this->num_infinite_hessian_values +
3743+
this->num_infinite_col_bounds + this->num_infinite_row_bounds >
37473744
0)
37483745
ss << ", and";
37493746
ss << " " << this->num_large_matrix_values << " large matrix value";

highs/lp_data/HighsLpUtils.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,10 @@ HighsStatus assessBounds(const HighsOptions& options, const char* type,
6161

6262
HighsStatus cleanBounds(const HighsOptions& options, HighsLp& lp);
6363

64-
HighsStatus userScaleLp(HighsLp& lp,
65-
HighsUserScaleData& data,
64+
HighsStatus userScaleLp(HighsLp& lp, HighsUserScaleData& data,
6665
const HighsLogOptions& log_options);
6766

68-
void userScaleLp(HighsLp& lp,
69-
HighsUserScaleData& data,
67+
void userScaleLp(HighsLp& lp, HighsUserScaleData& data,
7068
const bool apply = true);
7169

7270
void userScaleCosts(const vector<HighsVarType>& integrality,

0 commit comments

Comments
 (0)