Skip to content

Commit

Permalink
Merge pull request #2200 from ERGO-Code/fix-2188
Browse files Browse the repository at this point in the history
Fix 2188
  • Loading branch information
jajhall authored Mar 2, 2025
2 parents ef5be32 + b34b646 commit 528f4b7
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 50 deletions.
97 changes: 59 additions & 38 deletions check/TestCAPI.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ void assertLogical(const char* name, const HighsInt is) {
}
}

void version_api() {
void versionApi() {
if (dev_run) {
printf("HiGHS version %s\n", Highs_version());
printf("HiGHS version major %" HIGHSINT_FORMAT "\n", Highs_versionMajor());
Expand All @@ -250,7 +250,7 @@ void version_api() {
}
}

void minimal_api_lp() {
void minimalApiLp() {
// This illustrates the use of Highs_call, the simple C interface to
// HiGHS. It's designed to solve the general LP problem
//
Expand Down Expand Up @@ -375,7 +375,7 @@ void minimal_api_lp() {
free(row_basis_status);
}

void minimal_api_mip() {
void minimalApiMip() {
// The use of Highs_mipCall is illustrated for the MIP
//
// Min f = -3x_0 - 2x_1 - x_2
Expand Down Expand Up @@ -455,7 +455,7 @@ void minimal_api_mip() {
free(row_value);
}

void minimal_api_qp() {
void minimalApiQp() {
// Test solving the problem qjh
//
// minimize -x_2 - 3x_3 + (1/2)(2x_1^2 - 2x_1x_3 + 0.2x_2^2 + 2x_3^2)
Expand Down Expand Up @@ -503,7 +503,7 @@ void minimal_api_qp() {
free(col_value);
}

void minimal_api_illegal_lp() {
void minimalApiIllegalLp() {
const double inf = 1e30;
HighsInt num_col = 2;
HighsInt num_row = 1;
Expand All @@ -530,7 +530,7 @@ void minimal_api_illegal_lp() {
assert(model_status == kHighsModelStatusNotset);
}

void full_api() {
void fullApi() {
void* highs = Highs_create();

if (!dev_run) Highs_setBoolOptionValue(highs, "output_flag", 0);
Expand Down Expand Up @@ -698,7 +698,7 @@ void full_api() {
Highs_destroy(highs);
}

void full_api_options() {
void fullApiOptions() {
void* highs;

highs = Highs_create();
Expand Down Expand Up @@ -841,7 +841,7 @@ void full_api_options() {
Highs_destroy(highs);
}

void full_api_lp() {
void fullApiLp() {
// Form and solve the LP
// Min f = 2x_0 + 3x_1
// s.t. x_1 <= 6
Expand Down Expand Up @@ -1059,7 +1059,7 @@ void full_api_lp() {
Highs_destroy(highs);
}

void full_api_mip() {
void fullApiMip() {
// The use of the full HiGHS API is illustrated for the MIP
//
// Min f = -3x_0 - 2x_1 - x_2
Expand Down Expand Up @@ -1138,7 +1138,7 @@ void full_api_mip() {
free(row_value);
}

void full_api_qp() {
void fullApiQp() {
double required_objective_function_value;
double required_x0;
double required_x1;
Expand Down Expand Up @@ -1324,7 +1324,7 @@ void full_api_qp() {
free(col_solution);
}

void pass_presolve_get_lp() {
void passPresolveGetLp() {
// Form and solve the LP
// Min f = 2x_0 + 3x_1
// s.t. x_1 <= 6
Expand Down Expand Up @@ -1474,7 +1474,7 @@ void options() {
Highs_destroy(highs);
}

void test_getColsByRange() {
void testGetColsByRange() {
void* highs = Highs_create();
if (!dev_run) Highs_setBoolOptionValue(highs, "output_flag", 0);
HighsInt return_status;
Expand Down Expand Up @@ -1510,7 +1510,7 @@ void test_getColsByRange() {
Highs_destroy(highs);
}

void test_passHessian() {
void testPassHessian() {
void* highs = Highs_create();
if (!dev_run) Highs_setBoolOptionValue(highs, "output_flag", 0);
Highs_addCol(highs, 2.0, 0.0, 2.0, 0, NULL, NULL);
Expand Down Expand Up @@ -1540,7 +1540,7 @@ void test_passHessian() {
Highs_destroy(highs);
}

void test_ranging() {
void testRanging() {
void* highs = Highs_create();
if (!dev_run) Highs_setBoolOptionValue(highs, "output_flag", 0);
//
Expand Down Expand Up @@ -1678,7 +1678,7 @@ void test_ranging() {
Highs_destroy(highs);
}

void test_feasibilityRelaxation() {
void testFeasibilityRelaxation() {
void* highs;
highs = Highs_create();
const double kHighsInf = Highs_getInfinity(highs);
Expand Down Expand Up @@ -1728,7 +1728,7 @@ void test_feasibilityRelaxation() {
Highs_destroy(highs);
}

void test_callback() {
void testCallback() {
HighsInt num_col = 7;
HighsInt num_row = 1;
HighsInt num_nz = num_col;
Expand Down Expand Up @@ -1783,7 +1783,7 @@ void test_callback() {
Highs_destroy(highs);
}

void test_getModel() {
void testGetModel() {
void* highs;
highs = Highs_create();
Highs_setBoolOptionValue(highs, "output_flag", dev_run);
Expand Down Expand Up @@ -1855,7 +1855,7 @@ void test_getModel() {
Highs_destroy(highs);
}

void test_multiObjective() {
void testMultiObjective() {
void* highs;
highs = Highs_create();
const double inf = Highs_getInfinity(highs);
Expand Down Expand Up @@ -1967,11 +1967,31 @@ void test_multiObjective() {
free(col_value);
}

void testQpIndefiniteFailure() {
void* highs = Highs_create();
Highs_setBoolOptionValue(highs, "output_flag", dev_run);
HighsInt ret;
const double inf = Highs_getInfinity(highs);
ret = Highs_addCol(highs, 0.0, 1.0, inf, 0, NULL, NULL);
assert(ret == 0);
ret = Highs_addCol(highs, 0.0, 1.0, 1.0, 0, NULL, NULL);
HighsInt start[2] = {0, 1};
HighsInt index[1] = {1};
double value[1] = {1.0};
ret = Highs_passHessian(highs, 2, 1, kHighsHessianFormatTriangular, start, index, value);
assert(ret == 0);
HighsInt run_status = Highs_run(highs);
HighsInt model_status = Highs_getModelStatus(highs);
assert(run_status == kHighsStatusError);
assert(model_status == kHighsModelStatusSolveError);
Highs_destroy(highs);
}

/*
The horrible C in this causes problems in some of the CI tests,
so suppress thius test until the C has been improved
void test_setSolution() {
void testSetSolution() {
void* highs = Highs_create();
// Perform in C the equivalent of std::string model_file =
// std::string(HIGHS_DIR) + "/check/instances/shell.mps";
Expand Down Expand Up @@ -2013,25 +2033,26 @@ iteration_count1); assertLogical("Dual", logic);
}
*/
int main() {
minimal_api_illegal_lp();
test_callback();
version_api();
full_api();
minimal_api_lp();
minimal_api_mip();
minimal_api_qp();
full_api_options();
full_api_lp();
full_api_mip();
full_api_qp();
pass_presolve_get_lp();
minimalApiIllegalLp();
testCallback();
versionApi();
fullApi();
minimalApiLp();
minimalApiMip();
minimalApiQp();
fullApiOptions();
fullApiLp();
fullApiMip();
fullApiQp();
passPresolveGetLp();
options();
test_getColsByRange();
test_passHessian();
test_ranging();
test_feasibilityRelaxation();
test_getModel();
test_multiObjective();
testGetColsByRange();
testPassHessian();
testRanging();
testFeasibilityRelaxation();
testGetModel();
testMultiObjective();
testQpIndefiniteFailure();
return 0;
}
// test_setSolution();
// testSetSolution();
3 changes: 1 addition & 2 deletions src/Highs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1661,8 +1661,7 @@ class Highs {
bool aFormatOk(const HighsInt num_nz, const HighsInt format);
bool qFormatOk(const HighsInt num_nz, const HighsInt format);
void clearZeroHessian();
HighsStatus checkOptimality(const std::string& solver_type,
HighsStatus return_status);
HighsStatus checkOptimality(const std::string& solver_type);
HighsStatus invertRequirementError(std::string method_name) const;

HighsStatus handleInfCost();
Expand Down
8 changes: 3 additions & 5 deletions src/lp_data/Highs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3746,8 +3746,7 @@ HighsStatus Highs::callSolveLp(HighsLp& lp, const string message) {
return_status = solveLp(solver_object, message);
// Extract the model status
model_status_ = solver_object.model_status_;
if (model_status_ == HighsModelStatus::kOptimal)
checkOptimality("LP", return_status);
if (model_status_ == HighsModelStatus::kOptimal) return checkOptimality("LP");
return return_status;
}

Expand Down Expand Up @@ -3892,8 +3891,7 @@ HighsStatus Highs::callSolveQp() {
info_.simplex_iteration_count += stats.phase1_iterations;
info_.qp_iteration_count += stats.num_iterations;
info_.valid = true;
if (model_status_ == HighsModelStatus::kOptimal)
checkOptimality("QP", return_status);
if (model_status_ == HighsModelStatus::kOptimal) return checkOptimality("QP");
return return_status;
}

Expand Down Expand Up @@ -3988,7 +3986,7 @@ HighsStatus Highs::callSolveMip() {
: HighsInt(mip_total_lp_iterations);
info_.valid = true;
if (model_status_ == HighsModelStatus::kOptimal)
checkOptimality("MIP", return_status);
return_status = checkOptimality("MIP");
if (use_mip_feasibility_tolerance) {
// Overwrite max infeasibility to include integrality if there is a solution
if (solver.solution_objective_ != kHighsInf) {
Expand Down
13 changes: 8 additions & 5 deletions src/lp_data/HighsInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2442,24 +2442,25 @@ void Highs::clearZeroHessian() {
}
}

HighsStatus Highs::checkOptimality(const std::string& solver_type,
HighsStatus return_status) {
HighsStatus Highs::checkOptimality(const std::string& solver_type) {
// Check for infeasibility measures incompatible with optimality
assert(return_status != HighsStatus::kError);
assert(model_status_ == HighsModelStatus::kOptimal);
// Cannot expect to have no dual_infeasibilities since the QP solver
// (and, of course, the MIP solver) give no dual information
if (info_.num_primal_infeasibilities == 0 &&
info_.num_dual_infeasibilities <= 0)
return HighsStatus::kOk;
HighsLogType log_type = HighsLogType::kWarning;
return_status = HighsStatus::kWarning;
model_status_ = HighsModelStatus::kUnknown;
HighsStatus return_status = HighsStatus::kWarning;
// Check for gross errors
if (info_.max_primal_infeasibility >
sqrt(options_.primal_feasibility_tolerance) ||
(info_.dual_solution_status != kSolutionStatusNone &&
info_.max_dual_infeasibility >
sqrt(options_.dual_feasibility_tolerance))) {
// Check for gross errors
log_type = HighsLogType::kError;
model_status_ = HighsModelStatus::kSolveError;
return_status = HighsStatus::kError;
}
std::stringstream ss;
Expand All @@ -2476,6 +2477,8 @@ HighsStatus Highs::checkOptimality(const std::string& solver_type,
ss << " infeasibilities\n";
const std::string report_string = ss.str();
highsLogUser(options_.log_options, log_type, "%s", report_string.c_str());
highsLogUser(options_.log_options, log_type, "Setting model status to %s\n",
modelStatusToString(model_status_).c_str());
return return_status;
}

Expand Down

0 comments on commit 528f4b7

Please sign in to comment.