Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
qc_tests.cc
Go to the documentation of this file.
1// Copyright 2010-2024 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
32 const SolverType solver_type, SolveParameters parameters,
33 const bool supports_qc, const bool supports_incremental_add_and_deletes,
34 const bool supports_incremental_variable_deletions,
35 const bool use_integer_variables)
36 : solver_type(solver_type),
38 supports_qc(supports_qc),
39 supports_incremental_add_and_deletes(
40 supports_incremental_add_and_deletes),
41 supports_incremental_variable_deletions(
42 supports_incremental_variable_deletions),
43 use_integer_variables(use_integer_variables) {}
44
45std::ostream& operator<<(std::ostream& out, const QcTestParameters& params) {
46 out << "{ solver_type: " << params.solver_type
47 << ", parameters: " << ProtobufShortDebugString(params.parameters.Proto())
48 << ", supports_qc: " << (params.supports_qc ? "true" : "false")
49 << ", supports_incremental_add_and_deletes: "
50 << (params.supports_incremental_add_and_deletes ? "true" : "false")
51 << ", supports_incremental_variable_deletions: "
52 << (params.supports_incremental_variable_deletions ? "true" : "false")
53 << ", use_integer_variables: "
54 << (params.use_integer_variables ? "true" : "false") << " }";
55 return out;
56}
57
58namespace {
59
60using ::testing::AnyOf;
61using ::testing::HasSubstr;
62using ::testing::status::IsOkAndHolds;
63using ::testing::status::StatusIs;
64
65constexpr double kTolerance = 1.0e-4;
66constexpr absl::string_view no_qc_support_message =
67 "This test is disabled as the solver does not support quadratic "
68 "constraints";
69
70// Models the following problem:
71// min_x x + 5
72// s.t. x^2 - x <= 1
73// -1 <= x <= 1
74//
75// along with, if use_integer_variables = true, integrality on x.
76//
77// If use_integer_variables = false, the unique optimal solution is attained at
78// x = (1 - sqrt(5)) / 2 with objective value (1 - sqrt(5)) / 2 + 5. Otherwise,
79// the unique optimal solution is x = 0 with objective value 5.
80struct UnivariateQcProblem {
81 explicit UnivariateQcProblem(bool use_integer_variables)
82 : model(), x(model.AddVariable(-1.0, 1.0, use_integer_variables, "x")) {
83 model.AddQuadraticConstraint(x * x - x <= 1.0);
84 model.Minimize(x + 5.0);
85 }
86
87 Model model;
88 const Variable x;
89};
90
91TEST_P(SimpleQcTest, CanBuildQcModel) {
92 UnivariateQcProblem qc_problem(GetParam().use_integer_variables);
93 if (GetParam().supports_qc) {
95 NewIncrementalSolver(&qc_problem.model, GetParam().solver_type, {}));
96 } else {
98 NewIncrementalSolver(&qc_problem.model, GetParam().solver_type, {}),
99 StatusIs(AnyOf(absl::StatusCode::kInvalidArgument,
100 absl::StatusCode::kUnimplemented),
101 HasSubstr("quadratic constraints")));
102 }
103}
104
105TEST_P(SimpleQcTest, SolveSimpleQc) {
106 if (!GetParam().supports_qc) {
107 GTEST_SKIP() << no_qc_support_message;
108 }
109 const UnivariateQcProblem qc_problem(GetParam().use_integer_variables);
110 const double x_expected =
111 GetParam().use_integer_variables ? 0.0 : -0.618033988748785;
112 EXPECT_THAT(SimpleSolve(qc_problem.model),
114 5.0 + x_expected, {{qc_problem.x, x_expected}})));
115}
116
117// Models the following problem:
118// min_{x,y} y
119// s.t. (x - 1)^2 + (y - 1)^2 + xy == x^2 + xy + y^2 - 2x - 2y + 2 <= 1
120// x <= y
121// 0 <= x <= 0.5
122// 0 <= y <= 1
123//
124// along with, if use_integer_variables = true, integrality on x and y.
125//
126// If use_integer_variables = false, the unique optimal solution is attained at
127// (x, y) = (1/3, 1/3) with objective value 1/3. Otherwise, the unique optimal
128// solution is (x, y) = (0, 1) with objective value 1.
129struct HalfEllipseProblem {
130 explicit HalfEllipseProblem(bool use_integer_variables)
131 : model(),
132 x(model.AddVariable(0.0, 0.5, use_integer_variables, "x")),
133 y(model.AddVariable(0.0, 1.0, use_integer_variables, "y")),
134 q(model.AddQuadraticConstraint(x * x + x * y + y * y - 2 * x - 2 * y <=
135 -1)) {
136 model.Minimize(y);
137 model.AddLinearConstraint(x <= y);
138 }
139
140 Model model;
141 const Variable x;
142 const Variable y;
143 const QuadraticConstraint q;
144};
145
146TEST_P(SimpleQcTest, SolveHalfEllipseQc) {
147 if (!GetParam().supports_qc) {
148 GTEST_SKIP() << no_qc_support_message;
149 }
150 const HalfEllipseProblem qc_problem(GetParam().use_integer_variables);
151 if (GetParam().use_integer_variables) {
152 EXPECT_THAT(SimpleSolve(qc_problem.model),
154 1.0, {{qc_problem.x, 0.0}, {qc_problem.y, 1.0}})));
155 } else {
156 const double value = 1.0 / 3.0;
157 EXPECT_THAT(SimpleSolve(qc_problem.model),
159 value, {{qc_problem.x, value}, {qc_problem.y, value}})));
160 }
161}
162
163// We start with the simple LP:
164// max x + 1
165// s.t. 0 <= x <= 1
166//
167// The optimal value is 2. We then add a quadratic constraint:
168// x^2 <= 0.5
169//
170// The optimal solution is x = sqrt(0.5) with objective value 1 + sqrt(0.5).
171// Additionally, if we impose integrality on x, then the optimal solution is
172// x = 0 with objective value 1.
173TEST_P(IncrementalQcTest, LinearToQuadraticUpdate) {
174 Model model;
175 const Variable x =
176 model.AddVariable(0.0, 1.0, GetParam().use_integer_variables, "x");
177 model.Maximize(x + 1.0);
178
180 const auto solver,
181 NewIncrementalSolver(&model, GetParam().solver_type, {}));
182 ASSERT_THAT(solver->Solve({.parameters = GetParam().parameters}),
183 IsOkAndHolds(IsOptimalWithSolution(2.0, {{x, 1.0}})));
184
185 model.AddQuadraticConstraint(x * x <= 0.5);
186
187 if (!GetParam().supports_qc) {
188 // Here we test that solvers that don't support quadratic constraints return
189 // false in SolverInterface::CanUpdate(). Thus they should fail in their
190 // factory function instead of failing in their SolverInterface::Update()
191 // function. To assert we rely on status annotations added by
192 // IncrementalSolver::Update() to the returned status of Solver::Update()
193 // and Solver::New().
195 solver->Update(),
196 StatusIs(AnyOf(absl::StatusCode::kInvalidArgument,
197 absl::StatusCode::kUnimplemented),
198 AllOf(HasSubstr("quadratic constraint"),
199 // Sub-string expected for Solver::Update() error.
200 Not(HasSubstr("update failed")),
201 // Sub-string expected for Solver::New() error.
202 HasSubstr("solver re-creation failed"))));
203 return;
204 }
205
206 ASSERT_THAT(solver->Update(),
207 IsOkAndHolds(GetParam().supports_incremental_add_and_deletes
208 ? DidUpdate()
209 : Not(DidUpdate())));
210 const double expected_x =
211 GetParam().use_integer_variables ? 0.0 : std::sqrt(0.5);
213 solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
214 IsOkAndHolds(IsOptimalWithSolution(1.0 + expected_x, {{x, expected_x}})));
215}
216
217// We start with the QCP:
218// min_{x,y} y
219// s.t. (x - 1)^2 + (y - 1)^2 + xy <= 1
220// x <= y
221// 0 <= x <= 0.5
222// 0 <= y <= 1
223//
224// We then delete the quadratic constraint, leaving the LP:
225// min_{x,y} y
226// s.t. x <= y
227// 0 <= x <= 0.5
228// 0 <= y <= 1
229//
230// The optimal solution is attained at (x, y) = (0, 0).
231TEST_P(IncrementalQcTest, UpdateDeletesQuadraticConstraint) {
232 if (!GetParam().supports_qc) {
233 GTEST_SKIP() << no_qc_support_message;
234 }
235 HalfEllipseProblem qc_problem(GetParam().use_integer_variables);
237 const auto solver,
238 NewIncrementalSolver(&qc_problem.model, GetParam().solver_type, {}));
239 // We test that the solution is correct elsewhere.
240 ASSERT_OK(solver->Solve({.parameters = GetParam().parameters}));
241
242 qc_problem.model.DeleteQuadraticConstraint(qc_problem.q);
243
244 ASSERT_THAT(solver->Update(),
245 IsOkAndHolds(GetParam().supports_incremental_add_and_deletes
246 ? DidUpdate()
247 : Not(DidUpdate())));
248 EXPECT_THAT(solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
250 0.0, {{qc_problem.x, 0.0}, {qc_problem.y, 0.0}})));
251}
252
253// We start with the QCP:
254// min_{x,y} y
255// s.t. (x - 1)^2 + (y - 1)^2 + xy <= 1
256// x <= y
257// 0 <= x, y <= 2
258//
259// We then delete the x variable, leaving the QCP:
260// min_{y} y
261// s.t. 1 + (y - 1)^2 == y^2 - 2y + 2 <= 1
262// 0 <= y <= 2
263//
264// The optimal solution is attained at y = 1 with objective value 1.
265TEST_P(IncrementalQcTest, UpdateDeletesVariableInQuadraticConstraint) {
266 if (!GetParam().supports_qc) {
267 GTEST_SKIP() << no_qc_support_message;
268 }
269 HalfEllipseProblem qc_problem(GetParam().use_integer_variables);
270
272 const auto solver,
273 NewIncrementalSolver(&qc_problem.model, GetParam().solver_type, {}));
274 // We test that the solution is correct elsewhere.
275 ASSERT_OK(solver->Solve({.parameters = GetParam().parameters}));
276
277 qc_problem.model.DeleteVariable(qc_problem.x);
278
279 ASSERT_THAT(solver->Update(),
280 IsOkAndHolds(GetParam().supports_incremental_variable_deletions
281 ? DidUpdate()
282 : Not(DidUpdate())));
283 EXPECT_THAT(solver->SolveWithoutUpdate({.parameters = GetParam().parameters}),
284 IsOkAndHolds(IsOptimalWithSolution(1.0, {{qc_problem.y, 1.0}},
285 kTolerance)));
286}
287
288// Primal:
289// min_{x} x
290// s.t.
291// Quadratic constraint:
292// x^2 <= 1
293//
294// Optimal solution: x* = -1.
295//
296// Dual (go/mathopt-qcqp-dual):
297// max_{mu, x, r} mu + mu*x^2
298// s.t. mu*2*x + r = 1
299// mu <= 0
300// r = 0
301//
302// Optimal solution: x* = -1, mu* = -0.5.
303TEST_P(QcDualsTest, OnlyQuadraticConstraintLess) {
304 if (!GetParam().supports_qc) {
305 return;
306 }
307 Model model;
308 const Variable x = model.AddVariable();
309 const QuadraticConstraint mu = model.AddQuadraticConstraint(x * x <= 1);
310 model.Minimize(x);
311
312 ASSERT_OK_AND_ASSIGN(const SolveResult solve_result, SimpleSolve(model));
313 const double expected_objective_value = -1.0;
314 EXPECT_THAT(solve_result,
315 IsOptimalWithSolution(expected_objective_value, {{x, -1.0}}));
316 EXPECT_THAT(solve_result,
317 IsOptimalWithDualSolution(expected_objective_value, {},
318 {{mu, -0.5}}, {{x, 0.0}}));
319}
320
321// Primal:
322// min_{x} x
323// s.t.
324// Quadratic constraint:
325// -x^2 >= -1
326//
327// Optimal solution: x* = -1.
328//
329// Dual (go/mathopt-qcqp-dual):
330// max_{mu, x, r} -mu - mu*x^2
331// s.t. -mu*2*x + r = 1
332// mu >= 0
333// r = 0
334//
335// Optimal solution: x* = -1, mu* = 0.5.
336TEST_P(QcDualsTest, OnlyQuadraticConstraintGreater) {
337 if (!GetParam().supports_qc) {
338 return;
339 }
340 Model model;
341 const Variable x = model.AddVariable();
342 const QuadraticConstraint mu = model.AddQuadraticConstraint(-x * x >= -1);
343 model.Minimize(x);
344
345 ASSERT_OK_AND_ASSIGN(const SolveResult solve_result, SimpleSolve(model));
346 const double expected_objective_value = -1.0;
347 EXPECT_THAT(solve_result,
348 IsOptimalWithSolution(expected_objective_value, {{x, -1.0}}));
349 EXPECT_THAT(solve_result,
350 IsOptimalWithDualSolution(expected_objective_value, {},
351 {{mu, 0.5}}, {{x, 0.0}}));
352}
353
354// Primal:
355// min_{x} x1^2 - 10 x1
356// s.t.
357// Quadratic constraints:
358// x1^2 + x0 <= 2
359// Linear constraints:
360// x1 - x0 <= 0
361// -x1 - x0 <= 0
362//
363// Optimal solution: x* = (1, 1).
364//
365// Dual (go/mathopt-qcqp-dual):
366// max_{mu, x, y, r} 2*mu + mu*x1^2 - x1^2
367// s.t. -y0 - y1 + r0 + mu = 0
368// y0 - y1 + r1 + mu*2*x1 = 2*x1 - 10
369// mu <= 0
370// y0 <= 0
371// y1 <= 0
372// r0 = 0
373// r1 = 0
374//
375// Optimal solution: x* = (1, 1), mu* = -8/3, y = (-8/3, 0), r = (0, 0).
376TEST_P(QcDualsTest, QuadraticObjectiveAndLinearAndQuadraticConstraints) {
377 if (!GetParam().supports_qc) {
378 return;
379 }
380 Model model;
381 const Variable x0 = model.AddVariable();
382 const Variable x1 = model.AddVariable();
383 const LinearConstraint y0 = model.AddLinearConstraint(x1 - x0 <= 0.0);
384 const LinearConstraint y1 = model.AddLinearConstraint(-x1 - x0 <= 0.0);
385 const QuadraticConstraint mu =
386 model.AddQuadraticConstraint(x1 * x1 + x0 <= 2);
387 model.Minimize(x1 * x1 - 10.0 * x1);
388
389 ASSERT_OK_AND_ASSIGN(const SolveResult solve_result, SimpleSolve(model));
390 const double expected_objective_value = -9.0;
391 EXPECT_THAT(solve_result, IsOptimalWithSolution(expected_objective_value,
392 {{x0, 1.0}, {x1, 1.0}}));
393 EXPECT_THAT(solve_result,
395 expected_objective_value, {{y0, -8.0 / 3.0}, {y1, 0.0}},
396 {{mu, -8.0 / 3.0}}, {{x0, 0.0}, {x1, 0.0}}));
397}
398
399// Primal:
400// max_{x} -x0^2 + 4x0
401// s.t.
402// Quadratic constraints:
403// x0^2 + x1^2 + x2^2 <= 3
404// Linear constraints:
405// x1 = 1
406// Variable bounds:
407// x2 = 1
408//
409// Optimal solution: x* = (1, 1, 1).
410//
411// Dual (go/mathopt-qcqp-dual):
412// min_{mu, x, y, r} y + r2 + 3*mu + mu*(x0^2 + x1^2 + x2^2) + x0^2
413// s.t. r0 + mu*2*x0 = -2x0 + 4
414// r1 + y + mu*2*x1 = 0
415// r2 + mu*2*x2 = 0
416// mu >= 0
417// r0 = 0
418// r1 = 0
419//
420// Optimal solution: x* = (1, 1, 1), mu* = 1, y = -2, r = (0, 0, -2).
421TEST_P(QcDualsTest, MaxAndVariableBounds) {
422 if (!GetParam().supports_qc) {
423 return;
424 }
425 Model model;
426 const Variable x0 = model.AddVariable();
427 const Variable x1 = model.AddVariable();
428 const Variable x2 = model.AddContinuousVariable(1.0, 1.0);
429 const LinearConstraint y = model.AddLinearConstraint(x1 == 1.0);
430 const QuadraticConstraint mu =
431 model.AddQuadraticConstraint(x0 * x0 + x1 * x1 + x2 * x2 <= 3.0);
432 model.Maximize(-x0 * x0 + 4.0 * x0);
433
434 ASSERT_OK_AND_ASSIGN(const SolveResult solve_result, SimpleSolve(model));
435 const double expected_objective_value = 3.0;
436 EXPECT_THAT(solve_result,
437 IsOptimalWithSolution(expected_objective_value,
438 {{x0, 1.0}, {x1, 1.0}, {x2, 1.0}}));
439 EXPECT_THAT(solve_result,
440 IsOptimalWithDualSolution(expected_objective_value, {{y, -2.0}},
441 {{mu, 1.0}},
442 {{x0, 0.0}, {x1, 0.0}, {x2, -2.0}}));
443}
444
445} // namespace
446} // namespace operations_research::math_opt
IntegerValue y
SatParameters parameters
int64_t value
GRBmodel * model
const Variable x2
const LinearConstraint y1
const Variable x1
An object oriented wrapper for quadratic constraints in ModelStorage.
Definition gurobi_isv.cc:28
Matcher< SolveResult > IsOptimalWithSolution(const double expected_objective, const VariableMap< double > expected_variable_values, const double tolerance)
Definition matchers.cc:777
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.
Definition parameters.h:42
<=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.";} 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-> IsOkAndHolds(IsOptimal(1.5)))
ASSERT_THAT(solver->Update(), IsOkAndHolds(DidUpdate()))
std::ostream & operator<<(std::ostream &ostr, const IndicatorConstraint &constraint)
absl::StatusOr< std::unique_ptr< IncrementalSolver > > NewIncrementalSolver(Model *model, SolverType solver_type, SolverInitArguments arguments)
Definition solve.cc:82
Matcher< UpdateResult > DidUpdate()
Actual UpdateResult.did_update is true.
Definition matchers.cc:1027
Matcher< SolveResult > IsOptimalWithDualSolution(const double expected_objective, const LinearConstraintMap< double > expected_dual_values, const VariableMap< double > expected_reduced_costs, const double tolerance)
Definition matchers.cc:790
BoolVar Not(BoolVar x)
Definition cp_model.cc:87
std::string ProtobufShortDebugString(const P &message)
Definition proto_utils.h:41
STL namespace.
internal::StatusIsMatcher StatusIs(CodeMatcher code_matcher, MessageMatcher message_matcher)
const Variable x
Definition qp_tests.cc:127
#define ASSERT_OK(expression)
#define EXPECT_OK(expression)
#define ASSERT_OK_AND_ASSIGN(lhs, rexpr)
bool use_integer_variables
True if the solver supports integer variables.
Definition qc_tests.h:49
SolverType solver_type
The tested solver.
Definition qc_tests.h:33
bool supports_qc
True if the solver supports quadratic constraints.
Definition qc_tests.h:38
QcTestParameters(SolverType solver_type, SolveParameters parameters, bool supports_qc, bool supports_incremental_add_and_deletes, bool supports_incremental_variable_deletions, bool use_integer_variables)
Definition qc_tests.cc:31