Skip to content

Commit 300d02a

Browse files
committed
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into neos4LargeBnds
2 parents 4b7963f + 5f551b1 commit 300d02a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+5189
-761
lines changed

FEATURES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,7 @@ QP solver logging is now neater and quieter
3535
Any Hessian for the incumbent model is modified with zero entries when adding columns to the model, and rows/columns are removed when columns are deleted from the model.
3636

3737
Minor bug fix in MIP presolve
38+
39+
QP solver will now hot start given a basis and solution
40+
41+

check/TestQpSolver.cpp

Lines changed: 141 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -832,7 +832,7 @@ TEST_CASE("test-qp-delete-col", "[qpsolver]") {
832832
}
833833

834834
REQUIRE(highs.passModel(model) == HighsStatus::kOk);
835-
if (dev_run) incumbent_model.hessian_.print();
835+
if (dev_run && dim < 20) incumbent_model.hessian_.print();
836836

837837
arg0.resize(dim);
838838
for (HighsInt iCol = 0; iCol < dim; iCol++) arg0[iCol] = random.fraction();
@@ -850,7 +850,7 @@ TEST_CASE("test-qp-delete-col", "[qpsolver]") {
850850
mask[iRow] = 1;
851851
}
852852
highs.deleteCols(mask.data());
853-
if (dev_run) incumbent_model.hessian_.print();
853+
if (dev_run && dim < 20) incumbent_model.hessian_.print();
854854

855855
for (HighsInt iCol = 0; iCol < dim; iCol++) {
856856
HighsInt iRow = mask[iCol];
@@ -873,3 +873,142 @@ TEST_CASE("test-qp-delete-col", "[qpsolver]") {
873873
REQUIRE(result0[iCol] == result1[iCol]);
874874
}
875875
}
876+
877+
TEST_CASE("test-qp-hot-start", "[qpsolver]") {
878+
// Test hot start
879+
HighsStatus return_status;
880+
Highs highs;
881+
highs.setOptionValue("output_flag", dev_run);
882+
const HighsInfo& info = highs.getInfo();
883+
884+
for (HighsInt k = 0; k < 2; k++) {
885+
if (dev_run)
886+
printf(
887+
"\n"
888+
"===================\n"
889+
"Hot start test %d\n"
890+
"===================\n",
891+
int(k));
892+
if (k == 1) {
893+
const std::string filename =
894+
std::string(HIGHS_DIR) + "/check/instances/primal1.mps";
895+
REQUIRE(highs.readModel(filename) == HighsStatus::kOk);
896+
} else if (k == 2) {
897+
const std::string filename =
898+
std::string(HIGHS_DIR) + "/check/instances/qptestnw.lp";
899+
REQUIRE(highs.readModel(filename) == HighsStatus::kOk);
900+
} else {
901+
HighsModel model;
902+
model.lp_.num_col_ = 2;
903+
model.lp_.num_row_ = 1;
904+
model.lp_.col_cost_ = {-2, -2};
905+
model.lp_.col_lower_ = {-inf, -inf};
906+
model.lp_.col_upper_ = {inf, inf};
907+
model.lp_.row_lower_ = {1};
908+
model.lp_.row_upper_ = {inf};
909+
model.lp_.a_matrix_.format_ = MatrixFormat::kRowwise;
910+
model.lp_.a_matrix_.start_ = {0, 2};
911+
model.lp_.a_matrix_.index_ = {0, 1};
912+
model.lp_.a_matrix_.value_ = {1, 1};
913+
model.hessian_.dim_ = 2;
914+
model.hessian_.start_ = {0, 1, 2};
915+
model.hessian_.index_ = {0, 1};
916+
model.hessian_.value_ = {2, 2};
917+
REQUIRE(highs.passModel(model) == HighsStatus::kOk);
918+
}
919+
return_status = highs.run();
920+
REQUIRE(return_status == HighsStatus::kOk);
921+
922+
if (dev_run) highs.writeSolution("", 1);
923+
924+
HighsBasis basis = highs.getBasis();
925+
HighsSolution solution = highs.getSolution();
926+
if (dev_run) printf("Saved basis has validity = %d\n", basis.valid);
927+
928+
if (dev_run)
929+
printf(
930+
"================\n"
931+
"Hot start re-run\n"
932+
"================\n");
933+
return_status = highs.run();
934+
REQUIRE(return_status == HighsStatus::kOk);
935+
REQUIRE(info.qp_iteration_count == 0);
936+
937+
if (dev_run)
938+
printf(
939+
"===========================\n"
940+
"Hot start using saved basis\n"
941+
"===========================\n");
942+
highs.setBasis(basis);
943+
return_status = highs.run();
944+
REQUIRE(return_status == HighsStatus::kOk);
945+
REQUIRE(info.qp_iteration_count == 0);
946+
947+
// QP Hot start needs a saved solution as well as a basis after
948+
// clearSolver()
949+
if (dev_run)
950+
printf(
951+
"==============================================================\n"
952+
"Hot start using saved basis and solution after clearing solver\n"
953+
"==============================================================\n");
954+
highs.clearSolver();
955+
highs.setSolution(solution);
956+
highs.setBasis(basis);
957+
return_status = highs.run();
958+
REQUIRE(return_status == HighsStatus::kOk);
959+
REQUIRE(info.qp_iteration_count == 0);
960+
/*
961+
if (dev_run)
962+
printf("=================================================\n"
963+
"Hot start using saved basis after clearing solver\n"
964+
"=================================================\n");
965+
highs.clearSolver();
966+
highs.setBasis(basis);
967+
return_status = highs.run();
968+
REQUIRE(return_status == HighsStatus::kOk);
969+
REQUIRE(info.qp_iteration_count == 0);
970+
*/
971+
// QP Hot start needs a saved solution as well as a basis after
972+
// clearSolver()
973+
if (dev_run)
974+
printf(
975+
"==============================================================\n"
976+
"Hot start using alien basis and solution after clearing solver\n"
977+
"==============================================================\n");
978+
highs.clearSolver();
979+
highs.setSolution(solution);
980+
basis.alien = true;
981+
highs.setBasis(basis);
982+
return_status = highs.run();
983+
REQUIRE(return_status == HighsStatus::kOk);
984+
REQUIRE(info.qp_iteration_count == 0);
985+
}
986+
}
987+
988+
TEST_CASE("test-qp-terminations", "[qpsolver]") {
989+
Highs highs;
990+
highs.setOptionValue("output_flag", dev_run);
991+
const HighsInfo& info = highs.getInfo();
992+
std::string filename =
993+
std::string(HIGHS_DIR) + "/check/instances/qptestnw.lp";
994+
REQUIRE(highs.readModel(filename) == HighsStatus::kOk);
995+
996+
highs.setOptionValue("qp_iteration_limit", 1);
997+
REQUIRE(highs.run() == HighsStatus::kWarning);
998+
REQUIRE(highs.getModelStatus() == HighsModelStatus::kIterationLimit);
999+
highs.clearSolver();
1000+
highs.setOptionValue("qp_iteration_limit", kHighsIInf);
1001+
1002+
highs.setOptionValue("time_limit", 0);
1003+
REQUIRE(highs.run() == HighsStatus::kWarning);
1004+
REQUIRE(highs.getModelStatus() == HighsModelStatus::kTimeLimit);
1005+
highs.setOptionValue("time_limit", kHighsInf);
1006+
1007+
filename = std::string(HIGHS_DIR) + "/check/instances/primal1.mps";
1008+
REQUIRE(highs.readModel(filename) == HighsStatus::kOk);
1009+
1010+
highs.setOptionValue("qp_nullspace_limit", 1);
1011+
REQUIRE(highs.run() == HighsStatus::kError);
1012+
REQUIRE(highs.getModelStatus() == HighsModelStatus::kSolveError);
1013+
highs.setOptionValue("qp_nullspace_limit", 4000);
1014+
}

check/TestRays.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,3 +534,40 @@ TEST_CASE("Rays-464b", "[highs_test_rays]") {
534534
REQUIRE(ray_value[0] == ray_value[1]);
535535
REQUIRE(ray_value[0] > 0);
536536
}
537+
538+
/*
539+
TEST_CASE("Rays-infeasible-qp", "[highs_test_rays]") {
540+
HighsModel model;
541+
HighsLp& lp = model.lp_;
542+
HighsHessian& hessian = model.hessian_;
543+
lp.num_col_ = 2;
544+
lp.num_row_ = 1;
545+
lp.col_cost_ = {0, 0};
546+
lp.col_lower_ = {0, 0};
547+
lp.col_upper_ = {inf, inf};
548+
lp.row_lower_ = {-1};
549+
lp.row_upper_ = {-1};
550+
lp.a_matrix_.format_ = MatrixFormat::kRowwise;
551+
lp.a_matrix_.start_ = {0, 2};
552+
lp.a_matrix_.index_ = {0, 1};
553+
lp.a_matrix_.value_ = {1, 1};
554+
hessian.dim_ = 2;
555+
hessian.start_ = {0, 1, 2};
556+
hessian.index_ = {0, 1};
557+
hessian.value_ = {1, 1};
558+
Highs highs;
559+
//highs.setOptionValue("output_flag", dev_run);
560+
REQUIRE(highs.passModel(model) == HighsStatus::kOk);
561+
highs.run();
562+
// if (dev_run)
563+
printf("Solved infeasible QP: status = %s\n",
564+
highs.modelStatusToString(highs.getModelStatus()).c_str());
565+
REQUIRE(highs.getModelStatus() == HighsModelStatus::kInfeasible);
566+
bool has_ray = false;
567+
REQUIRE(highs.getDualRay(has_ray) == HighsStatus::kOk);
568+
REQUIRE(has_ray == true);
569+
std::vector<double> ray_value;
570+
ray_value.assign(2, NAN);
571+
highs.getDualRay(has_ray, ray_value.data());
572+
}
573+
*/

0 commit comments

Comments
 (0)