19 #include "absl/status/status.h"
20 #include "absl/strings/str_cat.h"
21 #include "absl/strings/string_view.h"
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
25 #include "ortools/pdlp/solvers.pb.h"
32 using ::testing::HasSubstr;
35 TerminationCriteria criteria;
41 TerminationCriteria criteria;
42 criteria.set_optimality_norm(OPTIMALITY_NORM_UNSPECIFIED);
44 EXPECT_EQ(
status.code(), absl::StatusCode::kInvalidArgument);
45 EXPECT_THAT(
status.message(), HasSubstr(
"optimality_norm"));
48 void TestTerminationCriteriaValidation(
49 absl::string_view termination_criteria_string,
50 absl::string_view error_substring) {
51 TerminationCriteria termination_criteria =
52 ParseTextOrDie<TerminationCriteria>(
53 std::string(termination_criteria_string));
55 EXPECT_EQ(
status.code(), absl::StatusCode::kInvalidArgument)
56 <<
"With termination criteria \"" << termination_criteria_string <<
"\"";
57 EXPECT_THAT(
status.message(), HasSubstr(error_substring))
58 <<
"With termination criteria \"" << termination_criteria_string <<
"\"";
63 void TestDetailedOptimalityCriteriaFieldValidation(
64 absl::string_view field_name) {
65 const std::string full_field_name =
66 absl::StrCat(
"detailed_optimality_criteria.", field_name);
67 TestTerminationCriteriaValidation(
68 absl::StrCat(
"detailed_optimality_criteria { ", field_name,
": -1.0 }"),
70 TestTerminationCriteriaValidation(
71 absl::StrCat(
"detailed_optimality_criteria { ", field_name,
": nan }"),
76 TestTerminationCriteriaValidation(
"eps_optimal_absolute: -1.0",
77 "eps_optimal_absolute");
78 TestTerminationCriteriaValidation(
"eps_optimal_absolute: nan",
79 "eps_optimal_absolute");
83 TestTerminationCriteriaValidation(
"eps_optimal_relative: -1.0",
84 "eps_optimal_relative");
85 TestTerminationCriteriaValidation(
"eps_optimal_relative: nan",
86 "eps_optimal_relative");
90 TestTerminationCriteriaValidation(
91 "simple_optimality_criteria { eps_optimal_absolute: -1.0}",
92 "simple_optimality_criteria.eps_optimal_absolute");
93 TestTerminationCriteriaValidation(
94 "simple_optimality_criteria { eps_optimal_absolute: nan}",
95 "simple_optimality_criteria.eps_optimal_absolute");
99 TestTerminationCriteriaValidation(
100 "simple_optimality_criteria { eps_optimal_relative: -1.0}",
101 "simple_optimality_criteria.eps_optimal_relative");
102 TestTerminationCriteriaValidation(
103 "simple_optimality_criteria { eps_optimal_relative: nan}",
104 "simple_optimality_criteria.eps_optimal_relative");
108 TestDetailedOptimalityCriteriaFieldValidation(
109 "eps_optimal_primal_residual_absolute");
113 TestDetailedOptimalityCriteriaFieldValidation(
114 "eps_optimal_primal_residual_relative");
118 TestDetailedOptimalityCriteriaFieldValidation(
119 "eps_optimal_dual_residual_absolute");
123 TestDetailedOptimalityCriteriaFieldValidation(
124 "eps_optimal_dual_residual_relative");
128 TestDetailedOptimalityCriteriaFieldValidation(
129 "eps_optimal_objective_gap_absolute");
133 TestDetailedOptimalityCriteriaFieldValidation(
134 "eps_optimal_objective_gap_relative");
138 TerminationCriteria termination_criteria =
139 ParseTextOrDie<TerminationCriteria>(
140 "eps_optimal_absolute: 1.0 simple_optimality_criteria { }");
142 EXPECT_EQ(
status.code(), absl::StatusCode::kInvalidArgument);
143 EXPECT_THAT(
status.message(), HasSubstr(
"simple_optimality_criteria"));
147 TerminationCriteria termination_criteria =
148 ParseTextOrDie<TerminationCriteria>(
149 "eps_optimal_relative: 1.0 simple_optimality_criteria { }");
151 EXPECT_EQ(
status.code(), absl::StatusCode::kInvalidArgument);
152 EXPECT_THAT(
status.message(), HasSubstr(
"simple_optimality_criteria"));
156 TerminationCriteria termination_criteria =
157 ParseTextOrDie<TerminationCriteria>(
158 "eps_optimal_absolute: 1.0 detailed_optimality_criteria { }");
160 EXPECT_EQ(
status.code(), absl::StatusCode::kInvalidArgument);
161 EXPECT_THAT(
status.message(), HasSubstr(
"detailed_optimality_criteria"));
165 TerminationCriteria termination_criteria =
166 ParseTextOrDie<TerminationCriteria>(
167 "eps_optimal_relative: 1.0 detailed_optimality_criteria { }");
169 EXPECT_EQ(
status.code(), absl::StatusCode::kInvalidArgument);
170 EXPECT_THAT(
status.message(), HasSubstr(
"detailed_optimality_criteria"));
174 TerminationCriteria criteria_negative;
175 criteria_negative.set_eps_primal_infeasible(-1.0);
176 const absl::Status status_negative =
178 EXPECT_EQ(status_negative.code(), absl::StatusCode::kInvalidArgument);
179 EXPECT_THAT(status_negative.message(), HasSubstr(
"eps_primal_infeasible"));
181 TerminationCriteria criteria_nan;
182 criteria_nan.set_eps_primal_infeasible(
183 std::numeric_limits<double>::quiet_NaN());
185 EXPECT_EQ(status_nan.code(), absl::StatusCode::kInvalidArgument);
186 EXPECT_THAT(status_nan.message(), HasSubstr(
"eps_primal_infeasible"));
190 TerminationCriteria criteria_negative;
191 criteria_negative.set_eps_dual_infeasible(-1.0);
192 const absl::Status status_negative =
194 EXPECT_EQ(status_negative.code(), absl::StatusCode::kInvalidArgument);
195 EXPECT_THAT(status_negative.message(), HasSubstr(
"eps_dual_infeasible"));
197 TerminationCriteria criteria_nan;
198 criteria_nan.set_eps_dual_infeasible(
199 std::numeric_limits<double>::quiet_NaN());
201 EXPECT_EQ(status_nan.code(), absl::StatusCode::kInvalidArgument);
202 EXPECT_THAT(status_nan.message(), HasSubstr(
"eps_dual_infeasible"));
206 TerminationCriteria criteria_negative;
207 criteria_negative.set_time_sec_limit(-1.0);
208 const absl::Status status_negative =
210 EXPECT_EQ(status_negative.code(), absl::StatusCode::kInvalidArgument);
211 EXPECT_THAT(status_negative.message(), HasSubstr(
"time_sec_limit"));
213 TerminationCriteria criteria_nan;
214 criteria_nan.set_time_sec_limit(std::numeric_limits<double>::quiet_NaN());
216 EXPECT_EQ(status_nan.code(), absl::StatusCode::kInvalidArgument);
217 EXPECT_THAT(status_nan.message(), HasSubstr(
"time_sec_limit"));
221 TerminationCriteria criteria;
222 criteria.set_iteration_limit(-1);
224 EXPECT_EQ(
status.code(), absl::StatusCode::kInvalidArgument);
225 EXPECT_THAT(
status.message(), HasSubstr(
"iteration_limit"));
229 TerminationCriteria criteria_negative;
230 criteria_negative.set_kkt_matrix_pass_limit(-1.0);
231 const absl::Status status_negative =
233 EXPECT_EQ(status_negative.code(), absl::StatusCode::kInvalidArgument);
234 EXPECT_THAT(status_negative.message(), HasSubstr(
"kkt_matrix_pass_limit"));
236 TerminationCriteria criteria_nan;
237 criteria_nan.set_kkt_matrix_pass_limit(
238 std::numeric_limits<double>::quiet_NaN());
240 EXPECT_EQ(status_nan.code(), absl::StatusCode::kInvalidArgument);
241 EXPECT_THAT(status_nan.message(), HasSubstr(
"kkt_matrix_pass_limit"));
245 AdaptiveLinesearchParams params;
251 AdaptiveLinesearchParams params_low;
252 params_low.set_step_size_reduction_exponent(0.0);
254 EXPECT_EQ(status_low.code(), absl::StatusCode::kInvalidArgument);
255 EXPECT_THAT(status_low.message(), HasSubstr(
"step_size_reduction_exponent"));
257 AdaptiveLinesearchParams params_nan;
258 params_nan.set_step_size_reduction_exponent(
259 std::numeric_limits<double>::quiet_NaN());
261 EXPECT_EQ(status_nan.code(), absl::StatusCode::kInvalidArgument);
262 EXPECT_THAT(status_nan.message(), HasSubstr(
"step_size_reduction_exponent"));
266 AdaptiveLinesearchParams params_low;
267 params_low.set_step_size_growth_exponent(0.0);
269 EXPECT_EQ(status_low.code(), absl::StatusCode::kInvalidArgument);
270 EXPECT_THAT(status_low.message(), HasSubstr(
"step_size_growth_exponent"));
272 AdaptiveLinesearchParams params_nan;
273 params_nan.set_step_size_growth_exponent(
274 std::numeric_limits<double>::quiet_NaN());
276 EXPECT_EQ(status_nan.code(), absl::StatusCode::kInvalidArgument);
277 EXPECT_THAT(status_nan.message(), HasSubstr(
"step_size_growth_exponent"));
281 MalitskyPockParams params;
287 MalitskyPockParams params_low;
288 params_low.set_step_size_downscaling_factor(0.0);
290 EXPECT_EQ(status_low.code(), absl::StatusCode::kInvalidArgument);
291 EXPECT_THAT(status_low.message(), HasSubstr(
"step_size_downscaling_factor"));
293 MalitskyPockParams params_high;
294 params_high.set_step_size_downscaling_factor(1.0);
296 EXPECT_EQ(status_high.code(), absl::StatusCode::kInvalidArgument);
297 EXPECT_THAT(status_high.message(), HasSubstr(
"step_size_downscaling_factor"));
299 MalitskyPockParams params_nan;
300 params_nan.set_step_size_downscaling_factor(
301 std::numeric_limits<double>::quiet_NaN());
303 EXPECT_EQ(status_nan.code(), absl::StatusCode::kInvalidArgument);
304 EXPECT_THAT(status_nan.message(), HasSubstr(
"step_size_downscaling_factor"));
308 MalitskyPockParams params_low;
309 params_low.set_linesearch_contraction_factor(0.0);
311 EXPECT_EQ(status_low.code(), absl::StatusCode::kInvalidArgument);
312 EXPECT_THAT(status_low.message(), HasSubstr(
"linesearch_contraction_factor"));
314 MalitskyPockParams params_high;
315 params_high.set_linesearch_contraction_factor(1.0);
317 EXPECT_EQ(status_high.code(), absl::StatusCode::kInvalidArgument);
318 EXPECT_THAT(status_high.message(),
319 HasSubstr(
"linesearch_contraction_factor"));
321 MalitskyPockParams params_nan;
322 params_nan.set_linesearch_contraction_factor(
323 std::numeric_limits<double>::quiet_NaN());
325 EXPECT_EQ(status_nan.code(), absl::StatusCode::kInvalidArgument);
326 EXPECT_THAT(status_nan.message(), HasSubstr(
"linesearch_contraction_factor"));
330 MalitskyPockParams params_negative;
331 params_negative.set_step_size_interpolation(-1.0);
332 const absl::Status status_negative =
334 EXPECT_EQ(status_negative.code(), absl::StatusCode::kInvalidArgument);
335 EXPECT_THAT(status_negative.message(), HasSubstr(
"step_size_interpolation"));
337 MalitskyPockParams params_nan;
338 params_nan.set_step_size_interpolation(
339 std::numeric_limits<double>::quiet_NaN());
341 EXPECT_EQ(status_nan.code(), absl::StatusCode::kInvalidArgument);
342 EXPECT_THAT(status_nan.message(), HasSubstr(
"step_size_interpolation"));
346 PrimalDualHybridGradientParams params;
352 PrimalDualHybridGradientParams params;
353 params.mutable_termination_criteria()->set_eps_dual_infeasible(-1.0);
355 EXPECT_EQ(
status.code(), absl::StatusCode::kInvalidArgument);
356 EXPECT_THAT(
status.message(), HasSubstr(
"eps_dual_infeasible"));
360 PrimalDualHybridGradientParams params;
361 params.set_num_threads(0);
363 EXPECT_EQ(
status.code(), absl::StatusCode::kInvalidArgument);
364 EXPECT_THAT(
status.message(), HasSubstr(
"num_threads"));
368 PrimalDualHybridGradientParams params;
369 params.set_verbosity_level(-1);
371 EXPECT_EQ(
status.code(), absl::StatusCode::kInvalidArgument);
372 EXPECT_THAT(
status.message(), HasSubstr(
"verbosity_level"));
376 PrimalDualHybridGradientParams params;
377 params.set_major_iteration_frequency(0);
379 EXPECT_EQ(
status.code(), absl::StatusCode::kInvalidArgument);
380 EXPECT_THAT(
status.message(), HasSubstr(
"major_iteration_frequency"));
384 PrimalDualHybridGradientParams params;
385 params.set_termination_check_frequency(0);
387 EXPECT_EQ(
status.code(), absl::StatusCode::kInvalidArgument);
388 EXPECT_THAT(
status.message(), HasSubstr(
"termination_check_frequency"));
392 PrimalDualHybridGradientParams params;
393 params.set_restart_strategy(
394 PrimalDualHybridGradientParams::RESTART_STRATEGY_UNSPECIFIED);
396 EXPECT_EQ(
status.code(), absl::StatusCode::kInvalidArgument);
397 EXPECT_THAT(
status.message(), HasSubstr(
"restart_strategy"));
401 PrimalDualHybridGradientParams params_high;
402 params_high.set_primal_weight_update_smoothing(1.1);
403 const absl::Status status_high =
405 EXPECT_EQ(status_high.code(), absl::StatusCode::kInvalidArgument);
406 EXPECT_THAT(status_high.message(),
407 HasSubstr(
"primal_weight_update_smoothing"));
409 PrimalDualHybridGradientParams params_low;
410 params_low.set_primal_weight_update_smoothing(-0.1);
411 const absl::Status status_low =
413 EXPECT_EQ(status_low.code(), absl::StatusCode::kInvalidArgument);
414 EXPECT_THAT(status_low.message(),
415 HasSubstr(
"primal_weight_update_smoothing"));
417 PrimalDualHybridGradientParams params_nan;
418 params_nan.set_primal_weight_update_smoothing(
419 std::numeric_limits<double>::quiet_NaN());
420 const absl::Status status_nan =
422 EXPECT_EQ(status_nan.code(), absl::StatusCode::kInvalidArgument);
423 EXPECT_THAT(status_nan.message(),
424 HasSubstr(
"primal_weight_update_smoothing"));
428 PrimalDualHybridGradientParams params_negative;
429 params_negative.set_initial_primal_weight(-1.0);
430 const absl::Status status_negative =
432 EXPECT_EQ(status_negative.code(), absl::StatusCode::kInvalidArgument);
433 EXPECT_THAT(status_negative.message(), HasSubstr(
"initial_primal_weight"));
435 PrimalDualHybridGradientParams params_nan;
436 params_nan.set_initial_primal_weight(
437 std::numeric_limits<double>::quiet_NaN());
438 const absl::Status status_nan =
440 EXPECT_EQ(status_nan.code(), absl::StatusCode::kInvalidArgument);
441 EXPECT_THAT(status_nan.message(), HasSubstr(
"initial_primal_weight"));
445 PrimalDualHybridGradientParams params;
446 params.set_l_inf_ruiz_iterations(-1);
447 const absl::Status status_low =
449 EXPECT_EQ(status_low.code(), absl::StatusCode::kInvalidArgument);
450 EXPECT_THAT(status_low.message(), HasSubstr(
"l_inf_ruiz_iterations"));
452 params.set_l_inf_ruiz_iterations(1000);
453 const absl::Status status_high =
455 EXPECT_EQ(status_high.code(), absl::StatusCode::kInvalidArgument);
456 EXPECT_THAT(status_high.message(), HasSubstr(
"l_inf_ruiz_iterations"));
460 PrimalDualHybridGradientParams params_high;
461 params_high.set_sufficient_reduction_for_restart(1.0);
462 const absl::Status status_high =
464 EXPECT_EQ(status_high.code(), absl::StatusCode::kInvalidArgument);
465 EXPECT_THAT(status_high.message(),
466 HasSubstr(
"sufficient_reduction_for_restart"));
468 PrimalDualHybridGradientParams params_low;
469 params_low.set_sufficient_reduction_for_restart(0.0);
470 const absl::Status status_low =
472 EXPECT_EQ(status_low.code(), absl::StatusCode::kInvalidArgument);
473 EXPECT_THAT(status_low.message(),
474 HasSubstr(
"sufficient_reduction_for_restart"));
476 PrimalDualHybridGradientParams params_nan;
477 params_nan.set_sufficient_reduction_for_restart(
478 std::numeric_limits<double>::quiet_NaN());
479 const absl::Status status_nan =
481 EXPECT_EQ(status_nan.code(), absl::StatusCode::kInvalidArgument);
482 EXPECT_THAT(status_nan.message(),
483 HasSubstr(
"sufficient_reduction_for_restart"));
487 PrimalDualHybridGradientParams params_high;
488 params_high.set_necessary_reduction_for_restart(1.0);
489 const absl::Status status_high =
491 EXPECT_EQ(status_high.code(), absl::StatusCode::kInvalidArgument);
492 EXPECT_THAT(status_high.message(),
493 HasSubstr(
"necessary_reduction_for_restart"));
495 PrimalDualHybridGradientParams params_low;
496 params_low.set_sufficient_reduction_for_restart(0.5);
497 params_low.set_necessary_reduction_for_restart(0.4);
498 const absl::Status status_low =
500 EXPECT_EQ(status_low.code(), absl::StatusCode::kInvalidArgument);
501 EXPECT_THAT(status_low.message(),
502 HasSubstr(
"necessary_reduction_for_restart"));
504 PrimalDualHybridGradientParams params_nan;
505 params_nan.set_necessary_reduction_for_restart(
506 std::numeric_limits<double>::quiet_NaN());
507 const absl::Status status_nan =
509 EXPECT_EQ(status_nan.code(), absl::StatusCode::kInvalidArgument);
510 EXPECT_THAT(status_nan.message(),
511 HasSubstr(
"necessary_reduction_for_restart"));
515 PrimalDualHybridGradientParams params;
516 params.set_linesearch_rule(
517 PrimalDualHybridGradientParams::LINESEARCH_RULE_UNSPECIFIED);
519 EXPECT_EQ(
status.code(), absl::StatusCode::kInvalidArgument);
520 EXPECT_THAT(
status.message(), HasSubstr(
"linesearch_rule"));
524 PrimalDualHybridGradientParams params;
525 params.mutable_adaptive_linesearch_parameters()
526 ->set_step_size_reduction_exponent(-1.0);
528 EXPECT_EQ(
status.code(), absl::StatusCode::kInvalidArgument);
529 EXPECT_THAT(
status.message(), HasSubstr(
"step_size_reduction_exponent"));
533 PrimalDualHybridGradientParams params;
534 params.mutable_malitsky_pock_parameters()->set_linesearch_contraction_factor(
537 EXPECT_EQ(
status.code(), absl::StatusCode::kInvalidArgument);
538 EXPECT_THAT(
status.message(), HasSubstr(
"linesearch_contraction_factor"));
542 PrimalDualHybridGradientParams params_negative;
543 params_negative.set_initial_step_size_scaling(-1.0);
544 const absl::Status status_negative =
546 EXPECT_EQ(status_negative.code(), absl::StatusCode::kInvalidArgument);
547 EXPECT_THAT(status_negative.message(),
548 HasSubstr(
"initial_step_size_scaling"));
550 PrimalDualHybridGradientParams params_nan;
551 params_nan.set_initial_step_size_scaling(
552 std::numeric_limits<double>::quiet_NaN());
553 const absl::Status status_nan =
555 EXPECT_EQ(status_nan.code(), absl::StatusCode::kInvalidArgument);
556 EXPECT_THAT(status_nan.message(), HasSubstr(
"initial_step_size_scaling"));
560 BadInfiniteConstraintBoundThreshold) {
561 PrimalDualHybridGradientParams params_negative;
562 params_negative.set_infinite_constraint_bound_threshold(-1.0);
563 const absl::Status status_negative =
565 EXPECT_EQ(status_negative.code(), absl::StatusCode::kInvalidArgument);
566 EXPECT_THAT(status_negative.message(),
567 HasSubstr(
"infinite_constraint_bound_threshold"));
569 PrimalDualHybridGradientParams params_nan;
570 params_nan.set_infinite_constraint_bound_threshold(
571 std::numeric_limits<double>::quiet_NaN());
572 const absl::Status status_nan =
574 EXPECT_EQ(status_nan.code(), absl::StatusCode::kInvalidArgument);
575 EXPECT_THAT(status_nan.message(),
576 HasSubstr(
"infinite_constraint_bound_threshold"));
580 BadDiagonalTrustRegionSolverTolerance) {
581 PrimalDualHybridGradientParams params_negative;
582 params_negative.set_diagonal_qp_trust_region_solver_tolerance(-1.0);
583 const absl::Status status_negative =
585 EXPECT_EQ(status_negative.code(), absl::StatusCode::kInvalidArgument);
586 EXPECT_THAT(status_negative.message(),
587 HasSubstr(
"diagonal_qp_trust_region_solver_tolerance"));
589 PrimalDualHybridGradientParams params_nan;
590 params_nan.set_diagonal_qp_trust_region_solver_tolerance(
591 std::numeric_limits<double>::quiet_NaN());
592 const absl::Status status_nan =
594 EXPECT_EQ(status_nan.code(), absl::StatusCode::kInvalidArgument);
595 EXPECT_THAT(status_nan.message(),
596 HasSubstr(
"diagonal_qp_trust_region_solver_tolerance"));
T ParseTextOrDie(const std::string &input)
absl::Status ValidateTerminationCriteria(const TerminationCriteria &criteria)
absl::Status ValidateMalitskyPockParams(const MalitskyPockParams ¶ms)
absl::Status ValidateAdaptiveLinesearchParams(const AdaptiveLinesearchParams ¶ms)
absl::Status ValidatePrimalDualHybridGradientParams(const PrimalDualHybridGradientParams ¶ms)
TEST(LinearAssignmentTest, NullMatrix)