20#include "absl/status/status.h"
21#include "absl/strings/string_view.h"
22#include "gtest/gtest.h"
60 <<
", supports_integer_variables: "
62 <<
", supports_sos1: " << (params.
supports_sos1 ?
"true" :
"false")
63 <<
", supports_sos2: " << (params.
supports_sos2 ?
"true" :
"false")
64 <<
", supports_indicator_constraints: "
66 <<
", supports_incremental_add_and_deletes: "
68 <<
", supports_incremental_variable_deletions: "
70 <<
", supports_deleting_indicator_variables: "
72 <<
", supports_updating_binary_variables: "
74 <<
", supports_sos_on_expressions: "
81using ::testing::AnyOf;
82using ::testing::HasSubstr;
83using ::testing::status::IsOkAndHolds;
84using ::testing::status::StatusIs;
86constexpr absl::string_view no_sos1_support_message =
87 "This test is disabled as the solver does not support sos1 constraints";
88constexpr absl::string_view no_sos2_support_message =
89 "This test is disabled as the solver does not support sos2 constraints";
90constexpr absl::string_view no_indicator_support_message =
91 "This test is disabled as the solver does not support indicator "
93constexpr absl::string_view no_updating_binary_variables_message =
94 "This test is disabled as the solver does not support updating "
96constexpr absl::string_view no_deleting_indicator_variables_message =
97 "This test is disabled as the solver does not support deleting "
98 "indicator variables";
99constexpr absl::string_view no_incremental_add_and_deletes_message =
100 "This test is disabled as the solver does not support incremental "
104TEST_P(SimpleLogicalConstraintTest, CanBuildSos1Model) {
105 if (!GetParam().supports_sos_on_expressions) {
106 GTEST_SKIP() <<
"skipped since SOS on expressions are not supported";
109 const Variable x = model.AddContinuousVariable(0.0, 1.0,
"x");
110 model.AddSos1Constraint({3.0 *
x + 2.0}, {3.0});
111 model.AddSos1Constraint({2.0 *
x + 1.0}, {});
112 if (GetParam().supports_sos1) {
116 StatusIs(AnyOf(absl::StatusCode::kInvalidArgument,
117 absl::StatusCode::kUnimplemented),
118 HasSubstr(
"sos1 constraints")));
124 if (!GetParam().supports_sos_on_expressions) {
125 GTEST_SKIP() <<
"skipped since SOS on expressions are not supported";
128 const Variable x = model.AddContinuousVariable(0.0, 1.0,
"x");
129 model.AddSos2Constraint({3.0 *
x + 2.0}, {3.0});
130 model.AddSos2Constraint({2.0 *
x + 1.0}, {});
131 if (GetParam().supports_sos2) {
135 StatusIs(AnyOf(absl::StatusCode::kInvalidArgument,
136 absl::StatusCode::kUnimplemented),
137 HasSubstr(
"sos2 constraints")));
149 if (!GetParam().supports_sos1) {
150 GTEST_SKIP() << no_sos1_support_message;
153 const Variable x = model.AddContinuousVariable(0.0, 1.0,
"x");
154 const Variable y = model.AddContinuousVariable(0.0, 1.0,
"y");
156 model.AddSos1Constraint({
x, y}, {});
170 if (!GetParam().supports_sos2) {
171 GTEST_SKIP() << no_sos2_support_message;
174 const Variable x = model.AddContinuousVariable(0.0, 1.0,
"x");
175 const Variable y = model.AddContinuousVariable(0.0, 1.0,
"y");
176 const Variable z = model.AddContinuousVariable(0.0, 1.0,
"z");
177 model.
Maximize(2.0 *
x + 1.0 * y + 3.0 * z);
178 model.AddSos2Constraint({
x, y, z}, {});
181 4.0, {{
x, 0.0}, {y, 1.0}, {z, 1.0}})));
193 if (!GetParam().supports_sos1) {
194 GTEST_SKIP() << no_sos1_support_message;
196 if (!GetParam().supports_sos2) {
197 GTEST_SKIP() << no_sos2_support_message;
200 const Variable x = model.AddContinuousVariable(0.0, 1.0,
"x");
201 const Variable y = model.AddContinuousVariable(0.0, 1.0,
"y");
202 const Variable z = model.AddContinuousVariable(0.0, 1.0,
"z");
203 model.
Maximize(2.0 *
x + 1.5 * y + 3.0 * z);
204 model.AddSos1Constraint({y, z}, {});
205 model.AddSos2Constraint({
x, y, z}, {});
208 3.5, {{
x, 1.0}, {y, 1.0}, {z, 0.0}})));
219 if (!GetParam().supports_sos1) {
220 GTEST_SKIP() << no_sos1_support_message;
223 const Variable x = model.AddContinuousVariable(0.0, 1.0,
"x");
224 const Variable y = model.AddContinuousVariable(0.0, 1.0,
"y");
226 model.AddSos1Constraint({2 *
x - 1, y - 0.75}, {});
240 if (!GetParam().supports_sos2) {
241 GTEST_SKIP() << no_sos2_support_message;
244 const Variable x = model.AddContinuousVariable(-1.0, 1.0,
"x");
245 const Variable y = model.AddContinuousVariable(-1.0, 1.0,
"y");
246 const Variable z = model.AddContinuousVariable(-1.0, 1.0,
"z");
248 model.AddSos2Constraint({2 *
x + 1, 8 * y + 1, 4 * z + 1}, {});
251 1.75, {{
x, 1.0}, {y, 1.0}, {z, -0.25}})));
262 if (!GetParam().supports_sos1) {
263 GTEST_SKIP() << no_sos2_support_message;
266 const Variable x = model.AddContinuousVariable(-1.0, 1.0,
"x");
268 model.AddSos1Constraint({
x,
x});
282 if (!GetParam().supports_sos2) {
283 GTEST_SKIP() << no_sos2_support_message;
286 const Variable x = model.AddContinuousVariable(-1.0, 1.0,
"x");
288 model.AddSos2Constraint({
x, 0.0,
x});
306 if (!GetParam().supports_incremental_add_and_deletes) {
307 GTEST_SKIP() << no_incremental_add_and_deletes_message;
310 const Variable x = model.AddContinuousVariable(0.0, 1.0,
"x");
311 const Variable y = model.AddContinuousVariable(0.0, 1.0,
"y");
317 ASSERT_THAT(solver->Solve({.parameters = GetParam().parameters}),
320 model.AddSos1Constraint({
x, y}, {});
322 if (!GetParam().supports_sos1) {
331 StatusIs(AnyOf(absl::StatusCode::kInvalidArgument,
332 absl::StatusCode::kUnimplemented),
333 AllOf(HasSubstr(
"sos1 constraint"),
335 Not(HasSubstr(
"update failed")),
337 HasSubstr(
"solver re-creation failed"))));
340 ASSERT_THAT(solver->Update(),
341 IsOkAndHolds(GetParam().supports_incremental_add_and_deletes
344 EXPECT_THAT(solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
360 if (!GetParam().supports_incremental_add_and_deletes) {
361 GTEST_SKIP() << no_incremental_add_and_deletes_message;
364 const Variable x = model.AddContinuousVariable(0.0, 1.0,
"x");
365 const Variable y = model.AddContinuousVariable(0.0, 1.0,
"y");
366 const Variable z = model.AddContinuousVariable(0.0, 1.0,
"z");
367 model.
Maximize(2.0 *
x + 1.0 * y + 3.0 * z);
373 solver->Solve({.parameters = GetParam().parameters}),
376 model.AddSos2Constraint({
x, y, z}, {});
378 if (!GetParam().supports_sos2) {
387 StatusIs(AnyOf(absl::StatusCode::kInvalidArgument,
388 absl::StatusCode::kUnimplemented),
389 AllOf(HasSubstr(
"sos2 constraint"),
391 Not(HasSubstr(
"update failed")),
393 HasSubstr(
"solver re-creation failed"))));
396 ASSERT_THAT(solver->Update(),
397 IsOkAndHolds(GetParam().supports_incremental_add_and_deletes
401 solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
422 if (!GetParam().supports_sos1) {
423 GTEST_SKIP() << no_sos1_support_message;
426 const Variable x = model.AddContinuousVariable(0.0, 1.0,
"x");
427 const Variable y = model.AddContinuousVariable(0.0, 1.0,
"y");
429 model.AddLinearConstraint(
x + y <= 1);
430 const Sos1Constraint c = model.AddSos1Constraint({2 *
x - 1, 4 * y - 3}, {});
435 ASSERT_THAT(solver->Solve({.parameters = GetParam().parameters}),
438 model.DeleteSos1Constraint(
c);
440 ASSERT_THAT(solver->Update(),
441 IsOkAndHolds(GetParam().supports_incremental_add_and_deletes
444 EXPECT_THAT(solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
466 if (!GetParam().supports_sos2) {
467 GTEST_SKIP() << no_sos1_support_message;
470 const Variable x = model.AddContinuousVariable(0.0, 1.0,
"x");
471 const Variable y = model.AddContinuousVariable(0.0, 1.0,
"y");
472 const Variable z = model.AddContinuousVariable(0.0, 1.0,
"z");
474 model.AddLinearConstraint(
x + y + z <= 2);
476 model.AddSos2Constraint({2 *
x - 1, 8 * y - 1, 4 * z - 1}, {});
482 solver->Solve({.parameters = GetParam().parameters}),
485 model.DeleteSos2Constraint(
c);
487 ASSERT_THAT(solver->Update(),
488 IsOkAndHolds(GetParam().supports_incremental_add_and_deletes
492 solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
514 UpdateDeletesVariableInSos1Constraint) {
515 if (!GetParam().supports_sos1) {
516 GTEST_SKIP() << no_sos1_support_message;
519 const Variable x = model.AddContinuousVariable(0.0, 1.0,
"x");
520 const Variable y = model.AddContinuousVariable(0.0, 1.0,
"y");
521 const Variable z = model.AddContinuousVariable(0.0, 1.0,
"z");
522 const Variable w = model.AddContinuousVariable(0.0, 1.0,
"w");
524 model.AddSos1Constraint({
x, y +
w, z}, {});
529 ASSERT_THAT(solver->Solve({.parameters = GetParam().parameters}),
531 3.0, {{
x, 0.0}, {y, 1.0}, {z, 0.0}, {
w, 1.0}})));
533 model.DeleteVariable(y);
535 ASSERT_THAT(solver->Update(),
536 IsOkAndHolds(GetParam().supports_incremental_variable_deletions
540 solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
562 UpdateDeletesVariableInSos2Constraint) {
563 if (!GetParam().supports_sos2) {
564 GTEST_SKIP() << no_sos2_support_message;
567 const Variable x = model.AddContinuousVariable(0.0, 1.0,
"x");
568 const Variable y = model.AddContinuousVariable(0.0, 1.0,
"y");
569 const Variable z = model.AddContinuousVariable(0.0, 1.0,
"z");
570 const Variable w = model.AddContinuousVariable(0.0, 1.0,
"w");
571 model.
Maximize(2.0 *
x + 2.0 * y + 2.0 * z +
w);
572 model.AddSos2Constraint({
x, y, z +
w}, {});
577 ASSERT_THAT(solver->Solve({.parameters = GetParam().parameters}),
579 5.0, {{
x, 0.0}, {y, 1.0}, {z, 1.0}, {
w, 1.0}})));
581 model.DeleteVariable(z);
583 ASSERT_THAT(solver->Update(),
584 IsOkAndHolds(GetParam().supports_incremental_variable_deletions
588 solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
609 if (!GetParam().supports_sos1) {
610 GTEST_SKIP() << no_sos1_support_message;
612 if (!GetParam().supports_sos2) {
613 GTEST_SKIP() << no_sos2_support_message;
616 const Variable x = model.AddContinuousVariable(0.0, 1.0,
"x");
617 const Variable y = model.AddContinuousVariable(0.0, 1.0,
"y");
618 const Variable z = model.AddContinuousVariable(0.0, 1.0,
"z");
619 model.
Maximize(2.0 *
x + 1.5 * y + 3.0 * z);
621 model.AddSos2Constraint({
x, y, z}, {});
627 solver->Solve({.parameters = GetParam().parameters}),
630 model.DeleteSos1Constraint(
c);
632 ASSERT_THAT(solver->Update(),
633 IsOkAndHolds(GetParam().supports_incremental_add_and_deletes
637 solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
649 const Variable x = model.AddContinuousVariable(0.0, 1.0,
"x");
650 const Variable y = model.AddContinuousVariable(0.0, 1.0,
"y");
651 model.AddIndicatorConstraint(
x, y <= 0.5);
653 if (GetParam().supports_indicator_constraints) {
657 StatusIs(AnyOf(absl::StatusCode::kInvalidArgument,
658 absl::StatusCode::kUnimplemented),
659 HasSubstr(
"indicator constraints")));
667 if (!GetParam().supports_indicator_constraints) {
668 GTEST_SKIP() << no_indicator_support_message;
671 const Variable x = model.AddContinuousVariable(0.0, 1.0,
"x");
672 const Variable y = model.AddContinuousVariable(0.0, 1.0,
"y");
673 model.AddIndicatorConstraint(
x, y >= 0.5);
676 StatusIs(absl::StatusCode::kInvalidArgument,
677 HasSubstr(
"indicator variable is not binary")));
689 if (!GetParam().supports_indicator_constraints) {
690 GTEST_SKIP() << no_indicator_support_message;
693 const Variable x = model.AddBinaryVariable(
"x");
694 const Variable y = model.AddContinuousVariable(0.0, 1.0,
"y");
696 model.AddIndicatorConstraint(
x, y >= 0.5);
711 if (!GetParam().supports_indicator_constraints) {
712 GTEST_SKIP() << no_indicator_support_message;
715 const Variable x = model.AddBinaryVariable(
"x");
716 const Variable y = model.AddContinuousVariable(0.0, 1.0,
"y");
718 model.AddIndicatorConstraint(
x, y >= 0.5,
true,
"c");
729 if (!GetParam().supports_indicator_constraints) {
730 GTEST_SKIP() << no_indicator_support_message;
733 const Variable x = model.AddBinaryVariable(
"x");
734 const Variable y = model.AddContinuousVariable(0.0, 1.0,
"y");
735 model.AddIndicatorConstraint(
x, 0.25 <= y <= 0.75);
738 StatusIs(AnyOf(absl::StatusCode::kInvalidArgument,
739 absl::StatusCode::kUnimplemented),
740 HasSubstr(
"ranged")));
755 if (!GetParam().supports_indicator_constraints) {
756 GTEST_SKIP() << no_indicator_support_message;
759 const Variable x = model.AddContinuousVariable(0.0, 1.0,
"x");
760 const Variable indicator = model.AddBinaryVariable(
"indicator");
762 model.AddIndicatorConstraint(indicator,
x == 0.5);
763 model.DeleteVariable(indicator);
785 if (!GetParam().supports_indicator_constraints) {
786 GTEST_SKIP() << no_indicator_support_message;
792 GTEST_SKIP() <<
"This test is disabled as Xpress does not support "
793 "indicator constraints on non-binary variables";
796 const Variable x = model.AddIntegerVariable(0.0, 0.0,
"x");
797 const Variable y = model.AddIntegerVariable(1.0, 1.0,
"y");
798 const Variable z = model.AddIntegerVariable(0.5, 1.0,
"z");
799 const Variable v = model.AddContinuousVariable(0.0, 1.0,
"v");
800 const Variable w = model.AddContinuousVariable(0.0, 1.0,
"w");
802 model.AddIndicatorConstraint(
x,
w >= 1.5);
803 model.AddIndicatorConstraint(y, v <= 0.6);
804 model.AddIndicatorConstraint(z,
w <= 0.4);
808 1.0, {{
x, 0.0}, {y, 1.0}, {z, 1.0}, {v, 0.6}, {
w, 0.4}})));
829 const Variable x = GetParam().supports_integer_variables
830 ? model.AddBinaryVariable(
"x")
831 : model.AddContinuousVariable(0.0, 1.0,
"x");
832 const Variable y = model.AddContinuousVariable(0.0, 1.0,
"y");
838 ASSERT_THAT(solver->Solve({.parameters = GetParam().parameters}),
841 model.AddIndicatorConstraint(
x, y <= 0.5);
843 if (!GetParam().supports_indicator_constraints) {
852 StatusIs(AnyOf(absl::StatusCode::kInvalidArgument,
853 absl::StatusCode::kUnimplemented),
854 AllOf(HasSubstr(
"indicator constraint"),
856 Not(HasSubstr(
"update failed")),
858 HasSubstr(
"solver re-creation failed"))));
861 ASSERT_THAT(solver->Update(),
862 IsOkAndHolds(GetParam().supports_incremental_add_and_deletes
865 EXPECT_THAT(solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
887 if (!GetParam().supports_indicator_constraints) {
888 GTEST_SKIP() << no_indicator_support_message;
890 if (!GetParam().supports_incremental_add_and_deletes) {
891 GTEST_SKIP() << no_incremental_add_and_deletes_message;
894 const Variable x = model.AddBinaryVariable(
"x");
895 const Variable y = model.AddContinuousVariable(0.0, 1.0,
"y");
901 ASSERT_THAT(solver->Solve({.parameters = GetParam().parameters}),
904 model.DeleteIndicatorConstraint(
c);
906 ASSERT_THAT(solver->Update(),
907 IsOkAndHolds(GetParam().supports_incremental_add_and_deletes
910 EXPECT_THAT(solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
932 UpdateDeletesIndicatorConstraintWithUnsetIndicatorVariable) {
933 if (!GetParam().supports_indicator_constraints) {
934 GTEST_SKIP() << no_indicator_support_message;
936 if (!GetParam().supports_incremental_add_and_deletes) {
937 GTEST_SKIP() << no_incremental_add_and_deletes_message;
940 const Variable x = model.AddContinuousVariable(0.0, 1.0,
"x");
941 const Variable indicator = model.AddBinaryVariable(
"indicator");
944 model.AddIndicatorConstraint(indicator,
x <= 0.5);
945 model.DeleteVariable(indicator);
950 ASSERT_THAT(solver->Solve({.parameters = GetParam().parameters}),
953 model.DeleteIndicatorConstraint(
c);
955 ASSERT_THAT(solver->Update(),
956 IsOkAndHolds(GetParam().supports_incremental_add_and_deletes
959 EXPECT_THAT(solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
980 if (!GetParam().supports_indicator_constraints) {
981 GTEST_SKIP() << no_indicator_support_message;
983 if (!GetParam().supports_deleting_indicator_variables) {
984 GTEST_SKIP() << no_deleting_indicator_variables_message;
987 const Variable x = model.AddBinaryVariable(
"x");
988 const Variable y = model.AddContinuousVariable(0.0, 1.0,
"y");
990 model.AddIndicatorConstraint(
x, y <= 0.5);
995 ASSERT_THAT(solver->Solve({.parameters = GetParam().parameters}),
998 model.DeleteVariable(
x);
1000 ASSERT_THAT(solver->Update(),
1001 IsOkAndHolds(GetParam().supports_deleting_indicator_variables
1004 EXPECT_THAT(solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
1029 UpdateDeletesVariableInImpliedExpression) {
1030 if (!GetParam().supports_indicator_constraints) {
1031 GTEST_SKIP() << no_indicator_support_message;
1034 const Variable x = model.AddBinaryVariable(
"x");
1035 const Variable y = model.AddContinuousVariable(0.0, 1.0,
"y");
1036 const Variable z = model.AddContinuousVariable(0.0, 1.0,
"z");
1038 model.AddIndicatorConstraint(
x, y <= 0.5);
1039 model.AddIndicatorConstraint(
x, z <= 0.5);
1045 solver->Solve({.parameters = GetParam().parameters}),
1048 model.DeleteVariable(y);
1050 ASSERT_THAT(solver->Update(),
1051 IsOkAndHolds(GetParam().supports_incremental_variable_deletions
1054 EXPECT_THAT(solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
1062 UpdateMakesIndicatorVariableTypeInvalid) {
1063 if (!GetParam().supports_indicator_constraints) {
1064 GTEST_SKIP() << no_indicator_support_message;
1066 if (!GetParam().supports_updating_binary_variables) {
1067 GTEST_SKIP() << no_updating_binary_variables_message;
1070 const Variable x = model.AddBinaryVariable(
"x");
1071 const Variable y = model.AddContinuousVariable(0.0, 1.0,
"y");
1072 model.AddIndicatorConstraint(
x, y <= 0.5);
1077 ASSERT_OK(solver->Solve({.parameters = GetParam().parameters}));
1079 model.set_continuous(
x);
1081 ASSERT_THAT(solver->Update(),
1082 IsOkAndHolds(GetParam().supports_updating_binary_variables
1085 EXPECT_THAT(solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
1086 StatusIs(absl::StatusCode::kInvalidArgument,
1087 HasSubstr(
"indicator variable is not binary")));
1113 if (!GetParam().supports_indicator_constraints) {
1114 GTEST_SKIP() << no_indicator_support_message;
1116 if (!GetParam().supports_updating_binary_variables) {
1117 GTEST_SKIP() << no_updating_binary_variables_message;
1120 const Variable x = model.AddIntegerVariable(0.0, 1.0,
"x");
1121 const Variable y = model.AddIntegerVariable(0.0, 1.0,
"y");
1122 const Variable u = model.AddContinuousVariable(0.0, 1.0,
"u");
1123 const Variable v = model.AddContinuousVariable(0.0, 1.0,
"z");
1125 model.AddLinearConstraint(
x + y == 1.0);
1126 model.AddIndicatorConstraint(
x, u <= 0.6);
1127 model.AddIndicatorConstraint(y, v <= 0.4);
1132 EXPECT_THAT(solver->Solve({.parameters = GetParam().parameters}),
1134 1.6, {{
x, 1.0}, {y, 0.0}, {u, 0.6}, {v, 1.0}})));
1136 model.set_lower_bound(
x, 0.0);
1137 model.set_upper_bound(
x, 0.0);
1139 ASSERT_THAT(solver->Update(),
1140 IsOkAndHolds(GetParam().supports_updating_binary_variables
1143 EXPECT_THAT(solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
1145 1.4, {{
x, 0.0}, {y, 1.0}, {u, 1.0}, {v, 0.4}})));
1147 model.set_lower_bound(
x, 0.5);
1148 model.set_upper_bound(
x, 1.0);
1149 model.set_lower_bound(y, 0.0);
1150 model.set_upper_bound(y, 0.5);
1152 ASSERT_THAT(solver->Update(),
1153 IsOkAndHolds(GetParam().supports_updating_binary_variables
1156 EXPECT_THAT(solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
1158 1.6, {{
x, 1.0}, {y, 0.0}, {u, 0.6}, {v, 1.0}})));
1160 model.set_lower_bound(
x, 0.0);
1161 model.set_upper_bound(
x, 1.0);
1162 model.set_lower_bound(y, 1.0);
1163 model.set_upper_bound(y, 1.0);
1165 ASSERT_THAT(solver->Update(),
1166 IsOkAndHolds(GetParam().supports_updating_binary_variables
1169 EXPECT_THAT(solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
1171 1.4, {{
x, 0.0}, {y, 1.0}, {u, 1.0}, {v, 0.4}})));
1179 UpdateMakesIndicatorVariableBoundsInvalid) {
1180 if (!GetParam().supports_indicator_constraints) {
1181 GTEST_SKIP() << no_indicator_support_message;
1183 if (!GetParam().supports_updating_binary_variables) {
1184 GTEST_SKIP() << no_updating_binary_variables_message;
1187 const Variable x = model.AddIntegerVariable(0.0, 1.0,
"x");
1188 const Variable y = model.AddContinuousVariable(0.0, 1.0,
"y");
1189 model.AddIndicatorConstraint(
x, y <= 0.5);
1194 ASSERT_OK(solver->Solve({.parameters = GetParam().parameters}));
1196 model.set_upper_bound(
x, 2.0);
1198 ASSERT_THAT(solver->Update(),
1199 IsOkAndHolds(GetParam().supports_updating_binary_variables
1202 EXPECT_THAT(solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
1203 StatusIs(absl::StatusCode::kInvalidArgument,
1204 HasSubstr(
"indicator variable is not binary")));
void Maximize(Variable *obj, std::vector< Annotation > search_annotations)
void Minimize(Variable *obj, std::vector< Annotation > search_annotations)
#define ASSERT_OK(expression)
#define EXPECT_OK(expression)
#define ASSERT_OK_AND_ASSIGN(lhs, rexpr)
Matcher< SolveResult > IsOptimalWithSolution(const double expected_objective, const VariableMap< double > expected_variable_values, const double tolerance)
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)
<=x<=1 IncrementalMipTest::IncrementalMipTest() :model_("incremental_solve_test"), x_(model_.AddContinuousVariable(0.0, 1.0, "x")), y_(model_.AddIntegerVariable(0.0, 2.0, "y")), c_(model_.AddLinearConstraint(0<=x_+y_<=1.5, "c")) { model_.Maximize(3.0 *x_+2.0 *y_+0.1);solver_=NewIncrementalSolver(&model_, TestedSolver()).value();const SolveResult first_solve=solver_->Solve().value();CHECK(first_solve.has_primal_feasible_solution());CHECK_LE(std::abs(first_solve.objective_value() - 3.6), kTolerance)<< first_solve.objective_value();} namespace { TEST_P(SimpleMipTest, OneVarMax) { Model model;const Variable x=model.AddVariable(0.0, 4.0, false, "x");model.Maximize(2.0 *x);ASSERT_OK_AND_ASSIGN(const SolveResult result, Solve(model, GetParam().solver_type));ASSERT_THAT(result, IsOptimal(8.0));EXPECT_THAT(result.variable_values(), IsNear({{x, 4.0}}));} TEST_P(SimpleMipTest, OneVarMin) { Model model;const Variable x=model.AddVariable(-2.4, 4.0, false, "x");model.Minimize(2.0 *x);ASSERT_OK_AND_ASSIGN(const SolveResult result, Solve(model, GetParam().solver_type));ASSERT_THAT(result, IsOptimal(-4.8));EXPECT_THAT(result.variable_values(), IsNear({{x, -2.4}}));} TEST_P(SimpleMipTest, OneIntegerVar) { Model model;const Variable x=model.AddVariable(0.0, 4.5, true, "x");model.Maximize(2.0 *x);ASSERT_OK_AND_ASSIGN(const SolveResult result, Solve(model, GetParam().solver_type));ASSERT_THAT(result, IsOptimal(8.0));EXPECT_THAT(result.variable_values(), IsNear({{x, 4.0}}));} TEST_P(SimpleMipTest, SimpleLinearConstraint) { Model model;const Variable x=model.AddBinaryVariable("x");const Variable y=model.AddBinaryVariable("y");model.Maximize(2.0 *x+y);model.AddLinearConstraint(0.0<=x+y<=1.5, "c");ASSERT_OK_AND_ASSIGN(const SolveResult result, Solve(model, GetParam().solver_type));ASSERT_THAT(result, IsOptimal(2.0));EXPECT_THAT(result.variable_values(), IsNear({{x, 1}, {y, 0}}));} TEST_P(SimpleMipTest, Unbounded) { Model model;const Variable x=model.AddVariable(0.0, kInf, true, "x");model.Maximize(2.0 *x);ASSERT_OK_AND_ASSIGN(const SolveResult result, Solve(model, GetParam().solver_type));if(GetParam().report_unboundness_correctly) { ASSERT_THAT(result, TerminatesWithOneOf({TerminationReason::kUnbounded, TerminationReason::kInfeasibleOrUnbounded}));} else { ASSERT_THAT(result, TerminatesWith(TerminationReason::kOtherError));} } TEST_P(SimpleMipTest, Infeasible) { Model model;const Variable x=model.AddVariable(0.0, 3.0, true, "x");model.Maximize(2.0 *x);model.AddLinearConstraint(x >=4.0);ASSERT_OK_AND_ASSIGN(const SolveResult result, Solve(model, GetParam().solver_type));ASSERT_THAT(result, TerminatesWith(TerminationReason::kInfeasible));} TEST_P(SimpleMipTest, FractionalBoundsContainNoInteger) { if(GetParam().solver_type==SolverType::kGurobi) { GTEST_SKIP()<< "TODO(b/272298816): Gurobi bindings are broken here.";} if(GetParam().solver_type==SolverType::kXpress) { GTEST_SKIP()<< "Xpress does not support contradictory bounds.";} Model model;const Variable x=model.AddIntegerVariable(0.5, 0.6, "x");model.Maximize(x);EXPECT_THAT(Solve(model, GetParam().solver_type), IsOkAndHolds(TerminatesWith(TerminationReason::kInfeasible)));} TEST_P(IncrementalMipTest, EmptyUpdate) { ASSERT_THAT(solver_->Update(), IsOkAndHolds(DidUpdate()));ASSERT_OK_AND_ASSIGN(const SolveResult result, solver_->SolveWithoutUpdate());ASSERT_THAT(result, IsOptimal(3.6));EXPECT_THAT(result.variable_values(), IsNear({{x_, 0.5}, {y_, 1.0}}));} TEST_P(IncrementalMipTest, MakeContinuous) { model_.set_continuous(y_);ASSERT_THAT(solver_->Update(), IsOkAndHolds(DidUpdate()));ASSERT_OK_AND_ASSIGN(const SolveResult result, solver_->SolveWithoutUpdate());ASSERT_THAT(result, IsOptimal(4.1));EXPECT_THAT(result.variable_values(), IsNear({{x_, 1.0}, {y_, 0.5}}));} TEST_P(IncrementalMipTest, DISABLED_MakeContinuousWithNonIntegralBounds) { solver_.reset();Model model("bounds");const Variable x=model.AddIntegerVariable(0.5, 1.5, "x");model.Maximize(x);ASSERT_OK_AND_ASSIGN(const auto solver, NewIncrementalSolver(&model, TestedSolver()));ASSERT_THAT(solver->Solve(), IsOkAndHolds(IsOptimal(1.0)));model.set_continuous(x);ASSERT_THAT(solver->Update(), IsOkAndHolds(DidUpdate()));ASSERT_THAT(solver->SolveWithoutUpdate(), IsOkAndHolds(IsOptimal(1.5)));model.Minimize(x);ASSERT_THAT(solver->Update(), IsOkAndHolds(DidUpdate()));ASSERT_THAT(solver-> IsOkAndHolds(IsOptimal(0.5)))
absl::StatusOr< std::unique_ptr< IncrementalSolver > > NewIncrementalSolver(Model *model, SolverType solver_type, SolverInitArguments arguments)
std::ostream & operator<<(std::ostream &ostr, const SecondOrderConeConstraint &constraint)
Matcher< UpdateResult > DidUpdate()
std::string ProtobufShortDebugString(const P &message)
trees with all degrees equal w the current value of w
bool supports_indicator_constraints
LogicalConstraintTestParameters(SolverType solver_type, SolveParameters parameters, bool supports_integer_variables, bool supports_sos1, bool supports_sos2, bool supports_indicator_constraints, bool supports_incremental_add_and_deletes, bool supports_incremental_variable_deletions, bool supports_deleting_indicator_variables, bool supports_updating_binary_variables, bool supports_sos_on_expressions=true)
bool supports_incremental_add_and_deletes
bool supports_deleting_indicator_variables
bool supports_updating_binary_variables
bool supports_integer_variables
bool supports_incremental_variable_deletions
SolveParameters parameters
bool supports_sos_on_expressions
SolveParametersProto Proto() const