Skip to content

Commit

Permalink
Removed dev logging; formatted
Browse files Browse the repository at this point in the history
  • Loading branch information
jajhall committed Nov 22, 2024
1 parent aa09efb commit 714ce34
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 129 deletions.
118 changes: 63 additions & 55 deletions check/TestMultiObjective.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,23 @@ TEST_CASE("multi-objective", "[util]") {

for (HighsInt k = 0; k < 2; k++) {
// Pass 0 is continuous; pass 1 integer
if (dev_run)
printf("\n******************\nPass %d: var type is %s\n******************\n", int(k), k==0 ? "continuous" : "integer");
if (dev_run)
printf(
"\n******************\nPass %d: var type is %s\n******************\n",
int(k), k == 0 ? "continuous" : "integer");
for (HighsInt l = 0; l < 2; l++) {
// Pass 0 is with unsigned weights and coefficients
double obj_mu = l == 0 ? 1 : -1;
if (dev_run)
printf("\n******************\nPass %d: objective multiplier is %g\n******************\n", int(l), obj_mu);
if (dev_run)
printf(
"\n******************\nPass %d: objective multiplier is "
"%g\n******************\n",
int(l), obj_mu);

if (k == 0) {
lp.integrality_.clear();
lp.integrality_.clear();
} else if (k == 1) {
lp.integrality_ = {HighsVarType::kInteger, HighsVarType::kInteger};
lp.integrality_ = {HighsVarType::kInteger, HighsVarType::kInteger};
}
h.passModel(lp);

Expand All @@ -51,14 +56,14 @@ TEST_CASE("multi-objective", "[util]") {
if (dev_run) printf("\nPass illegal linear objective\n");
linear_objective.weight = -obj_mu;
linear_objective.offset = -obj_mu;
linear_objective.coefficients = {obj_mu*2, obj_mu*1, obj_mu*0};
linear_objective.coefficients = {obj_mu * 2, obj_mu * 1, obj_mu * 0};
linear_objective.abs_tolerance = 0.0;
linear_objective.rel_tolerance = 0.0;
REQUIRE(h.addLinearObjective(linear_objective) == HighsStatus::kError);
// Now legalise the linear objective so LP has nonunique optimal
// solutions on the line joining (2, 6) and (5, 3)
if (dev_run) printf("\nPass legal linear objective\n");
linear_objective.coefficients = {obj_mu*1, obj_mu*1};
linear_objective.coefficients = {obj_mu * 1, obj_mu * 1};
REQUIRE(h.addLinearObjective(linear_objective) == HighsStatus::kOk);

REQUIRE(h.run() == HighsStatus::kOk);
Expand All @@ -70,9 +75,9 @@ TEST_CASE("multi-objective", "[util]") {
// Add a second linear objective with a very small minimization
// weight that should push the optimal solution to (2, 6)
if (dev_run) printf("\nPass second linear objective\n");
linear_objective.weight = obj_mu*1e-4;
linear_objective.weight = obj_mu * 1e-4;
linear_objective.offset = 0;
linear_objective.coefficients = {obj_mu*1, obj_mu*0};
linear_objective.coefficients = {obj_mu * 1, obj_mu * 0};
REQUIRE(h.addLinearObjective(linear_objective) == HighsStatus::kOk);

REQUIRE(h.run() == HighsStatus::kOk);
Expand All @@ -84,7 +89,7 @@ TEST_CASE("multi-objective", "[util]") {
if (dev_run) printf("\nClear and pass two linear objectives\n");
REQUIRE(h.clearLinearObjectives() == HighsStatus::kOk);
REQUIRE(h.passLinearObjectives(2, linear_objectives.data()) ==
HighsStatus::kOk);
HighsStatus::kOk);
REQUIRE(h.run() == HighsStatus::kOk);
h.writeSolution("", kSolutionStylePretty);
REQUIRE(smallDoubleDifference(h.getSolution().col_value[0], 2));
Expand All @@ -93,96 +98,99 @@ TEST_CASE("multi-objective", "[util]") {
// Set illegal priorities - that can be passed OK since
// blend_multi_objectives = true
if (dev_run)
printf(
"\nSetting priorities that will be illegal when using lexicographic "
"optimization\n");
printf(
"\nSetting priorities that will be illegal when using "
"lexicographic "
"optimization\n");
linear_objectives[0].priority = 0;
linear_objectives[1].priority = 0;
REQUIRE(h.passLinearObjectives(2, linear_objectives.data()) ==
HighsStatus::kOk);
HighsStatus::kOk);

// Now test lexicographic optimization
h.setOptionValue("blend_multi_objectives", false);

if (dev_run) printf("\nLexicographic using illegal priorities\n");
REQUIRE(h.run() == HighsStatus::kError);

if (dev_run)
printf(
"\nSetting priorities that are illegal now blend_multi_objectives = "
"false\n");
printf(
"\nSetting priorities that are illegal now blend_multi_objectives "
"= "
"false\n");
REQUIRE(h.passLinearObjectives(2, linear_objectives.data()) ==
HighsStatus::kError);
HighsStatus::kError);

if (dev_run)
printf("\nSetting legal priorities for blend_multi_objectives = false\n");
printf(
"\nSetting legal priorities for blend_multi_objectives = false\n");
linear_objectives[0].priority = 10;
REQUIRE(h.passLinearObjectives(2, linear_objectives.data()) ==
HighsStatus::kOk);

if (dev_run) printf("\nLexicographic using existing multi objective data\n");
HighsStatus::kOk);

if (dev_run)
printf("\nLexicographic using existing multi objective data\n");
REQUIRE(h.run() == HighsStatus::kOk);
h.writeSolution("", kSolutionStylePretty);
REQUIRE(smallDoubleDifference(h.getSolution().col_value[0], 2));
REQUIRE(smallDoubleDifference(h.getSolution().col_value[1], 6));

// Back to blending
h.setOptionValue("blend_multi_objectives", true);
// h.setOptionValue("output_flag", true);
REQUIRE(h.clearLinearObjectives() == HighsStatus::kOk);
linear_objectives[0].coefficients = {obj_mu*1.0001, obj_mu*1};
linear_objectives[0].coefficients = {obj_mu * 1.0001, obj_mu * 1};
linear_objectives[0].abs_tolerance = 1e-5;
linear_objectives[0].rel_tolerance = 0.05;
linear_objectives[1].weight = obj_mu*1e-3;
linear_objectives[1].weight = obj_mu * 1e-3;
if (dev_run)
printf(
"\nBlending: first solve objective just giving unique optimal "
"solution\n");
printf(
"\nBlending: first solve objective just giving unique optimal "
"solution\n");
REQUIRE(h.passLinearObjectives(1, linear_objectives.data()) ==
HighsStatus::kOk);
HighsStatus::kOk);

REQUIRE(h.run() == HighsStatus::kOk);
h.writeSolution("", kSolutionStylePretty);

REQUIRE(h.passLinearObjectives(2, linear_objectives.data()) ==
HighsStatus::kOk);
HighsStatus::kOk);

REQUIRE(h.run() == HighsStatus::kOk);
h.writeSolution("", kSolutionStylePretty);

// Back to lexicographic optimization
h.setOptionValue("blend_multi_objectives", false);

if (dev_run) printf("\nLexicographic using non-trivial tolerances\n");
REQUIRE(h.run() == HighsStatus::kOk);
h.writeSolution("", kSolutionStylePretty);

if (k == 0) {
REQUIRE(smallDoubleDifference(h.getSolution().col_value[0], 4.9));
REQUIRE(smallDoubleDifference(h.getSolution().col_value[1], 3.1));
REQUIRE(smallDoubleDifference(h.getSolution().col_value[0], 4.9));
REQUIRE(smallDoubleDifference(h.getSolution().col_value[1], 3.1));
} else {
REQUIRE(smallDoubleDifference(h.getSolution().col_value[0], 5));
REQUIRE(smallDoubleDifference(h.getSolution().col_value[1], 3));
REQUIRE(smallDoubleDifference(h.getSolution().col_value[0], 5));
REQUIRE(smallDoubleDifference(h.getSolution().col_value[1], 3));
}

linear_objectives[0].abs_tolerance = kHighsInf;

REQUIRE(h.passLinearObjectives(2, linear_objectives.data()) ==
HighsStatus::kOk);
HighsStatus::kOk);

REQUIRE(h.run() == HighsStatus::kOk);
h.writeSolution("", kSolutionStylePretty);
// printf("Solution = [%23.18g, %23.18g]\n", h.getSolution().col_value[0],
// h.getSolution().col_value[1]);

// printf("Solution = [%23.18g, %23.18g]\n",
// h.getSolution().col_value[0], h.getSolution().col_value[1]);
if (k == 0) {
REQUIRE(smallDoubleDifference(h.getSolution().col_value[0], 1.30069));
REQUIRE(smallDoubleDifference(h.getSolution().col_value[1], 6.34966));
REQUIRE(smallDoubleDifference(h.getSolution().col_value[0], 1.30069));
REQUIRE(smallDoubleDifference(h.getSolution().col_value[1], 6.34966));
} else {
REQUIRE(smallDoubleDifference(h.getSolution().col_value[0], 2));
REQUIRE(smallDoubleDifference(h.getSolution().col_value[1], 6));
REQUIRE(smallDoubleDifference(h.getSolution().col_value[0], 2));
REQUIRE(smallDoubleDifference(h.getSolution().col_value[1], 6));
}
}
}
}

111 changes: 37 additions & 74 deletions src/lp_data/HighsInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3638,25 +3638,13 @@ bool comparison(std::pair<HighsInt, HighsInt> x1,

HighsStatus Highs::returnFromLexicographicOptimization(
HighsStatus return_status, HighsInt original_lp_num_row) {
const bool lexicographic_optimization_logging = false;
if (lexicographic_optimization_logging)
printf("\nOn return, model status is %s\n",
this->modelStatusToString(this->model_status_).c_str());

// Save model_status_ and info_ since they are cleared by calling
// deleteRows
HighsModelStatus model_status = this->model_status_;
HighsInfo info = this->info_;
if (lexicographic_optimization_logging)
writeInfoToFile(stdout, true, info_.records, HighsFileType::kMinimal);

HighsInt num_linear_objective = this->multi_linear_objective_.size();
if (num_linear_objective > 1) {
this->deleteRows(original_lp_num_row, this->model_.lp_.num_row_ - 1);
if (lexicographic_optimization_logging)
printf("\nAfter deleteRows, model status %s\n",
this->modelStatusToString(model_status_).c_str());

// Recover model_status_ and info_, and then account for lack of basis or
// dual solution
this->model_status_ = model_status;
Expand All @@ -3671,16 +3659,6 @@ HighsStatus Highs::returnFromLexicographicOptimization(
info_.sum_complementarity_violations =
kHighsIllegalComplementarityViolation;
this->solution_.value_valid = true;

if (lexicographic_optimization_logging) {
printf("On return solution is\n");
for (HighsInt iCol = 0; iCol < this->model_.lp_.num_col_; iCol++)
printf("Col %2d Primal = %11.6g; Dual = %11.6g\n", int(iCol),
solution_.col_value[iCol], solution_.col_value[iCol]);
for (HighsInt iRow = 0; iRow < this->model_.lp_.num_row_; iRow++)
printf("Row %2d Primal = %11.6g; Dual = %11.6g\n", int(iRow),
solution_.row_value[iRow], solution_.row_value[iRow]);
}
this->model_.lp_.col_cost_.assign(this->model_.lp_.num_col_, 0);
}
return return_status;
Expand Down Expand Up @@ -3718,11 +3696,6 @@ HighsStatus Highs::multiobjectiveSolve() {
multi_linear_objective.coefficients[iCol];
}
lp.sense_ = ObjSense::kMinimize;
printf("Highs::run() LP objective function is %s %g ",
lp.sense_ == ObjSense::kMinimize ? "min" : "max", lp.offset_);
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++)
printf(" + (%g) x[%d]", lp.col_cost_[iCol], int(iCol));
printf("\n");
return this->solve();
}

Expand Down Expand Up @@ -3757,28 +3730,21 @@ HighsStatus Highs::multiobjectiveSolve() {
for (HighsInt iIx = 0; iIx < num_linear_objective; iIx++) {
HighsInt priority = priority_objective[iIx].first;
HighsInt iObj = priority_objective[iIx].second;
printf("\nHighs::run() Entry %d is objective %d with priority %d\n",
int(iIx), int(iObj), int(priority_objective[iIx].first));
// Use this objective
HighsLinearObjective& linear_objective =
this->multi_linear_objective_[iObj];
lp.offset_ = linear_objective.offset;
lp.col_cost_ = linear_objective.coefficients;
lp.sense_ =
linear_objective.weight > 0 ? ObjSense::kMinimize : ObjSense::kMaximize;
printf("Highs::run() LP objective function is %s %g ",
lp.sense_ == ObjSense::kMinimize ? "min" : "max", lp.offset_);
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++)
printf(" + %g x[%d]", lp.col_cost_[iCol], int(iCol));
printf("\n");
HighsStatus solve_status = this->solve();
if (solve_status == HighsStatus::kError)
return returnFromLexicographicOptimization(HighsStatus::kError,
original_lp_num_row);
if (model_status_ != HighsModelStatus::kOptimal) {
highsLogUser(options_.log_options, HighsLogType::kWarning,
"After priority %d solve, model status is %s\n", int(priority),
modelStatusToString(model_status_).c_str());
"After priority %d solve, model status is %s\n",
int(priority), modelStatusToString(model_status_).c_str());
return returnFromLexicographicOptimization(HighsStatus::kWarning,
original_lp_num_row);
}
Expand All @@ -3800,54 +3766,51 @@ HighsStatus Highs::multiobjectiveSolve() {
if (lp.sense_ == ObjSense::kMinimize) {
// Minimizing, so set a greater upper bound than the objective
if (linear_objective.abs_tolerance >= 0)
upper_bound = objective + linear_objective.abs_tolerance;
upper_bound = objective + linear_objective.abs_tolerance;
if (linear_objective.rel_tolerance >= 0) {
if (objective >= 0) {
// Guarantees objective of at least (1+t).f^*
//
// so ((1+t).f^*-f^*)/f^* = t
upper_bound = std::min(
objective * (1.0 + linear_objective.rel_tolerance), upper_bound);
} else if (objective < 0) {
// Guarantees objective of at least (1-t).f^*
//
// so ((1-t).f^*-f^*)/f^* = -t
upper_bound = std::min(
objective * (1.0 - linear_objective.rel_tolerance), upper_bound);
}
if (objective >= 0) {
// Guarantees objective of at least (1+t).f^*
//
// so ((1+t).f^*-f^*)/f^* = t
upper_bound = std::min(
objective * (1.0 + linear_objective.rel_tolerance), upper_bound);
} else if (objective < 0) {
// Guarantees objective of at least (1-t).f^*
//
// so ((1-t).f^*-f^*)/f^* = -t
upper_bound = std::min(
objective * (1.0 - linear_objective.rel_tolerance), upper_bound);
}
}
upper_bound -= lp.offset_;
} else {
// Maximizing, so set a lesser lower bound than the objective
if (linear_objective.abs_tolerance >= 0)
lower_bound = objective - linear_objective.abs_tolerance;
lower_bound = objective - linear_objective.abs_tolerance;
if (linear_objective.rel_tolerance >= 0) {
if (objective >= 0) {
// Guarantees objective of at most (1-t).f^*
//
// so ((1-t).f^*-f^*)/f^* = -t
lower_bound = std::max(
objective * (1.0 - linear_objective.rel_tolerance), lower_bound);
} else if (objective < 0) {
// Guarantees objective of at least (1+t).f^*
//
// so ((1+t).f^*-f^*)/f^* = t
lower_bound = std::max(
objective * (1.0 + linear_objective.rel_tolerance), lower_bound);
}
if (objective >= 0) {
// Guarantees objective of at most (1-t).f^*
//
// so ((1-t).f^*-f^*)/f^* = -t
lower_bound = std::max(
objective * (1.0 - linear_objective.rel_tolerance), lower_bound);
} else if (objective < 0) {
// Guarantees objective of at least (1+t).f^*
//
// so ((1+t).f^*-f^*)/f^* = t
lower_bound = std::max(
objective * (1.0 + linear_objective.rel_tolerance), lower_bound);
}
}
lower_bound -= lp.offset_;
}
if (lower_bound == -kHighsInf && upper_bound == kHighsInf)
highsLogUser(options_.log_options, HighsLogType::kWarning,
"After priority %d solve, no objective constraint due to absolute tolerance being %g < 0,"
" and relative tolerance being %g < 0\n",
int(priority), linear_objective.abs_tolerance, linear_objective.rel_tolerance);
printf("Highs::run() Add objective constraint %g <= ", lower_bound);
for (HighsInt iEl = 0; iEl < nnz; iEl++)
printf(" + (%g) x[%d]", value[iEl], int(index[iEl]));
printf(" <= %g\n", upper_bound);

if (lower_bound == -kHighsInf && upper_bound == kHighsInf)
highsLogUser(options_.log_options, HighsLogType::kWarning,
"After priority %d solve, no objective constraint due to "
"absolute tolerance being %g < 0,"
" and relative tolerance being %g < 0\n",
int(priority), linear_objective.abs_tolerance,
linear_objective.rel_tolerance);
add_row_status =
this->addRow(lower_bound, upper_bound, nnz, index.data(), value.data());
assert(add_row_status == HighsStatus::kOk);
Expand Down

0 comments on commit 714ce34

Please sign in to comment.