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