Skip to content

Commit 6014e90

Browse files
committed
First two test in TestUserScale pass
1 parent b5eb706 commit 6014e90

File tree

7 files changed

+384
-451
lines changed

7 files changed

+384
-451
lines changed

check/TestUserScale.cpp

Lines changed: 76 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include "Highs.h"
55
#include "catch.hpp"
66

7-
const bool dev_run = false;
7+
const bool dev_run = true; // false;
88
const double inf = kHighsInf;
99

1010
void checkModelScaling(const HighsInt user_bound_scale,
@@ -16,51 +16,43 @@ void checkLpScaling(const HighsInt user_bound_scale,
1616
const HighsInt user_cost_scale, const HighsLp& unscaled_lp,
1717
const HighsLp& scaled_lp);
1818

19-
void checkSolutionScaling(const HighsInt user_bound_scale,
20-
const HighsInt user_cost_scale,
21-
const HighsSolution& unscaled_solution,
22-
const HighsSolution& scaled_solution);
23-
2419
TEST_CASE("user-cost-scale-after-run", "[highs_user_scale]") {
2520
std::string filename =
2621
std::string(HIGHS_DIR) + "/check/instances/adlittle.mps";
2722
Highs highs;
2823
const HighsInfo& info = highs.getInfo();
2924
highs.setOptionValue("output_flag", dev_run);
30-
highs.readModel(filename);
31-
highs.run();
32-
HighsInfo unscaled_info = info;
33-
HighsSolution unscaled_solution = highs.getSolution();
34-
HighsLp unscaled_lp = highs.getLp();
35-
double max_primal_infeasibility = info.max_primal_infeasibility;
36-
double max_dual_infeasibility = info.max_dual_infeasibility;
37-
double sum_dual_infeasibilities = info.sum_dual_infeasibilities;
38-
double objective_function_value = info.objective_function_value;
39-
40-
HighsInt user_bound_scale = 10;
41-
double user_bound_scale_value = std::pow(2, user_bound_scale);
42-
highs.setOptionValue("user_bound_scale", user_bound_scale);
43-
44-
HighsInt user_cost_scale = 30;
45-
double user_cost_scale_value = std::pow(2, user_cost_scale);
46-
highs.setOptionValue("user_cost_scale", user_cost_scale);
47-
48-
HighsLp scaled_lp = highs.getLp();
49-
HighsSolution scaled_solution = highs.getSolution();
50-
checkLpScaling(user_bound_scale, user_cost_scale, unscaled_lp, scaled_lp);
51-
checkSolutionScaling(user_bound_scale, user_cost_scale, unscaled_solution,
52-
scaled_solution);
53-
54-
REQUIRE(highs.getModelStatus() == HighsModelStatus::kNotset);
55-
REQUIRE(info.dual_solution_status == kSolutionStatusNone);
56-
REQUIRE(info.objective_function_value == user_cost_scale_value *
57-
user_bound_scale_value *
58-
objective_function_value);
59-
REQUIRE(info.num_dual_infeasibilities == kHighsIllegalInfeasibilityCount);
60-
REQUIRE(info.max_dual_infeasibility ==
61-
user_cost_scale_value * max_dual_infeasibility);
62-
REQUIRE(info.sum_dual_infeasibilities ==
63-
user_cost_scale_value * sum_dual_infeasibilities);
25+
for (HighsInt k = 0; k < 2; k++) {
26+
highs.readModel(filename);
27+
highs.run();
28+
HighsInfo unscaled_info = info;
29+
HighsSolution unscaled_solution = highs.getSolution();
30+
HighsLp unscaled_lp = highs.getLp();
31+
32+
HighsInt user_bound_scale = 10;
33+
REQUIRE(highs.setOptionValue("user_bound_scale", user_bound_scale) == HighsStatus::kOk);
34+
35+
HighsInt user_cost_scale = 30;
36+
REQUIRE(highs.setOptionValue("user_cost_scale", user_cost_scale) == HighsStatus::kOk);
37+
38+
HighsLp scaled_lp = highs.getLp();
39+
checkLpScaling(user_bound_scale, user_cost_scale, unscaled_lp, scaled_lp);
40+
41+
REQUIRE(highs.getModelStatus() == HighsModelStatus::kNotset);
42+
REQUIRE(info.primal_solution_status == kSolutionStatusNone);
43+
REQUIRE(info.dual_solution_status == kSolutionStatusNone);
44+
REQUIRE(info.num_primal_infeasibilities == kHighsIllegalInfeasibilityCount);
45+
REQUIRE(info.max_primal_infeasibility == kHighsIllegalInfeasibilityMeasure);
46+
REQUIRE(info.sum_primal_infeasibilities == kHighsIllegalInfeasibilityMeasure);
47+
REQUIRE(info.num_dual_infeasibilities == kHighsIllegalInfeasibilityCount);
48+
REQUIRE(info.max_dual_infeasibility == kHighsIllegalInfeasibilityMeasure);
49+
REQUIRE(info.sum_dual_infeasibilities == kHighsIllegalInfeasibilityMeasure);
50+
51+
filename =
52+
std::string(HIGHS_DIR) + "/check/instances/flugpl.mps";
53+
REQUIRE(highs.setOptionValue("user_bound_scale", 0) == HighsStatus::kOk);
54+
REQUIRE(highs.setOptionValue("user_cost_scale", 0) == HighsStatus::kOk);
55+
}
6456

6557
highs.resetGlobalScheduler(true);
6658
}
@@ -72,24 +64,28 @@ TEST_CASE("user-cost-scale-after-load", "[highs_user_scale]") {
7264
const HighsInfo& info = highs.getInfo();
7365
highs.setOptionValue("output_flag", dev_run);
7466

75-
highs.readModel(filename);
76-
HighsLp unscaled_lp = highs.getLp();
67+
for (HighsInt k = 0; k < 2; k++) {
68+
highs.readModel(filename);
69+
HighsLp unscaled_lp = highs.getLp();
7770

78-
HighsInt user_bound_scale = 10;
79-
double user_bound_scale_value = std::pow(2, user_bound_scale);
80-
highs.setOptionValue("user_bound_scale", user_bound_scale);
71+
HighsInt user_bound_scale = 10;
72+
double user_bound_scale_value = std::pow(2, user_bound_scale);
73+
REQUIRE(highs.setOptionValue("user_bound_scale", user_bound_scale) == HighsStatus::kOk);
8174

82-
HighsInt user_cost_scale = 30;
83-
double user_cost_scale_value = std::pow(2, user_cost_scale);
84-
highs.setOptionValue("user_cost_scale", user_cost_scale);
75+
HighsInt user_cost_scale = 30;
76+
double user_cost_scale_value = std::pow(2, user_cost_scale);
77+
REQUIRE(highs.setOptionValue("user_cost_scale", user_cost_scale) == HighsStatus::kOk);
8578

86-
highs.readModel(filename);
87-
HighsLp scaled_lp = highs.getLp();
79+
REQUIRE(highs.readModel(filename) == HighsStatus::kOk);
80+
HighsLp scaled_lp = highs.getLp();
8881

89-
checkLpScaling(user_bound_scale, user_cost_scale, unscaled_lp, scaled_lp);
90-
// checkSolutionScaling(user_bound_scale, user_cost_scale, unscaled_solution,
91-
// scaled_solution);
92-
highs.run();
82+
checkLpScaling(user_bound_scale, user_cost_scale, unscaled_lp, scaled_lp);
83+
84+
filename =
85+
std::string(HIGHS_DIR) + "/check/instances/flugpl.mps";
86+
REQUIRE(highs.setOptionValue("user_bound_scale", 0) == HighsStatus::kOk);
87+
REQUIRE(highs.setOptionValue("user_cost_scale", 0) == HighsStatus::kOk);
88+
}
9389

9490
highs.resetGlobalScheduler(true);
9591
}
@@ -117,14 +113,14 @@ TEST_CASE("user-small-cost-scale", "[highs_user_scale]") {
117113
REQUIRE(solution.col_value[0] == 40);
118114
REQUIRE(solution.col_value[1] == 20);
119115

120-
highs.setOptionValue("user_cost_scale", -30);
116+
REQUIRE(highs.setOptionValue("user_cost_scale", -30) == HighsStatus::kOk);
121117
highs.clearSolver();
122118
highs.run();
123119
if (dev_run) highs.writeSolution("", 1);
124120
REQUIRE(solution.col_value[0] == 0);
125121
REQUIRE(solution.col_value[1] == 0);
126122

127-
highs.setOptionValue("user_cost_scale", 0);
123+
REQUIRE(highs.setOptionValue("user_cost_scale", 0) == HighsStatus::kOk);
128124

129125
highs.run();
130126
REQUIRE(solution.col_value[0] == 40);
@@ -214,15 +210,31 @@ void checkLpScaling(const HighsInt user_bound_scale,
214210
const double user_cost_scale_value = std::pow(2, user_cost_scale);
215211
REQUIRE(unscaled_lp.num_col_ == scaled_lp.num_col_);
216212
REQUIRE(unscaled_lp.num_row_ == scaled_lp.num_row_);
213+
REQUIRE(scaled_lp.user_cost_scale_ == user_cost_scale);
214+
REQUIRE(scaled_lp.user_bound_scale_ == user_bound_scale);
215+
const bool has_integrality = scaled_lp.integrality_.size() > 0;
216+
const HighsSparseMatrix& unscaled_matrix = unscaled_lp.a_matrix_;
217+
REQUIRE(unscaled_matrix.isColwise());
217218
for (HighsInt iCol = 0; iCol < unscaled_lp.num_col_; iCol++) {
218-
REQUIRE(scaled_lp.col_cost_[iCol] ==
219-
unscaled_lp.col_cost_[iCol] * user_cost_scale_value);
220-
if (unscaled_lp.col_lower_[iCol] > -inf)
221-
REQUIRE(scaled_lp.col_lower_[iCol] ==
222-
unscaled_lp.col_lower_[iCol] * user_bound_scale_value);
223-
if (unscaled_lp.col_upper_[iCol] < inf)
224-
REQUIRE(scaled_lp.col_upper_[iCol] ==
225-
unscaled_lp.col_upper_[iCol] * user_bound_scale_value);
219+
bool continuous = !has_integrality || scaled_lp.integrality_[iCol] == HighsVarType::kContinuous;
220+
double value = unscaled_lp.col_cost_[iCol] * user_cost_scale_value;
221+
if (!continuous) value *= user_bound_scale_value;
222+
REQUIRE(scaled_lp.col_cost_[iCol] == value);
223+
if (unscaled_lp.col_lower_[iCol] > -inf) {
224+
value = unscaled_lp.col_lower_[iCol];
225+
if (continuous) value *= user_bound_scale_value;
226+
REQUIRE(scaled_lp.col_lower_[iCol] == value);
227+
}
228+
if (unscaled_lp.col_upper_[iCol] < inf) {
229+
value = unscaled_lp.col_upper_[iCol];
230+
if (continuous) value *= user_bound_scale_value;
231+
REQUIRE(scaled_lp.col_upper_[iCol] == value);
232+
}
233+
for (HighsInt iEl = unscaled_matrix.start_[iCol]; iEl < unscaled_matrix.start_[iCol+1]; iEl++) {
234+
value = unscaled_matrix.value_[iEl];
235+
if (!continuous) value *= user_bound_scale_value;
236+
REQUIRE(scaled_lp.a_matrix_.value_[iEl] == value);
237+
}
226238
}
227239
for (HighsInt iRow = 0; iRow < unscaled_lp.num_row_; iRow++) {
228240
if (unscaled_lp.row_lower_[iRow] > -inf)
@@ -234,24 +246,3 @@ void checkLpScaling(const HighsInt user_bound_scale,
234246
}
235247
}
236248

237-
void checkSolutionScaling(const HighsInt user_bound_scale,
238-
const HighsInt user_cost_scale,
239-
const HighsSolution& unscaled_solution,
240-
const HighsSolution& scaled_solution) {
241-
const double user_bound_scale_value = std::pow(2, user_bound_scale);
242-
const double user_cost_scale_value = std::pow(2, user_cost_scale);
243-
for (HighsInt iCol = 0; iCol < HighsInt(unscaled_solution.col_value.size());
244-
iCol++) {
245-
REQUIRE(scaled_solution.col_value[iCol] ==
246-
unscaled_solution.col_value[iCol] * user_bound_scale_value);
247-
REQUIRE(scaled_solution.col_dual[iCol] ==
248-
unscaled_solution.col_dual[iCol] * user_cost_scale_value);
249-
}
250-
for (HighsInt iRow = 0; iRow < HighsInt(unscaled_solution.row_value.size());
251-
iRow++) {
252-
REQUIRE(scaled_solution.row_value[iRow] ==
253-
unscaled_solution.row_value[iRow] * user_bound_scale_value);
254-
REQUIRE(scaled_solution.row_dual[iRow] ==
255-
unscaled_solution.row_dual[iRow] * user_cost_scale_value);
256-
}
257-
}

highs/lp_data/HStruct.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,10 @@ struct HighsUserScaleData {
196196
HighsInt num_small_matrix_values;
197197
HighsInt num_large_matrix_values;
198198
void initialise(const HighsInt& user_cost_scale_,
199-
const HighsInt& user_bound_scale_,
200-
const double& infinite_cost_,
201-
const double& infinite_bound_,
202-
const double& small_matrix_value_,
203-
const double& large_matrix_value_);
199+
const HighsInt& user_bound_scale_,
200+
const double& infinite_cost_, const double& infinite_bound_,
201+
const double& small_matrix_value_,
202+
const double& large_matrix_value_);
204203
bool scaleError() const;
205204
bool scaleError(std::string& message) const;
206205
bool scaleWarning(std::string& message) const;

highs/lp_data/HighsInterface.cpp

Lines changed: 40 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -480,12 +480,9 @@ HighsStatus Highs::addColsInterface(
480480
if (lp.user_cost_scale_ || lp.user_bound_scale_) {
481481
HighsUserScaleData user_scale_data;
482482
initialiseUserScaleData(lp, options_, user_scale_data);
483-
return_status = userScaleNewCols(local_colCost,
484-
local_colLower,
485-
local_colUpper,
486-
local_a_matrix,
487-
user_scale_data,
488-
options.log_options);
483+
return_status =
484+
userScaleNewCols(local_colCost, local_colLower, local_colUpper,
485+
local_a_matrix, user_scale_data, options.log_options);
489486
if (return_status == HighsStatus::kError) return HighsStatus::kError;
490487
}
491488
// Append the columns to the LP vectors and matrix
@@ -584,10 +581,11 @@ HighsStatus Highs::addRowsInterface(HighsInt ext_num_new_row,
584581
std::vector<double> local_rowUpper{ext_row_upper,
585582
ext_row_upper + ext_num_new_row};
586583

587-
return_status = interpretCallStatus(options_.log_options,
588-
assessBounds(options, "Row", lp.num_row_, index_collection,
589-
local_rowLower, local_rowUpper, options.infinite_bound),
590-
return_status, "assessBounds");
584+
return_status = interpretCallStatus(
585+
options_.log_options,
586+
assessBounds(options, "Row", lp.num_row_, index_collection,
587+
local_rowLower, local_rowUpper, options.infinite_bound),
588+
return_status, "assessBounds");
591589
if (return_status == HighsStatus::kError) return return_status;
592590
// Form a row-wise HighsSparseMatrix of the new matrix rows so that
593591
// is easy to handle and, if there are nonzeros, it can be
@@ -604,11 +602,11 @@ HighsStatus Highs::addRowsInterface(HighsInt ext_num_new_row,
604602
local_ar_matrix.value_ = {ext_ar_value, ext_ar_value + ext_num_new_nz};
605603
// Assess the matrix columns
606604
return_status =
607-
interpretCallStatus(options_.log_options,
608-
local_ar_matrix.assess(options.log_options, "LP",
609-
options.small_matrix_value,
610-
options.large_matrix_value),
611-
return_status, "assessMatrix");
605+
interpretCallStatus(options_.log_options,
606+
local_ar_matrix.assess(options.log_options, "LP",
607+
options.small_matrix_value,
608+
options.large_matrix_value),
609+
return_status, "assessMatrix");
612610
if (return_status == HighsStatus::kError) return return_status;
613611
} else {
614612
// No nonzeros so, whether the constraint matrix is row-wise or
@@ -621,19 +619,12 @@ HighsStatus Highs::addRowsInterface(HighsInt ext_num_new_row,
621619
HighsUserScaleData user_scale_data;
622620
initialiseUserScaleData(lp, options_, user_scale_data);
623621
const bool apply = false;
624-
userScaleNewRows(lp.integrality_,
625-
local_rowLower,
626-
local_rowUpper,
627-
local_ar_matrix,
628-
user_scale_data,
629-
apply);
622+
userScaleNewRows(lp.integrality_, local_rowLower, local_rowUpper,
623+
local_ar_matrix, user_scale_data, apply);
630624
return_status = userScaleStatus(options.log_options, user_scale_data);
631625
if (return_status == HighsStatus::kError) return HighsStatus::kError;
632-
userScaleNewRows(lp.integrality_,
633-
local_rowLower,
634-
local_rowUpper,
635-
local_ar_matrix,
636-
user_scale_data);
626+
userScaleNewRows(lp.integrality_, local_rowLower, local_rowUpper,
627+
local_ar_matrix, user_scale_data);
637628
}
638629
// Append the rows to the LP vectors
639630
appendRowsToLpVectors(lp, ext_num_new_row, local_rowLower, local_rowUpper);
@@ -921,7 +912,8 @@ HighsStatus Highs::changeIntegralityInterface(
921912
if (index_collection.is_set_)
922913
assert(increasingSetOk(index_collection.set_, 0,
923914
index_collection.dimension_, true));
924-
HighsStatus return_status = changeLpIntegrality(model_.lp_, index_collection, local_integrality, options_);
915+
HighsStatus return_status = changeLpIntegrality(model_.lp_, index_collection,
916+
local_integrality, options_);
925917
assert(return_status != HighsStatus::kError);
926918
// Deduce the consequences of new integrality
927919
invalidateModelStatus();
@@ -950,7 +942,8 @@ HighsStatus Highs::changeCostsInterface(HighsIndexCollection& index_collection,
950942
if (lp.user_cost_scale_) {
951943
HighsUserScaleData user_scale_data;
952944
initialiseUserScaleData(lp, options_, user_scale_data);
953-
userScaleCosts(lp.integrality_, local_colCost, user_scale_data, options_.log_options);
945+
userScaleCosts(lp.integrality_, local_colCost, user_scale_data,
946+
options_.log_options);
954947
if (return_status == HighsStatus::kError) return HighsStatus::kError;
955948
}
956949
changeLpCosts(lp, index_collection, local_colCost, options_.infinite_cost);
@@ -1000,7 +993,9 @@ HighsStatus Highs::changeColBoundsInterface(
1000993
if (lp.user_bound_scale_) {
1001994
HighsUserScaleData user_scale_data;
1002995
initialiseUserScaleData(lp, options_, user_scale_data);
1003-
return_status = userScaleColBounds(lp.integrality_, local_colLower, local_colUpper, user_scale_data, options_.log_options);
996+
return_status =
997+
userScaleColBounds(lp.integrality_, local_colLower, local_colUpper,
998+
user_scale_data, options_.log_options);
1004999
if (return_status == HighsStatus::kError) return HighsStatus::kError;
10051000
}
10061001
changeLpColBounds(lp, index_collection, local_colLower, local_colUpper);
@@ -1049,7 +1044,8 @@ HighsStatus Highs::changeRowBoundsInterface(
10491044
if (lp.user_bound_scale_) {
10501045
HighsUserScaleData user_scale_data;
10511046
initialiseUserScaleData(lp, options_, user_scale_data);
1052-
return_status = userScaleRowBounds(local_rowLower, local_rowUpper, user_scale_data, options_.log_options);
1047+
return_status = userScaleRowBounds(local_rowLower, local_rowUpper,
1048+
user_scale_data, options_.log_options);
10531049
if (return_status == HighsStatus::kError) return HighsStatus::kError;
10541050
}
10551051
changeLpRowBounds(lp, index_collection, local_rowLower, local_rowUpper);
@@ -3038,32 +3034,32 @@ HighsStatus Highs::optionChangeAction() {
30383034
HighsOptions& options = this->options_;
30393035
HighsStatus return_status = HighsStatus::kOk;
30403036
HighsInt dl_user_cost_scale = options.user_cost_scale - lp.user_cost_scale_;
3041-
HighsInt dl_user_bound_scale = options.user_bound_scale - lp.user_bound_scale_;
3037+
HighsInt dl_user_bound_scale =
3038+
options.user_bound_scale - lp.user_bound_scale_;
3039+
30423040
if (dl_user_cost_scale || dl_user_bound_scale) {
30433041
HighsUserScaleData user_scale_data;
30443042
initialiseUserScaleData(lp, options_, user_scale_data);
30453043
user_scale_data.user_cost_scale = dl_user_cost_scale;
30463044
user_scale_data.user_bound_scale = dl_user_bound_scale;
3047-
return_status = userScaleLp(lp.integrality_,
3048-
lp.col_cost_,
3049-
lp.col_lower_,
3050-
lp.col_upper_,
3051-
lp.row_lower_,
3052-
lp.row_upper_,
3053-
lp.a_matrix_,
3054-
user_scale_data,
3055-
options.log_options);
3045+
return_status =
3046+
userScaleLp(lp.integrality_, lp.col_cost_, lp.col_lower_, lp.col_upper_,
3047+
lp.row_lower_, lp.row_upper_, lp.a_matrix_, user_scale_data,
3048+
options.log_options);
30563049
if (return_status == HighsStatus::kError) {
30573050
options.user_cost_scale = lp.user_cost_scale_;
30583051
options.user_bound_scale = lp.user_bound_scale_;
3059-
highsLogUser(options_.log_options, HighsLogType::kError,
3060-
"New user cost/bound scaling yields excessive costs/bounds: "
3061-
"reverting user cost scaling to %d, and user bound scaling to %d\n",
3062-
int(lp.user_cost_scale_), int(lp.user_bound_scale_));
3052+
highsLogUser(
3053+
options_.log_options, HighsLogType::kError,
3054+
"New user cost/bound scaling yields excessive costs/bounds: "
3055+
"reverting user cost scaling to %d, and user bound scaling to %d\n",
3056+
int(lp.user_cost_scale_), int(lp.user_bound_scale_));
30633057
return HighsStatus::kError;
30643058
}
30653059
this->invalidateModelStatusSolutionAndInfo();
30663060
this->invalidateSolverData();
3061+
lp.user_cost_scale_ = options.user_cost_scale;
3062+
lp.user_bound_scale_ = options.user_bound_scale;
30673063
}
30683064
return HighsStatus::kOk;
30693065
}
@@ -4149,4 +4145,3 @@ void HighsLinearObjective::clear() {
41494145
this->rel_tolerance = 0.0;
41504146
this->priority = 0;
41514147
}
4152-

0 commit comments

Comments
 (0)