Directory: | ./ |
---|---|
File: | include/crocoddyl/core/actions/lqr.hxx |
Date: | 2025-03-26 19:23:43 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 190 | 242 | 78.5% |
Branches: | 209 | 906 | 23.1% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /////////////////////////////////////////////////////////////////////////////// | ||
2 | // BSD 3-Clause License | ||
3 | // | ||
4 | // Copyright (C) 2019-2025, LAAS-CNRS, University of Edinburgh, | ||
5 | // Heriot-Watt University | ||
6 | // Copyright note valid unless otherwise stated in individual files. | ||
7 | // All rights reserved. | ||
8 | /////////////////////////////////////////////////////////////////////////////// | ||
9 | |||
10 | namespace crocoddyl { | ||
11 | |||
12 | template <typename Scalar> | ||
13 | ✗ | ActionModelLQRTpl<Scalar>::ActionModelLQRTpl(const MatrixXs& A, | |
14 | const MatrixXs& B, | ||
15 | const MatrixXs& Q, | ||
16 | const MatrixXs& R, | ||
17 | const MatrixXs& N) | ||
18 | ✗ | : Base(std::make_shared<StateVector>(A.cols()), B.cols(), 0), | |
19 | ✗ | drift_free_(true), | |
20 | ✗ | updated_lqr_(false) { | |
21 | ✗ | const std::size_t nx = state_->get_nx(); | |
22 | ✗ | MatrixXs G = MatrixXs::Zero(ng_, nx + nu_); | |
23 | ✗ | MatrixXs H = MatrixXs::Zero(nh_, nx + nu_); | |
24 | ✗ | VectorXs f = VectorXs::Zero(nx); | |
25 | ✗ | VectorXs q = VectorXs::Zero(nx); | |
26 | ✗ | VectorXs r = VectorXs::Zero(nu_); | |
27 | ✗ | VectorXs g = VectorXs::Zero(ng_); | |
28 | ✗ | VectorXs h = VectorXs::Zero(nh_); | |
29 | ✗ | set_LQR(A, B, Q, R, N, G, H, f, q, r, g, h); | |
30 | } | ||
31 | |||
32 | template <typename Scalar> | ||
33 | ✗ | ActionModelLQRTpl<Scalar>::ActionModelLQRTpl( | |
34 | const MatrixXs& A, const MatrixXs& B, const MatrixXs& Q, const MatrixXs& R, | ||
35 | const MatrixXs& N, const VectorXs& f, const VectorXs& q, const VectorXs& r) | ||
36 | ✗ | : Base(std::make_shared<StateVector>(A.cols()), B.cols(), 0), | |
37 | ✗ | drift_free_(false), | |
38 | ✗ | updated_lqr_(false) { | |
39 | ✗ | const std::size_t nx = state_->get_nx(); | |
40 | ✗ | MatrixXs G = MatrixXs::Zero(ng_, nx + nu_); | |
41 | ✗ | MatrixXs H = MatrixXs::Zero(ng_, nx + nu_); | |
42 | ✗ | VectorXs g = VectorXs::Zero(ng_); | |
43 | ✗ | VectorXs h = VectorXs::Zero(nh_); | |
44 | ✗ | set_LQR(A, B, Q, R, N, G, H, f, q, r, g, h); | |
45 | } | ||
46 | |||
47 | template <typename Scalar> | ||
48 | 57 | ActionModelLQRTpl<Scalar>::ActionModelLQRTpl( | |
49 | const MatrixXs& A, const MatrixXs& B, const MatrixXs& Q, const MatrixXs& R, | ||
50 | const MatrixXs& N, const MatrixXs& G, const MatrixXs& H, const VectorXs& f, | ||
51 | const VectorXs& q, const VectorXs& r, const VectorXs& g, const VectorXs& h) | ||
52 | ✗ | : Base(std::make_shared<StateVector>(A.cols()), B.cols(), 0, G.rows(), | |
53 | 171 | H.rows(), G.rows(), H.rows()), | |
54 | 57 | drift_free_(false), | |
55 |
15/30✓ Branch 7 taken 57 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 57 times.
✗ Branch 12 not taken.
✓ Branch 16 taken 57 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 57 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 57 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 57 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 57 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 57 times.
✗ Branch 32 not taken.
✓ Branch 34 taken 57 times.
✗ Branch 35 not taken.
✓ Branch 37 taken 57 times.
✗ Branch 38 not taken.
✓ Branch 40 taken 57 times.
✗ Branch 41 not taken.
✓ Branch 43 taken 57 times.
✗ Branch 44 not taken.
✓ Branch 46 taken 57 times.
✗ Branch 47 not taken.
✓ Branch 49 taken 57 times.
✗ Branch 50 not taken.
✓ Branch 52 taken 57 times.
✗ Branch 53 not taken.
|
57 | updated_lqr_(false) { |
56 |
1/2✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
|
57 | set_LQR(A, B, Q, R, N, G, H, f, q, r, g, h); |
57 | 57 | } | |
58 | |||
59 | template <typename Scalar> | ||
60 | 94 | ActionModelLQRTpl<Scalar>::ActionModelLQRTpl(const std::size_t nx, | |
61 | const std::size_t nu, | ||
62 | const bool drift_free) | ||
63 | : Base(std::make_shared<StateVector>(nx), nu, 0), | ||
64 |
1/2✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
|
94 | A_(MatrixXs::Identity(nx, nx)), |
65 |
2/4✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 94 times.
✗ Branch 5 not taken.
|
94 | B_(MatrixXs::Identity(nx, nu)), |
66 |
2/4✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 94 times.
✗ Branch 5 not taken.
|
94 | Q_(MatrixXs::Identity(nx, nx)), |
67 |
2/4✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 94 times.
✗ Branch 5 not taken.
|
94 | R_(MatrixXs::Identity(nu, nu)), |
68 |
2/4✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 94 times.
✗ Branch 5 not taken.
|
94 | N_(MatrixXs::Zero(nx, nu)), |
69 |
2/4✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 94 times.
✗ Branch 5 not taken.
|
94 | G_(MatrixXs::Zero(0, nx + nu)), |
70 |
2/4✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 94 times.
✗ Branch 5 not taken.
|
94 | H_(MatrixXs::Zero(0, nx + nu)), |
71 |
5/8✓ Branch 0 taken 38 times.
✓ Branch 1 taken 56 times.
✓ Branch 3 taken 38 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 56 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 94 times.
✗ Branch 10 not taken.
|
94 | f_(drift_free ? VectorXs::Zero(nx) : VectorXs::Ones(nx)), |
72 |
2/4✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 94 times.
✗ Branch 5 not taken.
|
94 | q_(VectorXs::Ones(nx)), |
73 |
2/4✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 94 times.
✗ Branch 5 not taken.
|
94 | r_(VectorXs::Ones(nu)), |
74 |
2/4✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 94 times.
✗ Branch 5 not taken.
|
94 | g_(VectorXs::Zero(0)), |
75 |
2/4✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 94 times.
✗ Branch 5 not taken.
|
94 | h_(VectorXs::Zero(0)), |
76 |
3/6✓ Branch 3 taken 94 times.
✗ Branch 4 not taken.
✓ Branch 8 taken 94 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 94 times.
✗ Branch 12 not taken.
|
188 | drift_free_(drift_free) {} |
77 | |||
78 | template <typename Scalar> | ||
79 | 59 | ActionModelLQRTpl<Scalar>::ActionModelLQRTpl(const ActionModelLQRTpl& copy) | |
80 | 59 | : Base(std::make_shared<StateVector>(copy.get_A().cols()), | |
81 | 177 | copy.get_B().cols(), 0, copy.get_G().rows(), copy.get_H().rows(), | |
82 | 118 | copy.get_G().rows(), copy.get_H().rows()), | |
83 | 59 | drift_free_(false), | |
84 |
15/30✓ Branch 7 taken 59 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 59 times.
✗ Branch 12 not taken.
✓ Branch 16 taken 59 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 59 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 59 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 59 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 59 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 59 times.
✗ Branch 32 not taken.
✓ Branch 34 taken 59 times.
✗ Branch 35 not taken.
✓ Branch 37 taken 59 times.
✗ Branch 38 not taken.
✓ Branch 40 taken 59 times.
✗ Branch 41 not taken.
✓ Branch 43 taken 59 times.
✗ Branch 44 not taken.
✓ Branch 46 taken 59 times.
✗ Branch 47 not taken.
✓ Branch 49 taken 59 times.
✗ Branch 50 not taken.
✓ Branch 52 taken 59 times.
✗ Branch 53 not taken.
|
413 | updated_lqr_(false) { |
85 |
5/10✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 59 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 59 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 59 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 59 times.
✗ Branch 14 not taken.
|
59 | set_LQR(copy.get_A(), copy.get_B(), copy.get_Q(), copy.get_R(), copy.get_N(), |
86 |
5/10✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 59 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 59 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 59 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 59 times.
✗ Branch 14 not taken.
|
59 | copy.get_G(), copy.get_H(), copy.get_f(), copy.get_q(), copy.get_r(), |
87 |
3/6✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 59 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 59 times.
✗ Branch 8 not taken.
|
59 | copy.get_g(), copy.get_h()); |
88 | 59 | } | |
89 | |||
90 | template <typename Scalar> | ||
91 | 2856 | void ActionModelLQRTpl<Scalar>::calc( | |
92 | const std::shared_ptr<ActionDataAbstract>& data, | ||
93 | const Eigen::Ref<const VectorXs>& x, const Eigen::Ref<const VectorXs>& u) { | ||
94 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 2856 times.
|
2856 | if (static_cast<std::size_t>(x.size()) != state_->get_nx()) { |
95 | ✗ | throw_pretty( | |
96 | "Invalid argument: " << "x has wrong dimension (it should be " + | ||
97 | std::to_string(state_->get_nx()) + ")"); | ||
98 | } | ||
99 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2856 times.
|
2856 | if (static_cast<std::size_t>(u.size()) != nu_) { |
100 | ✗ | throw_pretty( | |
101 | "Invalid argument: " << "u has wrong dimension (it should be " + | ||
102 | std::to_string(nu_) + ")"); | ||
103 | } | ||
104 | 2856 | Data* d = static_cast<Data*>(data.get()); | |
105 | |||
106 |
2/4✓ Branch 3 taken 2856 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2856 times.
✗ Branch 7 not taken.
|
2856 | data->xnext.noalias() = A_ * x; |
107 |
2/4✓ Branch 3 taken 2856 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2856 times.
✗ Branch 7 not taken.
|
2856 | data->xnext.noalias() += B_ * u; |
108 | 2856 | data->xnext += f_; | |
109 | |||
110 | // cost = 0.5 * x^T * Q * x + 0.5 * u^T * R * u + x^T * N * u + q^T * x + r^T | ||
111 | // * u | ||
112 |
2/4✓ Branch 2 taken 2856 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2856 times.
✗ Branch 6 not taken.
|
2856 | d->Q_x_tmp.noalias() = Q_ * x; |
113 | 2856 | data->cost = Scalar(0.5) * x.dot(d->Q_x_tmp); | |
114 |
2/4✓ Branch 2 taken 2856 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2856 times.
✗ Branch 6 not taken.
|
2856 | d->R_u_tmp.noalias() = R_ * u; |
115 | 2856 | data->cost += Scalar(0.5) * u.dot(d->R_u_tmp); | |
116 |
2/4✓ Branch 2 taken 2856 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2856 times.
✗ Branch 6 not taken.
|
2856 | d->Q_x_tmp.noalias() = N_ * u; |
117 | 2856 | data->cost += x.dot(d->Q_x_tmp); | |
118 | 2856 | data->cost += q_.dot(x); | |
119 | 2856 | data->cost += r_.dot(u); | |
120 | |||
121 | // constraints | ||
122 | 2856 | const std::size_t nx = state_->get_nx(); | |
123 |
3/6✓ Branch 2 taken 2856 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2856 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2856 times.
✗ Branch 10 not taken.
|
2856 | data->g.noalias() = G_.leftCols(nx) * x; |
124 |
3/6✓ Branch 2 taken 2856 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2856 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2856 times.
✗ Branch 10 not taken.
|
2856 | data->g.noalias() += G_.rightCols(nu_) * u; |
125 | 2856 | data->g += g_; | |
126 |
3/6✓ Branch 2 taken 2856 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2856 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2856 times.
✗ Branch 10 not taken.
|
2856 | data->h.noalias() = H_.leftCols(nx) * x; |
127 |
3/6✓ Branch 2 taken 2856 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2856 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2856 times.
✗ Branch 10 not taken.
|
2856 | data->h.noalias() += H_.rightCols(nu_) * u; |
128 | 2856 | data->h += h_; | |
129 | 2856 | } | |
130 | |||
131 | template <typename Scalar> | ||
132 | 232 | void ActionModelLQRTpl<Scalar>::calc( | |
133 | const std::shared_ptr<ActionDataAbstract>& data, | ||
134 | const Eigen::Ref<const VectorXs>& x) { | ||
135 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 232 times.
|
232 | if (static_cast<std::size_t>(x.size()) != state_->get_nx()) { |
136 | ✗ | throw_pretty( | |
137 | "Invalid argument: " << "x has wrong dimension (it should be " + | ||
138 | std::to_string(state_->get_nx()) + ")"); | ||
139 | } | ||
140 | 232 | Data* d = static_cast<Data*>(data.get()); | |
141 | |||
142 | 232 | d->xnext = x; | |
143 | |||
144 | // cost = 0.5 * x^T * Q * x + q^T * x | ||
145 |
2/4✓ Branch 2 taken 232 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 232 times.
✗ Branch 6 not taken.
|
232 | d->Q_x_tmp.noalias() = Q_ * x; |
146 | 232 | data->cost = Scalar(0.5) * x.dot(d->Q_x_tmp); | |
147 | 232 | data->cost += q_.dot(x); | |
148 | |||
149 | // constraints | ||
150 | 232 | const std::size_t nx = state_->get_nx(); | |
151 |
3/6✓ Branch 2 taken 232 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 232 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 232 times.
✗ Branch 10 not taken.
|
232 | data->g.noalias() = G_.leftCols(nx) * x; |
152 | 232 | data->g += g_; | |
153 |
3/6✓ Branch 2 taken 232 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 232 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 232 times.
✗ Branch 10 not taken.
|
232 | data->h.noalias() = H_.leftCols(nx) * x; |
154 | 232 | data->h += h_; | |
155 | 232 | } | |
156 | |||
157 | template <typename Scalar> | ||
158 | 1846 | void ActionModelLQRTpl<Scalar>::calcDiff( | |
159 | const std::shared_ptr<ActionDataAbstract>& data, | ||
160 | const Eigen::Ref<const VectorXs>& x, const Eigen::Ref<const VectorXs>& u) { | ||
161 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 1846 times.
|
1846 | if (static_cast<std::size_t>(x.size()) != state_->get_nx()) { |
162 | ✗ | throw_pretty( | |
163 | "Invalid argument: " << "x has wrong dimension (it should be " + | ||
164 | std::to_string(state_->get_nx()) + ")"); | ||
165 | } | ||
166 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1846 times.
|
1846 | if (static_cast<std::size_t>(u.size()) != nu_) { |
167 | ✗ | throw_pretty( | |
168 | "Invalid argument: " << "u has wrong dimension (it should be " + | ||
169 | std::to_string(nu_) + ")"); | ||
170 | } | ||
171 | |||
172 | 1846 | const std::size_t nx = state_->get_nx(); | |
173 |
2/2✓ Branch 0 taken 37 times.
✓ Branch 1 taken 1809 times.
|
1846 | if (!updated_lqr_) { |
174 | 37 | data->Fx = A_; | |
175 | 37 | data->Fu = B_; | |
176 | 37 | data->Lxx = Q_; | |
177 | 37 | data->Luu = R_; | |
178 | 37 | data->Lxu = N_; | |
179 |
1/2✓ Branch 3 taken 37 times.
✗ Branch 4 not taken.
|
37 | data->Gx = G_.leftCols(nx); |
180 |
1/2✓ Branch 3 taken 37 times.
✗ Branch 4 not taken.
|
37 | data->Gu = G_.rightCols(nu_); |
181 |
1/2✓ Branch 3 taken 37 times.
✗ Branch 4 not taken.
|
37 | data->Hx = H_.leftCols(nx); |
182 |
1/2✓ Branch 3 taken 37 times.
✗ Branch 4 not taken.
|
37 | data->Hu = H_.rightCols(nu_); |
183 | 37 | updated_lqr_ = true; | |
184 | } | ||
185 | 1846 | data->Lx = q_; | |
186 |
2/4✓ Branch 3 taken 1846 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1846 times.
✗ Branch 7 not taken.
|
1846 | data->Lx.noalias() += Q_ * x; |
187 |
2/4✓ Branch 3 taken 1846 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1846 times.
✗ Branch 7 not taken.
|
1846 | data->Lx.noalias() += N_ * u; |
188 | 1846 | data->Lu = r_; | |
189 |
3/6✓ Branch 2 taken 1846 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1846 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1846 times.
✗ Branch 10 not taken.
|
1846 | data->Lu.noalias() += N_.transpose() * x; |
190 |
2/4✓ Branch 3 taken 1846 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1846 times.
✗ Branch 7 not taken.
|
1846 | data->Lu.noalias() += R_ * u; |
191 | 1846 | } | |
192 | |||
193 | template <typename Scalar> | ||
194 | 110 | void ActionModelLQRTpl<Scalar>::calcDiff( | |
195 | const std::shared_ptr<ActionDataAbstract>& data, | ||
196 | const Eigen::Ref<const VectorXs>& x) { | ||
197 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 110 times.
|
110 | if (static_cast<std::size_t>(x.size()) != state_->get_nx()) { |
198 | ✗ | throw_pretty( | |
199 | "Invalid argument: " << "x has wrong dimension (it should be " + | ||
200 | std::to_string(state_->get_nx()) + ")"); | ||
201 | } | ||
202 | |||
203 | 110 | const std::size_t nx = state_->get_nx(); | |
204 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 97 times.
|
110 | if (!updated_lqr_) { |
205 | 13 | data->Lxx = Q_; | |
206 |
1/2✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
|
13 | data->Gx = G_.leftCols(nx); |
207 |
1/2✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
|
13 | data->Hx = H_.leftCols(nx); |
208 | 13 | updated_lqr_ = true; | |
209 | } | ||
210 | 110 | data->Lx = q_; | |
211 |
2/4✓ Branch 3 taken 110 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 110 times.
✗ Branch 7 not taken.
|
110 | data->Lx.noalias() += Q_ * x; |
212 | 110 | } | |
213 | |||
214 | template <typename Scalar> | ||
215 | std::shared_ptr<ActionDataAbstractTpl<Scalar>> | ||
216 | 1617 | ActionModelLQRTpl<Scalar>::createData() { | |
217 |
1/2✓ Branch 2 taken 1617 times.
✗ Branch 3 not taken.
|
1617 | return std::allocate_shared<Data>(Eigen::aligned_allocator<Data>(), this); |
218 | } | ||
219 | |||
220 | template <typename Scalar> | ||
221 | template <typename NewScalar> | ||
222 | ✗ | ActionModelLQRTpl<NewScalar> ActionModelLQRTpl<Scalar>::cast() const { | |
223 | typedef ActionModelLQRTpl<NewScalar> ReturnType; | ||
224 | ✗ | ReturnType ret(A_.template cast<NewScalar>(), B_.template cast<NewScalar>(), | |
225 | ✗ | Q_.template cast<NewScalar>(), R_.template cast<NewScalar>(), | |
226 | ✗ | N_.template cast<NewScalar>(), G_.template cast<NewScalar>(), | |
227 | ✗ | H_.template cast<NewScalar>(), f_.template cast<NewScalar>(), | |
228 | ✗ | q_.template cast<NewScalar>(), r_.template cast<NewScalar>(), | |
229 | ✗ | g_.template cast<NewScalar>(), h_.template cast<NewScalar>()); | |
230 | ✗ | return ret; | |
231 | } | ||
232 | |||
233 | template <typename Scalar> | ||
234 | 256 | bool ActionModelLQRTpl<Scalar>::checkData( | |
235 | const std::shared_ptr<ActionDataAbstract>& data) { | ||
236 | 256 | std::shared_ptr<Data> d = std::dynamic_pointer_cast<Data>(data); | |
237 |
1/2✓ Branch 1 taken 256 times.
✗ Branch 2 not taken.
|
256 | if (d != NULL) { |
238 | 256 | return true; | |
239 | } else { | ||
240 | ✗ | return false; | |
241 | } | ||
242 | 256 | } | |
243 | |||
244 | template <typename Scalar> | ||
245 | 57 | ActionModelLQRTpl<Scalar> ActionModelLQRTpl<Scalar>::Random( | |
246 | const std::size_t nx, const std::size_t nu, const std::size_t ng, | ||
247 | const std::size_t nh) { | ||
248 |
2/4✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 57 times.
✗ Branch 5 not taken.
|
57 | MatrixXs A = MatrixXs::Random(nx, nx); |
249 |
2/4✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 57 times.
✗ Branch 5 not taken.
|
57 | MatrixXs B = MatrixXs::Random(nx, nu); |
250 |
2/4✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 57 times.
✗ Branch 5 not taken.
|
57 | MatrixXs L_tmp = MatrixXs::Random(nx + nu, nx + nu); |
251 |
3/6✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 57 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 57 times.
✗ Branch 8 not taken.
|
57 | MatrixXs L = L_tmp.transpose() * L_tmp; |
252 |
1/2✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
|
57 | const Eigen::Block<MatrixXs> Q = L.topLeftCorner(nx, nx); |
253 |
1/2✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
|
57 | const Eigen::Block<MatrixXs> R = L.bottomRightCorner(nu, nu); |
254 |
1/2✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
|
57 | const Eigen::Block<MatrixXs> N = L.topRightCorner(nx, nu); |
255 |
2/4✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 57 times.
✗ Branch 5 not taken.
|
57 | MatrixXs G = MatrixXs::Random(ng, nx + nu); |
256 |
2/4✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 57 times.
✗ Branch 5 not taken.
|
57 | MatrixXs H = MatrixXs::Random(nh, nx + nu); |
257 |
2/4✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 57 times.
✗ Branch 5 not taken.
|
57 | VectorXs f = VectorXs::Random(nx); |
258 |
2/4✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 57 times.
✗ Branch 5 not taken.
|
57 | VectorXs q = VectorXs::Random(nx); |
259 |
2/4✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 57 times.
✗ Branch 5 not taken.
|
57 | VectorXs r = VectorXs::Random(nu); |
260 |
2/4✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 57 times.
✗ Branch 5 not taken.
|
57 | VectorXs g = VectorXs::Random(ng); |
261 |
2/4✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 57 times.
✗ Branch 5 not taken.
|
57 | VectorXs h = VectorXs::Random(nh); |
262 |
4/8✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 57 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 57 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 57 times.
✗ Branch 11 not taken.
|
114 | return ActionModelLQRTpl<Scalar>(A, B, Q, R, N, G, H, f, q, r, g, h); |
263 | 57 | } | |
264 | |||
265 | template <typename Scalar> | ||
266 | 88 | void ActionModelLQRTpl<Scalar>::print(std::ostream& os) const { | |
267 | 88 | os << "ActionModelLQR {nx=" << state_->get_nx() << ", nu=" << nu_ | |
268 | 88 | << ", ng=" << ng_ << ", nh=" << nh_ << ", drift_free=" << drift_free_ | |
269 | 88 | << "}"; | |
270 | 88 | } | |
271 | |||
272 | template <typename Scalar> | ||
273 | 1736 | const typename MathBaseTpl<Scalar>::MatrixXs& ActionModelLQRTpl<Scalar>::get_A() | |
274 | const { | ||
275 | 1736 | return A_; | |
276 | } | ||
277 | |||
278 | template <typename Scalar> | ||
279 | 1736 | const typename MathBaseTpl<Scalar>::MatrixXs& ActionModelLQRTpl<Scalar>::get_B() | |
280 | const { | ||
281 | 1736 | return B_; | |
282 | } | ||
283 | |||
284 | template <typename Scalar> | ||
285 | 60 | const typename MathBaseTpl<Scalar>::VectorXs& ActionModelLQRTpl<Scalar>::get_f() | |
286 | const { | ||
287 | 60 | return f_; | |
288 | } | ||
289 | |||
290 | template <typename Scalar> | ||
291 | 1677 | const typename MathBaseTpl<Scalar>::MatrixXs& ActionModelLQRTpl<Scalar>::get_Q() | |
292 | const { | ||
293 | 1677 | return Q_; | |
294 | } | ||
295 | |||
296 | template <typename Scalar> | ||
297 | 1677 | const typename MathBaseTpl<Scalar>::MatrixXs& ActionModelLQRTpl<Scalar>::get_R() | |
298 | const { | ||
299 | 1677 | return R_; | |
300 | } | ||
301 | |||
302 | template <typename Scalar> | ||
303 | 1677 | const typename MathBaseTpl<Scalar>::MatrixXs& ActionModelLQRTpl<Scalar>::get_N() | |
304 | const { | ||
305 | 1677 | return N_; | |
306 | } | ||
307 | |||
308 | template <typename Scalar> | ||
309 | 3411 | const typename MathBaseTpl<Scalar>::MatrixXs& ActionModelLQRTpl<Scalar>::get_G() | |
310 | const { | ||
311 | 3411 | return G_; | |
312 | } | ||
313 | |||
314 | template <typename Scalar> | ||
315 | 3411 | const typename MathBaseTpl<Scalar>::MatrixXs& ActionModelLQRTpl<Scalar>::get_H() | |
316 | const { | ||
317 | 3411 | return H_; | |
318 | } | ||
319 | |||
320 | template <typename Scalar> | ||
321 | 60 | const typename MathBaseTpl<Scalar>::VectorXs& ActionModelLQRTpl<Scalar>::get_q() | |
322 | const { | ||
323 | 60 | return q_; | |
324 | } | ||
325 | |||
326 | template <typename Scalar> | ||
327 | 60 | const typename MathBaseTpl<Scalar>::VectorXs& ActionModelLQRTpl<Scalar>::get_r() | |
328 | const { | ||
329 | 60 | return r_; | |
330 | } | ||
331 | |||
332 | template <typename Scalar> | ||
333 | 59 | const typename MathBaseTpl<Scalar>::VectorXs& ActionModelLQRTpl<Scalar>::get_g() | |
334 | const { | ||
335 | 59 | return g_; | |
336 | } | ||
337 | |||
338 | template <typename Scalar> | ||
339 | 59 | const typename MathBaseTpl<Scalar>::VectorXs& ActionModelLQRTpl<Scalar>::get_h() | |
340 | const { | ||
341 | 59 | return h_; | |
342 | } | ||
343 | |||
344 | template <typename Scalar> | ||
345 | 116 | void ActionModelLQRTpl<Scalar>::set_LQR(const MatrixXs& A, const MatrixXs& B, | |
346 | const MatrixXs& Q, const MatrixXs& R, | ||
347 | const MatrixXs& N, const MatrixXs& G, | ||
348 | const MatrixXs& H, const VectorXs& f, | ||
349 | const VectorXs& q, const VectorXs& r, | ||
350 | const VectorXs& g, const VectorXs& h) { | ||
351 |
1/2✓ Branch 2 taken 116 times.
✗ Branch 3 not taken.
|
116 | const std::size_t nx = state_->get_nx(); |
352 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 116 times.
|
116 | if (static_cast<std::size_t>(A.rows()) != nx) { |
353 | ✗ | throw_pretty( | |
354 | "Invalid argument: " << "A should be a squared matrix with size " + | ||
355 | std::to_string(nx)); | ||
356 | } | ||
357 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 116 times.
|
116 | if (static_cast<std::size_t>(B.rows()) != nx) { |
358 | ✗ | throw_pretty( | |
359 | "Invalid argument: " << "B has wrong dimension (it should have " + | ||
360 | std::to_string(nx) + " rows)"); | ||
361 | } | ||
362 |
2/4✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 116 times.
|
232 | if (static_cast<std::size_t>(Q.rows()) != nx || |
363 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 116 times.
|
116 | static_cast<std::size_t>(Q.cols()) != nx) { |
364 | ✗ | throw_pretty("Invalid argument: " | |
365 | << "Q has wrong dimension (it should be " + | ||
366 | std::to_string(nx) + " x " + std::to_string(nx) + ")"); | ||
367 | } | ||
368 |
2/4✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 116 times.
|
232 | if (static_cast<std::size_t>(R.rows()) != nu_ || |
369 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 116 times.
|
116 | static_cast<std::size_t>(R.cols()) != nu_) { |
370 | ✗ | throw_pretty( | |
371 | "Invalid argument: " << "R has wrong dimension (it should be " + | ||
372 | std::to_string(nu_) + " x " + | ||
373 | std::to_string(nu_) + ")"); | ||
374 | } | ||
375 |
2/4✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 116 times.
|
232 | if (static_cast<std::size_t>(N.rows()) != nx || |
376 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 116 times.
|
116 | static_cast<std::size_t>(N.cols()) != nu_) { |
377 | ✗ | throw_pretty("Invalid argument: " | |
378 | << "N has wrong dimension (it should be " + | ||
379 | std::to_string(nx) + " x " + std::to_string(nu_) + ")"); | ||
380 | } | ||
381 |
2/4✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 116 times.
|
232 | if (static_cast<std::size_t>(G.rows()) != ng_ || |
382 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 116 times.
|
116 | static_cast<std::size_t>(G.cols()) != nx + nu_) { |
383 | ✗ | throw_pretty( | |
384 | "Invalid argument: " << "G has wrong dimension (it should be " + | ||
385 | std::to_string(ng_) + " x " + | ||
386 | std::to_string(nx + nu_) + ")"); | ||
387 | } | ||
388 |
2/4✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 116 times.
|
232 | if (static_cast<std::size_t>(H.rows()) != nh_ || |
389 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 116 times.
|
116 | static_cast<std::size_t>(H.cols()) != nx + nu_) { |
390 | ✗ | throw_pretty( | |
391 | "Invalid argument: " << "H has wrong dimension (it should be " + | ||
392 | std::to_string(nh_) + " x " + | ||
393 | std::to_string(nx + nu_) + ")"); | ||
394 | } | ||
395 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 116 times.
|
116 | if (static_cast<std::size_t>(f.size()) != nx) { |
396 | ✗ | throw_pretty( | |
397 | "Invalid argument: " << "f has wrong dimension (it should be " + | ||
398 | std::to_string(nx) + ")"); | ||
399 | } | ||
400 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 116 times.
|
116 | if (static_cast<std::size_t>(q.size()) != nx) { |
401 | ✗ | throw_pretty( | |
402 | "Invalid argument: " << "q has wrong dimension (it should be " + | ||
403 | std::to_string(nx) + ")"); | ||
404 | } | ||
405 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 116 times.
|
116 | if (static_cast<std::size_t>(r.size()) != nu_) { |
406 | ✗ | throw_pretty( | |
407 | "Invalid argument: " << "r has wrong dimension (it should be " + | ||
408 | std::to_string(nu_) + ")"); | ||
409 | } | ||
410 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 116 times.
|
116 | if (static_cast<std::size_t>(g.size()) != ng_) { |
411 | ✗ | throw_pretty( | |
412 | "Invalid argument: " << "g has wrong dimension (it should be " + | ||
413 | std::to_string(ng_) + ")"); | ||
414 | } | ||
415 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 116 times.
|
116 | if (static_cast<std::size_t>(h.size()) != nh_) { |
416 | ✗ | throw_pretty( | |
417 | "Invalid argument: " << "h has wrong dimension (it should be " + | ||
418 | std::to_string(nh_) + ")"); | ||
419 | } | ||
420 |
2/4✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 116 times.
✗ Branch 5 not taken.
|
116 | L_ = MatrixXs::Zero(nx + nu_, nx + nu_); |
421 |
5/10✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 116 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 116 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 116 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 116 times.
✗ Branch 14 not taken.
|
116 | L_ << Q, N, N.transpose(), R; |
422 |
1/2✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
|
116 | Eigen::SelfAdjointEigenSolver<MatrixXs> eig(L_); |
423 |
3/6✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 116 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 116 times.
|
232 | if (eig.info() != Eigen::Success || |
424 |
1/2✓ Branch 2 taken 116 times.
✗ Branch 3 not taken.
|
116 | eig.eigenvalues().minCoeff() < ScaleNumerics<Scalar>(-1e-9)) { |
425 | ✗ | throw_pretty("Invalid argument " | |
426 | << "[Q, N; N.T, R] is not positive semi-definite"); | ||
427 | } | ||
428 | |||
429 |
1/2✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
|
116 | A_ = A; |
430 |
1/2✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
|
116 | B_ = B; |
431 |
1/2✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
|
116 | f_ = f; |
432 |
1/2✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
|
116 | Q_ = Q; |
433 |
1/2✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
|
116 | R_ = R; |
434 |
1/2✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
|
116 | N_ = N; |
435 |
1/2✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
|
116 | G_ = G; |
436 |
1/2✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
|
116 | H_ = H; |
437 |
1/2✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
|
116 | q_ = q; |
438 |
1/2✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
|
116 | r_ = r; |
439 |
1/2✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
|
116 | g_ = g; |
440 |
1/2✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
|
116 | h_ = h; |
441 | 116 | updated_lqr_ = false; | |
442 | 116 | } | |
443 | |||
444 | } // namespace crocoddyl | ||
445 |