24 #include "Eigen/SparseCore"
25 #include "absl/strings/str_cat.h"
26 #include "absl/strings/string_view.h"
27 #include "gmock/gmock.h"
28 #include "gtest/gtest.h"
38 using ::Eigen::VectorXd;
39 using ::testing::DoubleNear;
40 using ::testing::ElementsAre;
42 constexpr
double kInfinity = std::numeric_limits<double>::infinity();
44 class TrustRegion :
public testing::TestWithParam<
47 INSTANTIATE_TEST_SUITE_P(
48 TrustRegionSolvers, TrustRegion, testing::Bool(),
49 [](
const testing::TestParamInfo<TrustRegion::ParamType>& info) {
50 return (info.param) ?
"UseApproximateTRSolver" :
"UseLinearTimeTRSolver";
53 TEST_P(TrustRegion, SolvesWithoutVariableBounds) {
63 const double target_radius = std::sqrt(2.0);
65 Sharder sharder(2, 2,
nullptr);
67 VectorXd expected_solution(2);
68 expected_solution << 1.0, -6.0;
69 const double expected_objective_value = -2.0;
75 VectorXd::Ones(2), target_radius, sharder,
77 EXPECT_THAT(result.solution,
EigenArrayNear(expected_solution, 1.0e-6));
78 EXPECT_NEAR(result.objective_value, expected_objective_value, 1.0e-6);
84 EXPECT_THAT(result.solution,
EigenArrayEq(expected_solution));
85 EXPECT_DOUBLE_EQ(result.objective_value, expected_objective_value);
89 TEST_P(TrustRegion, SolvesWithVariableBounds) {
100 const double target_radius = std::sqrt(2.0);
102 Sharder sharder(3, 2,
nullptr);
104 VectorXd expected_solution(3);
105 expected_solution << 2.0, -4.0, 0.0;
106 const double expected_objective_value = -2.0;
112 VectorXd::Ones(3), target_radius, sharder,
114 EXPECT_THAT(result.solution,
EigenArrayNear(expected_solution, 1.0e-6));
115 EXPECT_NEAR(result.objective_value, expected_objective_value, 1.0e-6);
122 EXPECT_THAT(result.solution,
EigenArrayEq(expected_solution));
123 EXPECT_DOUBLE_EQ(result.objective_value, expected_objective_value);
127 TEST_P(TrustRegion, SolvesAtVariableBounds) {
139 const double target_radius = 1.0;
141 Sharder sharder(2, 2,
nullptr);
143 VectorXd expected_solution(2);
144 expected_solution << 2.0, -5.0;
145 const double expected_objective_value = 0.0;
151 VectorXd::Ones(2), target_radius, sharder,
154 EXPECT_THAT(result.solution,
EigenArrayNear(expected_solution, 1.0e-6));
155 EXPECT_NEAR(result.objective_value, expected_objective_value, 1.0e-6);
162 EXPECT_THAT(result.solution,
EigenArrayEq(expected_solution));
163 EXPECT_DOUBLE_EQ(result.objective_value, expected_objective_value);
167 TEST_P(TrustRegion, SolvesWithInactiveRadius) {
180 const double target_radius = 1.0;
182 Sharder sharder(3, 2,
nullptr);
184 VectorXd expected_solution(3);
185 expected_solution << 2.0, -5.0, 0.5;
186 const double expected_objective_value = -0.5;
192 VectorXd::Ones(3), target_radius, sharder,
195 EXPECT_THAT(result.solution,
EigenArrayNear(expected_solution, 1.0e-6));
196 EXPECT_NEAR(result.objective_value, expected_objective_value, 1.0e-6);
203 EXPECT_THAT(result.solution,
EigenArrayEq(expected_solution));
204 EXPECT_DOUBLE_EQ(result.objective_value, expected_objective_value);
208 TEST_P(TrustRegion, SolvesWithInfiniteRadius) {
221 Sharder sharder(3, 2,
nullptr);
223 VectorXd expected_solution(3);
224 expected_solution << 2.0, -5.0, 0.5;
225 const double expected_objective_value = -0.5;
231 VectorXd::Ones(3), target_radius, sharder,
234 EXPECT_THAT(result.solution,
EigenArrayNear(expected_solution, 1.0e-6));
235 EXPECT_NEAR(result.objective_value, expected_objective_value, 1.0e-6);
242 EXPECT_THAT(result.solution,
EigenArrayEq(expected_solution));
243 EXPECT_DOUBLE_EQ(result.objective_value, expected_objective_value);
247 TEST_P(TrustRegion, SolvesWithMixedObjective) {
260 const double target_radius = std::sqrt(1.25);
262 Sharder sharder(2, 2,
nullptr);
264 VectorXd expected_solution(2);
265 expected_solution << 1.0, 0.5;
266 const double expected_objective_value = -2.5;
272 VectorXd::Ones(2), target_radius, sharder,
274 EXPECT_THAT(result.solution,
EigenArrayNear(expected_solution, 1.0e-6));
275 EXPECT_NEAR(result.objective_value, expected_objective_value, 2.0e-6);
282 EXPECT_THAT(result.solution,
EigenArrayEq(expected_solution));
283 EXPECT_DOUBLE_EQ(result.objective_value, expected_objective_value);
287 TEST_P(TrustRegion, SolvesWithZeroObjectiveNoBounds) {
297 const double target_radius = 1.0;
299 Sharder sharder(1, 1,
nullptr);
301 VectorXd expected_solution(1);
302 expected_solution << 2.0;
303 const double expected_objective_value = 0.0;
309 VectorXd::Ones(1), target_radius, sharder,
312 EXPECT_THAT(result.solution,
EigenArrayNear(expected_solution, 1.0e-6));
313 EXPECT_NEAR(result.objective_value, expected_objective_value, 1.0e-6);
320 EXPECT_THAT(result.solution,
EigenArrayEq(expected_solution));
321 EXPECT_DOUBLE_EQ(result.objective_value, expected_objective_value);
325 class TrustRegionWithWeights :
public testing::TestWithParam<
328 INSTANTIATE_TEST_SUITE_P(
329 TrustRegionSolverWithWeights, TrustRegionWithWeights, testing::Bool(),
330 [](
const testing::TestParamInfo<TrustRegion::ParamType>& info) {
331 return (info.param) ?
"UseApproximateTRSolver" :
"UseLinearTimeTRSolver";
334 TEST_P(TrustRegionWithWeights, SolvesWithoutVariableBounds) {
346 const double target_radius = std::sqrt(3.0);
348 Sharder sharder(2, 2,
nullptr);
350 VectorXd expected_solution(2);
351 expected_solution << 1.0, -6.0;
352 const double expected_objective_value = -3.0;
360 EXPECT_THAT(result.solution,
EigenArrayNear(expected_solution, 1.0e-6));
361 EXPECT_NEAR(result.objective_value, expected_objective_value, 1.0e-5);
367 EXPECT_THAT(result.solution,
EigenArrayEq(expected_solution));
368 EXPECT_DOUBLE_EQ(result.objective_value, expected_objective_value);
372 TEST_P(TrustRegionWithWeights, SolvesWithVariableBounds) {
385 const double target_radius = std::sqrt(5.0);
387 Sharder sharder(3, 2,
nullptr);
389 VectorXd expected_solution(3);
390 expected_solution << 2.0, -4.0, 0.0;
391 const double expected_objective_value = -5.0;
399 EXPECT_THAT(result.solution,
EigenArrayNear(expected_solution, 1.0e-6));
400 EXPECT_NEAR(result.objective_value, expected_objective_value, 1.0e-5);
406 EXPECT_THAT(result.solution,
EigenArrayEq(expected_solution));
407 EXPECT_DOUBLE_EQ(result.objective_value, expected_objective_value);
411 TEST_P(TrustRegionWithWeights, SolvesWithVariableThatHitsBounds) {
426 const double target_radius = 1;
428 Sharder sharder(2, 2,
nullptr);
430 VectorXd expected_solution(2);
431 expected_solution << 1.0, 0.5;
432 const double expected_objective_value = -2.0;
441 EXPECT_THAT(result.solution,
EigenArrayNear(expected_solution, 1.0e-6));
442 EXPECT_NEAR(result.objective_value, expected_objective_value, 1.0e-6);
448 EXPECT_THAT(result.solution,
449 ElementsAre(expected_solution[0],
450 DoubleNear(expected_solution[1], 1.0e-13)));
451 EXPECT_DOUBLE_EQ(result.objective_value, expected_objective_value);
455 TEST_P(TrustRegionWithWeights, SolvesWithLargeWeight) {
470 const double target_radius = std::sqrt(500.5);
472 Sharder sharder(2, 2,
nullptr);
474 VectorXd expected_solution(2);
475 expected_solution << 1.0, 0.5;
476 const double expected_objective_value = -1001.0;
485 EXPECT_THAT(result.solution,
EigenArrayNear(expected_solution, 1.0e-6));
486 EXPECT_NEAR(result.objective_value, expected_objective_value, 1.0e-6);
492 EXPECT_THAT(result.solution,
493 ElementsAre(expected_solution[0],
494 DoubleNear(expected_solution[1], 1.0e-13)));
495 EXPECT_DOUBLE_EQ(result.objective_value, -1001.0);
499 TEST(TrustRegionDeathTest, CheckFailsWithNonPositiveWeights) {
510 const double target_radius = std::sqrt(2.0);
512 Sharder sharder(2, 2,
nullptr);
514 EXPECT_DEATH(TrustRegionResult result =
518 "Check failed: norm_weights_are_positive");
521 TEST(TrustRegionDeathTest, CheckFailsWithNonPositiveWeightsForDiagonalSolver) {
532 const double target_radius = std::sqrt(2.0);
534 Sharder sharder(2, 2,
nullptr);
542 "Check failed: norm_weights_are_positive");
545 TEST(TrustRegionDeathTest, CheckFailsWithNegativeRadius) {
555 const double target_radius = -std::sqrt(2.0);
557 Sharder sharder(2, 2,
nullptr);
562 VectorXd::Ones(2), target_radius, sharder),
563 "Check failed: target_radius >= 0.0");
566 TEST(TrustRegionDeathTest, CheckFailsWithNegativeRadiusForDiagonalSolver) {
576 const double target_radius = -std::sqrt(2.0);
578 Sharder sharder(2, 2,
nullptr);
584 VectorXd::Ones(2), target_radius, sharder,
586 "Check failed: target_radius >= 0.0");
589 class ComputeLocalizedLagrangianBoundsTest
590 :
public testing::TestWithParam<std::tuple<PrimalDualNorm, bool>> {
592 void SetUp()
override {
593 const auto [primal_dual_norm, use_diagonal_qp_trust_region_solver] =
595 if (use_diagonal_qp_trust_region_solver &&
597 GTEST_SKIP() <<
"The diagonal QP trust region solver can only be used "
598 <<
"when the underlying norms are Euclidean.";
603 INSTANTIATE_TEST_SUITE_P(
604 TrustRegionNorm, ComputeLocalizedLagrangianBoundsTest,
608 [](
const testing::TestParamInfo<
609 ComputeLocalizedLagrangianBoundsTest::ParamType>& info) {
610 const absl::string_view suffix =
611 std::get<1>(info.param) ?
"DiagonalTRSolver" :
"LinearTimeTRSolver";
612 switch (std::get<0>(info.param)) {
614 return absl::StrCat(
"EuclideanNorm",
"_", suffix);
616 return absl::StrCat(
"MaxNorm",
"_", suffix);
620 TEST_P(ComputeLocalizedLagrangianBoundsTest, ZeroGapAtOptimal) {
621 ShardedQuadraticProgram lp(
TestLp(), 2, 2);
623 VectorXd primal_solution(4), dual_solution(4);
624 primal_solution << -1.0, 8.0, 1.0, 2.5;
625 dual_solution << -2.0, 0.0, 2.375, 2.0 / 3.0;
627 const auto [primal_dual_norm, use_diagonal_qp_solver] = GetParam();
630 lp, primal_solution, dual_solution, primal_dual_norm,
633 nullptr, use_diagonal_qp_solver,
636 EXPECT_DOUBLE_EQ(
bounds.radius, 1.0);
637 EXPECT_DOUBLE_EQ(
bounds.lagrangian_value, -20.0);
638 EXPECT_DOUBLE_EQ(
bounds.lower_bound, -20.0);
639 EXPECT_DOUBLE_EQ(
bounds.upper_bound, -20.0);
644 TEST_P(ComputeLocalizedLagrangianBoundsTest, OptimalInBoundRange) {
645 ShardedQuadraticProgram lp(
TestLp(), 2, 2);
648 VectorXd primal_solution(4);
649 primal_solution << 0.0, 0.0, 0.0, 3.0;
652 const auto [primal_dual_norm, use_diagonal_qp_solver] = GetParam();
654 const double primal_distance_squared_to_optimal =
655 0.5 * (1.0 + 8.0 * 8.0 + 1.0 + 0.5 * 0.5);
656 const double dual_distance_squared_to_optimal =
657 0.5 * (4.0 + 2.375 * 2.375 + 4.0 / 9.0);
658 const double distance_to_optimal =
660 ? std::sqrt(primal_distance_squared_to_optimal +
661 dual_distance_squared_to_optimal)
662 : std::sqrt(std::
max(primal_distance_squared_to_optimal,
663 dual_distance_squared_to_optimal));
666 lp, primal_solution, dual_solution, primal_dual_norm,
670 nullptr, use_diagonal_qp_solver,
673 EXPECT_DOUBLE_EQ(
bounds.lagrangian_value, 3.0);
674 EXPECT_LE(
bounds.lower_bound, -20.0);
675 EXPECT_GE(
bounds.upper_bound, -20.0);
680 TEST_P(ComputeLocalizedLagrangianBoundsTest, OptimalNotInBoundRange) {
681 ShardedQuadraticProgram lp(
TestLp(), 2, 2);
684 VectorXd primal_solution(4);
685 primal_solution << 0.0, 0.0, 0.0, 3.0;
688 const auto [primal_dual_norm, use_diagonal_qp_solver] = GetParam();
691 lp, primal_solution, dual_solution, primal_dual_norm,
695 nullptr, use_diagonal_qp_solver,
697 const double expected_lagrangian = 3.0;
698 EXPECT_DOUBLE_EQ(
bounds.lagrangian_value, expected_lagrangian);
708 switch (primal_dual_norm) {
713 EXPECT_NEAR(
bounds.lower_bound,
714 expected_lagrangian - 0.1 * sqrt(2) * sqrt(36.25), 1.0e-6);
718 EXPECT_NEAR(
bounds.upper_bound,
719 expected_lagrangian + 0.1 * sqrt(2) * sqrt(40.0), 1.0e-6);
726 EXPECT_NEAR(
bounds.lower_bound,
727 expected_lagrangian - 0.1 * sqrt(2) * 36.25 / sqrt(76.25),
729 EXPECT_NEAR(
bounds.upper_bound,
730 expected_lagrangian + 0.1 * sqrt(2) * 40 / sqrt(76.25),
738 TEST(ComputeLocalizedLagrangianBoundsTest, ProcessesPrimalWeight) {
739 ShardedQuadraticProgram lp(
TestLp(), 2, 2);
742 VectorXd primal_solution(4);
743 primal_solution << 0.0, 0.0, 0.0, 3.0;
754 const double expected_lagrangian = 3.0;
755 EXPECT_DOUBLE_EQ(
bounds.lagrangian_value, expected_lagrangian);
759 EXPECT_LE(
bounds.lower_bound, expected_lagrangian - 0.028);
760 EXPECT_GE(
bounds.lower_bound, expected_lagrangian - 0.28);
761 EXPECT_GE(
bounds.upper_bound, expected_lagrangian + 2.8);
762 EXPECT_LE(
bounds.upper_bound, expected_lagrangian + 28);
767 TEST_P(ComputeLocalizedLagrangianBoundsTest, AcceptsCachedProducts) {
768 ShardedQuadraticProgram lp(
TestLp(), 2, 2);
771 VectorXd primal_solution(4);
772 primal_solution << 0.0, 0.0, 0.0, 3.0;
775 VectorXd primal_product(4);
776 primal_product << 6.0, 0.0, 0.0, -3.0;
779 const auto [primal_dual_norm, use_diagonal_qp_solver] = GetParam();
781 const double primal_distance_squared_to_optimal =
782 0.5 * (1.0 + 8.0 * 8.0 + 1.0 + 0.5 * 0.5);
783 const double dual_distance_squared_to_optimal =
784 0.5 * (4.0 + 2.375 * 2.375 + 4.0 / 9.0);
785 const double distance_to_optimal =
787 ? std::sqrt(primal_distance_squared_to_optimal +
788 dual_distance_squared_to_optimal)
789 : std::sqrt(std::
max(primal_distance_squared_to_optimal,
790 dual_distance_squared_to_optimal));
793 lp, primal_solution, dual_solution, primal_dual_norm,
797 &dual_product, use_diagonal_qp_solver,
800 EXPECT_DOUBLE_EQ(
bounds.lagrangian_value, 3.0);
801 EXPECT_LE(
bounds.lower_bound, -20.0);
802 EXPECT_GE(
bounds.upper_bound, -20.0);
808 QuadraticProgram OneDimLp() {
809 QuadraticProgram lp(1, 1);
810 lp.constraint_lower_bounds << 0;
811 lp.constraint_upper_bounds << 1;
814 std::vector<Eigen::Triplet<double, int64_t>> triplets = {{0, 0, 1}};
815 lp.constraint_matrix.setFromTriplets(triplets.begin(), triplets.end());
816 lp.objective_vector << 1.0;
823 QuadraticProgram OneDimQp() {
824 QuadraticProgram qp(1, 1);
825 qp.constraint_lower_bounds << 0;
826 qp.constraint_upper_bounds << 1;
829 std::vector<Eigen::Triplet<double, int64_t>> constraint_matrix_triplets = {
831 qp.constraint_matrix.setFromTriplets(constraint_matrix_triplets.begin(),
832 constraint_matrix_triplets.end());
833 qp.objective_matrix.emplace();
834 qp.objective_matrix->resize(1);
835 qp.objective_matrix->diagonal() << 2;
836 qp.objective_vector << 1;
841 VectorXd GetPrimalGradient(
const ShardedQuadraticProgram& sharded_qp,
842 const VectorXd& primal_solution,
843 const VectorXd& dual_solution) {
845 sharded_qp.Qp().constraint_matrix, dual_solution,
846 sharded_qp.ConstraintMatrixSharder());
851 VectorXd GetDualGradient(
const ShardedQuadraticProgram& sharded_qp,
852 const VectorXd& primal_solution,
853 const VectorXd& dual_solution) {
855 sharded_qp.TransposedConstraintMatrix(), primal_solution,
856 sharded_qp.TransposedConstraintMatrixSharder());
861 struct TestProblemData {
872 TestProblemData GenerateTestLpProblemData(
const double primal_weight) {
877 norm_weights << 0.5 * primal_weight, 0.5 / primal_weight;
890 TestProblemData GenerateTestQpProblemData(
const double primal_weight) {
891 TestProblemData lp_data = GenerateTestLpProblemData(primal_weight);
892 lp_data.objective_matrix_diagonal[0] = 2.0;
898 TEST_P(ComputeLocalizedLagrangianBoundsTest, NormsBehaveDifferently) {
899 ShardedQuadraticProgram lp(OneDimLp(), 2, 2);
902 VectorXd dual_solution(1);
908 const auto [primal_dual_norm, use_diagonal_qp_solver] = GetParam();
911 lp, primal_solution, dual_solution, primal_dual_norm,
912 1.0, 1.0 / std::sqrt(2.0),
914 nullptr, use_diagonal_qp_solver,
916 const double expected_lagrangian = -1;
917 EXPECT_DOUBLE_EQ(
bounds.lagrangian_value, expected_lagrangian);
919 switch (primal_dual_norm) {
921 EXPECT_DOUBLE_EQ(
bounds.lower_bound, expected_lagrangian - 2.0);
922 EXPECT_DOUBLE_EQ(
bounds.upper_bound, expected_lagrangian + 1.0);
925 if (use_diagonal_qp_solver) {
926 EXPECT_NEAR(
bounds.lower_bound,
927 expected_lagrangian - 4.0 / std::sqrt(5), 1.0e-6);
928 EXPECT_NEAR(
bounds.upper_bound,
929 expected_lagrangian + 1.0 / std::sqrt(5), 1.0e-6);
931 EXPECT_DOUBLE_EQ(
bounds.lower_bound,
932 expected_lagrangian - 4.0 / std::sqrt(5));
933 EXPECT_DOUBLE_EQ(
bounds.upper_bound,
934 expected_lagrangian + 1.0 / std::sqrt(5));
941 TEST_P(ComputeLocalizedLagrangianBoundsTest,
942 NormsBehaveDifferentlyWithLargePrimalWeight) {
943 ShardedQuadraticProgram lp(OneDimLp(), 2, 2);
946 VectorXd dual_solution(1);
951 const auto [primal_dual_norm, use_diagonal_qp_solver] = GetParam();
954 lp, primal_solution, dual_solution, primal_dual_norm,
955 100.0, 1.0 / std::sqrt(2.0),
957 nullptr, use_diagonal_qp_solver,
959 const double expected_lagrangian = -1;
960 EXPECT_DOUBLE_EQ(
bounds.lagrangian_value, expected_lagrangian);
962 switch (primal_dual_norm) {
964 EXPECT_DOUBLE_EQ(
bounds.lower_bound, expected_lagrangian - 0.2);
965 EXPECT_DOUBLE_EQ(
bounds.upper_bound, expected_lagrangian + 10.0);
970 if (use_diagonal_qp_solver) {
971 EXPECT_NEAR(
bounds.upper_bound -
bounds.lower_bound, 10.00199980003999,
974 EXPECT_DOUBLE_EQ(
bounds.upper_bound -
bounds.lower_bound,
981 TEST(DiagonalTrustRegionSolverTest, JointSolverWorksWithOneDimQpUnitWeight) {
982 ShardedQuadraticProgram sharded_qp(OneDimQp(), 2,
984 const auto problem_data = GenerateTestQpProblemData(1.0);
986 problem_data.objective_vector, problem_data.objective_matrix_diagonal,
987 problem_data.variable_lower_bounds, problem_data.variable_upper_bounds,
988 problem_data.center_point, problem_data.norm_weights,
990 Sharder(2, 2,
nullptr),
992 EXPECT_THAT(result.solution,
993 ElementsAre(DoubleNear(-0.5, 1.0e-6), DoubleNear(-0.5, 1.0e-6)));
994 EXPECT_NEAR(result.solution_step_size, 4.0, 4.0 * 1.0e-6);
995 EXPECT_NEAR(result.objective_value, -1.25, 1.0e-6);
998 TEST(DiagonalTrustRegionSolverTest,
999 DiagonalQpSolverWorksWithOneDimQpUnitWeight) {
1000 ShardedQuadraticProgram sharded_qp(OneDimQp(), 2,
1003 VectorXd dual_solution = -1.0 * VectorXd::Ones(1);
1004 VectorXd primal_gradient =
1005 GetPrimalGradient(sharded_qp, primal_solution, dual_solution);
1006 VectorXd dual_gradient =
1007 GetDualGradient(sharded_qp, primal_solution, dual_solution);
1009 sharded_qp, primal_solution, dual_solution, primal_gradient,
1010 dual_gradient, 1.0, 0.5,
1012 EXPECT_THAT(result.solution,
1013 ElementsAre(DoubleNear(-0.5, 1.0e-6), DoubleNear(-0.5, 1.0e-6)));
1014 EXPECT_NEAR(result.solution_step_size, 4.0, 4.0 * 1.0e-6);
1015 EXPECT_NEAR(result.objective_value, -1.25, 1.0e-6);
1018 TEST(DiagonalTrustRegionSolverTest, JointSolverWorksWithOneDimQpLargeWeight) {
1019 ShardedQuadraticProgram sharded_qp(OneDimQp(), 2,
1021 const auto problem_data = GenerateTestQpProblemData(100.0);
1023 problem_data.objective_vector, problem_data.objective_matrix_diagonal,
1024 problem_data.variable_lower_bounds, problem_data.variable_upper_bounds,
1025 problem_data.center_point, problem_data.norm_weights,
1026 std::sqrt(2705.0 / 2) * (5.0 / 13),
1027 Sharder(2, 2,
nullptr),
1029 EXPECT_NEAR(result.solution_step_size, 1.0, 1.0e-6);
1032 TEST(DiagonalTrustRegionSolverTest,
1033 DiagonalQpSolverWorksWithOneDimQpLargeWeight) {
1034 ShardedQuadraticProgram sharded_qp(OneDimQp(), 2,
1037 VectorXd dual_solution = -1.0 * VectorXd::Ones(1);
1038 VectorXd primal_gradient =
1039 GetPrimalGradient(sharded_qp, primal_solution, dual_solution);
1040 VectorXd dual_gradient =
1041 GetDualGradient(sharded_qp, primal_solution, dual_solution);
1043 sharded_qp, primal_solution, dual_solution, primal_gradient,
1044 dual_gradient, 100.0,
1045 std::sqrt(2705.0 / 2.0) * (5.0 / 13),
1047 EXPECT_NEAR(result.solution_step_size, 1.0, 1.0e-6);
1050 TEST(DiagonalTrustRegionSolverTest, JointSolverWorksWithOneDimQpSmallWeight) {
1051 ShardedQuadraticProgram sharded_qp(OneDimQp(), 2,
1053 const auto problem_data = GenerateTestQpProblemData(0.01);
1055 problem_data.objective_vector, problem_data.objective_matrix_diagonal,
1056 problem_data.variable_lower_bounds, problem_data.variable_upper_bounds,
1057 problem_data.center_point, problem_data.norm_weights,
1059 Sharder(2, 2,
nullptr),
1061 EXPECT_THAT(result.solution, ElementsAre(DoubleNear(-0.99950025, 1.0e-6),
1062 DoubleNear(-0.9, 1.0e-6)));
1063 EXPECT_NEAR(result.solution_step_size, 0.2, 1.0e-6);
1064 EXPECT_NEAR(result.objective_value, -1.0999996, 1.0e-6);
1067 TEST(DiagonalTrustRegionSolverTest,
1068 DiagonalQpSolverWorksWithOneDimQpSmallWeight) {
1069 ShardedQuadraticProgram sharded_qp(OneDimQp(), 2,
1072 VectorXd dual_solution = -1.0 * VectorXd::Ones(1);
1073 VectorXd primal_gradient =
1074 GetPrimalGradient(sharded_qp, primal_solution, dual_solution);
1075 VectorXd dual_gradient =
1076 GetDualGradient(sharded_qp, primal_solution, dual_solution);
1078 sharded_qp, primal_solution, dual_solution, primal_gradient,
1079 dual_gradient, 0.01,
1082 EXPECT_THAT(result.solution, ElementsAre(DoubleNear(-0.99950025, 1.0e-6),
1083 DoubleNear(-0.9, 1.0e-6)));
1084 EXPECT_NEAR(result.solution_step_size, 0.2, 1.0e-6);
1085 EXPECT_NEAR(result.objective_value, -1.0999996, 1.0e-6);
1089 TEST(ComputeLocalizedLagrangianBoundsTest, SolvesForTestQpUnitWeight) {
1090 ShardedQuadraticProgram qp(OneDimQp(), 2, 2);
1093 VectorXd dual_solution(1);
1094 dual_solution << -1;
1105 const double expected_lagrangian = -1;
1106 EXPECT_DOUBLE_EQ(
bounds.lagrangian_value, expected_lagrangian);
1107 EXPECT_NEAR(
bounds.upper_bound, expected_lagrangian + 0.5, 1.0e-5);
1108 EXPECT_NEAR(
bounds.lower_bound, expected_lagrangian - 0.75, 1.0e-5);
SharedBoundsManager * bounds
LagrangianPart ComputeDualGradient(const ShardedQuadraticProgram &sharded_qp, const VectorXd &dual_solution, const VectorXd &primal_product)
LagrangianPart ComputePrimalGradient(const ShardedQuadraticProgram &sharded_qp, const VectorXd &primal_solution, const VectorXd &dual_product)
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)
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)
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)
EigenArrayNearMatcherP2< Eigen::Array< T, Eigen::Dynamic, 1 >, double > EigenArrayNear(absl::Span< const T > data, double tolerance)
EigenArrayEqMatcherP< Eigen::Array< T, Eigen::Dynamic, 1 > > EigenArrayEq(absl::Span< const T > data)
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