1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
|
#include "HCheckConfig.h"
#include "Highs.h"
#include "catch.hpp"
#include "lp_data/HighsModelUtils.h"
const bool dev_run = false;
const double inf = kHighsInf;
void test_crossover(Highs& highs, HighsLp& lp);
void report(const std::string message, const HighsLp& lp,
const HighsSolution& solution, const HighsBasis& basis);
// No commas in test case name.
TEST_CASE("test-crossover", "[highs_crossover]") {
HighsLp lp;
lp.num_col_ = 2;
lp.num_row_ = 1;
lp.sense_ = ObjSense::kMaximize;
lp.col_cost_ = {1, 2};
lp.col_lower_ = {0, 0};
lp.col_upper_ = {inf, inf};
lp.row_lower_ = {-inf};
lp.row_upper_ = {4};
lp.a_matrix_.format_ = MatrixFormat::kRowwise;
lp.a_matrix_.start_ = {0, 2};
lp.a_matrix_.index_ = {0, 1};
lp.a_matrix_.value_ = {1, 2};
HighsLp df_lp = lp;
Highs highs;
// From feasible non-vertex for feasible LP
if (dev_run) printf("\nCrossover from feasible non-vertex for feasible LP\n");
test_crossover(highs, lp);
if (dev_run)
printf("\nCrossover from infeasible non-vertex for feasible LP\n");
lp = df_lp;
lp.col_lower_[0] = 4;
test_crossover(highs, lp);
if (dev_run)
printf("\nCrossover from infeasible non-vertex for infeasible LP\n");
lp = df_lp;
lp.col_lower_ = {4, 2};
test_crossover(highs, lp);
if (dev_run)
printf("\nCrossover from feasible non-vertex for unbounded LP\n");
lp = df_lp;
lp.row_lower_ = {4};
lp.row_upper_ = {inf};
test_crossover(highs, lp);
}
void test_crossover(Highs& highs, HighsLp& lp) {
HighsStatus return_status;
highs.clear();
highs.setOptionValue("output_flag", dev_run);
// highs.setOptionValue("output_flag", false);
return_status = highs.passModel(lp);
REQUIRE(return_status == HighsStatus::kOk);
highs.run();
const std::vector<double> from_primal_value = {2, 1};
HighsModelStatus model_status = highs.getModelStatus();
const HighsInfo& info = highs.getInfo();
const double require_optimal_objective = info.objective_function_value;
highs.clearSolver();
// Set solution to interior of optimal face
HighsSolution solution;
solution.col_value = from_primal_value;
HighsBasis basis;
report("Before crossover", lp, solution, basis);
return_status = highs.crossover(solution);
if (model_status == HighsModelStatus::kOptimal) {
REQUIRE(return_status == HighsStatus::kOk);
REQUIRE(highs.getModelStatus() == model_status);
REQUIRE(require_optimal_objective == info.objective_function_value);
} else if (model_status == HighsModelStatus::kInfeasible) {
// Crossover returns "imprecise" => HighsStatus::kWarning and
// HighsModelStatus::kUnknown
REQUIRE(return_status == HighsStatus::kWarning);
REQUIRE(highs.getModelStatus() == HighsModelStatus::kUnknown);
} else if (model_status == HighsModelStatus::kUnbounded) {
// Crossover returns "imprecise" => HighsStatus::kWarning and
// HighsModelStatus::kUnknown
REQUIRE(return_status == HighsStatus::kWarning);
REQUIRE(highs.getModelStatus() == HighsModelStatus::kUnknown);
} else {
assert(1 == 0);
}
report("After crossover", lp, solution, basis);
report("From Highs", lp, highs.getSolution(), highs.getBasis());
}
void report(const std::string message, const HighsLp& lp,
const HighsSolution& solution, const HighsBasis& basis) {
if (!dev_run) return;
double objective = lp.offset_;
printf("Solution: %s\n Ix Value Status\n", message.c_str());
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
const double value = solution.col_value[iCol];
const std::string status =
basis.valid ? utilBasisStatusToString(basis.col_status[iCol]) : "";
objective += value * lp.col_cost_[iCol];
printf("%4d %11.4g %s\n", (int)iCol, value, status.c_str());
}
printf(" Obj %11.4g\n", objective);
}
|