smooth_feedback
Control and estimation on Lie groups
Loading...
Searching...
No Matches
ocp.hpp
Go to the documentation of this file.
1// Copyright (C) 2022 Petter Nilsson. MIT License.
2
3#pragma once
4
10#include <iostream>
11
12#include <Eigen/Core>
13#include <smooth/concepts/lie_group.hpp>
14#include <smooth/diff.hpp>
15
16#include "traits.hpp"
17
18namespace smooth::feedback {
19
20// \cond
21// Forward declaration
22template<LieGroup _X, Manifold _U, int _Nq, int _Ncr, int _Nce>
23struct OCPSolution;
24// \endcond
25
50template<LieGroup _X, Manifold _U, typename Theta, typename F, typename G, typename CR, typename CE>
51struct OCP
52{
54 using X = _X;
56 using U = _U;
57
59 static constexpr int Nx = Dof<X>;
61 static constexpr int Nu = Dof<U>;
63 static constexpr int Nq = std::invoke_result_t<G, double, X, U>::SizeAtCompileTime;
65 static constexpr int Ncr = std::invoke_result_t<CR, double, X, U>::SizeAtCompileTime;
67 static constexpr int Nce = std::invoke_result_t<CE, double, X, X, Eigen::Matrix<double, Nq, 1>>::SizeAtCompileTime;
68
71
72 static_assert(Nx > 0, "Static size required");
73 static_assert(Nu > 0, "Static size required");
74 static_assert(Nq > 0, "Static size required");
75 static_assert(Ncr > 0, "Static size required");
76 static_assert(Nce > 0, "Static size required");
77
79 Theta theta;
80
82 F f;
84 G g;
85
87 CR cr;
89 Eigen::Vector<double, Ncr> crl = Eigen::Vector<double, Ncr>::Zero();
91 Eigen::Vector<double, Ncr> cru = Eigen::Vector<double, Ncr>::Zero();
92
94 CE ce;
96 Eigen::Vector<double, Nce> cel = Eigen::Vector<double, Nce>::Zero();
98 Eigen::Vector<double, Nce> ceu = Eigen::Vector<double, Nce>::Zero();
99};
100
102template<typename T>
103concept OCPType = traits::is_specialization_of_v<std::decay_t<T>, OCP>;
104
106template<typename T>
107concept FlatOCPType =
108 OCPType<T> &&(smooth::RnType<typename std::decay_t<T>::X> && smooth::RnType<typename std::decay_t<T>::U>);
109
113template<LieGroup _X, Manifold _U, int _Nq, int _Ncr, int _Nce>
115{
117 using X = _X;
119 using U = _U;
120
122 static constexpr int Nq = _Nq;
124 static constexpr int Ncr = _Ncr;
126 static constexpr int Nce = _Nce;
127
130 double t0, tf;
131 //}@
132
134 Eigen::Vector<double, Nq> Q{};
135
138 std::function<U(double)> u;
139 std::function<X(double)> x;
140 //}@
141
143 Eigen::Vector<double, Nq> lambda_q{};
144
146 Eigen::Vector<double, Nce> lambda_ce{};
147
149 std::function<Eigen::Vector<double, Dof<X>>(double)> lambda_dyn{};
150
152 std::function<Eigen::Vector<double, Ncr>(double)> lambda_cr{};
153};
154
165template<diff::Type DT = diff::Type::Numerical>
166bool test_ocp_derivatives(OCPType auto & ocp, uint32_t num_trials = 1, double eps = 1e-4)
167{
168 using OCP = std::decay_t<decltype(ocp)>;
169
170 using X = typename OCP::X;
171 using U = typename OCP::U;
172 using Q = Eigen::Vector<double, OCP::Nq>;
173
174 if (!diff::detail::diffable_order1<decltype(ocp.theta), std::tuple<double, X, X, Q>>) {
175 std::cout << "no jacobian for theta\n";
176 }
177 if (!diff::detail::diffable_order2<decltype(ocp.theta), std::tuple<double, X, X, Q>>) {
178 std::cout << "no hessian for theta\n";
179 }
180 if (!diff::detail::diffable_order1<decltype(ocp.f), std::tuple<double, X, U>>) { std::cout << "no jacobian for f\n"; }
181 if (!diff::detail::diffable_order2<decltype(ocp.f), std::tuple<double, X, U>>) { std::cout << "no hessian for f\n"; }
182 if (!diff::detail::diffable_order1<decltype(ocp.g), std::tuple<double, X, U>>) { std::cout << "no jacobian for g\n"; }
183 if (!diff::detail::diffable_order2<decltype(ocp.g), std::tuple<double, X, U>>) { std::cout << "no hessian for g\n"; }
184 if (!diff::detail::diffable_order1<decltype(ocp.cr), std::tuple<double, X, U>>) {
185 std::cout << "no jacobian for cr\n";
186 }
187 if (!diff::detail::diffable_order2<decltype(ocp.cr), std::tuple<double, X, U>>) {
188 std::cout << "no hessian for cr\n";
189 }
190 if (!diff::detail::diffable_order1<decltype(ocp.ce), std::tuple<double, X, X, Q>>) {
191 std::cout << "no jacobian for ce\n";
192 }
193 if (!diff::detail::diffable_order2<decltype(ocp.ce), std::tuple<double, X, X, Q>>) {
194 std::cout << "no hessian for ce\n";
195 }
196
197 const auto cmp = [&eps](const auto & m1, const auto & m2) {
198 return (
199 // clang-format off
200 (m1.cols() == m2.cols())
201 && (m1.rows() == m2.rows())
202 && (
203 m1.isApprox(m2, 1e-4) ||
204 Eigen::MatrixXd(m1 - m2).cwiseAbs().maxCoeff() < eps
205 )
206 // clang-format on
207 );
208 };
209
210 bool success = true;
211
212 for (auto trial = 0u; trial < num_trials; ++trial) {
213 // endpt parameters
214 const double tf = 1 + static_cast<double>(std::rand()) / RAND_MAX;
215 const X x0 = Random<X>();
216 const X xf = Random<X>();
217 const Eigen::Vector<double, OCP::Nq> q = Eigen::Vector<double, OCP::Nq>::Random();
218 const double t = 1 + static_cast<double>(std::rand()) / RAND_MAX;
219 const X x = Random<X>();
220 const U u = Random<U>();
221
222 // theta
223 if constexpr (diff::detail::diffable_order1<decltype(ocp.theta), std::tuple<double, X, X, Q>>) {
224 const auto [f_def, df_def] = diff::dr<1, diff::Type::Analytic>(ocp.theta, wrt(tf, x0, xf, q));
225 const auto [f_num, df_num] = diff::dr<1, DT>(ocp.theta, wrt(tf, x0, xf, q));
226
227 if (!cmp(df_def, df_num)) {
228 std::cout << "Error in 1st derivative of theta: got\n"
229 << Eigen::MatrixXd(df_def) << "\nbut expected\n"
230 << Eigen::MatrixXd(df_num) << '\n';
231 success = false;
232 };
233 }
234 if constexpr (diff::detail::diffable_order2<decltype(ocp.theta), std::tuple<double, X, X, Q>>) {
235 const auto [f_def, df_def, d2f_def] = diff::dr<2, diff::Type::Analytic>(ocp.theta, wrt(tf, x0, xf, q));
236 const auto [f_num, df_num, d2f_num] = diff::dr<2, DT>(ocp.theta, wrt(tf, x0, xf, q));
237
238 if (!cmp(d2f_def, d2f_num)) {
239 std::cout << "Error in 2nd derivative of theta: got\n"
240 << Eigen::MatrixXd(d2f_def) << "\nbut expected\n"
241 << Eigen::MatrixXd(d2f_num) << '\n';
242 success = false;
243 };
244 }
245
246 // end constraints
247 if constexpr (diff::detail::diffable_order1<decltype(ocp.ce), std::tuple<double, X, X, Q>>) {
248 const auto [f_def, df_def] = diff::dr<1, diff::Type::Analytic>(ocp.ce, wrt(tf, x0, xf, q));
249 const auto [f_num, df_num] = diff::dr<1, DT>(ocp.ce, wrt(tf, x0, xf, q));
250
251 if (!cmp(df_def, df_num)) {
252 std::cout << "Error in 1st derivative of ce: got\n"
253 << Eigen::MatrixXd(df_def) << "\nbut expected\n"
254 << Eigen::MatrixXd(df_num) << '\n';
255 success = false;
256 };
257 }
258 if constexpr (diff::detail::diffable_order2<decltype(ocp.ce), std::tuple<double, X, X, Q>>) {
259 const auto [f_def, df_def, d2f_def] = diff::dr<2, diff::Type::Analytic>(ocp.ce, wrt(tf, x0, xf, q));
260 const auto [f_num, df_num, d2f_num] = diff::dr<2, DT>(ocp.ce, wrt(tf, x0, xf, q));
261
262 if (!cmp(d2f_def, d2f_num)) {
263 std::cout << "Error in 2nd derivative of ce: got\n"
264 << Eigen::MatrixXd(d2f_def) << "\nbut expected\n"
265 << Eigen::MatrixXd(d2f_num) << '\n';
266 success = false;
267 };
268 }
269
270 // dynamics
271 if constexpr (diff::detail::diffable_order1<decltype(ocp.f), std::tuple<double, X, U>>) {
272 const auto [f_def, df_def] = diff::dr<1, diff::Type::Analytic>(ocp.f, wrt(t, x, u));
273 const auto [f_num, df_num] = diff::dr<1, DT>(ocp.f, wrt(t, x, u));
274 if (!cmp(df_def, df_num)) {
275 std::cout << "Error in 1st derivative of f: got\n"
276 << Eigen::MatrixXd(df_def) << "\nbut expected\n"
277 << Eigen::MatrixXd(df_num) << '\n';
278 success = false;
279 };
280 }
281 if constexpr (diff::detail::diffable_order2<decltype(ocp.f), std::tuple<double, X, U>>) {
282 const auto [f_def, df_def, d2f_def] = diff::dr<2, diff::Type::Analytic>(ocp.f, wrt(t, x, u));
283 const auto [f_num, df_num, d2f_num] = diff::dr<2, DT>(ocp.f, wrt(t, x, u));
284 if (!cmp(d2f_def, d2f_num)) {
285 std::cout << "Error in 2nd derivative of f: got\n"
286 << Eigen::MatrixXd(d2f_def) << "\nbut expected\n"
287 << Eigen::MatrixXd(d2f_num) << '\n';
288 success = false;
289 };
290 }
291
292 // integrand
293 if constexpr (diff::detail::diffable_order1<decltype(ocp.g), std::tuple<double, X, U>>) {
294 const auto [f_def, df_def] = diff::dr<1, diff::Type::Analytic>(ocp.g, wrt(t, x, u));
295 const auto [f_num, df_num] = diff::dr<1, DT>(ocp.g, wrt(t, x, u));
296 if (!cmp(df_def, df_num)) {
297 std::cout << "Error in 1st derivative of g: got\n"
298 << Eigen::MatrixXd(df_def) << "\nbut expected\n"
299 << Eigen::MatrixXd(df_num) << '\n';
300 success = false;
301 };
302 }
303 if constexpr (diff::detail::diffable_order2<decltype(ocp.g), std::tuple<double, X, U>>) {
304 const auto [f_def, df_def, d2f_def] = diff::dr<2, diff::Type::Analytic>(ocp.g, wrt(t, x, u));
305 const auto [f_num, df_num, d2f_num] = diff::dr<2, DT>(ocp.g, wrt(t, x, u));
306 if (!cmp(d2f_def, d2f_num)) {
307 std::cout << "Error in 2nd derivative of g: got\n"
308 << Eigen::MatrixXd(d2f_def) << "\nbut expected\n"
309 << Eigen::MatrixXd(d2f_num) << '\n';
310 success = false;
311 };
312 }
313
314 // running constraints
315 if constexpr (diff::detail::diffable_order1<decltype(ocp.cr), std::tuple<double, X, U>>) {
316 const auto [f_def, df_def] = diff::dr<1, diff::Type::Analytic>(ocp.cr, wrt(t, x, u));
317 const auto [f_num, df_num] = diff::dr<1, DT>(ocp.cr, wrt(t, x, u));
318 if (!cmp(df_def, df_num)) {
319 std::cout << "Error in 1st derivative of cr: got\n"
320 << Eigen::MatrixXd(df_def) << "\nbut expected\n"
321 << Eigen::MatrixXd(df_num) << '\n';
322 success = false;
323 };
324 }
325 if constexpr (diff::detail::diffable_order2<decltype(ocp.cr), std::tuple<double, X, U>>) {
326 const auto [f_def, df_def, d2f_def] = diff::dr<2, diff::Type::Analytic>(ocp.cr, wrt(t, x, u));
327 const auto [f_num, df_num, d2f_num] = diff::dr<2, DT>(ocp.cr, wrt(t, x, u));
328 if (!cmp(d2f_def, d2f_num)) {
329 std::cout << "Error in 2nd derivative of cr: got\n"
330 << Eigen::MatrixXd(d2f_def) << "\nbut expected\n"
331 << Eigen::MatrixXd(d2f_num) << '\n';
332 success = false;
333 };
334 }
335 }
336
337 return success;
338}
339
340} // namespace smooth::feedback
Concept that is true for FlatOCP specializations.
Definition: ocp.hpp:107
Concept that is true for OCP specializations.
Definition: ocp.hpp:103
bool test_ocp_derivatives(OCPType auto &ocp, uint32_t num_trials=1, double eps=1e-4)
Test analytic derivatives for an OCP problem.
Definition: ocp.hpp:166
Solution to OCP.
Definition: ocp.hpp:115
static constexpr int Nq
Number of integrals.
Definition: ocp.hpp:122
static constexpr int Ncr
Number of running constraints.
Definition: ocp.hpp:124
std::function< Eigen::Vector< double, Dof< X > >(double)> lambda_dyn
Multipliers for dynamics equality constraint.
Definition: ocp.hpp:149
double tf
Initial and final time.
Definition: ocp.hpp:130
std::function< Eigen::Vector< double, Ncr >(double)> lambda_cr
Multipliers for active running constraints.
Definition: ocp.hpp:152
static constexpr int Nce
Number of end constraints.
Definition: ocp.hpp:126
double t0
Initial and final time.
Definition: ocp.hpp:130
std::function< X(double)> x
Initial and final time.
Definition: ocp.hpp:139
std::function< U(double)> u
Callable functions for state and input.
Definition: ocp.hpp:138
Eigen::Vector< double, Nce > lambda_ce
Multipliers for endpoint constraints.
Definition: ocp.hpp:146
Eigen::Vector< double, Nq > lambda_q
Multipliers for integral constraints.
Definition: ocp.hpp:143
Eigen::Vector< double, Nq > Q
Integral values.
Definition: ocp.hpp:134
Optimal control problem definition.
Definition: ocp.hpp:52
F f
System dynamics .
Definition: ocp.hpp:82
static constexpr int Nu
Input space dimension.
Definition: ocp.hpp:61
static constexpr int Nx
State space dimension.
Definition: ocp.hpp:59
static constexpr int Nq
Number of integrals.
Definition: ocp.hpp:63
static constexpr int Ncr
Number of running constraints.
Definition: ocp.hpp:65
Eigen::Vector< double, Ncr > cru
Running constraint upper bound .
Definition: ocp.hpp:91
_X X
State space.
Definition: ocp.hpp:54
Theta theta
Objective function .
Definition: ocp.hpp:79
Eigen::Vector< double, Nce > ceu
End constraint upper bound .
Definition: ocp.hpp:98
static constexpr int Nce
Number of end constraints.
Definition: ocp.hpp:67
CR cr
Running constraint .
Definition: ocp.hpp:87
CE ce
End constraint .
Definition: ocp.hpp:94
Eigen::Vector< double, Nce > cel
End constraint lower bound .
Definition: ocp.hpp:96
_U U
Input space.
Definition: ocp.hpp:56
G g
Integrals .
Definition: ocp.hpp:84
Eigen::Vector< double, Ncr > crl
Running constraint lower bound .
Definition: ocp.hpp:89