15 #include <unsupported/Eigen/MatrixFunctions>
20 template <concepts::LieGroup TGroup>
24 using Scalar =
typename Group::Scalar;
26 static int constexpr
kDof = Group::kDof;
47 if (Group::kIsOriginPreserving) {
55 size_t num_preserves = 0;
61 if ((g * o).norm() < kEpsilon<Scalar>) {
66 float percentage = float(num_preserves) / float(num);
70 if (Group::kIsAxisDirectionPreserving) {
83 size_t num_preserves = 0;
94 if (((g * e).params() - e.params()).norm() < kEpsilon<Scalar>) {
100 float percentage = float(num_preserves) / float(num);
104 if (Group::kIsDirectionVectorPreserving) {
110 if (p.norm() < kEpsilon<Scalar>) {
119 size_t num_preserves = 0;
126 if (p.norm() < kEpsilon<Scalar>) {
131 if (((g * d).params() - d.params()).norm() < kEpsilon<Scalar>) {
137 float percentage = float(num_preserves) / float(num);
142 static auto expTests(std::string group_name) ->
void {
145 auto matrix_before = g.compactMatrix();
146 auto matrix_after = Group::exp(g.log()).compactMatrix();
151 kEpsilonSqrt<Scalar>,
152 "`exp(log(g)) == g` Test for {}\n"
160 Group exp_inverse = Group::exp(tangent).inverse();
161 Group exp_neg_tangent = Group::exp(-tangent);
164 exp_inverse.compactMatrix(),
165 exp_neg_tangent.compactMatrix(),
167 "`exp(-t) == inv(exp(t))` Test for {}\n"
168 "Group::exp(tangent): \n{}\ntangent #{} {}",
170 Group::exp(tangent).compactMatrix(),
177 Matrix exp_x = Group::exp(omega).matrix();
178 Matrix expmap_hat_x = (Group::hat(omega)).exp();
180 exp_x, expmap_hat_x, 0.003,
"expmap(hat(x)) - exp(x) case: %", i);
188 Eigen::Matrix<Scalar, Group::kDof, Group::kDof> mat_adj = g.adj();
192 Tangent mat_adj_x = mat_adj * x;
194 Group::vee(mat * Group::hat(x) * g.inverse().matrix());
198 10 * kEpsilonSqrt<Scalar>,
199 "`Adj * x == vee(g * hat(x) * inv(g))` Test for {}\n"
201 "tangent # {} ({})\n"
202 "params # {} ({}); matrix:\n"
209 g.params().transpose(),
222 Eigen::Matrix<Scalar, kDof, kDof> ad_a = Group::ad(a);
224 Tangent lie_bracket_a_b = Group::vee(
225 Group::hat(a) * Group::hat(b) - Group::hat(b) * Group::hat(a));
229 10 * kEpsilonSqrt<Scalar>,
230 "`Ad_A vee(B) == vee([A, B])` Test for {}\n"
241 if constexpr (
kDof > 0) {
242 Eigen::Matrix<Scalar, kDof, kDof>
const num_diff_ad_a =
243 vectorFieldNumDiff<Scalar, kDof, kDof>(
246 Group::hat(a) * Group::hat(x) -
247 Group::hat(x) * Group::hat(a));
254 10 * kEpsilonSqrt<Scalar>,
255 "`Ad_A == d/dx [a, x]` Test for {}\n");
261 static auto hatTests(std::string group_name) ->
void {
266 Group::vee(Group::hat(tangent)),
267 kEpsilonSqrt<Scalar>,
268 "`t = vee(hat(t))` Test for {}, tangent #{}: {}",
271 tangent.transpose());
283 Group left_hugging = (g1 * g2) * g3;
284 Group right_hugging = g1 * (g2 * g3);
286 left_hugging.compactMatrix(),
287 right_hugging.compactMatrix(),
288 10.0 * kEpsilonSqrt<Scalar>,
289 "`(g1*g2)*g3 == g1*(g2*g3)` Test for {}, #{}/#{}/#{}",
303 Group daz_from_foo_transform_1 =
304 bar_from_daz_transform.inverse() * foo_from_bar_transform.inverse();
305 Group daz_from_foo_transform_2 =
306 (foo_from_bar_transform * bar_from_daz_transform).inverse();
309 daz_from_foo_transform_1.compactMatrix(),
310 daz_from_foo_transform_2.compactMatrix(),
311 10 * kEpsilonSqrt<Scalar>,
312 "`ing(g2) * inv(g1) == inv(g1 *g2)` Test for {}, #{}/#{}",
321 for (
size_t point_id = 0; point_id <
kPointExamples.size(); ++point_id) {
325 Point out_point_from_matrix =
326 g.compactMatrix() * Group::toAmbient(point_in);
327 Point out_point_from_action = g * point_in;
330 out_point_from_matrix,
331 out_point_from_action,
332 kEpsilonSqrt<Scalar>,
333 "`g.matrix() * point == g * point`: {}\n"
335 "params # {} ({}); matrix:\n"
339 point_in.transpose(),
341 g.params().transpose(),
344 Point in_point_through_inverse = g.inverse() * out_point_from_matrix;
347 in_point_through_inverse,
348 10.0 * kEpsilonSqrt<Scalar>,
349 "`inv(g) * (g * point) == point` Test for {}\n"
351 "params # {} ({}); matrix:\n"
355 point_in.transpose(),
357 g.params().transpose(),
364 if constexpr (
kDof == 0) {
387 Eigen::Matrix<Scalar, kNumParams, kDof> j = Group::dxExpXAt0();
388 Eigen::Matrix<Scalar, kNumParams, kDof> j_num =
389 vectorFieldNumDiff<Scalar, kNumParams, kDof>(
391 Params p = Group::exp(x).params();
398 10.0 * kEpsilonSqrt<Scalar>,
399 "`dx exp(x)|x=0` Test {}",
402 for (
size_t point_id = 0; point_id <
kPointExamples.size(); ++point_id) {
404 Eigen::Matrix<Scalar, kPointDim, kDof> j =
405 Group::dxExpXTimesPointAt0(point_in);
408 Eigen::Matrix<Scalar, kPointDim, kDof>
const j_num =
409 vectorFieldNumDiff<Scalar, kPointDim, kDof>(
411 return Group::exp(x) * point_in;
418 10.0 * kEpsilonSqrt<Scalar>,
419 "expJacobiansTest #1: {}",
428 Eigen::Matrix<Scalar, kNumParams, kDof> j = g.dxThisMulExpXAt0();
429 Eigen::Matrix<Scalar, kNumParams, kDof> j_num =
430 vectorFieldNumDiff<Scalar, kNumParams, kDof>(
432 return (g * Group::exp(x)).params();
439 10.0 * kEpsilonSqrt<Scalar>,
440 "expJacobiansTest #2: {}",
447 Eigen::Matrix<Scalar, kDof, kDof> j =
448 g.dxLogThisInvTimesXAtThis() * g.dxThisMulExpXAt0();
449 Eigen::Matrix<Scalar, kDof, kDof> j_exp =
450 Eigen::Matrix<Scalar, kDof, kDof>::Identity();
455 10.0 * kEpsilonSqrt<Scalar>,
456 "expJacobiansTest #3: {}",
475 template <concepts::LieGroup TGroup>
476 decltype(TGroup::elementExamples())
477 const LieGroupPropTestSuite<TGroup>::kElementExamples =
478 TGroup::elementExamples();
480 template <concepts::
LieGroup TGroup>
481 decltype(TGroup::tangentExamples())
482 const LieGroupPropTestSuite<TGroup>::kTangentExamples =
483 TGroup::tangentExamples();
485 template <concepts::
LieGroup TGroup>
486 decltype(
pointExamples<typename TGroup::Scalar, TGroup::kPointDim>())
487 const LieGroupPropTestSuite<TGroup>::kPointExamples =