23#include "Eigen/SparseCore"
24#include "gmock/gmock.h"
25#include "gtest/gtest.h"
35using ::Eigen::VectorXd;
36using ::testing::DoubleNear;
37using ::testing::ElementsAre;
39constexpr double kInfinity = std::numeric_limits<double>::infinity();
41class TrustRegion :
public testing::TestWithParam<
44INSTANTIATE_TEST_SUITE_P(
45 TrustRegionSolvers, TrustRegion, testing::Bool(),
46 [](
const testing::TestParamInfo<TrustRegion::ParamType>& info) {
47 return (info.param) ?
"UseApproximateTRSolver" :
"UseLinearTimeTRSolver";
50TEST_P(TrustRegion, SolvesWithoutVariableBounds) {
60 const double target_radius = std::sqrt(2.0);
62 Sharder sharder(2, 2,
nullptr);
64 VectorXd expected_solution(2);
65 expected_solution << 1.0, -6.0;
66 const double expected_objective_value = -2.0;
72 VectorXd::Ones(2), target_radius, sharder,
74 EXPECT_THAT(result.solution,
EigenArrayNear(expected_solution, 1.0e-6));
75 EXPECT_NEAR(result.objective_value, expected_objective_value, 1.0e-6);
81 EXPECT_THAT(result.solution,
EigenArrayEq(expected_solution));
82 EXPECT_DOUBLE_EQ(result.objective_value, expected_objective_value);
86TEST_P(TrustRegion, SolvesWithVariableBounds) {
97 const double target_radius = std::sqrt(2.0);
99 Sharder sharder(3, 2,
nullptr);
101 VectorXd expected_solution(3);
102 expected_solution << 2.0, -4.0, 0.0;
103 const double expected_objective_value = -2.0;
109 VectorXd::Ones(3), target_radius, sharder,
111 EXPECT_THAT(result.solution,
EigenArrayNear(expected_solution, 1.0e-6));
112 EXPECT_NEAR(result.objective_value, expected_objective_value, 1.0e-6);
119 EXPECT_THAT(result.solution,
EigenArrayEq(expected_solution));
120 EXPECT_DOUBLE_EQ(result.objective_value, expected_objective_value);
124TEST_P(TrustRegion, SolvesAtVariableBounds) {
136 const double target_radius = 1.0;
138 Sharder sharder(2, 2,
nullptr);
140 VectorXd expected_solution(2);
141 expected_solution << 2.0, -5.0;
142 const double expected_objective_value = 0.0;
148 VectorXd::Ones(2), target_radius, sharder,
151 EXPECT_THAT(result.solution,
EigenArrayNear(expected_solution, 1.0e-6));
152 EXPECT_NEAR(result.objective_value, expected_objective_value, 1.0e-6);
159 EXPECT_THAT(result.solution,
EigenArrayEq(expected_solution));
160 EXPECT_DOUBLE_EQ(result.objective_value, expected_objective_value);
164TEST_P(TrustRegion, SolvesWithInactiveRadius) {
177 const double target_radius = 1.0;
179 Sharder sharder(3, 2,
nullptr);
181 VectorXd expected_solution(3);
182 expected_solution << 2.0, -5.0, 0.5;
183 const double expected_objective_value = -0.5;
189 VectorXd::Ones(3), target_radius, sharder,
192 EXPECT_THAT(result.solution,
EigenArrayNear(expected_solution, 1.0e-6));
193 EXPECT_NEAR(result.objective_value, expected_objective_value, 1.0e-6);
200 EXPECT_THAT(result.solution,
EigenArrayEq(expected_solution));
201 EXPECT_DOUBLE_EQ(result.objective_value, expected_objective_value);
205TEST_P(TrustRegion, SolvesWithInfiniteRadius) {
218 Sharder sharder(3, 2,
nullptr);
220 VectorXd expected_solution(3);
221 expected_solution << 2.0, -5.0, 0.5;
222 const double expected_objective_value = -0.5;
228 VectorXd::Ones(3), target_radius, sharder,
231 EXPECT_THAT(result.solution,
EigenArrayNear(expected_solution, 1.0e-6));
232 EXPECT_NEAR(result.objective_value, expected_objective_value, 1.0e-6);
239 EXPECT_THAT(result.solution,
EigenArrayEq(expected_solution));
240 EXPECT_DOUBLE_EQ(result.objective_value, expected_objective_value);
244TEST_P(TrustRegion, SolvesWithMixedObjective) {
257 const double target_radius = std::sqrt(1.25);
259 Sharder sharder(2, 2,
nullptr);
261 VectorXd expected_solution(2);
262 expected_solution << 1.0, 0.5;
263 const double expected_objective_value = -2.5;
269 VectorXd::Ones(2), target_radius, sharder,
271 EXPECT_THAT(result.solution,
EigenArrayNear(expected_solution, 1.0e-6));
272 EXPECT_NEAR(result.objective_value, expected_objective_value, 2.0e-6);
279 EXPECT_THAT(result.solution,
EigenArrayEq(expected_solution));
280 EXPECT_DOUBLE_EQ(result.objective_value, expected_objective_value);
284TEST_P(TrustRegion, SolvesWithZeroObjectiveNoBounds) {
294 const double target_radius = 1.0;
296 Sharder sharder(1, 1,
nullptr);
298 VectorXd expected_solution(1);
299 expected_solution << 2.0;
300 const double expected_objective_value = 0.0;
306 VectorXd::Ones(1), target_radius, sharder,
309 EXPECT_THAT(result.solution,
EigenArrayNear(expected_solution, 1.0e-6));
310 EXPECT_NEAR(result.objective_value, expected_objective_value, 1.0e-6);
317 EXPECT_THAT(result.solution,
EigenArrayEq(expected_solution));
318 EXPECT_DOUBLE_EQ(result.objective_value, expected_objective_value);
322class TrustRegionWithWeights :
public testing::TestWithParam<
325INSTANTIATE_TEST_SUITE_P(
326 TrustRegionSolverWithWeights, TrustRegionWithWeights, testing::Bool(),
327 [](
const testing::TestParamInfo<TrustRegion::ParamType>& info) {
328 return (info.param) ?
"UseApproximateTRSolver" :
"UseLinearTimeTRSolver";
331TEST_P(TrustRegionWithWeights, SolvesWithoutVariableBounds) {
343 const double target_radius = std::sqrt(3.0);
345 Sharder sharder(2, 2,
nullptr);
347 VectorXd expected_solution(2);
348 expected_solution << 1.0, -6.0;
349 const double expected_objective_value = -3.0;
357 EXPECT_THAT(result.solution,
EigenArrayNear(expected_solution, 1.0e-6));
358 EXPECT_NEAR(result.objective_value, expected_objective_value, 1.0e-5);
364 EXPECT_THAT(result.solution,
EigenArrayEq(expected_solution));
365 EXPECT_DOUBLE_EQ(result.objective_value, expected_objective_value);
369TEST_P(TrustRegionWithWeights, SolvesWithVariableBounds) {
382 const double target_radius = std::sqrt(5.0);
384 Sharder sharder(3, 2,
nullptr);
386 VectorXd expected_solution(3);
387 expected_solution << 2.0, -4.0, 0.0;
388 const double expected_objective_value = -5.0;
396 EXPECT_THAT(result.solution,
EigenArrayNear(expected_solution, 1.0e-6));
397 EXPECT_NEAR(result.objective_value, expected_objective_value, 1.0e-5);
403 EXPECT_THAT(result.solution,
EigenArrayEq(expected_solution));
404 EXPECT_DOUBLE_EQ(result.objective_value, expected_objective_value);
408TEST_P(TrustRegionWithWeights, SolvesWithVariableThatHitsBounds) {
423 const double target_radius = 1;
425 Sharder sharder(2, 2,
nullptr);
427 VectorXd expected_solution(2);
428 expected_solution << 1.0, 0.5;
429 const double expected_objective_value = -2.0;
438 EXPECT_THAT(result.solution,
EigenArrayNear(expected_solution, 1.0e-6));
439 EXPECT_NEAR(result.objective_value, expected_objective_value, 1.0e-6);
445 EXPECT_THAT(result.solution,
446 ElementsAre(expected_solution[0],
447 DoubleNear(expected_solution[1], 1.0e-13)));
448 EXPECT_DOUBLE_EQ(result.objective_value, expected_objective_value);
452TEST_P(TrustRegionWithWeights, SolvesWithLargeWeight) {
467 const double target_radius = std::sqrt(500.5);
469 Sharder sharder(2, 2,
nullptr);
471 VectorXd expected_solution(2);
472 expected_solution << 1.0, 0.5;
473 const double expected_objective_value = -1001.0;
482 EXPECT_THAT(result.solution,
EigenArrayNear(expected_solution, 1.0e-6));
483 EXPECT_NEAR(result.objective_value, expected_objective_value, 1.0e-6);
489 EXPECT_THAT(result.solution,
490 ElementsAre(expected_solution[0],
491 DoubleNear(expected_solution[1], 1.0e-13)));
492 EXPECT_DOUBLE_EQ(result.objective_value, -1001.0);
496TEST(TrustRegionDeathTest, CheckFailsWithNonPositiveWeights) {
507 const double target_radius = std::sqrt(2.0);
509 Sharder sharder(2, 2,
nullptr);
511 EXPECT_DEATH(TrustRegionResult result =
515 "Check failed: norm_weights_are_positive");
518TEST(TrustRegionDeathTest, CheckFailsWithNonPositiveWeightsForDiagonalSolver) {
529 const double target_radius = std::sqrt(2.0);
531 Sharder sharder(2, 2,
nullptr);
539 "Check failed: norm_weights_are_positive");
542TEST(TrustRegionDeathTest, CheckFailsWithNegativeRadius) {
552 const double target_radius = -std::sqrt(2.0);
554 Sharder sharder(2, 2,
nullptr);
559 VectorXd::Ones(2), target_radius, sharder),
560 "Check failed: target_radius >= 0.0");
563TEST(TrustRegionDeathTest, CheckFailsWithNegativeRadiusForDiagonalSolver) {
573 const double target_radius = -std::sqrt(2.0);
575 Sharder sharder(2, 2,
nullptr);
581 VectorXd::Ones(2), target_radius, sharder,
583 "Check failed: target_radius >= 0.0");
586class ComputeLocalizedLagrangianBoundsTest
587 :
public testing::TestWithParam<std::tuple<PrimalDualNorm, bool>> {
589 void SetUp()
override {
590 const auto [primal_dual_norm, use_diagonal_qp_trust_region_solver] =
592 if (use_diagonal_qp_trust_region_solver &&
594 GTEST_SKIP() <<
"The diagonal QP trust region solver can only be used "
595 <<
"when the underlying norms are Euclidean.";
600INSTANTIATE_TEST_SUITE_P(
601 TrustRegionNorm, ComputeLocalizedLagrangianBoundsTest,
605 [](
const testing::TestParamInfo<
606 ComputeLocalizedLagrangianBoundsTest::ParamType>& info) {
607 const absl::string_view suffix =
608 std::get<1>(info.param) ?
"DiagonalTRSolver" :
"LinearTimeTRSolver";
609 switch (std::get<0>(info.param)) {
611 return absl::StrCat(
"EuclideanNorm",
"_", suffix);
613 return absl::StrCat(
"MaxNorm",
"_", suffix);
617TEST_P(ComputeLocalizedLagrangianBoundsTest, ZeroGapAtOptimal) {
618 ShardedQuadraticProgram lp(
TestLp(), 2, 2);
620 VectorXd primal_solution(4), dual_solution(4);
621 primal_solution << -1.0, 8.0, 1.0, 2.5;
622 dual_solution << -2.0, 0.0, 2.375, 2.0 / 3.0;
624 const auto [primal_dual_norm, use_diagonal_qp_solver] = GetParam();
627 lp, primal_solution, dual_solution, primal_dual_norm,
630 nullptr, use_diagonal_qp_solver,
633 EXPECT_DOUBLE_EQ(
bounds.radius, 1.0);
634 EXPECT_DOUBLE_EQ(
bounds.lagrangian_value, -20.0);
635 EXPECT_DOUBLE_EQ(
bounds.lower_bound, -20.0);
636 EXPECT_DOUBLE_EQ(
bounds.upper_bound, -20.0);
641TEST_P(ComputeLocalizedLagrangianBoundsTest, OptimalInBoundRange) {
642 ShardedQuadraticProgram lp(
TestLp(), 2, 2);
645 VectorXd primal_solution(4);
646 primal_solution << 0.0, 0.0, 0.0, 3.0;
649 const auto [primal_dual_norm, use_diagonal_qp_solver] = GetParam();
651 const double primal_distance_squared_to_optimal =
652 0.5 * (1.0 + 8.0 * 8.0 + 1.0 + 0.5 * 0.5);
653 const double dual_distance_squared_to_optimal =
654 0.5 * (4.0 + 2.375 * 2.375 + 4.0 / 9.0);
655 const double distance_to_optimal =
657 ? std::sqrt(primal_distance_squared_to_optimal +
658 dual_distance_squared_to_optimal)
659 :
std::sqrt(
std::
max(primal_distance_squared_to_optimal,
660 dual_distance_squared_to_optimal));
663 lp, primal_solution, dual_solution, primal_dual_norm,
667 nullptr, use_diagonal_qp_solver,
670 EXPECT_DOUBLE_EQ(
bounds.lagrangian_value, 3.0);
671 EXPECT_LE(
bounds.lower_bound, -20.0);
672 EXPECT_GE(
bounds.upper_bound, -20.0);
677TEST_P(ComputeLocalizedLagrangianBoundsTest, OptimalNotInBoundRange) {
678 ShardedQuadraticProgram lp(
TestLp(), 2, 2);
681 VectorXd primal_solution(4);
682 primal_solution << 0.0, 0.0, 0.0, 3.0;
685 const auto [primal_dual_norm, use_diagonal_qp_solver] = GetParam();
688 lp, primal_solution, dual_solution, primal_dual_norm,
692 nullptr, use_diagonal_qp_solver,
694 const double expected_lagrangian = 3.0;
695 EXPECT_DOUBLE_EQ(
bounds.lagrangian_value, expected_lagrangian);
705 switch (primal_dual_norm) {
711 EXPECT_NEAR(
bounds.lower_bound,
712 expected_lagrangian - 0.1 * sqrt(2) * sqrt(36.25), 1.0e-6);
717 EXPECT_NEAR(
bounds.upper_bound,
718 expected_lagrangian + 0.1 * sqrt(2) * sqrt(40.0), 1.0e-6);
725 EXPECT_NEAR(
bounds.lower_bound,
726 expected_lagrangian - 0.1 * sqrt(2) * 36.25 / sqrt(76.25),
728 EXPECT_NEAR(
bounds.upper_bound,
729 expected_lagrangian + 0.1 * sqrt(2) * 40 / sqrt(76.25),
737TEST(ComputeLocalizedLagrangianBoundsTest, ProcessesPrimalWeight) {
738 ShardedQuadraticProgram lp(
TestLp(), 2, 2);
741 VectorXd primal_solution(4);
742 primal_solution << 0.0, 0.0, 0.0, 3.0;
753 const double expected_lagrangian = 3.0;
754 EXPECT_DOUBLE_EQ(
bounds.lagrangian_value, expected_lagrangian);
758 EXPECT_LE(
bounds.lower_bound, expected_lagrangian - 0.028);
759 EXPECT_GE(
bounds.lower_bound, expected_lagrangian - 0.28);
760 EXPECT_GE(
bounds.upper_bound, expected_lagrangian + 2.8);
761 EXPECT_LE(
bounds.upper_bound, expected_lagrangian + 28);
765TEST_P(ComputeLocalizedLagrangianBoundsTest, AcceptsCachedProducts) {
766 ShardedQuadraticProgram lp(
TestLp(), 2, 2);
769 VectorXd primal_solution(4);
770 primal_solution << 0.0, 0.0, 0.0, 3.0;
773 VectorXd primal_product(4);
774 primal_product << 6.0, 0.0, 0.0, -3.0;
777 const auto [primal_dual_norm, use_diagonal_qp_solver] = GetParam();
779 const double primal_distance_squared_to_optimal =
780 0.5 * (1.0 + 8.0 * 8.0 + 1.0 + 0.5 * 0.5);
781 const double dual_distance_squared_to_optimal =
782 0.5 * (4.0 + 2.375 * 2.375 + 4.0 / 9.0);
783 const double distance_to_optimal =
785 ? std::sqrt(primal_distance_squared_to_optimal +
786 dual_distance_squared_to_optimal)
787 :
std::sqrt(
std::
max(primal_distance_squared_to_optimal,
788 dual_distance_squared_to_optimal));
791 lp, primal_solution, dual_solution, primal_dual_norm,
795 &dual_product, use_diagonal_qp_solver,
798 EXPECT_DOUBLE_EQ(
bounds.lagrangian_value, 3.0);
799 EXPECT_LE(
bounds.lower_bound, -20.0);
800 EXPECT_GE(
bounds.upper_bound, -20.0);
806QuadraticProgram OneDimLp() {
807 QuadraticProgram lp(1, 1);
808 lp.constraint_lower_bounds << 0;
809 lp.constraint_upper_bounds << 1;
812 std::vector<Eigen::Triplet<double, int64_t>> triplets = {{0, 0, 1}};
813 lp.constraint_matrix.setFromTriplets(triplets.begin(), triplets.end());
814 lp.objective_vector << 1.0;
821QuadraticProgram OneDimQp() {
822 QuadraticProgram qp(1, 1);
823 qp.constraint_lower_bounds << 0;
824 qp.constraint_upper_bounds << 1;
827 std::vector<Eigen::Triplet<double, int64_t>> constraint_matrix_triplets = {
829 qp.constraint_matrix.setFromTriplets(constraint_matrix_triplets.begin(),
830 constraint_matrix_triplets.end());
831 qp.objective_matrix.emplace();
832 qp.objective_matrix->resize(1);
833 qp.objective_matrix->diagonal() << 2;
834 qp.objective_vector << 1;
839VectorXd GetPrimalGradient(
const ShardedQuadraticProgram& sharded_qp,
840 const VectorXd& primal_solution,
841 const VectorXd& dual_solution) {
843 sharded_qp.Qp().constraint_matrix, dual_solution,
844 sharded_qp.ConstraintMatrixSharder());
849VectorXd GetDualGradient(
const ShardedQuadraticProgram& sharded_qp,
850 const VectorXd& primal_solution,
851 const VectorXd& dual_solution) {
853 sharded_qp.TransposedConstraintMatrix(), primal_solution,
854 sharded_qp.TransposedConstraintMatrixSharder());
859struct TestProblemData {
870TestProblemData GenerateTestLpProblemData(
const double primal_weight) {
876 norm_weights << 0.5 * primal_weight, 0.5 / primal_weight;
889TestProblemData GenerateTestQpProblemData(
const double primal_weight) {
890 TestProblemData lp_data = GenerateTestLpProblemData(primal_weight);
891 lp_data.objective_matrix_diagonal[0] = 2.0;
897TEST_P(ComputeLocalizedLagrangianBoundsTest, NormsBehaveDifferently) {
898 ShardedQuadraticProgram lp(OneDimLp(), 2, 2);
901 VectorXd dual_solution(1);
907 const auto [primal_dual_norm, use_diagonal_qp_solver] = GetParam();
910 lp, primal_solution, dual_solution, primal_dual_norm,
911 1.0, 1.0 / std::sqrt(2.0),
913 nullptr, use_diagonal_qp_solver,
915 const double expected_lagrangian = -1;
916 EXPECT_DOUBLE_EQ(
bounds.lagrangian_value, expected_lagrangian);
918 switch (primal_dual_norm) {
920 EXPECT_DOUBLE_EQ(
bounds.lower_bound, expected_lagrangian - 2.0);
921 EXPECT_DOUBLE_EQ(
bounds.upper_bound, expected_lagrangian + 1.0);
924 if (use_diagonal_qp_solver) {
925 EXPECT_NEAR(
bounds.lower_bound,
926 expected_lagrangian - 4.0 / std::sqrt(5), 1.0e-6);
927 EXPECT_NEAR(
bounds.upper_bound,
928 expected_lagrangian + 1.0 / std::sqrt(5), 1.0e-6);
930 EXPECT_DOUBLE_EQ(
bounds.lower_bound,
931 expected_lagrangian - 4.0 / std::sqrt(5));
932 EXPECT_DOUBLE_EQ(
bounds.upper_bound,
933 expected_lagrangian + 1.0 / std::sqrt(5));
940TEST_P(ComputeLocalizedLagrangianBoundsTest,
941 NormsBehaveDifferentlyWithLargePrimalWeight) {
942 ShardedQuadraticProgram lp(OneDimLp(), 2, 2);
945 VectorXd dual_solution(1);
950 const auto [primal_dual_norm, use_diagonal_qp_solver] = GetParam();
953 lp, primal_solution, dual_solution, primal_dual_norm,
954 100.0, 1.0 / std::sqrt(2.0),
956 nullptr, use_diagonal_qp_solver,
958 const double expected_lagrangian = -1;
959 EXPECT_DOUBLE_EQ(
bounds.lagrangian_value, expected_lagrangian);
961 switch (primal_dual_norm) {
963 EXPECT_DOUBLE_EQ(
bounds.lower_bound, expected_lagrangian - 0.2);
964 EXPECT_DOUBLE_EQ(
bounds.upper_bound, expected_lagrangian + 10.0);
969 if (use_diagonal_qp_solver) {
970 EXPECT_NEAR(
bounds.upper_bound -
bounds.lower_bound, 10.00199980003999,
973 EXPECT_DOUBLE_EQ(
bounds.upper_bound -
bounds.lower_bound,
980TEST(DiagonalTrustRegionSolverTest, JointSolverWorksWithOneDimQpUnitWeight) {
981 ShardedQuadraticProgram sharded_qp(OneDimQp(), 2,
983 const auto problem_data = GenerateTestQpProblemData(1.0);
985 problem_data.objective_vector, problem_data.objective_matrix_diagonal,
986 problem_data.variable_lower_bounds, problem_data.variable_upper_bounds,
987 problem_data.center_point, problem_data.norm_weights,
989 Sharder(2, 2,
nullptr),
991 EXPECT_THAT(result.solution,
992 ElementsAre(DoubleNear(-0.5, 1.0e-6), DoubleNear(-0.5, 1.0e-6)));
993 EXPECT_NEAR(result.solution_step_size, 4.0, 4.0 * 1.0e-6);
994 EXPECT_NEAR(result.objective_value, -1.25, 1.0e-6);
997TEST(DiagonalTrustRegionSolverTest,
998 DiagonalQpSolverWorksWithOneDimQpUnitWeight) {
999 ShardedQuadraticProgram sharded_qp(OneDimQp(), 2,
1002 VectorXd dual_solution = -1.0 * VectorXd::Ones(1);
1003 VectorXd primal_gradient =
1004 GetPrimalGradient(sharded_qp, primal_solution, dual_solution);
1005 VectorXd dual_gradient =
1006 GetDualGradient(sharded_qp, primal_solution, dual_solution);
1008 sharded_qp, primal_solution, dual_solution, primal_gradient,
1009 dual_gradient, 1.0, 0.5,
1011 EXPECT_THAT(result.solution,
1012 ElementsAre(DoubleNear(-0.5, 1.0e-6), DoubleNear(-0.5, 1.0e-6)));
1013 EXPECT_NEAR(result.solution_step_size, 4.0, 4.0 * 1.0e-6);
1014 EXPECT_NEAR(result.objective_value, -1.25, 1.0e-6);
1017TEST(DiagonalTrustRegionSolverTest, JointSolverWorksWithOneDimQpLargeWeight) {
1018 ShardedQuadraticProgram sharded_qp(OneDimQp(), 2,
1020 const auto problem_data = GenerateTestQpProblemData(100.0);
1022 problem_data.objective_vector, problem_data.objective_matrix_diagonal,
1023 problem_data.variable_lower_bounds, problem_data.variable_upper_bounds,
1024 problem_data.center_point, problem_data.norm_weights,
1025 std::sqrt(2705.0 / 2) * (5.0 / 13),
1026 Sharder(2, 2,
nullptr),
1028 EXPECT_NEAR(result.solution_step_size, 1.0, 1.0e-6);
1031TEST(DiagonalTrustRegionSolverTest,
1032 DiagonalQpSolverWorksWithOneDimQpLargeWeight) {
1033 ShardedQuadraticProgram sharded_qp(OneDimQp(), 2,
1036 VectorXd dual_solution = -1.0 * VectorXd::Ones(1);
1037 VectorXd primal_gradient =
1038 GetPrimalGradient(sharded_qp, primal_solution, dual_solution);
1039 VectorXd dual_gradient =
1040 GetDualGradient(sharded_qp, primal_solution, dual_solution);
1042 sharded_qp, primal_solution, dual_solution, primal_gradient,
1043 dual_gradient, 100.0,
1044 std::sqrt(2705.0 / 2.0) * (5.0 / 13),
1046 EXPECT_NEAR(result.solution_step_size, 1.0, 1.0e-6);
1049TEST(DiagonalTrustRegionSolverTest, JointSolverWorksWithOneDimQpSmallWeight) {
1050 ShardedQuadraticProgram sharded_qp(OneDimQp(), 2,
1052 const auto problem_data = GenerateTestQpProblemData(0.01);
1054 problem_data.objective_vector, problem_data.objective_matrix_diagonal,
1055 problem_data.variable_lower_bounds, problem_data.variable_upper_bounds,
1056 problem_data.center_point, problem_data.norm_weights,
1058 Sharder(2, 2,
nullptr),
1060 EXPECT_THAT(result.solution, ElementsAre(DoubleNear(-0.99950025, 1.0e-6),
1061 DoubleNear(-0.9, 1.0e-6)));
1062 EXPECT_NEAR(result.solution_step_size, 0.2, 1.0e-6);
1063 EXPECT_NEAR(result.objective_value, -1.0999996, 1.0e-6);
1066TEST(DiagonalTrustRegionSolverTest,
1067 DiagonalQpSolverWorksWithOneDimQpSmallWeight) {
1068 ShardedQuadraticProgram sharded_qp(OneDimQp(), 2,
1071 VectorXd dual_solution = -1.0 * VectorXd::Ones(1);
1072 VectorXd primal_gradient =
1073 GetPrimalGradient(sharded_qp, primal_solution, dual_solution);
1074 VectorXd dual_gradient =
1075 GetDualGradient(sharded_qp, primal_solution, dual_solution);
1077 sharded_qp, primal_solution, dual_solution, primal_gradient,
1078 dual_gradient, 0.01,
1081 EXPECT_THAT(result.solution, ElementsAre(DoubleNear(-0.99950025, 1.0e-6),
1082 DoubleNear(-0.9, 1.0e-6)));
1083 EXPECT_NEAR(result.solution_step_size, 0.2, 1.0e-6);
1084 EXPECT_NEAR(result.objective_value, -1.0999996, 1.0e-6);
1088TEST(ComputeLocalizedLagrangianBoundsTest, SolvesForTestQpUnitWeight) {
1089 ShardedQuadraticProgram qp(OneDimQp(), 2, 2);
1092 VectorXd dual_solution(1);
1093 dual_solution << -1;
1104 const double expected_lagrangian = -1;
1105 EXPECT_DOUBLE_EQ(
bounds.lagrangian_value, expected_lagrangian);
1106 EXPECT_NEAR(
bounds.upper_bound, expected_lagrangian + 0.5, 1.0e-5);
1107 EXPECT_NEAR(
bounds.lower_bound, expected_lagrangian - 0.75, 1.0e-5);
SharedBoundsManager * bounds
LagrangianPart ComputePrimalGradient(const ShardedQuadraticProgram &sharded_qp, const VectorXd &primal_solution, const VectorXd &dual_product)
EigenArrayNearMatcherP2< Eigen::Array< T, Eigen::Dynamic, 1 >, double > EigenArrayNear(absl::Span< const T > data, double tolerance)
VectorXd TransposedMatrixVectorProduct(const Eigen::SparseMatrix< double, Eigen::ColMajor, int64_t > &matrix, const VectorXd &vector, const Sharder &sharder)
TrustRegionResult SolveDiagonalTrustRegion(const VectorXd &objective_vector, const VectorXd &objective_matrix_diagonal, const VectorXd &variable_lower_bounds, const VectorXd &variable_upper_bounds, const VectorXd ¢er_point, const VectorXd &norm_weights, const double target_radius, const Sharder &sharder, const double solve_tolerance)
LagrangianPart ComputeDualGradient(const ShardedQuadraticProgram &sharded_qp, const Eigen::VectorXd &dual_solution, const Eigen::VectorXd &primal_product)
constexpr double kInfinity
TrustRegionResult SolveDiagonalQpTrustRegion(const ShardedQuadraticProgram &sharded_qp, const VectorXd &primal_solution, const VectorXd &dual_solution, const VectorXd &primal_gradient, const VectorXd &dual_gradient, const double primal_weight, double target_radius, const double solve_tolerance)
EigenArrayEqMatcherP< Eigen::Array< T, Eigen::Dynamic, 1 > > EigenArrayEq(absl::Span< const T > data)
TrustRegionResult SolveTrustRegion(const VectorXd &objective_vector, const VectorXd &variable_lower_bounds, const VectorXd &variable_upper_bounds, const VectorXd ¢er_point, const VectorXd &norm_weights, const double target_radius, const Sharder &sharder)
QuadraticProgram TestLp()
LocalizedLagrangianBounds ComputeLocalizedLagrangianBounds(const ShardedQuadraticProgram &sharded_qp, const VectorXd &primal_solution, const VectorXd &dual_solution, const PrimalDualNorm primal_dual_norm, const double primal_weight, const double radius, const VectorXd *primal_product, const VectorXd *dual_product, const bool use_diagonal_qp_trust_region_solver, const double diagonal_qp_trust_region_solver_tolerance)
TEST(LinearAssignmentTest, NullMatrix)
VectorXd variable_lower_bounds
VectorXd variable_upper_bounds
VectorXd objective_vector
VectorXd objective_matrix_diagonal