OR-Tools  9.3
matchers.cc
Go to the documentation of this file.
1// Copyright 2010-2021 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 <algorithm>
17#include <cmath>
18#include <cstdlib>
19#include <optional>
20#include <string>
21#include <type_traits>
22#include <utility>
23#include <vector>
24
25#include "absl/strings/str_cat.h"
26#include "absl/types/span.h"
27#include "gmock/gmock.h"
28#include "gtest/gtest.h"
31
32namespace operations_research {
33namespace math_opt {
34
35namespace {
36
37using ::testing::AllOf;
38using ::testing::AllOfArray;
39using ::testing::AnyOf;
40using ::testing::AnyOfArray;
41using ::testing::Contains;
42using ::testing::DoubleNear;
43using ::testing::ExplainMatchResult;
44using ::testing::Field;
45using ::testing::IsEmpty;
46using ::testing::Matcher;
47using ::testing::MatcherInterface;
48using ::testing::MatchResultListener;
49using ::testing::Optional;
50using ::testing::PrintToString;
51} // namespace
52
54// Printing
56
57namespace {
58
59template <typename T>
60struct Printer {
61 explicit Printer(const T& t) : value(t) {}
62
63 const T& value;
64
65 friend std::ostream& operator<<(std::ostream& os, const Printer& printer) {
66 os << PrintToString(printer.value);
67 return os;
68 }
69};
70
71template <typename T>
72Printer<T> Print(const T& t) {
73 return Printer<T>(t);
74}
75
76} // namespace
77
78void PrintTo(const Termination& termination, std::ostream* os) {
79 *os << "{reason: " << termination.reason;
80 if (termination.limit.has_value()) {
81 *os << ", limit: " << *termination.limit;
82 }
83 *os << ", detail: " << Print(termination.detail) << "}";
84}
85
86void PrintTo(const PrimalSolution& primal_solution, std::ostream* const os) {
87 *os << "{variable_values: " << Print(primal_solution.variable_values)
88 << ", objective_value: " << Print(primal_solution.objective_value)
89 << ", feasibility_status: " << Print(primal_solution.feasibility_status)
90 << "}";
91}
92
93void PrintTo(const DualSolution& dual_solution, std::ostream* const os) {
94 *os << "{dual_values: " << Print(dual_solution.dual_values)
95 << ", reduced_costs: " << Print(dual_solution.reduced_costs)
96 << ", objective_value: " << Print(dual_solution.objective_value)
97 << ", feasibility_status: " << Print(dual_solution.feasibility_status)
98 << "}";
99}
100
101void PrintTo(const PrimalRay& primal_ray, std::ostream* const os) {
102 *os << "{variable_values: " << Print(primal_ray.variable_values) << "}";
103}
104
105void PrintTo(const DualRay& dual_ray, std::ostream* const os) {
106 *os << "{dual_values: " << Print(dual_ray.dual_values)
107 << ", reduced_costs: " << Print(dual_ray.reduced_costs) << "}";
108}
109
110void PrintTo(const Basis& basis, std::ostream* const os) {
111 *os << "{variable_status: " << Print(basis.variable_status)
112 << ", constraint_status: " << Print(basis.constraint_status)
113 << ", basic_dual_feasibility: " << Print(basis.basic_dual_feasibility)
114 << "}";
115}
116
117void PrintTo(const Solution& solution, std::ostream* const os) {
118 *os << "{primal_solution: " << Print(solution.primal_solution)
119 << ", dual_solution: " << Print(solution.dual_solution)
120 << ", basis: " << Print(solution.basis) << "}";
121}
122
123void PrintTo(const SolveResult& result, std::ostream* const os) {
124 *os << "{termination: " << Print(result.termination)
125 << ", solve_stats: " << Print(result.solve_stats)
126 << ", solutions: " << Print(result.solutions)
127 << ", primal_rays: " << Print(result.primal_rays)
128 << ", dual_rays: " << Print(result.dual_rays) << "}";
129}
130
132// IdMap Matchers
134
135namespace {
136
137template <typename K>
138class IdMapMatcher : public MatcherInterface<IdMap<K, double>> {
139 public:
140 IdMapMatcher(IdMap<K, double> expected, const bool all_keys,
141 const double tolerance)
142 : expected_(std::move(expected)),
143 all_keys_(all_keys),
144 tolerance_(tolerance) {
145 for (const auto [k, v] : expected_) {
146 CHECK(!std::isnan(v)) << "Illegal NaN for key: " << k;
147 }
148 }
149
150 bool MatchAndExplain(IdMap<K, double> actual,
151 MatchResultListener* const os) const override {
152 for (const auto& [key, value] : expected_) {
153 if (!actual.contains(key)) {
154 *os << "expected key " << key << " not found";
155 return false;
156 }
157 if (!(std::abs(value - actual.at(key)) <= tolerance_)) {
158 *os << "value for key " << key
159 << " not within tolerance, expected: " << value
160 << " but found: " << actual.at(key);
161 return false;
162 }
163 }
164 // Post condition: expected_ is a subset of actual.
165 if (all_keys_ && expected_.size() != actual.size()) {
166 for (const auto& [key, value] : actual) {
167 if (!expected_.contains(key)) {
168 *os << "found unexpected key " << key << " in actual";
169 return false;
170 }
171 }
172 // expected_ subset of actual && expected_.size() != actual.size() implies
173 // that there is a member A of actual not in expected. When the loop above
174 // hits A, it will return, thus this line is unreachable.
175 LOG(FATAL) << "unreachable";
176 }
177 return true;
178 }
179
180 void DescribeTo(std::ostream* const os) const override {
181 if (all_keys_) {
182 *os << "has identical keys to ";
183 } else {
184 *os << "keys are contained in ";
185 }
186 PrintTo(expected_, os);
187 *os << " and values within " << tolerance_;
188 }
189
190 void DescribeNegationTo(std::ostream* const os) const override {
191 if (all_keys_) {
192 *os << "either keys differ from ";
193 } else {
194 *os << "either has a key not in ";
195 }
196 PrintTo(expected_, os);
197 *os << " or a value differs by more than " << tolerance_;
198 }
199
200 private:
201 const IdMap<K, double> expected_;
202 const bool all_keys_;
203 const double tolerance_;
204};
205
206} // namespace
207
208Matcher<VariableMap<double>> IsNearlySubsetOf(VariableMap<double> expected,
209 double tolerance) {
210 return Matcher<VariableMap<double>>(new IdMapMatcher<Variable>(
211 std::move(expected), /*all_keys=*/false, tolerance));
212}
213
214Matcher<VariableMap<double>> IsNear(VariableMap<double> expected,
215 const double tolerance) {
216 return Matcher<VariableMap<double>>(new IdMapMatcher<Variable>(
217 std::move(expected), /*all_keys=*/true, tolerance));
218}
219
220Matcher<LinearConstraintMap<double>> IsNearlySubsetOf(
221 LinearConstraintMap<double> expected, double tolerance) {
222 return Matcher<LinearConstraintMap<double>>(
223 new IdMapMatcher<LinearConstraint>(std::move(expected),
224 /*all_keys=*/false, tolerance));
225}
226
227Matcher<LinearConstraintMap<double>> IsNear(
228 LinearConstraintMap<double> expected, const double tolerance) {
229 return Matcher<LinearConstraintMap<double>>(
230 new IdMapMatcher<LinearConstraint>(std::move(expected), /*all_keys=*/true,
231 tolerance));
232}
233
235// Matcher helpers
237
238namespace {
239
240template <typename RayType>
241class RayMatcher : public MatcherInterface<RayType> {
242 public:
243 RayMatcher(RayType expected, const double tolerance)
244 : expected_(std::move(expected)), tolerance_(tolerance) {}
245 void DescribeTo(std::ostream* os) const final {
246 *os << "after L_inf normalization, is within tolerance: " << tolerance_
247 << " of expected: ";
248 PrintTo(expected_, os);
249 }
250 void DescribeNegationTo(std::ostream* const os) const final {
251 *os << "after L_inf normalization, is not within tolerance: " << tolerance_
252 << " of expected: ";
253 PrintTo(expected_, os);
254 }
255
256 protected:
257 const RayType expected_;
258 const double tolerance_;
259};
260
261// Alias to use the std::optional templated adaptor.
262Matcher<double> IsNear(double expected, const double tolerance) {
263 return DoubleNear(expected, tolerance);
264}
265
266template <typename Type>
267Matcher<std::optional<Type>> IsNear(std::optional<Type> expected,
268 const double tolerance) {
269 if (expected.has_value()) {
270 return Optional(IsNear(*expected, tolerance));
271 }
272 return testing::Eq(std::nullopt);
273}
274
275// Custom std::optional for basis.
276Matcher<std::optional<Basis>> BasisIs(const std::optional<Basis>& expected) {
277 if (expected.has_value()) {
278 return Optional(BasisIs(*expected));
279 }
280 return testing::Eq(std::nullopt);
281}
282
283testing::Matcher<std::vector<Solution>> IsNear(
284 const std::vector<Solution>& expected_solutions,
285 const SolutionMatcherOptions options) {
286 if (expected_solutions.empty()) {
287 return IsEmpty();
288 }
289 std::vector<Matcher<Solution>> matchers;
290 for (const Solution& sol : expected_solutions) {
291 matchers.push_back(IsNear(sol, options));
292 }
293 return ::testing::ElementsAreArray(matchers);
294}
295
296} // namespace
297
299// Matchers for Solutions
301
302Matcher<PrimalSolution> IsNear(PrimalSolution expected,
303 const double tolerance) {
304 return AllOf(Field("variable_values", &PrimalSolution::variable_values,
305 IsNear(expected.variable_values, tolerance)),
306 Field("objective_value", &PrimalSolution::objective_value,
307 IsNear(expected.objective_value, tolerance)),
308 Field("feasibility_status", &PrimalSolution::feasibility_status,
309 expected.feasibility_status));
310}
311
312Matcher<DualSolution> IsNear(DualSolution expected, const double tolerance) {
313 return AllOf(Field("dual_values", &DualSolution::dual_values,
314 IsNear(expected.dual_values, tolerance)),
315 Field("reduced_costs", &DualSolution::reduced_costs,
316 IsNear(expected.reduced_costs, tolerance)),
317 Field("objective_value", &DualSolution::objective_value,
318 IsNear(expected.objective_value, tolerance)),
319 Field("feasibility_status", &DualSolution::feasibility_status,
320 expected.feasibility_status));
321}
322
323Matcher<Basis> BasisIs(const Basis& expected) {
324 return AllOf(Field("variable_status", &Basis::variable_status,
325 expected.variable_status),
326 Field("constraint_status", &Basis::constraint_status,
327 expected.constraint_status),
328 Field("basic_dual_feasibility", &Basis::basic_dual_feasibility,
329 expected.basic_dual_feasibility));
330}
331
332Matcher<Solution> IsNear(Solution expected,
333 const SolutionMatcherOptions options) {
334 std::vector<Matcher<Solution>> to_check;
335 if (options.check_primal) {
336 to_check.push_back(
337 Field("primal_solution", &Solution::primal_solution,
338 IsNear(expected.primal_solution, options.tolerance)));
339 }
340 if (options.check_dual) {
341 to_check.push_back(
342 Field("dual_solution", &Solution::dual_solution,
343 IsNear(expected.dual_solution, options.tolerance)));
344 }
345 if (options.check_basis) {
346 to_check.push_back(
347 Field("basis", &Solution::basis, BasisIs(expected.basis)));
348 }
349 return AllOfArray(to_check);
350}
351
353// Primal Ray Matcher
355
356namespace {
357
358template <typename K>
359double InfinityNorm(const IdMap<K, double>& vector) {
360 double infinity_norm = 0.0;
361 for (auto [id, value] : vector) {
362 infinity_norm = std::max(infinity_norm, std::abs(value));
363 }
364 return infinity_norm;
365}
366
367// Returns a normalized primal ray.
368//
369// The normalization is done using infinity norm:
370//
371// ray / ||ray||_inf
372//
373// If the input ray norm is zero, the ray is returned unchanged.
374PrimalRay NormalizePrimalRay(PrimalRay ray) {
375 const double norm = InfinityNorm(ray.variable_values);
376 if (norm != 0.0) {
377 for (auto entry : ray.variable_values) {
378 entry.second /= norm;
379 }
380 }
381 return ray;
382}
383
384class PrimalRayMatcher : public RayMatcher<PrimalRay> {
385 public:
386 PrimalRayMatcher(PrimalRay expected, const double tolerance)
387 : RayMatcher(std::move(expected), tolerance) {}
388
389 bool MatchAndExplain(PrimalRay actual,
390 MatchResultListener* const os) const override {
391 auto normalized_actual = NormalizePrimalRay(actual);
392 auto normalized_expected = NormalizePrimalRay(expected_);
393 if (os->IsInterested()) {
394 *os << "actual normalized: " << PrintToString(normalized_actual)
395 << ", expected normalized: " << PrintToString(normalized_expected);
396 }
397 return ExplainMatchResult(
398 IsNear(normalized_expected.variable_values, tolerance_),
399 normalized_actual.variable_values, os);
400 }
401};
402
403} // namespace
404
405Matcher<PrimalRay> IsNear(PrimalRay expected, const double tolerance) {
406 return Matcher<PrimalRay>(
407 new PrimalRayMatcher(std::move(expected), tolerance));
408}
409
410Matcher<PrimalRay> PrimalRayIsNear(VariableMap<double> expected_var_values,
411 const double tolerance) {
412 PrimalRay expected;
413 expected.variable_values = std::move(expected_var_values);
414 return IsNear(expected, tolerance);
415}
416
418// Dual Ray Matcher
420
421namespace {
422
423// Returns a normalized dual ray.
424//
425// The normalization is done using infinity norm:
426//
427// ray / ||ray||_inf
428//
429// If the input ray norm is zero, the ray is returned unchanged.
430DualRay NormalizeDualRay(DualRay ray) {
431 const double norm =
432 std::max(InfinityNorm(ray.dual_values), InfinityNorm(ray.reduced_costs));
433 if (norm != 0.0) {
434 for (auto entry : ray.dual_values) {
435 entry.second /= norm;
436 }
437 for (auto entry : ray.reduced_costs) {
438 entry.second /= norm;
439 }
440 }
441 return ray;
442}
443
444class DualRayMatcher : public RayMatcher<DualRay> {
445 public:
446 DualRayMatcher(DualRay expected, const double tolerance)
447 : RayMatcher(std::move(expected), tolerance) {}
448
449 bool MatchAndExplain(DualRay actual, MatchResultListener* os) const override {
450 auto normalized_actual = NormalizeDualRay(actual);
451 auto normalized_expected = NormalizeDualRay(expected_);
452 if (os->IsInterested()) {
453 *os << "actual normalized: " << PrintToString(normalized_actual)
454 << ", expected normalized: " << PrintToString(normalized_expected);
455 }
456 return ExplainMatchResult(
457 IsNear(normalized_expected.dual_values, tolerance_),
458 normalized_actual.dual_values, os) &&
459 ExplainMatchResult(
460 IsNear(normalized_expected.reduced_costs, tolerance_),
461 normalized_actual.reduced_costs, os);
462 }
463};
464
465} // namespace
466
467Matcher<DualRay> IsNear(DualRay expected, const double tolerance) {
468 return Matcher<DualRay>(new DualRayMatcher(std::move(expected), tolerance));
469}
470
472// SolveResult termination reason matchers
474
475Matcher<SolveResult> TerminatesWithOneOf(
476 const std::vector<TerminationReason>& allowed) {
477 return Field("termination", &SolveResult::termination,
478 Field("reason", &Termination::reason, AnyOfArray(allowed)));
479}
480
481Matcher<SolveResult> TerminatesWith(const TerminationReason expected) {
482 return Field("termination", &SolveResult::termination,
483 Field("reason", &Termination::reason, expected));
484}
485
486namespace {
487testing::Matcher<SolveResult> LimitIs(const Limit expected,
488 const bool allow_limit_undetermined) {
489 if (allow_limit_undetermined) {
490 return Field("termination", &SolveResult::termination,
491 Field("limit", &Termination::limit,
492 AnyOf(Limit::kUndetermined, expected)));
493 }
494 return Field("termination", &SolveResult::termination,
495 Field("limit", &Termination::limit, expected));
496}
497
498} // namespace
499
500testing::Matcher<SolveResult> TerminatesWithLimit(
501 const Limit expected, const bool allow_limit_undetermined) {
502 std::vector<Matcher<SolveResult>> matchers;
503 matchers.push_back(LimitIs(expected, allow_limit_undetermined));
504 matchers.push_back(TerminatesWithOneOf(
506 return ::testing::AllOfArray(matchers);
507}
508
509testing::Matcher<SolveResult> TerminatesWithReasonFeasible(
510 const Limit expected, const bool allow_limit_undetermined) {
511 std::vector<Matcher<SolveResult>> matchers;
512 matchers.push_back(LimitIs(expected, allow_limit_undetermined));
513 matchers.push_back(TerminatesWith(TerminationReason::kFeasible));
514 return ::testing::AllOfArray(matchers);
515}
516
517testing::Matcher<SolveResult> TerminatesWithReasonNoSolutionFound(
518 const Limit expected, const bool allow_limit_undetermined) {
519 std::vector<Matcher<SolveResult>> matchers;
520 matchers.push_back(LimitIs(expected, allow_limit_undetermined));
522 return ::testing::AllOfArray(matchers);
523}
524
525template <typename MatcherType>
526std::string MatcherToStringImpl(const MatcherType& matcher, const bool negate) {
527 std::ostringstream os;
528 if (negate) {
529 matcher.DescribeNegationTo(&os);
530 } else {
531 matcher.DescribeTo(&os);
532 }
533 return os.str();
534}
535
536template <typename T>
537std::string MatcherToString(const Matcher<T>& matcher, bool negate) {
538 return MatcherToStringImpl(matcher, negate);
539}
540
541// Polymorphic matchers do not always define DescribeTo, see
542// The <T> type may not be a matcher, but it will implement DescribeTo.
543template <typename T>
544std::string MatcherToString(const ::testing::PolymorphicMatcher<T>& matcher,
545 bool negate) {
546 return MatcherToStringImpl(matcher.impl(), negate);
547}
548
549MATCHER_P(FirstElementIs, first_element_matcher,
550 (negation
551 ? absl::StrCat("is empty or first element ",
552 MatcherToString(first_element_matcher, true))
553 : absl::StrCat("has at least one element and first element ",
554 MatcherToString(first_element_matcher, false)))) {
555 return ExplainMatchResult(UnorderedElementsAre(first_element_matcher),
556 absl::MakeSpan(arg).subspan(0, 1), result_listener);
557}
558
559Matcher<SolveResult> IsOptimal(const std::optional<double> expected_objective,
560 const double tolerance) {
561 std::vector<Matcher<SolveResult>> matchers;
562 matchers.push_back(Field(
563 "termination", &SolveResult::termination,
565 if (expected_objective.has_value()) {
566 matchers.push_back(Field(
567 "solutions", &SolveResult::solutions,
568 FirstElementIs(Field(
569 "primal_solution", &Solution::primal_solution,
570 Optional(Field("objective_value", &PrimalSolution::objective_value,
571 IsNear(*expected_objective, tolerance)))))));
572 }
573 return ::testing::AllOfArray(matchers);
574}
575
576Matcher<SolveResult> IsOptimalWithSolution(
577 const double expected_objective,
578 const VariableMap<double> expected_variable_values,
579 const double tolerance) {
580 return AllOf(
581 IsOptimal(std::make_optional(expected_objective), tolerance),
583 PrimalSolution{.variable_values = expected_variable_values,
584 .objective_value = expected_objective,
585 .feasibility_status = SolutionStatus::kFeasible},
586 tolerance));
587}
588
589Matcher<SolveResult> IsOptimalWithDualSolution(
590 const double expected_objective,
591 const LinearConstraintMap<double> expected_dual_values,
592 const VariableMap<double> expected_reduced_costs, const double tolerance) {
593 return AllOf(
594 IsOptimal(std::make_optional(expected_objective), tolerance),
597 .dual_values = expected_dual_values,
598 .reduced_costs = expected_reduced_costs,
599 .objective_value = std::make_optional(expected_objective),
600 .feasibility_status = SolutionStatus::kFeasible},
601 tolerance));
602}
603
604Matcher<SolveResult> HasSolution(PrimalSolution expected,
605 const double tolerance) {
606 return ::testing::Field(
607 "solutions", &SolveResult::solutions,
608 Contains(Field("primal_solution", &Solution::primal_solution,
609 Optional(IsNear(std::move(expected), tolerance)))));
610}
611
612Matcher<SolveResult> HasDualSolution(DualSolution expected,
613 const double tolerance) {
614 return ::testing::Field(
615 "solutions", &SolveResult::solutions,
616 Contains(Field("dual_solution", &Solution::dual_solution,
617 Optional(IsNear(std::move(expected), tolerance)))));
618}
619
620Matcher<SolveResult> HasPrimalRay(PrimalRay expected, const double tolerance) {
621 return ::testing::Field("primal_rays", &SolveResult::primal_rays,
622 Contains(IsNear(std::move(expected), tolerance)));
623}
624
625Matcher<SolveResult> HasPrimalRay(VariableMap<double> expected_vars,
626 const double tolerance) {
627 PrimalRay ray;
628 ray.variable_values = std::move(expected_vars);
629 return HasPrimalRay(std::move(ray), tolerance);
630}
631
632Matcher<SolveResult> HasDualRay(DualRay expected, const double tolerance) {
633 return ::testing::Field("dual_rays", &SolveResult::dual_rays,
634 Contains(IsNear(std::move(expected), tolerance)));
635}
636
637namespace {
638
639bool MightTerminateWithRays(const TerminationReason reason) {
640 switch (reason) {
644 return true;
645 default:
646 return false;
647 }
648}
649
650std::vector<TerminationReason> CompatibleReasons(
651 const TerminationReason expected, const bool inf_or_unb_soft_match) {
652 if (!inf_or_unb_soft_match) {
653 return {expected};
654 }
655 switch (expected) {
665 default:
666 return {expected};
667 }
668}
669
670Matcher<std::vector<Solution>> CheckSolutions(
671 const std::vector<Solution>& expected_solutions,
672 const SolveResultMatcherOptions& options) {
673 if (options.first_solution_only && !expected_solutions.empty()) {
674 return FirstElementIs(
675 IsNear(expected_solutions[0],
676 SolutionMatcherOptions{.tolerance = options.tolerance,
677 .check_primal = true,
678 .check_dual = options.check_dual,
679 .check_basis = options.check_basis}));
680 }
681 return IsNear(expected_solutions,
682 SolutionMatcherOptions{.tolerance = options.tolerance,
683 .check_primal = true,
684 .check_dual = options.check_dual,
685 .check_basis = options.check_basis});
686}
687
688template <typename RayType>
689Matcher<std::vector<RayType>> AnyRayNear(
690 const std::vector<RayType>& expected_rays, const double tolerance) {
691 std::vector<Matcher<RayType>> matchers;
692 for (const RayType& ray : expected_rays) {
693 matchers.push_back(IsNear(ray, tolerance));
694 }
695 return ::testing::Contains(::testing::AnyOfArray(matchers));
696}
697
698template <typename RayType>
699Matcher<std::vector<RayType>> AllRaysNear(
700 const std::vector<RayType>& expected_rays, const double tolerance) {
701 std::vector<Matcher<RayType>> matchers;
702 for (const RayType& ray : expected_rays) {
703 matchers.push_back(IsNear(ray, tolerance));
704 }
705 return ::testing::UnorderedElementsAreArray(matchers);
706}
707
708template <typename RayType>
709Matcher<std::vector<RayType>> CheckRays(
710 const std::vector<RayType>& expected_rays, const double tolerance,
711 bool check_all) {
712 if (expected_rays.empty()) {
713 return ::testing::IsEmpty();
714 }
715 if (check_all) {
716 return AllRaysNear(expected_rays, tolerance);
717 }
718 return AnyRayNear(expected_rays, tolerance);
719}
720
721} // namespace
722
723Matcher<SolveResult> IsConsistentWith(
724 const SolveResult& expected, const SolveResultMatcherOptions& options) {
725 std::vector<Matcher<SolveResult>> to_check;
726 to_check.push_back(TerminatesWithOneOf(CompatibleReasons(
727 expected.termination.reason, options.inf_or_unb_soft_match)));
728 const bool skip_solution =
729 MightTerminateWithRays(expected.termination.reason) &&
731 if (!skip_solution) {
732 to_check.push_back(Field("solutions", &SolveResult::solutions,
733 CheckSolutions(expected.solutions, options)));
734 }
735 if (options.check_rays) {
736 to_check.push_back(Field("primal_rays", &SolveResult::primal_rays,
737 CheckRays(expected.primal_rays, options.tolerance,
738 !options.first_solution_only)));
739 to_check.push_back(Field("dual_rays", &SolveResult::dual_rays,
740 CheckRays(expected.dual_rays, options.tolerance,
741 !options.first_solution_only)));
742 }
743
744 return AllOfArray(to_check);
745}
746
748// Rarely used
750
751Matcher<IncrementalSolver::UpdateResult> DidUpdate() {
752 return ::testing::Field("did_update",
754 ::testing::IsTrue());
755}
756
757} // namespace math_opt
758} // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
#define CHECK(condition)
Definition: base/logging.h:495
#define LOG(severity)
Definition: base/logging.h:420
const int FATAL
Definition: log_severity.h:32
const T & value
Definition: matchers.cc:63
Fractional InfinityNorm(const DenseColumn &v)
Matcher< SolveResult > HasDualSolution(DualSolution expected, const double tolerance)
Definition: matchers.cc:612
Matcher< SolveResult > HasSolution(PrimalSolution expected, const double tolerance)
Definition: matchers.cc:604
testing::Matcher< SolveResult > TerminatesWithReasonNoSolutionFound(const Limit expected, const bool allow_limit_undetermined)
Definition: matchers.cc:517
Matcher< SolveResult > IsOptimal(const std::optional< double > expected_objective, const double tolerance)
Definition: matchers.cc:559
void PrintTo(const Termination &termination, std::ostream *os)
Definition: matchers.cc:78
std::ostream & operator<<(std::ostream &out, const E value)
Definition: enums.h:231
Matcher< IncrementalSolver::UpdateResult > DidUpdate()
Definition: matchers.cc:751
Matcher< SolveResult > IsOptimalWithSolution(const double expected_objective, const VariableMap< double > expected_variable_values, const double tolerance)
Definition: matchers.cc:576
Matcher< SolveResult > TerminatesWithOneOf(const std::vector< TerminationReason > &allowed)
Definition: matchers.cc:475
Matcher< SolveResult > IsConsistentWith(const SolveResult &expected, const SolveResultMatcherOptions &options)
Definition: matchers.cc:723
std::string MatcherToString(const Matcher< T > &matcher, bool negate)
Definition: matchers.cc:537
testing::Matcher< SolveResult > TerminatesWithReasonFeasible(const Limit expected, const bool allow_limit_undetermined)
Definition: matchers.cc:509
Matcher< VariableMap< double > > IsNearlySubsetOf(VariableMap< double > expected, double tolerance)
Definition: matchers.cc:208
std::string MatcherToStringImpl(const MatcherType &matcher, const bool negate)
Definition: matchers.cc:526
MATCHER_P(SparseVectorMatcher, pairs, "")
testing::Matcher< SolveResult > TerminatesWithLimit(const Limit expected, const bool allow_limit_undetermined)
Definition: matchers.cc:500
Matcher< SolveResult > HasDualRay(DualRay expected, const double tolerance)
Definition: matchers.cc:632
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:589
Matcher< SolveResult > TerminatesWith(const TerminationReason expected)
Definition: matchers.cc:481
Matcher< SolveResult > HasPrimalRay(PrimalRay expected, const double tolerance)
Definition: matchers.cc:620
Matcher< VariableMap< double > > IsNear(VariableMap< double > expected, const double tolerance)
Definition: matchers.cc:214
Matcher< Basis > BasisIs(const Basis &expected)
Definition: matchers.cc:323
Matcher< PrimalRay > PrimalRayIsNear(VariableMap< double > expected_var_values, const double tolerance)
Definition: matchers.cc:410
Collection of objects used to extend the Constraint Solver library.
STL namespace.
VariableMap< BasisStatus > variable_status
Definition: solution.h:204
LinearConstraintMap< BasisStatus > constraint_status
Definition: solution.h:203
LinearConstraintMap< double > dual_values
Definition: solution.h:165
VariableMap< double > reduced_costs
Definition: solution.h:166
LinearConstraintMap< double > dual_values
Definition: solution.h:134
std::optional< double > objective_value
Definition: solution.h:136
VariableMap< double > variable_values
Definition: solution.h:113
std::optional< DualSolution > dual_solution
Definition: solution.h:224
std::optional< PrimalSolution > primal_solution
Definition: solution.h:223
std::optional< Basis > basis
Definition: solution.h:225