aligator  0.14.0
A primal-dual augmented Lagrangian-type solver for nonlinear trajectory optimization.
Loading...
Searching...
No Matches
lqr-problem.hpp
Go to the documentation of this file.
1
2#pragma once
3
5#include "aligator/math.hpp"
8#include "aligator/tags.hpp"
9#include <fmt/format.h>
10
11#include <optional>
12
13namespace aligator {
14namespace gar {
15
32template <typename Scalar> struct LqrKnotTpl {
34 static constexpr int Alignment = Eigen::AlignedMax;
38
44
45 MMat Q, S, R;
47 MMat A, B, E;
51
57
58 template <typename T, bool Cond>
59 using add_const_if_t = std::conditional_t<Cond, std::add_const_t<T>, T>;
60
61 template <bool IsConst> struct __view_base {
62 using mat_t = Eigen::Map<add_const_if_t<MatrixXs, IsConst>, Alignment>;
63 using vec_t = Eigen::Map<add_const_if_t<VectorXs, IsConst>, Alignment>;
69
76
79 };
80
83
88 return view_t{
89 nx,
90 nu,
91 nc,
92 nx2,
93 nth,
94 //
95 Q.to_map(),
96 S.to_map(),
97 R.to_map(),
98 q.to_map(),
99 r.to_map(),
100 //
101 A.to_map(),
102 B.to_map(),
103 E.to_map(),
104 f.to_map(),
105 //
106 C.to_map(),
107 D.to_map(),
108 d.to_map(),
109 //
110 Gth.to_map(),
111 Gx.to_map(),
112 Gu.to_map(),
113 Gv.to_map(),
114 gamma.to_map(),
115 };
116 }
117
120 return const_view_t{
121 nx,
122 nu,
123 nc,
124 nx2,
125 nth,
126 //
127 Q.to_const_map(),
128 S.to_const_map(),
129 R.to_const_map(),
130 q.to_const_map(),
131 r.to_const_map(),
132 //
133 A.to_const_map(),
134 B.to_const_map(),
135 E.to_const_map(),
136 f.to_const_map(),
137 //
138 C.to_const_map(),
139 D.to_const_map(),
140 d.to_const_map(),
141 //
142 Gth.to_const_map(),
143 Gx.to_const_map(),
144 Gu.to_const_map(),
145 Gv.to_const_map(),
146 gamma.to_const_map(),
147 };
148 }
149
150 const_view_t to_view() const { return to_const_view(); }
151
152 operator view_t() { return to_view(); }
153 operator const_view_t() const { return to_const_view(); }
154
156 allocator_type alloc = {});
157
160 : LqrKnotTpl(nx, nu, nc, nx2, 0, alloc) {}
161
164 : LqrKnotTpl(nx, nu, nc, nx, 0, alloc) {}
165
167 LqrKnotTpl(const LqrKnotTpl &other, allocator_type alloc = {});
175
177
179 void assign(const LqrKnotTpl<Scalar> &other);
180
181 // reallocates entire buffer for contigousness
183
184 bool isApprox(const LqrKnotTpl &other,
185 Scalar prec = std::numeric_limits<Scalar>::epsilon()) const;
186
187 friend bool operator==(const LqrKnotTpl &lhs, const LqrKnotTpl &rhs) {
188 return lhs.isApprox(rhs);
189 }
190
191 allocator_type get_allocator() const { return m_allocator; }
192
193private:
194 explicit LqrKnotTpl(no_alloc_t, allocator_type alloc = {});
195 allocator_type m_allocator;
196};
197
198template <typename Scalar> struct LqrProblemTpl {
200 static constexpr int Alignment = Eigen::AlignedMax;
202 using KnotVector = std::pmr::vector<KnotType>;
209
210 inline int horizon() const noexcept { return (int)stages.size() - 1; }
212 inline uint nc0() const noexcept { return (uint)g0.rows(); }
213
214 explicit LqrProblemTpl(allocator_type alloc = {})
215 : G0(alloc)
216 , g0(alloc)
217 , stages(alloc) {
218 assert(check_allocators());
219 }
220
222 LqrProblemTpl(const KnotVector &knots, long nc0, allocator_type alloc = {});
226
229 : LqrProblemTpl(other.stages, other.nc0(), alloc) {
230 this->G0 = other.G0;
231 this->g0 = other.g0;
232 }
233
236 : LqrProblemTpl(std::move(other.stages), other.nc0()) {
237 this->G0 = other.G0;
238 this->g0 = other.g0;
239 }
240
242
244 if (stages.empty())
245 return;
246 for (uint i = 0; i <= (uint)horizon(); i++) {
247 stages[i].addParameterization(nth);
248 }
249 }
250
251 inline bool isParameterized() const {
252 return !stages.empty() && (stages[0].nth > 0);
253 }
254
255 inline bool isInitialized() const { return !stages.empty() && !m_is_invalid; }
256
257 inline uint ntheta() const { return stages[0].nth; }
258
259 inline bool isApprox(const LqrProblemTpl &other) {
260 if (horizon() != other.horizon() || !G0.isApprox(other.G0) ||
261 !g0.isApprox(other.g0))
262 return false;
263 for (uint i = 0; i < uint(horizon()); i++) {
264 if (!stages[i].isApprox(other.stages[i]))
265 return false;
266 }
267 return true;
268 }
269
271 Scalar evaluate(const VectorOfVectors &xs, const VectorOfVectors &us,
272 const std::optional<ConstVectorRef> &theta_) const;
273
274 allocator_type get_allocator() const { return G0.get_allocator(); }
275
276private:
278 bool m_is_invalid{true};
280 [[nodiscard]] bool check_allocators() const {
281 return get_allocator() == g0.get_allocator() &&
282 get_allocator() == stages.get_allocator();
283 }
284};
285
286template <typename Scalar>
288 const LqrKnotTpl<Scalar> &rhs) {
289 return (lhs.nx == rhs.nx) && (lhs.nu == rhs.nu) && (lhs.nc == rhs.nc) &&
290 (lhs.nx2 == rhs.nx2) && (lhs.nth == rhs.nth);
291}
292
293template <typename Scalar>
294std::ostream &operator<<(std::ostream &oss, const LqrKnotTpl<Scalar> &self_) {
295 auto self = self_.to_const_view();
296 oss << "LqrKnot {";
297 oss << fmt::format("\n nx: {:d}", self.nx) //
298 << fmt::format("\n nu: {:d}", self.nu) //
299 << fmt::format("\n nc: {:d}", self.nc);
300 if (self.nth > 0) {
301 oss << fmt::format("\n nth: {:d}", self.nth);
302 }
303#ifndef NDEBUG
304 oss << eigenPrintWithPreamble(self.Q, "\n Q: ") //
305 << eigenPrintWithPreamble(self.S, "\n S: ") //
306 << eigenPrintWithPreamble(self.R, "\n R: ") //
307 << eigenPrintWithPreamble(self.q, "\n q: ") //
308 << eigenPrintWithPreamble(self.r, "\n r: ");
309
310 oss << eigenPrintWithPreamble(self.A, "\n A: ") //
311 << eigenPrintWithPreamble(self.B, "\n B: ") //
312 << eigenPrintWithPreamble(self.E, "\n E: ") //
313 << eigenPrintWithPreamble(self.f, "\n f: ");
314
315 oss << eigenPrintWithPreamble(self.C, "\n C: ") //
316 << eigenPrintWithPreamble(self.D, "\n D: ") //
317 << eigenPrintWithPreamble(self.d, "\n d: ");
318 if (self.nth > 0) {
319 oss << eigenPrintWithPreamble(self.Gth, "\n Gth: ") //
320 << eigenPrintWithPreamble(self.Gx, "\n Gx: ") //
321 << eigenPrintWithPreamble(self.Gu, "\n Gu: ") //
322 << eigenPrintWithPreamble(self.gamma, "\n gamma: ");
323 }
324#endif
325 oss << "\n}";
326 return oss;
327}
328
329#ifdef ALIGATOR_ENABLE_TEMPLATE_INSTANTIATION
330extern template struct LqrKnotTpl<context::Scalar>;
331extern template struct LqrProblemTpl<context::Scalar>;
332#endif
333
334} // namespace gar
335} // namespace aligator
Thin wrapper around Eigen::Map representing a matrix object with memory managed by a C++17 polymorphi...
allocator_type get_allocator() const noexcept
Accessor to retrieve the allocator used for this matrix.
A convenience subclass of std::pmr::polymorphic_allocator for bytes.
Definition allocator.hpp:17
Math utilities.
unsigned int uint
Definition work.hpp:8
std::ostream & operator<<(std::ostream &oss, const LqrKnotTpl< Scalar > &self_)
bool lqrKnotsSameDim(const LqrKnotTpl< Scalar > &lhs, const LqrKnotTpl< Scalar > &rhs)
Main package namespace.
auto eigenPrintWithPreamble(const Eigen::EigenBase< D > &mat, const std::string &text, Eigen::IOFormat ft=EIGEN_DEFAULT_IO_FORMAT)
Definition math.hpp:109
Eigen::Map< add_const_if_t< MatrixXs, IsConst >, Alignment > mat_t
Eigen::Map< add_const_if_t< VectorXs, IsConst >, Alignment > vec_t
Struct describing a stage of a constrained LQ problem.
ManagedMatrix< Scalar, Eigen::Dynamic, 1 > MVec
allocator_type get_allocator() const
void assign(const LqrKnotTpl< Scalar > &other)
Assign matrices (and dimensions) from another LqrKnotTpl.
ManagedMatrix< Scalar, Eigen::Dynamic, Eigen::Dynamic > MMat
LqrKnotTpl(uint nx, uint nu, uint nc, uint nx2, uint nth, allocator_type alloc={})
friend bool operator==(const LqrKnotTpl &lhs, const LqrKnotTpl &rhs)
LqrKnotTpl(LqrKnotTpl &&other)
Move constructor. Allocator will be moved from other. Other will be have m_empty_after_move set to tr...
LqrKnotTpl(uint nx, uint nu, uint nc, allocator_type alloc={})
Delegating constructor, assumes nx2 = nx, and nth = 0.
__view_base< true > const_view_t
bool isApprox(const LqrKnotTpl &other, Scalar prec=std::numeric_limits< Scalar >::epsilon()) const
LqrKnotTpl & operator=(LqrKnotTpl &&)
Move assignment. Other allocator will be stolen.
std::conditional_t< Cond, std::add_const_t< T >, T > add_const_if_t
LqrKnotTpl & addParameterization(uint nth)
LqrKnotTpl(const LqrKnotTpl &other, allocator_type alloc={})
Copy constructor. Allocator must be given.
polymorphic_allocator allocator_type
const_view_t to_const_view() const
Convert knot to an aggregate of Eigen::Map to const.
const_view_t to_view() const
LqrKnotTpl & operator=(const LqrKnotTpl &other)
Copy assignment. Current allocator will be reused if required.
__view_base< false > view_t
view_t to_view()
Convert knot to an aggregate of Eigen::Map.
LqrKnotTpl(uint nx, uint nu, uint nc, uint nx2, allocator_type alloc={})
Delegating constructor, assumes nth = 0.
LqrProblemTpl(const LqrProblemTpl &other, allocator_type alloc={})
Copy constructor. Will copy the allocator from other.
std::pmr::vector< KnotType > KnotVector
allocator_type get_allocator() const
LqrProblemTpl(allocator_type alloc={})
ManagedMatrix< Scalar, Eigen::Dynamic, Eigen::Dynamic > MMat
LqrKnotTpl< Scalar > KnotType
Scalar evaluate(const VectorOfVectors &xs, const VectorOfVectors &us, const std::optional< ConstVectorRef > &theta_) const
Evaluate the quadratic objective.
polymorphic_allocator allocator_type
LqrProblemTpl(const KnotVector &knots, long nc0, allocator_type alloc={})
This constructor will take the knots as-is.
LqrProblemTpl(LqrProblemTpl &&other)
Move constructor - we steal the allocator from the source object.
int horizon() const noexcept
uint nc0() const noexcept
Dimension of the initial condition constraint.
ManagedMatrix< Scalar, Eigen::Dynamic, 1 > MVec
bool isApprox(const LqrProblemTpl &other)
LqrProblemTpl(KnotVector &&knots, long nc0)
This constructor will take the knots as-is, copying their specified allocator.
Tag type for e.g. non-allocating constructors.
Definition tags.hpp:7