aligator  0.15.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 this->G0 = std::move(other.G0);
243 this->g0 = std::move(other.g0);
244 this->stages = std::move(other.stages);
245 return *this;
246 }
247
249
251 if (stages.empty())
252 return;
253 for (uint i = 0; i <= (uint)horizon(); i++) {
254 stages[i].addParameterization(nth);
255 }
256 }
257
258 inline bool isParameterized() const {
259 return !stages.empty() && (stages[0].nth > 0);
260 }
261
262 inline bool isInitialized() const { return !stages.empty(); }
263
264 inline uint ntheta() const { return stages[0].nth; }
265
266 inline bool isApprox(const LqrProblemTpl &other) {
267 if (horizon() != other.horizon() || !G0.isApprox(other.G0) ||
268 !g0.isApprox(other.g0))
269 return false;
270 for (uint i = 0; i < uint(horizon()); i++) {
271 if (!stages[i].isApprox(other.stages[i]))
272 return false;
273 }
274 return true;
275 }
276
278 Scalar evaluate(const VectorOfVectors &xs, const VectorOfVectors &us,
279 const std::optional<ConstVectorRef> &theta_) const;
280
281 allocator_type get_allocator() const { return G0.get_allocator(); }
282
283private:
285 [[nodiscard]] bool check_allocators() const {
286 return get_allocator() == g0.get_allocator() &&
287 get_allocator() == stages.get_allocator();
288 }
289};
290
291template <typename Scalar>
293 const LqrKnotTpl<Scalar> &rhs) {
294 return (lhs.nx == rhs.nx) && (lhs.nu == rhs.nu) && (lhs.nc == rhs.nc) &&
295 (lhs.nx2 == rhs.nx2) && (lhs.nth == rhs.nth);
296}
297
298template <typename Scalar>
299std::ostream &operator<<(std::ostream &oss, const LqrKnotTpl<Scalar> &self_) {
300 auto self = self_.to_const_view();
301 oss << "LqrKnot {";
302 oss << fmt::format("\n nx: {:d}", self.nx) //
303 << fmt::format("\n nu: {:d}", self.nu) //
304 << fmt::format("\n nc: {:d}", self.nc);
305 if (self.nth > 0) {
306 oss << fmt::format("\n nth: {:d}", self.nth);
307 }
308#ifndef NDEBUG
309 oss << eigenPrintWithPreamble(self.Q, "\n Q: ") //
310 << eigenPrintWithPreamble(self.S, "\n S: ") //
311 << eigenPrintWithPreamble(self.R, "\n R: ") //
312 << eigenPrintWithPreamble(self.q, "\n q: ") //
313 << eigenPrintWithPreamble(self.r, "\n r: ");
314
315 oss << eigenPrintWithPreamble(self.A, "\n A: ") //
316 << eigenPrintWithPreamble(self.B, "\n B: ") //
317 << eigenPrintWithPreamble(self.E, "\n E: ") //
318 << eigenPrintWithPreamble(self.f, "\n f: ");
319
320 oss << eigenPrintWithPreamble(self.C, "\n C: ") //
321 << eigenPrintWithPreamble(self.D, "\n D: ") //
322 << eigenPrintWithPreamble(self.d, "\n d: ");
323 if (self.nth > 0) {
324 oss << eigenPrintWithPreamble(self.Gth, "\n Gth: ") //
325 << eigenPrintWithPreamble(self.Gx, "\n Gx: ") //
326 << eigenPrintWithPreamble(self.Gu, "\n Gu: ") //
327 << eigenPrintWithPreamble(self.gamma, "\n gamma: ");
328 }
329#endif
330 oss << "\n}";
331 return oss;
332}
333
334#ifdef ALIGATOR_ENABLE_TEMPLATE_INSTANTIATION
335extern template struct LqrKnotTpl<context::Scalar>;
336extern template struct LqrProblemTpl<context::Scalar>;
337#endif
338
339} // namespace gar
340} // 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
LqrProblemTpl & operator=(LqrProblemTpl &&other)
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