26#include "absl/container/flat_hash_map.h"
27#include "absl/log/check.h"
28#include "absl/strings/str_cat.h"
29#include "absl/types/span.h"
30#include "gtest/gtest.h"
42using ::testing::AllOf;
43using ::testing::AllOfArray;
44using ::testing::AnyOf;
45using ::testing::AnyOfArray;
46using ::testing::Contains;
47using ::testing::DoubleNear;
49using ::testing::ExplainMatchResult;
50using ::testing::Field;
51using ::testing::IsEmpty;
52using ::testing::Matcher;
53using ::testing::MatcherInterface;
54using ::testing::MatchResultListener;
55using ::testing::Optional;
56using ::testing::PrintToString;
57using ::testing::Property;
69 explicit Printer(
const T& t) :
value(t) {}
73 friend std::ostream&
operator<<(std::ostream& os,
const Printer& printer) {
74 os << PrintToString(printer.value);
80Printer<T> Print(
const T& t) {
86void PrintTo(
const PrimalSolution& primal_solution, std::ostream*
const os) {
88 <<
", objective_value: " << Print(primal_solution.objective_value)
89 <<
", feasibility_status: " << Print(primal_solution.feasibility_status)
93void PrintTo(
const DualSolution& dual_solution, std::ostream*
const os) {
94 *os <<
"{dual_values: " << Print(dual_solution.dual_values)
95 <<
", quadratic_dual_values: "
96 << Print(dual_solution.quadratic_dual_values)
97 <<
", reduced_costs: " << Print(dual_solution.reduced_costs)
98 <<
", objective_value: " << Print(dual_solution.objective_value)
99 <<
", feasibility_status: " << Print(dual_solution.feasibility_status)
103void PrintTo(
const PrimalRay& primal_ray, std::ostream*
const os) {
104 *os <<
"{variable_values: " << Print(primal_ray.variable_values) <<
"}";
107void PrintTo(
const DualRay& dual_ray, std::ostream*
const os) {
108 *os <<
"{dual_values: " << Print(dual_ray.dual_values)
109 <<
", reduced_costs: " << Print(dual_ray.reduced_costs) <<
"}";
112void PrintTo(
const Basis& basis, std::ostream*
const os) {
113 *os <<
"{variable_status: " << Print(basis.variable_status)
114 <<
", constraint_status: " << Print(basis.constraint_status)
115 <<
", basic_dual_feasibility: " << Print(basis.basic_dual_feasibility)
120 *os <<
"{primal_solution: " << Print(
solution.primal_solution)
121 <<
", dual_solution: " << Print(
solution.dual_solution)
122 <<
", basis: " << Print(
solution.basis) <<
"}";
125void PrintTo(
const SolveResult& result, std::ostream*
const os) {
126 *os <<
"{termination: " << Print(result.termination)
127 <<
", solve_stats: " << Print(result.solve_stats)
128 <<
", solutions: " << Print(result.solutions)
129 <<
", primal_rays: " << Print(result.primal_rays)
130 <<
", dual_rays: " << Print(result.dual_rays) <<
"}";
140class MapToDoubleMatcher
141 :
public MatcherInterface<absl::flat_hash_map<K, double>> {
143 MapToDoubleMatcher(absl::flat_hash_map<K, double> expected,
144 const bool all_keys,
const double tolerance)
145 : expected_(std::move(expected)),
147 tolerance_(tolerance) {
148 for (
const auto [k, v] : expected_) {
149 CHECK(!std::isnan(v)) <<
"Illegal NaN for key: " << k;
153 bool MatchAndExplain(absl::flat_hash_map<K, double> actual,
154 MatchResultListener*
const os)
const override {
155 for (
const auto& [key,
value] : expected_) {
156 if (!actual.contains(key)) {
157 *os <<
"expected key " << key <<
" not found";
160 if (!(std::abs(
value - actual.at(key)) <= tolerance_)) {
161 *os <<
"value for key " << key
162 <<
" not within tolerance, expected: " <<
value
163 <<
" but found: " << actual.at(key);
168 if (all_keys_ && expected_.size() != actual.size()) {
169 for (
const auto& [key,
value] : actual) {
170 if (!expected_.contains(key)) {
171 *os <<
"found unexpected key " << key <<
" in actual";
178 LOG(FATAL) <<
"unreachable";
183 void DescribeTo(std::ostream*
const os)
const override {
185 *os <<
"has identical keys to ";
187 *os <<
"keys are contained in ";
190 *os <<
" and values within " << tolerance_;
193 void DescribeNegationTo(std::ostream*
const os)
const override {
195 *os <<
"either keys differ from ";
197 *os <<
"either has a key not in ";
200 *os <<
" or a value differs by more than " << tolerance_;
204 const absl::flat_hash_map<K, double> expected_;
205 const bool all_keys_;
206 const double tolerance_;
213 return Matcher<VariableMap<double>>(
new MapToDoubleMatcher<Variable>(
214 std::move(expected),
false, tolerance));
218 const double tolerance) {
219 return Matcher<VariableMap<double>>(
new MapToDoubleMatcher<Variable>(
220 std::move(expected),
true, tolerance));
225 return Matcher<LinearConstraintMap<double>>(
226 new MapToDoubleMatcher<LinearConstraint>(std::move(expected),
230Matcher<LinearConstraintMap<double>>
IsNear(
232 return Matcher<LinearConstraintMap<double>>(
233 new MapToDoubleMatcher<LinearConstraint>(std::move(expected),
237Matcher<absl::flat_hash_map<QuadraticConstraint, double>>
IsNear(
238 absl::flat_hash_map<QuadraticConstraint, double> expected,
239 const double tolerance) {
240 return Matcher<absl::flat_hash_map<QuadraticConstraint, double>>(
241 new MapToDoubleMatcher<QuadraticConstraint>(
242 std::move(expected),
true, tolerance));
246 absl::flat_hash_map<QuadraticConstraint, double> expected,
248 return Matcher<absl::flat_hash_map<QuadraticConstraint, double>>(
249 new MapToDoubleMatcher<QuadraticConstraint>(std::move(expected),
255Matcher<absl::flat_hash_map<K, double>>
IsNear(
256 absl::flat_hash_map<K, double> expected,
const double tolerance) {
257 return Matcher<absl::flat_hash_map<K, double>>(
new MapToDoubleMatcher<K>(
258 std::move(expected),
true, tolerance));
263 absl::flat_hash_map<K, double> expected,
const double tolerance) {
264 return Matcher<absl::flat_hash_map<K, double>>(
new MapToDoubleMatcher<K>(
265 std::move(expected),
false, tolerance));
272testing::Matcher<LinearExpression>
IsIdentical(LinearExpression expected) {
277 const LinearExpression expected,
const double tolerance) {
278 CHECK(!std::isnan(expected.offset())) <<
"Illegal NaN-valued offset";
282 testing::DoubleNear(expected.offset(), tolerance)),
284 IsNear(expected.terms(), tolerance)));
288testing::Matcher<BoundedLinearExpression> IsNearForSign(
289 const BoundedLinearExpression& expected,
const double tolerance) {
290 return AllOf(Property(
"upper_bound_minus_offset",
292 testing::DoubleNear(expected.upper_bound_minus_offset(),
294 Property(
"lower_bound_minus_offset",
296 testing::DoubleNear(expected.lower_bound_minus_offset(),
300 IsNear(expected.expression.terms(), tolerance))));
305 const BoundedLinearExpression& expected,
const double tolerance) {
306 const BoundedLinearExpression expected_negation(
307 -expected.expression, -expected.upper_bound,
308 -expected.lower_bound);
309 return AnyOf(IsNearForSign(expected, tolerance),
310 IsNearForSign(expected_negation, tolerance));
314 QuadraticExpression expected) {
315 CHECK(!std::isnan(expected.offset())) <<
"Illegal NaN-valued offset";
318 Eq(expected.storage())),
320 testing::Eq(expected.offset())),
322 IsNear(expected.linear_terms(), 0)),
324 IsNear(expected.quadratic_terms(), 0)));
333template <
typename RayType>
334class RayMatcher :
public MatcherInterface<RayType> {
336 RayMatcher(RayType expected,
const double tolerance)
337 : expected_(
std::move(expected)), tolerance_(tolerance) {}
338 void DescribeTo(std::ostream* os)
const final {
339 *os <<
"after L_inf normalization, is within tolerance: " << tolerance_
343 void DescribeNegationTo(std::ostream*
const os)
const final {
344 *os <<
"after L_inf normalization, is not within tolerance: " << tolerance_
350 const RayType expected_;
351 const double tolerance_;
355Matcher<double>
IsNear(
double expected,
const double tolerance) {
356 return DoubleNear(expected, tolerance);
359template <
typename Type>
360Matcher<std::optional<Type>>
IsNear(std::optional<Type> expected,
361 const double tolerance) {
362 if (expected.has_value()) {
363 return Optional(
IsNear(*expected, tolerance));
365 return testing::Eq(std::nullopt);
368template <
typename Type>
369Matcher<std::optional<Type>>
IsNear(std::optional<Type> expected,
370 const double tolerance,
371 const bool allow_undetermined) {
372 if (expected.has_value()) {
373 return Optional(
IsNear(*expected, tolerance, allow_undetermined));
375 return testing::Eq(std::nullopt);
379Matcher<std::optional<Basis>>
BasisIs(
const std::optional<Basis>& expected) {
380 if (expected.has_value()) {
381 return Optional(
BasisIs(*expected));
383 return testing::Eq(std::nullopt);
386testing::Matcher<std::vector<Solution>>
IsNear(
387 absl::Span<const Solution> expected_solutions,
388 const SolutionMatcherOptions options) {
389 if (expected_solutions.empty()) {
392 std::vector<Matcher<Solution>> matchers;
393 for (
const Solution& sol : expected_solutions) {
394 matchers.push_back(
IsNear(sol, options));
396 return ::testing::ElementsAreArray(matchers);
406 const bool allow_undetermined) {
407 if (allow_undetermined) {
413Matcher<PrimalSolution>
IsNear(PrimalSolution expected,
const double tolerance,
414 const bool allow_undetermined) {
417 IsNear(expected.variable_values, tolerance)),
419 IsNear(expected.objective_value, tolerance)),
425 const bool allow_undetermined) {
439Matcher<Basis>
BasisIs(
const Basis& expected) {
441 expected.variable_status),
443 expected.constraint_status),
445 expected.basic_dual_feasibility));
448Matcher<Solution>
IsNear(Solution expected,
450 std::vector<Matcher<Solution>> to_check;
465 return AllOfArray(to_check);
475double InfinityNorm(
const absl::flat_hash_map<K, double>& vector) {
476 double infinity_norm = 0.0;
477 for (
auto [
id,
value] : vector) {
478 infinity_norm = std::max(infinity_norm, std::abs(
value));
480 return infinity_norm;
490PrimalRay NormalizePrimalRay(PrimalRay ray) {
493 for (
auto& entry : ray.variable_values) {
494 entry.second /= norm;
500class PrimalRayMatcher :
public RayMatcher<PrimalRay> {
502 PrimalRayMatcher(PrimalRay expected,
const double tolerance)
503 : RayMatcher(
std::move(expected), tolerance) {}
505 bool MatchAndExplain(PrimalRay actual,
506 MatchResultListener*
const os)
const override {
507 auto normalized_actual = NormalizePrimalRay(actual);
508 auto normalized_expected = NormalizePrimalRay(expected_);
509 if (os->IsInterested()) {
510 *os <<
"actual normalized: " << PrintToString(normalized_actual)
511 <<
", expected normalized: " << PrintToString(normalized_expected);
513 return ExplainMatchResult(
514 IsNear(normalized_expected.variable_values, tolerance_),
515 normalized_actual.variable_values, os);
521Matcher<PrimalRay>
IsNear(PrimalRay expected,
const double tolerance) {
522 return Matcher<PrimalRay>(
523 new PrimalRayMatcher(std::move(expected), tolerance));
527 const double tolerance) {
529 expected.variable_values = std::move(expected_var_values);
530 return IsNear(expected, tolerance);
551 entry.second /= norm;
554 entry.second /= norm;
560class DualRayMatcher :
public RayMatcher<DualRay> {
562 DualRayMatcher(DualRay expected,
const double tolerance)
563 : RayMatcher(
std::move(expected), tolerance) {}
565 bool MatchAndExplain(DualRay actual, MatchResultListener* os)
const override {
566 auto normalized_actual = NormalizeDualRay(actual);
567 auto normalized_expected = NormalizeDualRay(expected_);
568 if (os->IsInterested()) {
569 *os <<
"actual normalized: " << PrintToString(normalized_actual)
570 <<
", expected normalized: " << PrintToString(normalized_expected);
572 return ExplainMatchResult(
573 IsNear(normalized_expected.dual_values, tolerance_),
574 normalized_actual.dual_values, os) &&
576 IsNear(normalized_expected.reduced_costs, tolerance_),
577 normalized_actual.reduced_costs, os);
583Matcher<DualRay>
IsNear(DualRay expected,
const double tolerance) {
584 return Matcher<DualRay>(
new DualRayMatcher(std::move(expected), tolerance));
592 const double tolerance) {
594 DoubleNear(expected.primal_bound, tolerance)),
596 DoubleNear(expected.dual_bound, tolerance)));
600 const std::vector<TerminationReason>& allowed) {
601 return Field(
"termination", &SolveResult::termination,
606 return Field(
"termination", &SolveResult::termination,
619testing::Matcher<SolveResult> TerminationLimitIs(
620 const Limit expected,
const bool allow_limit_undetermined) {
621 if (allow_limit_undetermined) {
622 return Field(
"termination", &SolveResult::termination,
626 return Field(
"termination", &SolveResult::termination,
633 const Limit expected,
const bool allow_limit_undetermined) {
634 std::vector<Matcher<SolveResult>> matchers;
635 matchers.push_back(TerminationLimitIs(expected, allow_limit_undetermined));
638 return AllOfArray(matchers);
642 const Limit expected,
const bool allow_limit_undetermined) {
643 std::vector<Matcher<SolveResult>> matchers;
644 matchers.push_back(TerminationLimitIs(expected, allow_limit_undetermined));
646 return AllOfArray(matchers);
650 const Limit expected,
const bool allow_limit_undetermined) {
651 std::vector<Matcher<SolveResult>> matchers;
652 matchers.push_back(TerminationLimitIs(expected, allow_limit_undetermined));
654 return AllOfArray(matchers);
657template <
typename MatcherType>
659 std::ostringstream os;
661 matcher.DescribeNegationTo(&os);
663 matcher.DescribeTo(&os);
678std::string
MatcherToString(const ::testing::PolymorphicMatcher<T>& matcher,
683MATCHER_P(FirstElementIs, first_element_matcher,
685 ? absl::StrCat(
"is empty or first element ",
687 : absl::StrCat(
"has at least one element and first element ",
689 return ExplainMatchResult(UnorderedElementsAre(first_element_matcher),
690 absl::MakeSpan(arg).subspan(0, 1), result_listener);
694 const Matcher<std::string> detail_matcher) {
715 Field(
"primal_or_dual_infeasible",
726 .primal_or_dual_infeasible =
false})));
730 const double primal_objective_value,
731 const std::optional<double> dual_objective_value,
const double tolerance) {
736 .dual_bound = dual_objective_value.value_or(
737 primal_objective_value)},
747 const std::optional<double> expected_primal_objective,
748 const double tolerance) {
749 if (expected_primal_objective.has_value()) {
752 Property(
"has_primal_feasible_solution",
753 &SolveResult::has_primal_feasible_solution,
true),
754 Property(
"objective_value", &SolveResult::objective_value,
755 DoubleNear(*expected_primal_objective, tolerance)));
757 return Field(
"termination", &SolveResult::termination,
762 const double expected_objective,
764 const double tolerance) {
766 IsOptimal(std::make_optional(expected_objective), tolerance),
769 .objective_value = expected_objective,
775 const double expected_objective,
779 IsOptimal(std::make_optional(expected_objective), tolerance),
782 .dual_values = expected_dual_values,
783 .reduced_costs = expected_reduced_costs,
784 .objective_value = std::make_optional(expected_objective),
790 const double expected_objective,
792 const absl::flat_hash_map<QuadraticConstraint, double>
793 expected_quadratic_dual_values,
796 IsOptimal(std::make_optional(expected_objective), tolerance),
799 .dual_values = expected_dual_values,
800 .quadratic_dual_values = expected_quadratic_dual_values,
801 .reduced_costs = expected_reduced_costs,
802 .objective_value = std::make_optional(expected_objective),
807Matcher<SolveResult>
HasSolution(PrimalSolution expected,
808 const double tolerance) {
810 "solutions", &SolveResult::solutions,
812 Optional(
IsNear(std::move(expected), tolerance)))));
816 const double tolerance) {
818 "solutions", &SolveResult::solutions,
820 Optional(
IsNear(std::move(expected), tolerance)))));
824 return Field(
"primal_rays", &SolveResult::primal_rays,
825 Contains(
IsNear(std::move(expected), tolerance)));
829 const double tolerance) {
831 ray.variable_values = std::move(expected_vars);
835Matcher<SolveResult>
HasDualRay(DualRay expected,
const double tolerance) {
836 return Field(
"dual_rays", &SolveResult::dual_rays,
837 Contains(
IsNear(std::move(expected), tolerance)));
853std::vector<TerminationReason> CompatibleReasons(
855 if (!inf_or_unb_soft_match) {
873Matcher<std::vector<Solution>> CheckSolutions(
874 const std::vector<Solution>& expected_solutions,
875 const SolveResultMatcherOptions& options) {
876 if (options.first_solution_only && !expected_solutions.empty()) {
877 return FirstElementIs(
878 IsNear(expected_solutions[0],
879 SolutionMatcherOptions{.tolerance = options.tolerance,
880 .check_primal =
true,
881 .check_dual = options.check_dual,
882 .check_basis = options.check_basis}));
884 return IsNear(expected_solutions,
885 SolutionMatcherOptions{.tolerance = options.tolerance,
886 .check_primal =
true,
887 .check_dual = options.check_dual,
888 .check_basis = options.check_basis});
891template <
typename RayType>
892Matcher<std::vector<RayType>> AnyRayNear(
893 const std::vector<RayType>& expected_rays,
const double tolerance) {
894 std::vector<Matcher<RayType>> matchers;
895 for (
const RayType& ray : expected_rays) {
896 matchers.push_back(
IsNear(ray, tolerance));
898 return Contains(AnyOfArray(matchers));
901template <
typename RayType>
902Matcher<std::vector<RayType>> AllRaysNear(
903 const std::vector<RayType>& expected_rays,
const double tolerance) {
904 std::vector<Matcher<RayType>> matchers;
905 for (
const RayType& ray : expected_rays) {
906 matchers.push_back(
IsNear(ray, tolerance));
908 return ::testing::UnorderedElementsAreArray(matchers);
911template <
typename RayType>
912Matcher<std::vector<RayType>> CheckRays(
913 const std::vector<RayType>& expected_rays,
const double tolerance,
915 if (expected_rays.empty()) {
919 return AllRaysNear(expected_rays, tolerance);
921 return AnyRayNear(expected_rays, tolerance);
927 const SolveResult& expected,
const SolveResultMatcherOptions& options) {
928 std::vector<Matcher<SolveResult>> to_check;
930 expected.termination.reason, options.inf_or_unb_soft_match)));
931 const bool skip_solution =
932 MightTerminateWithRays(expected.termination.reason) &&
933 !options.check_solutions_if_inf_or_unbounded;
934 if (!skip_solution) {
935 to_check.push_back(Field(
"solutions", &SolveResult::solutions,
936 CheckSolutions(expected.solutions, options)));
938 if (options.check_rays) {
939 to_check.push_back(Field(
"primal_rays", &SolveResult::primal_rays,
940 CheckRays(expected.primal_rays, options.tolerance,
941 !options.first_solution_only)));
942 to_check.push_back(Field(
"dual_rays", &SolveResult::dual_rays,
943 CheckRays(expected.dual_rays, options.tolerance,
944 !options.first_solution_only)));
947 return AllOfArray(to_check);
954testing::Matcher<ComputeInfeasibleSubsystemResult>
IsFeasible() {
958 Field(
"infeasible_subsystem",
965testing::Matcher<ComputeInfeasibleSubsystemResult>
IsUndetermined() {
969 Field(
"infeasible_subsystem",
976testing::Matcher<ComputeInfeasibleSubsystemResult>
IsInfeasible(
977 const std::optional<bool> expected_is_minimal,
978 const std::optional<ModelSubset> expected_infeasible_subsystem) {
979 std::vector<Matcher<ComputeInfeasibleSubsystemResult>> matchers;
980 matchers.push_back(Field(
"feasibility",
984 Field(
"infeasible_subsystem",
987 if (expected_is_minimal.has_value()) {
988 matchers.push_back(Field(
"is_minimal",
990 Eq(expected_is_minimal.value())));
992 if (expected_infeasible_subsystem.has_value()) {
994 Field(
"infeasible_subsystem",
998 expected_infeasible_subsystem.value().Proto()))));
1000 return AllOfArray(matchers);
const ModelStorage * storage() const
const VariableMap< double > & terms() const
Returns the terms in this expression.
const QuadraticTermMap< double > & quadratic_terms() const
const ModelStorage * storage() const
const VariableMap< double > & linear_terms() const
Fractional InfinityNorm(const DenseColumn &v)
Returns the maximum of the coefficients of 'v'.
Matcher< SolveResult > IsOptimalWithSolution(const double expected_objective, const VariableMap< double > expected_variable_values, const double tolerance)
Matcher< SolveResult > HasPrimalRay(PrimalRay expected, const double tolerance)
Matcher< Termination > TerminationIsOptimal()
absl::flat_hash_map< Variable, V > VariableMap
Matcher< Termination > ReasonIsOptimal()
Matcher< ObjectiveBounds > ObjectiveBoundsNear(const ObjectiveBounds &expected, const double tolerance)
Matcher< SolutionStatus > SolutionStatusIs(const SolutionStatus expected, const bool allow_undetermined)
TerminationReason
The reason a call to Solve() terminates.
@ kOptimal
A provably optimal solution (up to numerical tolerances) has been found.
@ kInfeasible
The primal problem has no feasible solutions.
absl::flat_hash_map< LinearConstraint, V > LinearConstraintMap
Matcher< Termination > ReasonIs(TerminationReason reason)
Matcher< SolveResult > TerminatesWithOneOf(const std::vector< TerminationReason > &allowed)
Checks that the result has one of the allowed termination reasons.
Matcher< ProblemStatus > ProblemStatusIs(const ProblemStatus &expected)
testing::Matcher< ComputeInfeasibleSubsystemResult > IsInfeasible(const std::optional< bool > expected_is_minimal, const std::optional< ModelSubset > expected_infeasible_subsystem)
Matcher< Termination > LimitIs(math_opt::Limit limit, const Matcher< std::string > detail_matcher)
testing::Matcher< BoundedLinearExpression > IsNearlyEquivalent(const BoundedLinearExpression &expected, const double tolerance)
std::ostream & operator<<(std::ostream &ostr, const IndicatorConstraint &constraint)
Matcher< SolveResult > IsConsistentWith(const SolveResult &expected, const SolveResultMatcherOptions &options)
Matcher< Termination > TerminationIsIgnoreDetail(const Termination &expected)
Matcher< SolveResult > HasSolution(PrimalSolution expected, const double tolerance)
SolveResult has a primal solution matching expected within tolerance.
SolutionStatus
Feasibility of a primal or dual solution as claimed by the solver.
@ kUndetermined
Solver does not claim a feasibility status.
@ kFeasible
Solver claims the solution is feasible.
Matcher< SolveResult > HasDualRay(DualRay expected, const double tolerance)
testing::Matcher< SolveResult > TerminatesWithReasonFeasible(const Limit expected, const bool allow_limit_undetermined)
Matcher< SolveResult > TerminatesWith(const TerminationReason expected)
std::string MatcherToString(const Matcher< T > &matcher, bool negate)
testing::Matcher< SolveResult > TerminatesWithLimit(const Limit expected, const bool allow_limit_undetermined)
Matcher< PrimalRay > PrimalRayIsNear(VariableMap< double > expected_var_values, const double tolerance)
std::string MatcherToStringImpl(const MatcherType &matcher, const bool negate)
testing::Matcher< LinearExpression > IsIdentical(LinearExpression expected)
Matcher< VariableMap< double > > IsNear(VariableMap< double > expected, const double tolerance)
Matcher< VariableMap< double > > IsNearlySubsetOf(VariableMap< double > expected, double tolerance)
Matcher< UpdateResult > DidUpdate()
Actual UpdateResult.did_update is true.
void PrintTo(const PrimalSolution &primal_solution, std::ostream *const os)
MATCHER_P(FirstElementIs, first_element_matcher,(negation ? absl::StrCat("is empty or first element ", MatcherToString(first_element_matcher, true)) :absl::StrCat("has at least one element and first element ", MatcherToString(first_element_matcher, false))))
testing::Matcher< LinearExpression > LinearExpressionIsNear(const LinearExpression expected, const double tolerance)
Matcher< SolveResult > IsOptimalWithDualSolution(const double expected_objective, const LinearConstraintMap< double > expected_dual_values, const VariableMap< double > expected_reduced_costs, const double tolerance)
Matcher< SolveResult > HasDualSolution(DualSolution expected, const double tolerance)
Matcher< Basis > BasisIs(const Basis &expected)
testing::Matcher< ComputeInfeasibleSubsystemResult > IsFeasible()
testing::Matcher< ComputeInfeasibleSubsystemResult > IsUndetermined()
Matcher< SolveResult > IsOptimal(const std::optional< double > expected_primal_objective, const double tolerance)
@ kUndetermined
Solver does not claim a status.
@ kFeasible
Solver claims the problem is feasible.
@ kInfeasible
Solver claims the problem is infeasible.
testing::Matcher< SolveResult > TerminatesWithReasonNoSolutionFound(const Limit expected, const bool allow_limit_undetermined)
In SWIG mode, we don't want anything besides these top-level includes.
internal::ProtoMatcher EqualsProto(const ::google::protobuf::Message &message)
LinearConstraintMap< BasisStatus > constraint_status
VariableMap< BasisStatus > variable_status
std::optional< SolutionStatus > basic_dual_feasibility
double upper_bound_minus_offset() const
LinearExpression expression
double lower_bound_minus_offset() const
ModelSubset infeasible_subsystem
FeasibilityStatus feasibility
The primal feasibility status of the model, as determined by the solver.
LinearConstraintMap< double > dual_values
VariableMap< double > reduced_costs
LinearConstraintMap< double > dual_values
absl::flat_hash_map< QuadraticConstraint, double > quadratic_dual_values
std::optional< double > objective_value
SolutionStatus feasibility_status
VariableMap< double > reduced_costs
bool empty() const
True if this object corresponds to the empty subset.
ModelSubsetProto Proto() const
SolutionStatus feasibility_status
VariableMap< double > variable_values
FeasibilityStatus primal_status
Status for the primal problem.
bool primal_or_dual_infeasible
FeasibilityStatus dual_status
Status for the dual problem (or for the dual of a continuous relaxation).
Options for IsNear(Solution).
std::optional< Basis > basis
std::optional< PrimalSolution > primal_solution
std::optional< DualSolution > dual_solution
ProblemStatus problem_status
Feasibility statuses for primal and dual problems.
std::optional< Limit > limit
ObjectiveBounds objective_bounds
Bounds on the optimal objective value.