24#include "absl/strings/str_cat.h"
25#include "gtest/gtest.h"
30#include "ortools/math_opt/parameters.pb.h"
31#include "ortools/math_opt/result.pb.h"
32#include "ortools/math_opt/solution.pb.h"
39 const SolverType solver_type,
const std::optional<LPAlgorithm> lp_algorithm,
40 const bool supports_iteration_limit,
const bool supports_initial_basis,
41 const bool supports_incremental_solve,
const bool supports_basis,
42 const bool supports_presolve,
const bool check_primal_objective,
43 const bool primal_solution_status_always_set,
44 const bool dual_solution_status_always_set)
45 : solver_type(solver_type),
46 lp_algorithm(lp_algorithm),
47 supports_iteration_limit(supports_iteration_limit),
48 supports_initial_basis(supports_initial_basis),
49 supports_incremental_solve(supports_incremental_solve),
50 supports_basis(supports_basis),
51 supports_presolve(supports_presolve),
52 check_primal_objective(check_primal_objective),
53 primal_solution_status_always_set(primal_solution_status_always_set),
54 dual_solution_status_always_set(dual_solution_status_always_set) {}
66 <<
" primal_solution_status_always_set:"
68 <<
" dual_solution_status_always_set:"
73using ::testing::AnyOf;
74using ::testing::ElementsAreArray;
78constexpr double kInf = std::numeric_limits<double>::infinity();
86 if (!GetParam().supports_iteration_limit) {
88 <<
"Ignoring this test as it requires support for iteration limit.";
92 const std::unique_ptr<Model>
model =
98 if (GetParam().supports_presolve) {
107 ASSERT_FALSE(result.solutions.empty());
108 ASSERT_TRUE(result.solutions[0].primal_solution.has_value());
110 ElementsAreArray(
model->SortedVariables()));
111 ASSERT_TRUE(result.solutions[0].dual_solution.has_value());
113 ElementsAreArray(
model->SortedVariables()));
114 EXPECT_EQ(
SortedKeys(result.solutions[0].dual_solution->dual_values),
115 model->SortedLinearConstraints());
118bool ApproxEq(
const double first_double,
const double second_double,
120 return std::abs(first_double - second_double) <= tolerance;
184 !GetParam().supports_iteration_limit ||
185 !GetParam().supports_initial_basis) {
187 <<
"Ignoring this test as it requires support for dual simplex, "
188 "iteration limit and initial basis.";
192 std::vector<Variable>
x;
193 std::vector<LinearConstraint>
c;
194 for (
int i = 0; i < n; ++i) {
195 x.push_back(
model.AddContinuousVariable(-2.0, 2.0));
196 c.push_back(
model.AddLinearConstraint(-1.0 <=
x[i] <= 1.0));
201 if (GetParam().supports_presolve) {
205 for (
int i = 0; i < n; ++i) {
217 if (GetParam().supports_basis) {
218 ASSERT_TRUE(result.has_basis());
219 if (GetParam().dual_solution_status_always_set) {
220 EXPECT_EQ(result.solutions[0].basis->basic_dual_feasibility,
223 EXPECT_NE(result.solutions[0].basis->basic_dual_feasibility,
227 LOG(INFO) <<
"Skipping basis check as solver does not return a basis.";
229 ASSERT_FALSE(result.solutions.empty());
230 ASSERT_TRUE(result.solutions[0].primal_solution.has_value());
231 ASSERT_TRUE(result.solutions[0].dual_solution.has_value());
232 int n1_variables = 0;
233 int p1_variables = 0;
234 int n2_variables = 0;
235 int p2_variables = 0;
236 for (
int i = 0; i < n; ++i) {
237 SCOPED_TRACE(absl::StrCat(i));
238 const double variable_value =
239 result.solutions[0].primal_solution->variable_values.at(
x[i]);
240 const double reduced_cost =
241 result.solutions[0].dual_solution->reduced_costs.at(
x[i]);
242 const double dual_value =
243 result.solutions[0].dual_solution->dual_values.at(
c[i]);
246 if (ApproxEq(variable_value, -1.0)) {
252 }
else if (ApproxEq(variable_value, 1.0)) {
258 }
else if (ApproxEq(variable_value, -2.0)) {
272 if (GetParam().supports_basis) {
273 ASSERT_TRUE(result.has_basis());
274 EXPECT_EQ(result.solutions[0].basis->variable_status.at(
x[i]),
275 expected_variable_status);
276 EXPECT_EQ(result.solutions[0].basis->constraint_status.at(
c[i]),
277 expected_constraint_status);
280 EXPECT_EQ(p1_variables, 0);
281 EXPECT_EQ(p2_variables, 0);
282 EXPECT_GT(n2_variables, 1);
283 EXPECT_GT(n1_variables, 1);
284 EXPECT_LT(n2_variables, n);
285 EXPECT_LT(n1_variables, n);
286 if (GetParam().primal_solution_status_always_set) {
287 EXPECT_EQ(result.solutions[0].primal_solution->feasibility_status,
290 EXPECT_NE(result.solutions[0].primal_solution->feasibility_status,
293 ASSERT_TRUE(result.solutions[0].dual_solution.has_value());
294 if (GetParam().dual_solution_status_always_set) {
295 EXPECT_EQ(result.solutions[0].dual_solution->feasibility_status,
298 EXPECT_NE(result.solutions[0].dual_solution->feasibility_status,
301 if (GetParam().check_primal_objective) {
302 EXPECT_NEAR(-1 * n1_variables - 2 * n2_variables,
303 result.solutions[0].primal_solution->objective_value,
305 if (GetParam().supports_basis &&
306 GetParam().dual_solution_status_always_set) {
311 result.solutions[0].dual_solution->objective_value.has_value());
312 EXPECT_NEAR(-1 * n1_variables - 2 * n2_variables,
313 *result.solutions[0].dual_solution->objective_value,
317 LOG(INFO) <<
"Skipping primal objective check as solver does not "
318 "reliably support it for incomplete solves.";
373 !GetParam().supports_iteration_limit ||
374 !GetParam().supports_initial_basis) {
376 <<
"Ignoring this test as it requires support for primal simplex,"
377 " iteration limit and initial basis.";
381 std::vector<Variable>
x;
382 for (
int i = 0; i < n; ++i) {
383 x.push_back(
model.AddContinuousVariable(0.0, 2.0));
390 if (GetParam().supports_presolve) {
394 for (
int i = 0; i < n; ++i) {
406 if (GetParam().supports_basis) {
407 ASSERT_TRUE(result.has_basis());
408 EXPECT_NE(result.solutions[0].basis->basic_dual_feasibility,
411 LOG(INFO) <<
"Skipping basis check as solver does not return a basis.";
413 ASSERT_FALSE(result.solutions.empty());
414 ASSERT_TRUE(result.solutions[0].primal_solution.has_value());
415 ASSERT_TRUE(result.solutions[0].dual_solution.has_value());
416 int variable_values_at_two = 0;
417 const double dual_value =
418 result.solutions[0].dual_solution->dual_values.at(
c);
420 if (GetParam().supports_basis) {
421 EXPECT_EQ(result.solutions[0].basis->constraint_status.at(
c),
424 for (
int i = 0; i < n; ++i) {
425 SCOPED_TRACE(absl::StrCat(i));
426 const double variable_value =
427 result.solutions[0].primal_solution->variable_values.at(
x[i]);
428 const double reduced_cost =
429 result.solutions[0].dual_solution->reduced_costs.at(
x[i]);
436 if (ApproxEq(variable_value, 2.0)) {
437 ++variable_values_at_two;
442 if (GetParam().supports_basis) {
443 EXPECT_EQ(result.solutions[0].basis->variable_status.at(
x[i]),
447 EXPECT_GT(variable_values_at_two, 1);
448 EXPECT_LT(variable_values_at_two, n);
449 if (GetParam().primal_solution_status_always_set) {
450 EXPECT_EQ(result.solutions[0].primal_solution->feasibility_status,
453 EXPECT_NE(result.solutions[0].primal_solution->feasibility_status,
458 EXPECT_NE(result.solutions[0].dual_solution->feasibility_status,
461 if (GetParam().check_primal_objective) {
462 EXPECT_NEAR(2 * variable_values_at_two,
463 result.solutions[0].primal_solution->objective_value,
466 LOG(INFO) <<
"Skipping primal objective check as solver does not "
467 "reliably support it for incomplete solves.";
520 !GetParam().supports_iteration_limit ||
521 !(GetParam().supports_incremental_solve ||
522 GetParam().supports_initial_basis)) {
524 <<
"Ignoring this test as it requires support for primal simplex, "
525 "iteration limit and either incremental solve or initial basis.";
528 Model model(
"Primal Feasible Incomplete Solve LP");
529 std::vector<Variable>
x;
530 std::vector<LinearConstraint>
c;
531 for (
int i = 0; i < n; ++i) {
532 x.push_back(
model.AddContinuousVariable(0.0,
kInf));
533 c.push_back(
model.AddLinearConstraint(
x[i] <= 1));
537 const std::unique_ptr<IncrementalSolver> incremental_solver,
541 if (GetParam().supports_presolve) {
545 if (GetParam().supports_initial_basis) {
547 for (
int i = 0; i < n; ++i) {
554 ASSERT_OK(incremental_solver->Solve(args));
560 incremental_solver->Solve(args));
561 if (GetParam().primal_solution_status_always_set) {
569 if (GetParam().supports_basis) {
570 ASSERT_TRUE(result.has_basis());
571 if (GetParam().dual_solution_status_always_set) {
572 EXPECT_EQ(result.solutions[0].basis->basic_dual_feasibility,
575 EXPECT_NE(result.solutions[0].basis->basic_dual_feasibility,
579 LOG(INFO) <<
"Skipping basis check as solver does not return a basis.";
581 ASSERT_FALSE(result.solutions.empty());
582 ASSERT_TRUE(result.solutions[0].primal_solution.has_value());
583 ASSERT_TRUE(result.solutions[0].dual_solution.has_value());
584 int variable_values_at_one = 0;
585 for (
int i = 0; i < n; ++i) {
586 SCOPED_TRACE(absl::StrCat(i));
587 double variable_value =
588 result.solutions[0].primal_solution->variable_values.at(
x[i]);
589 double reduced_cost =
590 result.solutions[0].dual_solution->reduced_costs.at(
x[i]);
591 double dual_value = result.solutions[0].dual_solution->dual_values.at(
c[i]);
592 if (std::abs(variable_value - 1.0) <=
kTolerance) {
593 ++variable_values_at_one;
596 if (GetParam().supports_basis) {
597 EXPECT_EQ(result.solutions[0].basis->variable_status.at(
x[i]),
599 EXPECT_EQ(result.solutions[0].basis->constraint_status.at(
c[i]),
606 if (GetParam().supports_basis) {
607 EXPECT_EQ(result.solutions[0].basis->variable_status.at(
x[i]),
609 EXPECT_EQ(result.solutions[0].basis->constraint_status.at(
c[i]),
614 EXPECT_GT(variable_values_at_one, 0);
615 EXPECT_LT(variable_values_at_one, n);
616 if (GetParam().primal_solution_status_always_set) {
617 EXPECT_EQ(result.solutions[0].primal_solution->feasibility_status,
620 EXPECT_NE(result.solutions[0].primal_solution->feasibility_status,
623 EXPECT_NE(result.solutions[0].dual_solution->feasibility_status,
625 if (GetParam().check_primal_objective) {
626 EXPECT_NEAR(variable_values_at_one,
627 result.solutions[0].primal_solution->objective_value,
630 LOG(INFO) <<
"Skipping primal objective check as solver does not "
631 "reliably support it for incomplete solves.";
691 !GetParam().supports_iteration_limit ||
692 !(GetParam().supports_incremental_solve ||
693 GetParam().supports_initial_basis)) {
695 <<
"Ignoring this test as it requires support for primal simplex, "
696 "iteration limit and either incremental solve or initial basis.";
699 Model model(
"Primal Feasible Incomplete Solve LP");
700 std::vector<Variable>
x;
701 for (
int i = 0; i < n; ++i) {
702 x.push_back(
model.AddContinuousVariable(0.0, 2.0));
706 const std::unique_ptr<IncrementalSolver> incremental_solver,
711 if (GetParam().supports_presolve) {
715 if (GetParam().supports_initial_basis) {
718 for (
int i = 1; i < n; ++i) {
725 ASSERT_OK(incremental_solver->Solve(args));
730 incremental_solver->Solve(args));
731 if (GetParam().primal_solution_status_always_set) {
739 if (GetParam().supports_basis) {
740 EXPECT_TRUE(result.has_basis());
741 EXPECT_EQ(result.solutions[0].basis->constraint_status.at(
c),
744 LOG(INFO) <<
"Skipping basis check as solver does not return a basis.";
746 int variable_values_at_two = 0;
747 ASSERT_FALSE(result.solutions.empty());
748 ASSERT_TRUE(result.solutions[0].primal_solution.has_value());
749 ASSERT_TRUE(result.solutions[0].dual_solution.has_value());
750 EXPECT_NEAR(result.solutions[0].dual_solution->dual_values.at(
c), 0.0,
752 for (
int i = 0; i < n; ++i) {
753 SCOPED_TRACE(absl::StrCat(i));
754 const double variable_value =
755 result.solutions[0].primal_solution->variable_values.at(
x[i]);
756 const double reduced_cost =
757 result.solutions[0].dual_solution->reduced_costs.at(
x[i]);
765 if (std::abs(variable_value - 2.0) <=
kTolerance) {
766 ++variable_values_at_two;
767 if (GetParam().supports_basis && result.has_basis()) {
768 EXPECT_EQ(result.solutions[0].basis->variable_status.at(
x[i]),
772 if (GetParam().supports_basis && result.has_basis()) {
773 EXPECT_EQ(result.solutions[0].basis->variable_status.at(
x[i]),
778 EXPECT_GT(variable_values_at_two, 0);
779 EXPECT_LT(variable_values_at_two, n);
784 if (GetParam().primal_solution_status_always_set) {
785 EXPECT_EQ(result.solutions[0].primal_solution->feasibility_status,
788 EXPECT_NE(result.solutions[0].primal_solution->feasibility_status,
791 if (GetParam().check_primal_objective) {
792 EXPECT_NEAR(2 * variable_values_at_two,
793 result.solutions[0].primal_solution->objective_value,
796 LOG(INFO) <<
"Skipping primal objective check as solver does not "
797 "reliably support it for incomplete solves.";
843 !GetParam().supports_iteration_limit ||
844 !GetParam().supports_initial_basis) {
846 <<
"Ignoring this test as it requires support for dual simplex, "
847 "iteration limit and initial basis.";
850 Model model(
"Dual Feasible Incomplete Solve LP");
851 std::vector<Variable>
x;
852 std::vector<LinearConstraint>
c;
853 for (
int i = 0; i < n; ++i) {
854 x.push_back(
model.AddContinuousVariable(0.0, 2.0));
855 c.push_back(
model.AddLinearConstraint(
x[i] <= 1));
861 if (GetParam().supports_presolve) {
865 for (
int i = 0; i < n; ++i) {
877 if (GetParam().supports_basis) {
878 EXPECT_TRUE(result.has_basis());
880 LOG(INFO) <<
"Skipping basis check as solver does not return a basis.";
882 int variable_values_at_two = 0;
883 ASSERT_FALSE(result.solutions.empty());
884 ASSERT_TRUE(result.solutions[0].primal_solution.has_value());
885 ASSERT_TRUE(result.solutions[0].dual_solution.has_value());
886 for (
int i = 0; i < n; ++i) {
887 SCOPED_TRACE(absl::StrCat(i));
888 const double variable_value =
889 result.solutions[0].primal_solution->variable_values.at(
x[i]);
890 const double reduced_cost =
891 result.solutions[0].dual_solution->reduced_costs.at(
x[i]);
892 const double dual_value =
893 result.solutions[0].dual_solution->dual_values.at(
c[i]);
894 if (std::abs(variable_value - 2.0) <=
kTolerance) {
897 ++variable_values_at_two;
898 if (GetParam().supports_basis && result.has_basis()) {
899 EXPECT_EQ(result.solutions[0].basis->variable_status.at(
x[i]),
901 EXPECT_EQ(result.solutions[0].basis->constraint_status.at(
c[i]),
908 if (GetParam().supports_basis && result.has_basis()) {
909 EXPECT_EQ(result.solutions[0].basis->variable_status.at(
x[i]),
911 EXPECT_EQ(result.solutions[0].basis->constraint_status.at(
c[i]),
916 EXPECT_GT(variable_values_at_two, 0);
917 EXPECT_LT(variable_values_at_two, n);
918 if (GetParam().primal_solution_status_always_set) {
919 EXPECT_EQ(result.solutions[0].primal_solution->feasibility_status,
922 EXPECT_NE(result.solutions[0].primal_solution->feasibility_status,
925 if (GetParam().dual_solution_status_always_set) {
926 EXPECT_EQ(result.solutions[0].dual_solution->feasibility_status,
929 EXPECT_NE(result.solutions[0].dual_solution->feasibility_status,
932 if (GetParam().check_primal_objective) {
933 EXPECT_NEAR(2 * variable_values_at_two + 1 * (n - variable_values_at_two),
934 result.solutions[0].primal_solution->objective_value,
937 LOG(INFO) <<
"Skipping primal objective check as solver does not "
938 "reliably support it for incomplete solves.";
950 !GetParam().supports_iteration_limit ||
951 !GetParam().supports_incremental_solve) {
953 <<
"Ignoring this test as it requires support for dual simplex, "
954 "iteration limit and incremental solves.";
957 Model model(
"dual Feasible Incomplete Solve LP");
958 std::vector<Variable>
x;
959 for (
int i = 0; i < n; ++i) {
960 x.push_back(
model.AddContinuousVariable(0.0, 2.0));
964 const std::unique_ptr<IncrementalSolver> incremental_solver,
969 std::vector<LinearConstraint>
c;
970 for (
int i = 0; i < n; ++i) {
971 c.push_back(
model.AddLinearConstraint(
x[i] <= 1));
975 if (GetParam().supports_presolve) {
981 incremental_solver->Solve(args));
985 if (GetParam().supports_basis) {
986 EXPECT_TRUE(result.has_basis());
988 LOG(INFO) <<
"Skipping basis check as solver does not return a basis.";
991 int variable_values_at_two = 0;
992 ASSERT_FALSE(result.solutions.empty());
993 ASSERT_TRUE(result.solutions[0].primal_solution.has_value());
994 ASSERT_TRUE(result.solutions[0].dual_solution.has_value());
995 for (
int i = 0; i < n; ++i) {
996 double variable_value =
997 result.solutions[0].primal_solution->variable_values.at(
x[i]);
998 double reduced_cost =
999 result.solutions[0].dual_solution->reduced_costs.at(
x[i]);
1000 double dual_value = result.solutions[0].dual_solution->dual_values.at(
c[i]);
1001 if (std::abs(variable_value - 2.0) <=
kTolerance) {
1004 ++variable_values_at_two;
1005 if (GetParam().supports_basis && result.has_basis()) {
1006 EXPECT_EQ(result.solutions[0].basis->variable_status.at(
x[i]),
1008 EXPECT_EQ(result.solutions[0].basis->constraint_status.at(
c[i]),
1012 EXPECT_NEAR(variable_value, 1.0,
kTolerance);
1015 if (GetParam().supports_basis && result.has_basis()) {
1016 EXPECT_EQ(result.solutions[0].basis->variable_status.at(
x[i]),
1018 EXPECT_EQ(result.solutions[0].basis->constraint_status.at(
c[i]),
1023 EXPECT_GT(variable_values_at_two, 0);
1024 EXPECT_LT(variable_values_at_two, n);
1025 if (GetParam().primal_solution_status_always_set) {
1026 EXPECT_EQ(result.solutions[0].primal_solution->feasibility_status,
1029 EXPECT_NE(result.solutions[0].primal_solution->feasibility_status,
1032 if (GetParam().dual_solution_status_always_set) {
1033 EXPECT_EQ(result.solutions[0].dual_solution->feasibility_status,
1036 EXPECT_NE(result.solutions[0].dual_solution->feasibility_status,
1039 if (GetParam().check_primal_objective) {
1040 EXPECT_NEAR(2 * variable_values_at_two + 1 * (n - variable_values_at_two),
1041 result.solutions[0].primal_solution->objective_value,
1044 LOG(INFO) <<
"Skipping primal objective check as solver does not "
1045 "reliably support it for incomplete solves.";
1094 !GetParam().supports_iteration_limit ||
1095 !GetParam().supports_initial_basis) {
1097 <<
"Ignoring this test as it requires support for dual simplex, "
1098 "iteration limit and initial basis.";
1101 Model model(
"Dual Phase I Incomplete Solve LP");
1102 std::vector<Variable>
x;
1103 std::vector<LinearConstraint>
c;
1104 for (
int i = 0; i < n; ++i) {
1105 x.push_back(
model.AddContinuousVariable(0.0,
kInf));
1106 c.push_back(
model.AddLinearConstraint(
x[i] <= 1));
1110 const std::unique_ptr<IncrementalSolver> incremental_solver,
1114 if (GetParam().supports_presolve) {
1118 Basis initial_basis;
1119 for (
int i = 0; i < n; ++i) {
1128 incremental_solver->Solve(args));
1132 ASSERT_FALSE(result.solutions.empty());
1133 ASSERT_TRUE(result.solutions[0].primal_solution.has_value());
1134 ASSERT_TRUE(result.solutions[0].dual_solution.has_value());
1135 bool primal_feasible =
true;
1136 bool dual_feasible =
true;
1137 int variable_values_at_one = 0;
1138 for (
int i = 0; i < n; ++i) {
1139 SCOPED_TRACE(absl::StrCat(i));
1140 const double variable_value =
1141 result.solutions[0].primal_solution->variable_values.at(
x[i]);
1142 const double reduced_cost =
1143 result.solutions[0].dual_solution->reduced_costs.at(
x[i]);
1144 const double dual_value =
1145 result.solutions[0].dual_solution->dual_values.at(
c[i]);
1146 if (std::abs(variable_value - 1.0) <=
kTolerance) {
1147 ++variable_values_at_one;
1150 if (GetParam().supports_basis) {
1151 EXPECT_EQ(result.solutions[0].basis->variable_status.at(
x[i]),
1153 EXPECT_EQ(result.solutions[0].basis->constraint_status.at(
c[i]),
1156 }
else if (std::abs(variable_value) <=
kTolerance) {
1157 dual_feasible =
false;
1160 if (GetParam().supports_basis) {
1161 ASSERT_TRUE(result.has_basis());
1162 EXPECT_EQ(result.solutions[0].basis->variable_status.at(
x[i]),
1164 EXPECT_EQ(result.solutions[0].basis->constraint_status.at(
c[i]),
1168 EXPECT_THAT(variable_value, AnyOf(Lt(0.0), Gt(1.0)));
1169 primal_feasible =
false;
1171 dual_feasible =
false;
1178 EXPECT_EQ(result.solutions[0].basis->variable_status.at(
x[i]),
1183 EXPECT_FALSE(dual_feasible);
1184 EXPECT_GT(variable_values_at_one, 0);
1185 EXPECT_LT(variable_values_at_one, n);
1186 if (GetParam().supports_basis) {
1187 ASSERT_TRUE(result.has_basis());
1188 if (!dual_feasible) {
1189 if (GetParam().dual_solution_status_always_set) {
1190 EXPECT_EQ(result.solutions[0].basis->basic_dual_feasibility,
1193 EXPECT_NE(result.solutions[0].basis->basic_dual_feasibility,
1198 LOG(INFO) <<
"Skipping basis check as solver does not return a basis.";
1200 if (primal_feasible) {
1201 EXPECT_NE(result.solutions[0].primal_solution->feasibility_status,
1204 EXPECT_NE(result.solutions[0].primal_solution->feasibility_status,
1207 EXPECT_NE(result.solutions[0].dual_solution->feasibility_status,
EXPECT_THAT(ComputeInfeasibleSubsystem(model, GetParam().solver_type), IsOkAndHolds(IsInfeasible(true, ModelSubset{ .variable_bounds={{x, ModelSubset::Bounds{.lower=false,.upper=true}}},.linear_constraints={ {c, ModelSubset::Bounds{.lower=true,.upper=false}}}})))
TEST_P(InfeasibleSubsystemTest, CanComputeInfeasibleSubsystem)
SolverType
The solvers supported by MathOpt.
ASSERT_THAT(solver->Update(), IsOkAndHolds(DidUpdate()))
LinearExpression Sum(const Iterable &items)
absl::StatusOr< SolveResult > Solve(const Model &model, const SolverType solver_type, const SolveArguments &solve_args, const SolverInitArguments &init_args)
std::ostream & operator<<(std::ostream &ostr, const IndicatorConstraint &constraint)
absl::StatusOr< std::unique_ptr< IncrementalSolver > > NewIncrementalSolver(Model *model, SolverType solver_type, SolverInitArguments arguments)
@ kFeasible
Solver claims the solution is feasible.
@ kInfeasible
Solver claims the solution is infeasible.
testing::Matcher< SolveResult > TerminatesWithReasonFeasible(const Limit expected, const bool allow_limit_undetermined)
std::unique_ptr< Model > IndependentSetCompleteGraph(const bool integer, const int n)
BasisStatus
Status of a variable/constraint in a LP basis.
@ kBasic
The variable/constraint is basic.
@ kAtLowerBound
The variable/constraint is at its lower bound (which must be finite).
@ kAtUpperBound
The variable/constraint is at its upper bound (which must be finite).
testing::Matcher< SolveResult > TerminatesWithLimit(const Limit expected, const bool allow_limit_undetermined)
constexpr double kTolerance
std::vector< typename Map::key_type > SortedKeys(const Map &map)
testing::Matcher< SolveResult > TerminatesWithReasonNoSolutionFound(const Limit expected, const bool allow_limit_undetermined)
In SWIG mode, we don't want anything besides these top-level includes.
#define ASSERT_OK(expression)
#define ASSERT_OK_AND_ASSIGN(lhs, rexpr)
LinearConstraintMap< BasisStatus > constraint_status
VariableMap< BasisStatus > variable_status
Parameters for the LpIncompleteSolveTest suite below.
bool supports_presolve
Indicates if the solver supports setting the presolve emphasis.
SolverType solver_type
The tested solver.
LpIncompleteSolveTestParams(SolverType solver_type, std::optional< LPAlgorithm > lp_algorithm, bool supports_iteration_limit, bool supports_initial_basis, bool supports_incremental_solve, bool supports_basis, bool supports_presolve, bool check_primal_objective, bool primal_solution_status_always_set, bool dual_solution_status_always_set)
bool supports_iteration_limit
Indicates if the solver supports iteration limit.
bool supports_basis
Indicates if the solver supports returning a basis.
bool dual_solution_status_always_set
bool check_primal_objective
Indicates if we should check primal objective values.
bool primal_solution_status_always_set
std::optional< LPAlgorithm > lp_algorithm
The tested algorithm.
bool supports_incremental_solve
Indicates if the solver supports incremental solves.
bool supports_initial_basis
Indicates if the solver supports initial basis.
std::optional< Basis > initial_basis
ModelSolveParameters model_parameters
Model dependent parameters, e.g. solution hint.
SolveParameters parameters
Model independent parameters, e.g. time limit.
std::optional< LPAlgorithm > lp_algorithm
std::optional< int32_t > threads
If unset, use the solver default. If set, it must be >= 1.
std::optional< int64_t > iteration_limit
std::optional< Emphasis > presolve