blob: 63a94093052120b15102ede86af877ce72c327dc [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.
Philipp Schrader790cb542023-07-05 21:06:52 -070039 Eigen::VectorXd f(Eigen::Ref<const Eigen::VectorXd> X) const override {
Austin Schuh29441032023-05-31 19:32:24 -070040 return C_ * X - c_;
41 }
42 Eigen::SparseMatrix<double> df(
43 Eigen::Ref<const Eigen::VectorXd> /*X*/) const override {
44 return C_.sparseView();
45 }
46
47 // Returns the equality constraints of the form A x = b
48 Eigen::SparseMatrix<double> A() const override {
49 return Eigen::Matrix<double, 1, 2>(1, -1).sparseView();
50 }
Philipp Schrader790cb542023-07-05 21:06:52 -070051 Eigen::VectorXd b() const override { return Eigen::Matrix<double, 1, 1>(0); }
Austin Schuh29441032023-05-31 19:32:24 -070052
53 private:
54 Eigen::Matrix<double, 2, 2> Q_;
55 Eigen::Matrix<double, 2, 1> p_;
56
57 Eigen::Matrix<double, 4, 2> C_;
58 Eigen::Matrix<double, 4, 1> c_;
59};
60
61// Test a constrained quadratic problem where the constraints aren't active.
62TEST(SolverTest, SimpleQP) {
63 Eigen::Matrix<double, 2, 2> Q = Eigen::DiagonalMatrix<double, 2>(1.0, 1.0);
64 Eigen::Matrix<double, 2, 1> p(-4, -6);
65
66 SimpleQP qp(Q, p, 6, -1, 6, -1);
67 SparseSolver s;
68 Eigen::Vector2d result = s.Solve(qp, Eigen::Matrix<double, 2, 1>(0, 0));
69 LOG(INFO) << "Result is " << std::setprecision(12)
70 << result.transpose().format(kHeavyFormat);
71 EXPECT_NEAR((result - Eigen::Vector2d(5.0, 5.0)).norm(), 0.0, 1e-6);
72}
73
74// Test a constrained quadratic problem where the constraints are active.
75TEST(SolverTest, Constrained) {
76 Eigen::Matrix<double, 2, 2> Q = Eigen::DiagonalMatrix<double, 2>(1.0, 2.0);
77 Eigen::Matrix<double, 2, 1> p(-5, -10);
78
79 SimpleQP qp(Q, p, 4, -1, 5, -1);
80 SparseSolver s;
81 Eigen::Vector2d result = s.Solve(qp, Eigen::Matrix<double, 2, 1>(3, 4));
82 LOG(INFO) << "Result is " << std::setprecision(12)
83 << result.transpose().format(kHeavyFormat);
84 EXPECT_NEAR((result - Eigen::Vector2d(4.0, 4.0)).norm(), 0.0, 1e-6);
85}
86
87// Test a constrained quadratic problem where the constraints are active and the
88// initial value is the solution.
89TEST(SolverTest, ConstrainedFromSolution) {
90 Eigen::Matrix<double, 2, 2> Q = Eigen::DiagonalMatrix<double, 2>(1.0, 2.0);
91 Eigen::Matrix<double, 2, 1> p(-5, -10);
92
93 SimpleQP qp(Q, p, 4, -1, 5, -1);
94 SparseSolver s;
95 Eigen::Vector2d result = s.Solve(qp, Eigen::Matrix<double, 2, 1>(4, 4));
96 LOG(INFO) << "Result is " << std::setprecision(12)
97 << result.transpose().format(kHeavyFormat);
98 EXPECT_NEAR((result - Eigen::Vector2d(4.0, 4.0)).norm(), 0.0, 1e-6);
99}
100
101} // namespace testing
102} // namespace solvers
103} // namespace frc971