Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
second_order_cone_tests.cc
Go to the documentation of this file.
1// Copyright 2010-2025 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
15
16#include <cmath>
17#include <memory>
18#include <ostream>
19#include <utility>
20
21#include "absl/status/status.h"
22#include "absl/strings/string_view.h"
23#include "gtest/gtest.h"
24#include "ortools/base/gmock.h"
28
30
40
41std::ostream& operator<<(std::ostream& out,
42 const SecondOrderConeTestParameters& params) {
43 out << "{ solver_type: " << params.solver_type
44 << ", parameters: " << ProtobufShortDebugString(params.parameters.Proto())
45 << ", supports_soc_constraints: "
46 << (params.supports_soc_constraints ? "true" : "false")
47 << ", supports_incremental_add_and_deletes: "
48 << (params.supports_incremental_add_and_deletes ? "true" : "false");
49 return out;
50}
51
52namespace {
53
54using ::testing::AnyOf;
55using ::testing::HasSubstr;
56using ::testing::status::IsOkAndHolds;
57using ::testing::status::StatusIs;
58
59// A bit larger than expected; as of 2023-01-31 Gurobi produces slightly
60// inaccurate solutions on some of the tests.
61constexpr double kTolerance = 1.0e-3;
62constexpr absl::string_view kNoSocSupportMessage =
63 "This test is disabled as the solver does not support second-order cone "
64 "constraints";
65constexpr absl::string_view kNoIncrementalAddAndDeletes =
66 "This test is disabled as the solver does not support incremental add and "
67 "deletes";
68
69// Builds the simple (and uninteresting) SOC model:
70//
71// min 0
72// s.t. ||x||_2 <= 2x
73// 0 <= x <= 1.
74TEST_P(SimpleSecondOrderConeTest, CanBuildSecondOrderConeModel) {
75 if (GetParam().solver_type == SolverType::kXpress) {
76 // For Xpress the second order cone constraint results in
77 // x^2 - 4x^2 <= 0
78 // This has two entries for x and will thus be rejected by the library.
79 // Hence we have to skip the test.
80 GTEST_SKIP()
81 << "This test is disabled as Xpress rejects duplicate Q entries";
82 }
83 Model model;
84 const Variable x = model.AddContinuousVariable(0.0, 1.0, "x");
85 model.AddSecondOrderConeConstraint({x}, 2 * x);
86 if (GetParam().supports_soc_constraints) {
87 EXPECT_OK(NewIncrementalSolver(&model, GetParam().solver_type, {}));
88 } else {
89 EXPECT_THAT(NewIncrementalSolver(&model, GetParam().solver_type, {}),
90 StatusIs(AnyOf(absl::StatusCode::kInvalidArgument,
91 absl::StatusCode::kUnimplemented),
92 HasSubstr("second-order cone constraints")));
93 }
94}
95
96// We model the second-order cone program:
97//
98// max x + y + z
99// s.t. ||(x, 2y, 3z)||_2 <= 1
100// 0 <= x, y <= 1
101//
102// The unique optimal solution is (x*, y*, z*) = (6/7, 3/14, 2/21) with
103// objective value 7/6.
104TEST_P(SimpleSecondOrderConeTest, SolveSimpleSocModel) {
105 if (!GetParam().supports_soc_constraints) {
106 GTEST_SKIP() << kNoSocSupportMessage;
107 }
108 if (GetParam().solver_type == SolverType::kXpress) {
109 GTEST_SKIP() << "This test is disabled as Xpress only supports second "
110 "order cone constraints on singletons";
111 }
112 Model model;
113 const Variable x = model.AddContinuousVariable(0.0, 1.0, "x");
114 const Variable y = model.AddContinuousVariable(0.0, 1.0, "y");
115 const Variable z = model.AddContinuousVariable(0.0, 1.0, "z");
116 model.Maximize(x + y + z);
117 model.AddSecondOrderConeConstraint({x, 2.0 * y, 3.0 * z}, 1.0);
118 EXPECT_THAT(SimpleSolve(model),
120 7.0 / 6.0, {{x, 6.0 / 7.0}, {y, 3.0 / 14.0}, {z, 2.0 / 21.0}},
121 kTolerance)));
122}
123
124// We model the second-order cone program:
125//
126// max x + y
127// s.t. ||(x, 2y)||_2 <= 2x + 3
128// ||(2x, y)||_2 <= 2y + 3
129//
130// The unique optimal solution is (x*, y*) = (1, 1) with objective value 2.
131TEST_P(SimpleSecondOrderConeTest, SolveMultipleSocConstraintModel) {
132 if (!GetParam().supports_soc_constraints) {
133 GTEST_SKIP() << kNoSocSupportMessage;
134 }
135 if (GetParam().solver_type == SolverType::kXpress) {
136 GTEST_SKIP() << "This test is disabled as Xpress only supports second "
137 "order cone constraints on singletons";
138 }
139 Model model;
140 const Variable x = model.AddContinuousVariable(0.0, 1.0, "x");
141 const Variable y = model.AddContinuousVariable(0.0, 1.0, "y");
142 model.Maximize(x + y);
143 model.AddSecondOrderConeConstraint({x, 2.0 * y}, 2.0 * x + 3.0);
144 model.AddSecondOrderConeConstraint({2.0 * x, y}, 2.0 * y + 3.0);
145 EXPECT_THAT(SimpleSolve(model),
146 IsOkAndHolds(IsOptimalWithSolution(2.0, {{x, 1.0}, {y, 1.0}})));
147}
148
149// We model the second-order cone program:
150//
151// max x
152// s.t. x - y <= 1
153// ||(x, y)||_2 <= 2
154//
155// The unique optimal solution is (x*, y*) = ((sqrt(7)+1)/2, (sqrt(7)-1)/2) with
156// objective value (sqrt(7)+1)/2.
157TEST_P(SimpleSecondOrderConeTest, SolveModelWithSocAndLinearConstraints) {
158 if (!GetParam().supports_soc_constraints) {
159 GTEST_SKIP() << kNoSocSupportMessage;
160 }
161 Model model;
162 const Variable x = model.AddVariable("x");
163 const Variable y = model.AddVariable("y");
164 model.Maximize(x);
165 model.AddLinearConstraint(x - y <= 1.0);
166 model.AddSecondOrderConeConstraint({x, y}, 2.0);
167 const double sqrt_of_seven = std::sqrt(7.0);
169 SimpleSolve(model),
171 (sqrt_of_seven + 1.0) / 2.0,
172 {{x, (sqrt_of_seven + 1.0) / 2.0}, {y, (sqrt_of_seven - 1.0) / 2.0}},
173 kTolerance)));
174}
175
176// We start with the LP:
177//
178// max x + y
179// s.t. x + 0.5y <= 1
180// 0 <= x, y <= 1
181//
182// The unique optimal solution is (x*, y*) = (0.5, 1) with objective value 1.5.
183//
184// We then add the second-order cone constraint
185//
186// ||(x, y)||_2 <= sqrt(0.5)
187//
188// The unique optimal solution is then (x*, y*) = (0.5, 0.5) with objective
189// value 1.
190TEST_P(IncrementalSecondOrderConeTest, LinearToSecondOrderConeUpdate) {
191 if (!GetParam().supports_incremental_add_and_deletes) {
192 GTEST_SKIP() << kNoIncrementalAddAndDeletes;
193 }
194 Model model;
195 const Variable x = model.AddContinuousVariable(0.0, 1.0, "x");
196 const Variable y = model.AddContinuousVariable(0.0, 1.0, "y");
197 model.AddLinearConstraint(x + 0.5 * y <= 1.0);
198 model.Maximize(x + y);
199
201 const auto solver,
202 NewIncrementalSolver(&model, GetParam().solver_type, {}));
203 ASSERT_THAT(solver->Solve({.parameters = GetParam().parameters}),
204 IsOkAndHolds(IsOptimalWithSolution(1.5, {{x, 0.5}, {y, 1.0}})));
205
206 model.AddSecondOrderConeConstraint({x, y}, std::sqrt(0.5));
207
208 if (!GetParam().supports_soc_constraints) {
209 // Here we test that solvers that don't support second-order cone
210 // constraints return false in SolverInterface::CanUpdate(). Thus they
211 // should fail in their factory function instead of failing in their
212 // SolverInterface::Update() function. To assert we rely on status
213 // annotations added by IncrementalSolver::Update() to the returned status
214 // of Solver::Update() and Solver::New().
216 solver->Update(),
217 StatusIs(AnyOf(absl::StatusCode::kInvalidArgument,
218 absl::StatusCode::kUnimplemented),
219 AllOf(HasSubstr("second-order cone constraint"),
220 // Sub-string expected for Solver::Update() error.
221 Not(HasSubstr("update failed")),
222 // Sub-string expected for Solver::New() error.
223 HasSubstr("solver re-creation failed"))));
224 return;
225 }
226
227 ASSERT_THAT(solver->Update(),
228 IsOkAndHolds(GetParam().supports_incremental_add_and_deletes
229 ? DidUpdate()
230 : Not(DidUpdate())));
231 EXPECT_THAT(solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
232 IsOkAndHolds(IsOptimalWithSolution(1.0, {{x, 0.5}, {y, 0.5}},
233 kTolerance)));
234}
235
236// We start with the SOCP:
237//
238// max x + y
239// s.t. x + 0.5y <= 1
240// ||(x, y)||_2 <= sqrt(0.5)
241// 0 <= x, y <= 1
242//
243// The unique optimal solution is then (x*, y*) = (0.5, 0.5) with objective
244// value 1.
245//
246// We then delete the SOC constraint, leaving the LP:
247//
248// max x + y
249// s.t. x + 0.5y <= 1
250// 0 <= x, y <= 1
251//
252// The unique optimal solution is (x*, y*) = (0.5, 1) with objective value 1.5.
253TEST_P(IncrementalSecondOrderConeTest, UpdateDeletesSecondOrderConeConstraint) {
254 if (!GetParam().supports_soc_constraints) {
255 GTEST_SKIP() << kNoSocSupportMessage;
256 }
257 if (!GetParam().supports_incremental_add_and_deletes) {
258 GTEST_SKIP() << kNoIncrementalAddAndDeletes;
259 }
260 Model model;
261 const Variable x = model.AddContinuousVariable(0.0, 1.0, "x");
262 const Variable y = model.AddContinuousVariable(0.0, 1.0, "y");
263 model.AddLinearConstraint(x + 0.5 * y <= 1.0);
265 model.AddSecondOrderConeConstraint({x, y}, std::sqrt(0.5));
266 model.Maximize(x + y);
267
269 const auto solver,
270 NewIncrementalSolver(&model, GetParam().solver_type, {}));
271 ASSERT_THAT(solver->Solve({.parameters = GetParam().parameters}),
272 IsOkAndHolds(IsOptimalWithSolution(1.0, {{x, 0.5}, {y, 0.5}},
273 kTolerance)));
274
275 model.DeleteSecondOrderConeConstraint(c);
276
277 ASSERT_THAT(solver->Update(),
278 IsOkAndHolds(GetParam().supports_incremental_add_and_deletes
279 ? DidUpdate()
280 : Not(DidUpdate())));
281 EXPECT_THAT(solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
282 IsOkAndHolds(IsOptimalWithSolution(1.5, {{x, 0.5}, {y, 1.0}})));
283}
284
285// We start with the SOCP:
286//
287// max x + y
288// s.t. ||x||_2 <= y
289// 0 <= x, y <= 1
290//
291// The unique optimal solution is then (x*, y*) = (1, 1) with objective value 2.
292//
293// We then delete the y variable, leaving the SOCP:
294//
295// max x
296// s.t. ||x||_2 <= 0
297// 0 <= x <= 1
298//
299// The unique optimal solution is x* = 0 with objective value 0.
300TEST_P(IncrementalSecondOrderConeTest, UpdateDeletesUpperBoundingVariable) {
301 if (!GetParam().supports_soc_constraints) {
302 GTEST_SKIP() << kNoSocSupportMessage;
303 }
304 Model model;
305 const Variable x = model.AddContinuousVariable(0.0, 1.0, "x");
306 const Variable y = model.AddContinuousVariable(0.0, 1.0, "y");
307 model.AddSecondOrderConeConstraint({x}, y);
308 model.Maximize(x + y);
309
311 const auto solver,
312 NewIncrementalSolver(&model, GetParam().solver_type, {}));
313 ASSERT_THAT(solver->Solve({.parameters = GetParam().parameters}),
314 IsOkAndHolds(IsOptimalWithSolution(2.0, {{x, 1.0}, {y, 1.0}})));
315
316 model.DeleteVariable(y);
317
318 ASSERT_THAT(solver->Update(),
319 IsOkAndHolds(GetParam().supports_incremental_add_and_deletes
320 ? DidUpdate()
321 : Not(DidUpdate())));
322 EXPECT_THAT(solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
323 IsOkAndHolds(IsOptimalWithSolution(0.0, {{x, 0.0}})));
324}
325
326// We start with the SOCP:
327//
328// max x + y
329// s.t. ||x||_2 <= y + 1
330// 0 <= x <= 2
331// 0 <= y <= 1
332//
333// The unique optimal solution is then (x*, y*) = (2, 1) with objective value 3.
334//
335// We then delete the y variable, leaving the SOCP:
336//
337// max x
338// s.t. ||x||_2 <= 1
339// 0 <= x <= 2
340//
341// The unique optimal solution is x* = 1 with objective value 1.
343 UpdateDeletesVariableInUpperBoundingExpression) {
344 if (!GetParam().supports_soc_constraints) {
345 GTEST_SKIP() << kNoSocSupportMessage;
346 }
347 if (!GetParam().supports_incremental_add_and_deletes) {
348 GTEST_SKIP() << kNoIncrementalAddAndDeletes;
349 }
350 Model model;
351 const Variable x = model.AddContinuousVariable(0.0, 2.0, "x");
352 const Variable y = model.AddContinuousVariable(0.0, 1.0, "y");
353 model.AddSecondOrderConeConstraint({x}, y + 1.0);
354 model.Maximize(x + y);
355
357 const auto solver,
358 NewIncrementalSolver(&model, GetParam().solver_type, {}));
359 ASSERT_THAT(solver->Solve({.parameters = GetParam().parameters}),
360 IsOkAndHolds(IsOptimalWithSolution(3.0, {{x, 2.0}, {y, 1.0}})));
361
362 model.DeleteVariable(y);
363
364 ASSERT_THAT(solver->Update(),
365 IsOkAndHolds(GetParam().supports_incremental_add_and_deletes
366 ? DidUpdate()
367 : Not(DidUpdate())));
368 EXPECT_THAT(solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
369 IsOkAndHolds(IsOptimalWithSolution(1.0, {{x, 1.0}})));
370}
371
372// We start with the SOCP:
373//
374// min y
375// s.t. ||x||_2 <= y
376// 1 <= x <= 1
377// 0 <= y <= 1
378//
379// The unique optimal solution is then (x*, y*) = (1, 1) with objective value 1.
380//
381// We then delete the x variable, leaving the SOCP:
382//
383// max y
384// s.t. ||0||_2 <= y
385// 0 <= y <= 1
386//
387// The unique optimal solution is y* = 0 with objective value 0.
388TEST_P(IncrementalSecondOrderConeTest, UpdateDeletesVariableThatIsAnArgument) {
389 if (!GetParam().supports_soc_constraints) {
390 GTEST_SKIP() << kNoSocSupportMessage;
391 }
392 if (!GetParam().supports_incremental_add_and_deletes) {
393 GTEST_SKIP() << kNoIncrementalAddAndDeletes;
394 }
395 Model model;
396 const Variable x = model.AddContinuousVariable(1.0, 1.0, "x");
397 const Variable y = model.AddContinuousVariable(0.0, 1.0, "y");
398 model.AddSecondOrderConeConstraint({x}, y);
399 model.Minimize(y);
400
402 const auto solver,
403 NewIncrementalSolver(&model, GetParam().solver_type, {}));
404 ASSERT_THAT(solver->Solve({.parameters = GetParam().parameters}),
405 IsOkAndHolds(IsOptimalWithSolution(1.0, {{x, 1.0}, {y, 1.0}})));
406
407 model.DeleteVariable(x);
408
409 ASSERT_THAT(solver->Update(),
410 IsOkAndHolds(GetParam().supports_incremental_add_and_deletes
411 ? DidUpdate()
412 : Not(DidUpdate())));
413 EXPECT_THAT(solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
414 IsOkAndHolds(IsOptimalWithSolution(0.0, {{y, 0.0}})));
415}
416
417// We start with the SOCP:
418//
419// min y
420// s.t. ||x + 1||_2 <= y
421// 1 <= x <= 1
422// 0 <= y <= 2
423//
424// The unique optimal solution is then (x*, y*) = (1, 2) with objective value 2.
425//
426// We then delete the x variable, leaving the SOCP:
427//
428// max y
429// s.t. ||1||_2 <= y
430// 0 <= y <= 2
431//
432// The unique optimal solution is y* = 1 with objective value 1.
433TEST_P(IncrementalSecondOrderConeTest, UpdateDeletesVariableInAnArgument) {
434 if (!GetParam().supports_soc_constraints) {
435 GTEST_SKIP() << kNoSocSupportMessage;
436 }
437 if (!GetParam().supports_incremental_add_and_deletes) {
438 GTEST_SKIP() << kNoIncrementalAddAndDeletes;
439 }
440 Model model;
441 const Variable x = model.AddContinuousVariable(1.0, 1.0, "x");
442 const Variable y = model.AddContinuousVariable(0.0, 2.0, "y");
443 model.AddSecondOrderConeConstraint({x + 1.0}, y);
444 model.Minimize(y);
445
447 const auto solver,
448 NewIncrementalSolver(&model, GetParam().solver_type, {}));
449 ASSERT_THAT(solver->Solve({.parameters = GetParam().parameters}),
450 IsOkAndHolds(IsOptimalWithSolution(2.0, {{x, 1.0}, {y, 2.0}})));
451
452 model.DeleteVariable(x);
453
454 ASSERT_THAT(solver->Update(),
455 IsOkAndHolds(GetParam().supports_incremental_add_and_deletes
456 ? DidUpdate()
457 : Not(DidUpdate())));
458 EXPECT_THAT(solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
459 IsOkAndHolds(IsOptimalWithSolution(1.0, {{y, 1.0}})));
460}
461
462} // namespace
463} // namespace operations_research::math_opt
Definition model.h:345
Variable * AddVariable(absl::string_view name, const Domain &domain, bool defined, bool set_is_fixed=false)
Definition model.cc:1020
void Maximize(Variable *obj, std::vector< Annotation > search_annotations)
Definition model.cc:1074
void Minimize(Variable *obj, std::vector< Annotation > search_annotations)
Definition model.cc:1067
#define EXPECT_OK(expression)
Definition gmock.h:45
#define ASSERT_OK_AND_ASSIGN(lhs, rexpr)
Definition gmock.h:53
Matcher< SolveResult > IsOptimalWithSolution(const double expected_objective, const VariableMap< double > expected_variable_values, const double tolerance)
Definition matchers.cc:778
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)
Definition solve.cc:82
std::ostream & operator<<(std::ostream &ostr, const SecondOrderConeConstraint &constraint)
Matcher< UpdateResult > DidUpdate()
Definition matchers.cc:1028
BoolVar Not(BoolVar x)
Definition cp_model.cc:87
std::string ProtobufShortDebugString(const P &message)
Definition proto_utils.h:46
STL namespace.
SecondOrderConeTestParameters(SolverType solver_type, SolveParameters parameters, bool supports_soc_constraints, bool supports_incremental_add_and_deletes)