blob: e391aa4f56d3aef114febf0263207633f991dc69 [file] [log] [blame]
Austin Schuh29441032023-05-31 19:32:24 -07001#include "frc971/solvers/sparse_convex.h"
2
3#include "gtest/gtest.h"
4
5namespace frc971 {
6namespace solvers {
7namespace testing {
8
9const Eigen::IOFormat kHeavyFormat(Eigen::StreamPrecision, 0, ", ",
10 ",\n "
11 " ",
12 "[", "]", "[", "]");
13
14class SimpleQP : public SparseConvexProblem {
15 public:
16 // QP of the for 0.5 * X^t Q_ X + p.T * X
17 SimpleQP(Eigen::Matrix<double, 2, 2> Q, Eigen::Matrix<double, 2, 1> p,
18 double x0_max, double x0_min, double x1_max, double x1_min)
19 : SparseConvexProblem(2, 4, 1), Q_(Q), p_(p) {
20 C_ << 1, 0, -1, 0, 0, 1, 0, -1;
21 c_ << x0_max, -x0_min, x1_max, -x1_min;
22 }
23
24 double f0(Eigen::Ref<const Eigen::VectorXd> X) const override {
25 return 0.5 * (X.transpose() * Q_ * X)(0, 0);
26 }
27
28 Eigen::SparseMatrix<double> df0(
29 Eigen::Ref<const Eigen::VectorXd> X) const override {
30 return (Q_ * X + p_).sparseView();
31 }
32
33 Eigen::SparseMatrix<double> ddf0(
34 Eigen::Ref<const Eigen::VectorXd> /*X*/) const override {
35 return Q_.sparseView();
36 }
37
38 // Returns the constraints f(X) < 0, and their derivitive.
39 Eigen::VectorXd f(
40 Eigen::Ref<const Eigen::VectorXd> X) const override {
41 return C_ * X - c_;
42 }
43 Eigen::SparseMatrix<double> df(
44 Eigen::Ref<const Eigen::VectorXd> /*X*/) const override {
45 return C_.sparseView();
46 }
47
48 // Returns the equality constraints of the form A x = b
49 Eigen::SparseMatrix<double> A() const override {
50 return Eigen::Matrix<double, 1, 2>(1, -1).sparseView();
51 }
52 Eigen::VectorXd b() const override {
53 return Eigen::Matrix<double, 1, 1>(0);
54 }
55
56 private:
57 Eigen::Matrix<double, 2, 2> Q_;
58 Eigen::Matrix<double, 2, 1> p_;
59
60 Eigen::Matrix<double, 4, 2> C_;
61 Eigen::Matrix<double, 4, 1> c_;
62};
63
64// Test a constrained quadratic problem where the constraints aren't active.
65TEST(SolverTest, SimpleQP) {
66 Eigen::Matrix<double, 2, 2> Q = Eigen::DiagonalMatrix<double, 2>(1.0, 1.0);
67 Eigen::Matrix<double, 2, 1> p(-4, -6);
68
69 SimpleQP qp(Q, p, 6, -1, 6, -1);
70 SparseSolver s;
71 Eigen::Vector2d result = s.Solve(qp, Eigen::Matrix<double, 2, 1>(0, 0));
72 LOG(INFO) << "Result is " << std::setprecision(12)
73 << result.transpose().format(kHeavyFormat);
74 EXPECT_NEAR((result - Eigen::Vector2d(5.0, 5.0)).norm(), 0.0, 1e-6);
75}
76
77// Test a constrained quadratic problem where the constraints are active.
78TEST(SolverTest, Constrained) {
79 Eigen::Matrix<double, 2, 2> Q = Eigen::DiagonalMatrix<double, 2>(1.0, 2.0);
80 Eigen::Matrix<double, 2, 1> p(-5, -10);
81
82 SimpleQP qp(Q, p, 4, -1, 5, -1);
83 SparseSolver s;
84 Eigen::Vector2d result = s.Solve(qp, Eigen::Matrix<double, 2, 1>(3, 4));
85 LOG(INFO) << "Result is " << std::setprecision(12)
86 << result.transpose().format(kHeavyFormat);
87 EXPECT_NEAR((result - Eigen::Vector2d(4.0, 4.0)).norm(), 0.0, 1e-6);
88}
89
90// Test a constrained quadratic problem where the constraints are active and the
91// initial value is the solution.
92TEST(SolverTest, ConstrainedFromSolution) {
93 Eigen::Matrix<double, 2, 2> Q = Eigen::DiagonalMatrix<double, 2>(1.0, 2.0);
94 Eigen::Matrix<double, 2, 1> p(-5, -10);
95
96 SimpleQP qp(Q, p, 4, -1, 5, -1);
97 SparseSolver s;
98 Eigen::Vector2d result = s.Solve(qp, Eigen::Matrix<double, 2, 1>(4, 4));
99 LOG(INFO) << "Result is " << std::setprecision(12)
100 << result.transpose().format(kHeavyFormat);
101 EXPECT_NEAR((result - Eigen::Vector2d(4.0, 4.0)).norm(), 0.0, 1e-6);
102}
103
104} // namespace testing
105} // namespace solvers
106} // namespace frc971