20#include "gtest/gtest.h"
36 <<
", supports_primal_only_warm_starts: "
45constexpr double kInf = std::numeric_limits<double>::infinity();
81 y2(
model.AddLinearConstraint(
x1 + 4 *
x2 >= 2,
"y2")) {
82 model.Minimize(2 * x1 + x2);
88 const LinearConstraint
y1;
89 const LinearConstraint
y2;
116 y2(
model.AddLinearConstraint(
x2 <= 0,
"y2")) {
123 const LinearConstraint
y1;
124 const LinearConstraint
y2;
161 y1(
model.AddLinearConstraint(
x1 <= -2,
"y1")),
162 y2(
model.AddLinearConstraint(
x2 <= 3,
"y2")) {
163 model.Minimize(x1 - x2);
169 const LinearConstraint
y1;
170 const LinearConstraint
y2;
173TEST_P(LpModelSolveParametersTest, SolutionFilterSkipZerosPrimalVars) {
174 if (!GetParam().exact_zeros) {
176 <<
"Solver " << GetParam().solver_type
177 <<
" does not reliably return exact zeros; this test is disabled.";
181 const SolveArguments args = {
182 .parameters = GetParam().parameters,
183 .model_parameters = {
184 .variable_values_filter = {.skip_zero_values =
true}}};
186 Solve(lp.model, GetParam().solver_type, args));
189 if (GetParam().supports_duals) {
190 const DualSolution expected_dual = {
191 .dual_values = {{lp.y1, 1.0}, {lp.y2, 0.0}},
192 .reduced_costs = {{lp.x1, 1.0}, {lp.x2, 0.0}},
193 .objective_value = 1.0,
200TEST_P(LpModelSolveParametersTest, SolutionFilterSkipZerosReducedCosts) {
201 if (!GetParam().exact_zeros) {
203 <<
"Solver " << GetParam().solver_type
204 <<
" does not reliably return exact zeros; this test is disabled.";
206 if (!GetParam().supports_duals) {
207 GTEST_SKIP() <<
"Solver " << GetParam().solver_type
208 <<
" can't produce dual solutions; this test is disabled.";
211 const SolveArguments args = {
212 .parameters = GetParam().parameters,
213 .model_parameters = {.reduced_costs_filter = {.skip_zero_values =
true}}};
215 Solve(lp.model, GetParam().solver_type, args));
218 const DualSolution expected_dual = {
219 .dual_values = {{lp.y1, 1.0}, {lp.y2, 0.0}},
220 .reduced_costs = {{lp.x1, 1.0}},
221 .objective_value = 1.0,
226TEST_P(LpModelSolveParametersTest, SolutionFilterSkipZerosDualVars) {
227 if (!GetParam().exact_zeros) {
229 <<
"Solver " << GetParam().solver_type
230 <<
" does not reliably return exact zeros; this test is disabled.";
232 if (!GetParam().supports_duals) {
233 GTEST_SKIP() <<
"Solver " << GetParam().solver_type
234 <<
" can't produce dual solutions; this test is disabled.";
238 const SolveArguments args = {
239 .parameters = GetParam().parameters,
240 .model_parameters = {.dual_values_filter = {.skip_zero_values =
true}}};
242 Solve(lp.model, GetParam().solver_type, args));
245 const DualSolution expected_dual = {
246 .dual_values = {{lp.y1, 1.0}},
247 .reduced_costs = {{lp.x1, 1.0}, {lp.x2, 0.0}},
248 .objective_value = 1.0,
255TEST_P(LpModelSolveParametersTest, SolutionFilterByKey) {
258 const SolveArguments args = {
259 .parameters = GetParam().parameters,
260 .model_parameters = {
265 Solve(lp.model, GetParam().solver_type, args));
268 if (GetParam().supports_duals) {
269 const DualSolution expected_dual = {
270 .dual_values = {{lp.y2, 0.0}},
271 .reduced_costs = {{lp.x2, 0.0}},
272 .objective_value = 1.0,
278TEST_P(LpModelSolveParametersTest, SolutionFilterSkipZerosPrimalRay) {
279 if (!GetParam().exact_zeros) {
281 <<
"Solver " << GetParam().solver_type
282 <<
" does not reliably return exact zeros; this test is disabled.";
286 SolveArguments args = {.parameters = GetParam().parameters,
287 .model_parameters = {.variable_values_filter = {
288 .skip_zero_values =
true}}};
291 GTEST_SKIP() <<
"Solver " << GetParam().solver_type
292 <<
" can't produce primal rays; this test is disabled.";
296 Solve(lp.model, GetParam().solver_type, args));
303TEST_P(LpModelSolveParametersTest, SolutionFilterByKeyPrimalRay) {
306 SolveArguments args = {.parameters = GetParam().parameters,
307 .model_parameters = {.variable_values_filter =
311 GTEST_SKIP() <<
"Solver " << GetParam().solver_type
312 <<
" can't produce primal rays; this test is disabled.";
316 Solve(lp.model, GetParam().solver_type, args));
323TEST_P(LpModelSolveParametersTest, SolutionFilterSkipZerosDualRayDuals) {
324 if (!GetParam().exact_zeros) {
326 <<
"Solver " << GetParam().solver_type
327 <<
" does not reliably return exact zeros; this test is disabled.";
331 SolveArguments args = {
332 .parameters = GetParam().parameters,
333 .model_parameters = {.dual_values_filter = {.skip_zero_values =
true}}};
336 GTEST_SKIP() <<
"Solver " << GetParam().solver_type
337 <<
" can't produce dual rays; this test is disabled.";
341 Solve(lp.model, GetParam().solver_type, args));
343 const DualRay expected = {.dual_values = {{lp.y1, -1.0}},
344 .reduced_costs = {{lp.x1, 1.0}, {lp.x2, 0.0}}};
348TEST_P(LpModelSolveParametersTest, SolutionFilterSkipZerosDualRayReducedCosts) {
349 if (!GetParam().exact_zeros) {
351 <<
"Solver " << GetParam().solver_type
352 <<
" does not reliably return exact zeros; this test is disabled.";
356 SolveArguments args = {
357 .parameters = GetParam().parameters,
358 .model_parameters = {.reduced_costs_filter = {.skip_zero_values =
true}}};
361 GTEST_SKIP() <<
"Solver " << GetParam().solver_type
362 <<
" can't produce dual rays; this test is disabled.";
366 Solve(lp.model, GetParam().solver_type, args));
368 const DualRay expected = {.dual_values = {{lp.y1, -1.0}, {lp.y2, 0.0}},
369 .reduced_costs = {{lp.x1, 1.0}}};
373TEST_P(LpModelSolveParametersTest, SolutionFilterByKeysDualRay) {
376 SolveArguments args = {
377 .parameters = GetParam().parameters,
378 .model_parameters = {
383 GTEST_SKIP() <<
"Solver " << GetParam().solver_type
384 <<
" can't produce dual rays; this test is disabled.";
388 Solve(lp.model, GetParam().solver_type, args));
390 const DualRay expected = {.dual_values = {{lp.y2, 0.0}},
391 .reduced_costs = {{lp.x2, 0.0}}};
395TEST_P(LpModelSolveParametersTest, PrimalWarmStart) {
396 constexpr int n = 10;
398 int baseline_num_iters = 0;
402 {.parameters = GetParam().parameters}));
404 baseline_num_iters = result.solve_stats.simplex_iterations +
405 result.solve_stats.barrier_iterations +
406 result.solve_stats.first_order_iterations;
410 ModelSolveParameters::SolutionHint warm_start;
411 for (
const Variable
var :
model->Variables()) {
412 warm_start.variable_values[
var] = 1.0 / 2.0;
417 {.parameters = GetParam().parameters,
418 .model_parameters = {.solution_hints = {warm_start}}}));
420 const int actual_num_iters = result.solve_stats.simplex_iterations +
421 result.solve_stats.barrier_iterations +
422 result.solve_stats.first_order_iterations;
423 if (!GetParam().supports_primal_only_warm_starts) {
424 EXPECT_EQ(actual_num_iters, baseline_num_iters);
427 EXPECT_LT(actual_num_iters, baseline_num_iters);
const LinearConstraint y1
const LinearConstraint y2
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}}}})))
Matcher< SolveResult > HasPrimalRay(PrimalRay expected, const double tolerance)
TEST_P(InfeasibleSubsystemTest, CanComputeInfeasibleSubsystem)
@ kInfeasible
The primal problem has no feasible solutions.
ASSERT_THAT(solver->Update(), IsOkAndHolds(DidUpdate()))
Matcher< SolveResult > TerminatesWithOneOf(const std::vector< TerminationReason > &allowed)
Checks that the result has one of the allowed termination reasons.
bool ActivatePrimalRay(SolverType solver_type, SolveParameters ¶ms)
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)
@ kFeasible
Solver claims the solution is feasible.
Matcher< SolveResult > HasDualRay(DualRay expected, const double tolerance)
Matcher< SolveResult > TerminatesWith(const TerminationReason expected)
std::unique_ptr< Model > IndependentSetCompleteGraph(const bool integer, const int n)
Matcher< VariableMap< double > > IsNear(VariableMap< double > expected, const double tolerance)
MapFilter< ValueType > MakeKeepKeysFilter(const Collection &keys)
Matcher< SolveResult > HasDualSolution(DualSolution expected, const double tolerance)
bool ActivateDualRay(SolverType solver_type, SolveParameters ¶ms)
Matcher< SolveResult > IsOptimal(const std::optional< double > expected_primal_objective, const double tolerance)
In SWIG mode, we don't want anything besides these top-level includes.
std::string ProtobufShortDebugString(const P &message)
#define ASSERT_OK_AND_ASSIGN(lhs, rexpr)
SolveParameters parameters
bool supports_primal_only_warm_starts
True if the solver supports warm starts on the primal solution only.
SolveParametersProto Proto() const