23#include <unsupported/Eigen/MatrixFunctions>
27template <
int D,
int Blocks,
int Extra = 0>
28inline constexpr int semidirectAugmentedDimension =
29 D == Eigen::Dynamic ? Eigen::Dynamic : Blocks * D + Extra;
31template <
int D,
int Blocks,
int Extra = 0>
32using SemidirectAugmentedMatrix =
33 Eigen::Matrix<double, semidirectAugmentedDimension<D, Blocks, Extra>,
34 semidirectAugmentedDimension<D, Blocks, Extra>>;
36template <
typename Dst,
typename Src>
37void semidirectAssignBlock(
const Src& source,
size_t row,
size_t column,
39 constexpr int rows = Src::RowsAtCompileTime;
40 constexpr int columns = Src::ColsAtCompileTime;
41 if constexpr (rows != Eigen::Dynamic && columns != Eigen::Dynamic) {
42 destination->template block<rows, columns>(row, column) = source;
44 destination->block(row, column, source.rows(), source.cols()) = source;
52template <
typename G,
typename H,
typename Action>
53typename SemidirectLieGroup<G, H, Action>::Phi1KernelResult
54SemidirectLieGroup<G, H, Action>::phi1Kernel(
const Jacobian2& A) {
55 const int r = A.rows();
56 using Augmented = SemidirectAugmentedMatrix<m, 2>;
57 Augmented M = Augmented::Zero(2 * r, 2 * r);
58 M.topLeftCorner(r, r) = A;
59 M.topRightCorner(r, r).setIdentity();
60 const Augmented expM = M.exp();
61 return {expM.topLeftCorner(r, r), expM.topRightCorner(r, r)};
64template <
typename G,
typename H,
typename Action>
66SemidirectLieGroup<G, H, Action>::phi1FrechetAction(
67 const Jacobian2& A,
const Jacobian2& B,
69 const int r = A.rows();
70 using Augmented = SemidirectAugmentedMatrix<m, 2, 1>;
71 Augmented M = Augmented::Zero(2 * r + 1, 2 * r + 1);
72 M.block(0, 0, r, r) = A;
73 M.block(0, r, r, r) = B;
74 M.block(r, r, r, r) = A;
75 M.block(r, 2 * r, r, 1) = v;
76 return M.exp().block(0, 2 * r, r, 1);
79template <
typename G,
typename H,
typename Action>
80typename SemidirectLieGroup<G, H, Action>::Jacobian
81SemidirectLieGroup<G, H, Action>::rightJacobian(
const TangentVector& xi) {
82 const int d = xi.size();
83 using Augmented = SemidirectAugmentedMatrix<dimension, 2>;
84 Augmented M = Augmented::Zero(2 * d, 2 * d);
85 M.topLeftCorner(d, d) = -adjointMap(xi);
86 M.topRightCorner(d, d).setIdentity();
87 return M.exp().topRightCorner(d, d);
90template <
typename G,
typename H,
typename Action>
93 checkMatchingDimensions(other,
"operator*");
94 const H acted = Action{}(this->first, other.second);
99template <
typename G,
typename H,
typename Action>
106template <
typename G,
typename H,
typename Action>
108 const TangentVector& xi, ChartJacobian H1, ChartJacobian H2)
const {
109 const size_t d1 = firstDim(), d2 = secondDim(), d = d1 + d2;
110 if (
static_cast<size_t>(xi.size()) != d) {
111 throw std::invalid_argument(
112 "SemidirectLieGroup::retract tangent dimension mismatch");
117 Expmap(tangentSegment<G>(xi, 0, d1), tangentSegment<H>(xi, d1, d2),
118 H2 ? DynamicJacobian(D1) : DynamicJacobian(),
119 H2 ? DynamicJacobian(D2) : DynamicJacobian());
121 if (H1) *H1 = delta.inverse().AdjointMap();
123 *H2 = zeroJacobian(d);
124 H2->leftCols(d1) = D1;
125 H2->rightCols(d2) = D2;
130template <
typename G,
typename H,
typename Action>
131typename SemidirectLieGroup<G, H, Action>::TangentVector
132SemidirectLieGroup<G, H, Action>::localCoordinates(
134 checkMatchingDimensions(other,
"localCoordinates");
137 const TangentVector xi =
138 Logmap(relative, H1 || H2 ? ChartJacobian(&Dlog) : ChartJacobian());
139 if (H1) *H1 = -Dlog * relative.inverse().AdjointMap();
144template <
typename G,
typename H,
typename Action>
146 const TangentVector& xi, ChartJacobian D) {
148 if constexpr (firstDynamic) {
150 throw std::invalid_argument(
151 "SemidirectLieGroup::Expmap tangent dimension is too small");
153 d1 =
static_cast<size_t>(xi.size() - m);
157 constexpr size_t d2 = m;
158 if (
static_cast<size_t>(xi.size()) != d1 + d2) {
159 throw std::invalid_argument(
160 "SemidirectLieGroup::Expmap tangent dimension mismatch");
165 Expmap(tangentSegment<G>(xi, 0, d1), tangentSegment<H>(xi, d1, d2),
166 D ? DynamicJacobian(D1) : DynamicJacobian(),
167 D ? DynamicJacobian(D2) : DynamicJacobian());
169 *D = zeroJacobian(d1 + d2);
170 D->leftCols(d1) = D1;
171 D->rightCols(d2) = D2;
176template <
typename G,
typename H,
typename Action>
182 const size_t d1 = u.size(), d2 = v.size(), d = d1 + d2;
183 constexpr bool hasAdjoint =
189 if constexpr (hasAdjoint) {
190 const TangentVector xi = makeTangentVector(u, v, d1, d2);
191 const Jacobian derivative = rightJacobian(xi);
192 const Jacobian2 actionJacobian = derivative.bottomRightCorner(d2, d2);
193 const H h = Action{}(g, actionJacobian * v);
194 *H1 = derivative.leftCols(d1);
195 if (H2) *H2 = derivative.rightCols(d2);
198 const Jacobian2 A = Action::generator(u);
199 const Phi1KernelResult kernels = phi1Kernel(A);
200 const auto phi0Solver = kernels.phi0.lu();
201 const H h = kernels.phi1 * v;
202 *H1 = Matrix::Zero(d, d1);
203 if constexpr (firstDynamic) {
204 H1->topRows(d1) = Dg;
206 H1->template topLeftCorner<n, n>() = Dg;
209 if constexpr (firstDynamic) ej.resize(d1);
211 for (Eigen::Index j = 0; j < static_cast<Eigen::Index>(d1); ++j) {
213 H1->col(j).tail(d2) =
214 phi0Solver.solve(phi1FrechetAction(A, Action::generator(ej), v));
218 *H2 = Matrix::Zero(d, d2);
219 H2->bottomRows(d2) = phi0Solver.solve(kernels.phi1);
225 const Jacobian2 A = Action::generator(u);
227 const Jacobian2 actionJacobian = phi1Kernel(-A).phi1;
228 const H h = Action{}(g, actionJacobian * v);
229 *H2 = Matrix::Zero(d, d2);
230 H2->bottomRows(d2) = actionJacobian;
233 return {g, phi1Kernel(A).phi1 * v};
236template <
typename G,
typename H,
typename Action>
237typename SemidirectLieGroup<G, H, Action>::TangentVector
240 const size_t d1 = p.firstDim(), d2 = p.secondDim(), d = d1 + d2;
241 constexpr bool hasAdjoint =
245 const Jacobian2 A = Action::generator(u);
248 if constexpr (hasAdjoint) {
249 const auto solver = phi1Kernel(A).phi1.lu();
251 const TangentVector xi = makeTangentVector(u, v, d1, d2);
252 *D = rightJacobian(xi).partialPivLu().solve(identityJacobian(d));
255 const Phi1KernelResult kernels = phi1Kernel(A);
256 const auto solver = kernels.phi1.lu();
258 *D = zeroJacobian(d);
259 if constexpr (firstDynamic) {
260 D->topLeftCorner(d1, d1) = Dg;
262 D->template topLeftCorner<n, n>() = Dg;
264 D->bottomRightCorner(d2, d2) = solver.solve(kernels.phi0);
265 for (Eigen::Index j = 0; j < static_cast<Eigen::Index>(d1); ++j) {
266 const Jacobian2 B = Action::generator(Dg.col(j));
267 D->col(j).tail(d2) = -solver.solve(phi1FrechetAction(A, B, v));
269 return makeTangentVector(u, v, d1, d2);
273 const Jacobian2 phi1 = phi1Kernel(A).phi1;
275 return makeTangentVector(u, v, d1, d2);
278template <
typename G,
typename H,
typename Action>
279typename SemidirectLieGroup<G, H, Action>::Jacobian
280SemidirectLieGroup<G, H, Action>::AdjointMap()
const {
281 const size_t d1 = firstDim(), d2 = secondDim(), d = d1 + d2;
284 Action{}(defaultIdentity<G>(), this->second, &Jg, {});
287 Jacobian result = zeroJacobian(d);
288 semidirectAssignBlock(AdG, 0, 0, &result);
289 semidirectAssignBlock(Jh, d1, d1, &result);
290 result.block(d1, 0, d2, d1) = -Jg * AdG;
294template <
typename G,
typename H,
typename Action>
295typename SemidirectLieGroup<G, H, Action>::Jacobian
296SemidirectLieGroup<G, H, Action>::adjointMap(
const TangentVector& xi) {
297 const size_t d = xi.size();
300 throw std::invalid_argument(
301 "SemidirectLieGroup::adjointMap tangent dimension is too small");
303 const size_t d1 = d - d2;
304 const auto u = tangentSegment<G>(xi, 0, d1);
305 const auto v = tangentSegment<H>(xi, d1, d2);
306 Jacobian result = zeroJacobian(d);
307 semidirectAssignBlock(G::adjointMap(u), 0, 0, &result);
310 if constexpr (firstDynamic) ei.resize(d1);
312 for (Eigen::Index i = 0; i < static_cast<Eigen::Index>(d1); ++i) {
314 result.block(d1, i, d2, 1) = -(Action::generator(ei) * v);
317 semidirectAssignBlock(Action::generator(u), d1, d1, &result);
321template <
typename G,
typename H,
typename Action>
323T SemidirectLieGroup<G, H, Action>::defaultIdentity() {
331template <
typename G,
typename H,
typename Action>
332template <
typename T,
int D>
334SemidirectLieGroup<G, H, Action>::tangentSegment(
const TangentVector& xi,
335 size_t start,
size_t d) {
336 if constexpr (D == Eigen::Dynamic) {
337 return xi.segment(start, d);
339 return xi.template segment<D>(start);
343template <
typename G,
typename H,
typename Action>
344typename SemidirectLieGroup<G, H, Action>::TangentVector
345SemidirectLieGroup<G, H, Action>::makeTangentVector(
348 if constexpr (dimension == Eigen::Dynamic) {
349 TangentVector xi(d1 + d2);
359template <
typename G,
typename H,
typename Action>
360typename SemidirectLieGroup<G, H, Action>::Jacobian
361SemidirectLieGroup<G, H, Action>::zeroJacobian(
size_t d) {
362 if constexpr (dimension == Eigen::Dynamic)
return Jacobian::Zero(d, d);
363 return Jacobian::Zero();
366template <
typename G,
typename H,
typename Action>
367typename SemidirectLieGroup<G, H, Action>::Jacobian
368SemidirectLieGroup<G, H, Action>::identityJacobian(
size_t d) {
369 if constexpr (dimension == Eigen::Dynamic)
return Jacobian::Identity(d, d);
370 return Jacobian::Identity();
373template <
typename G,
typename H,
typename Action>
374void SemidirectLieGroup<G, H, Action>::checkMatchingDimensions(
376 if (firstDim() != other.firstDim() || secondDim() != other.secondDim()) {
377 throw std::invalid_argument(std::string(
"SemidirectLieGroup::") +
378 operation +
" dimension mismatch");
382template <
typename G,
typename H,
typename Action>
383void SemidirectLieGroup<G, H, Action>::print(
const std::string& s)
const {
384 std::cout << s <<
"SemidirectLieGroup" << std::endl;
Global functions in a separate testing namespace.
Definition chartTesting.h:28
@ Logmap
Use the SE_2(3) NavState Logmap for every backend.
Definition PreintegrationParams.h:32
A manifold defines a space in which there is a notion of a linear tangent space that can be centered ...
Definition Group.h:37
OptionalJacobian is an Eigen::Ref like class that can take be constructed using either a fixed size o...
Definition OptionalJacobian.h:40
Detects the optional static algebra adjoint on the base group.
Definition SemidirectLieGroup.h:54
Left semidirect product G ⋉ H induced by Action.
Definition SemidirectLieGroup.h:96