GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: unittest/liegroups.cpp Lines: 384 386 99.5 %
Date: 2024-01-23 21:41:47 Branches: 1484 2899 51.2 %

Line Branch Exec Source
1
// Copyright (c) 2017-2020, CNRS INRIA
2
// Authors: Joseph Mirabel (joseph.mirabel@laas.fr)
3
//
4
5
#include "pinocchio/multibody/liegroup/liegroup.hpp"
6
#include "pinocchio/multibody/liegroup/liegroup-collection.hpp"
7
#include "pinocchio/multibody/liegroup/liegroup-generic.hpp"
8
#include "pinocchio/multibody/liegroup/cartesian-product-variant.hpp"
9
10
#include "pinocchio/multibody/joint/joint-generic.hpp"
11
12
#include <boost/test/unit_test.hpp>
13
#include <boost/utility/binary.hpp>
14
#include <boost/algorithm/string.hpp>
15
#include <boost/mpl/vector.hpp>
16
17
#define EIGEN_VECTOR_IS_APPROX(Va, Vb, precision)                              \
18
  BOOST_CHECK_MESSAGE((Va).isApprox(Vb, precision),                            \
19
      "check " #Va ".isApprox(" #Vb ") failed "                                \
20
      "[\n" << (Va).transpose() << "\n!=\n" << (Vb).transpose() << "\n]")
21
#define EIGEN_MATRIX_IS_APPROX(Va, Vb, precision)                              \
22
  BOOST_CHECK_MESSAGE((Va).isApprox(Vb, precision),                            \
23
      "check " #Va ".isApprox(" #Vb ") failed "                                \
24
      "[\n" << (Va) << "\n!=\n" << (Vb) << "\n]")
25
26
using namespace pinocchio;
27
28
#define VERBOSE false
29
#define IFVERBOSE if(VERBOSE)
30
31
namespace pinocchio {
32
template<typename Derived>
33
std::ostream& operator<< (std::ostream& os, const LieGroupBase<Derived>& lg)
34
{
35
  return os << lg.name();
36
}
37
template<typename LieGroupCollection>
38
std::ostream& operator<< (std::ostream& os, const LieGroupGenericTpl<LieGroupCollection>& lg)
39
{
40
  return os << lg.name();
41
}
42
} // namespace pinocchio
43
44
template <typename T>
45
28640
void test_lie_group_methods (T & jmodel, typename T::JointDataDerived &)
46
{
47
  typedef typename LieGroup<T>::type LieGroupType;
48
  typedef double Scalar;
49
50
28640
  const Scalar prec = Eigen::NumTraits<Scalar>::dummy_precision();
51



28640
  BOOST_TEST_MESSAGE ("Testing Joint over " << jmodel.shortname());
52
  typedef typename T::ConfigVector_t  ConfigVector_t;
53
  typedef typename T::TangentVector_t TangentVector_t;
54
55

28640
  ConfigVector_t  q1(ConfigVector_t::Random (jmodel.nq()));
56

28640
  TangentVector_t q1_dot(TangentVector_t::Random (jmodel.nv()));
57

28640
  ConfigVector_t  q2(ConfigVector_t::Random (jmodel.nq()));
58
59



28640
  static ConfigVector_t Ones(ConfigVector_t::Ones(jmodel.nq()));
60
28640
  const Scalar u = 0.3;
61
  // pinocchio::Inertia::Matrix6 Ia(pinocchio::Inertia::Random().matrix());
62
  // bool update_I = false;
63
64

28640
  q1 = LieGroupType().randomConfiguration(-Ones, Ones);
65




28640
  BOOST_CHECK(LieGroupType().isNormalized(q1));
66
67
28640
  typename T::JointDataDerived jdata = jmodel.createData();
68
69
  // Check integrate
70
28640
  jmodel.calc(jdata, q1, q1_dot);
71
28640
  SE3 M1 = jdata.M;
72
28640
  Motion v1(jdata.v);
73
74

28640
  q2 = LieGroupType().integrate(q1,q1_dot);
75




28640
  BOOST_CHECK(LieGroupType().isNormalized(q2));
76
28640
  jmodel.calc(jdata,q2);
77
28640
  SE3 M2 = jdata.M;
78
79
28640
  double tol_test = 1e2;
80

28640
  if(jmodel.shortname() == "JointModelPlanar")
81
2040
    tol_test = 5e4;
82
83

28640
  const SE3 M2_exp = M1*exp6(v1);
84
85

28640
  if(jmodel.shortname() != "JointModelSphericalZYX")
86
  {
87




26600
    BOOST_CHECK_MESSAGE(M2.isApprox(M2_exp), std::string("Error when integrating1 " + jmodel.shortname()));
88
  }
89
90
  // Check integrate when the same vector is passed as input and output
91

28640
  ConfigVector_t  qTest(ConfigVector_t::Random (jmodel.nq()));
92

28640
  TangentVector_t qTest_dot(TangentVector_t::Random (jmodel.nv()));
93

28640
  ConfigVector_t  qResult(ConfigVector_t::Random (jmodel.nq()));
94

28640
  qTest = LieGroupType().randomConfiguration(-Ones, Ones);
95

28640
  qResult = LieGroupType().integrate(qTest, qTest_dot);
96

28640
  LieGroupType().integrate(qTest, qTest_dot, qTest);
97





28640
  BOOST_CHECK_MESSAGE(LieGroupType().isNormalized(qTest),
98
    std::string("Normalization error when integrating with same input and output " + jmodel.shortname()));
99
100

28640
  SE3 MTest, MResult;
101
  {
102
28640
    typename T::JointDataDerived jdata = jmodel.createData();
103
28640
    jmodel.calc(jdata, qTest);
104
28640
    MTest = jdata.M;
105
  }
106
  {
107
28640
    typename T::JointDataDerived jdata = jmodel.createData();
108
28640
    jmodel.calc(jdata, qResult);
109
28640
    MResult = jdata.M;
110
  }
111




28640
  BOOST_CHECK_MESSAGE(MTest.isApprox(MResult),
112
                      std::string("Inconsistent value when integrating with same input and output " + jmodel.shortname()));
113
114




28640
  BOOST_CHECK_MESSAGE(qTest.isApprox(qResult,prec),
115
    std::string("Inconsistent value when integrating with same input and output " + jmodel.shortname()));
116
117
  // Check the reversability of integrate
118

28640
  ConfigVector_t q3 = LieGroupType().integrate(q2,-q1_dot);
119
28640
  jmodel.calc(jdata,q3);
120
28640
  SE3 M3 = jdata.M;
121
122




28640
  BOOST_CHECK_MESSAGE(M3.isApprox(M1), std::string("Error when integrating back " + jmodel.shortname()));
123
124
  // Check interpolate
125

28640
  ConfigVector_t q_interpolate = LieGroupType().interpolate(q1,q2,0.);
126




28640
  BOOST_CHECK_MESSAGE(q_interpolate.isApprox(q1), std::string("Error when interpolating " + jmodel.shortname()));
127
128

28640
  q_interpolate = LieGroupType().interpolate(q1,q2,1.);
129




28640
  BOOST_CHECK_MESSAGE(q_interpolate.isApprox(q2,tol_test*prec), std::string("Error when interpolating " + jmodel.shortname()));
130
131

28640
  if(jmodel.shortname() != "JointModelSphericalZYX")
132
  {
133

26600
    q_interpolate = LieGroupType().interpolate(q1,q2,u);
134
26600
    jmodel.calc(jdata,q_interpolate);
135
26600
    SE3 M_interpolate = jdata.M;
136
137

26600
    SE3 M_interpolate_expected = M1*exp6(u*v1);
138




26600
    BOOST_CHECK_MESSAGE(M_interpolate_expected.isApprox(M_interpolate,1e4*prec), std::string("Error when interpolating " + jmodel.shortname()));
139
  }
140
141
  // Check that difference between two equal configuration is exactly 0
142

28640
  TangentVector_t zero = LieGroupType().difference(q1,q1);
143




28640
  BOOST_CHECK_MESSAGE (zero.isZero(), std::string ("Error: difference between two equal configurations is not 0."));
144

28640
  zero = LieGroupType().difference(q2,q2);
145




28640
  BOOST_CHECK_MESSAGE (zero.isZero(), std::string ("Error: difference between two equal configurations is not 0."));
146
147
  // Check difference
148
  // TODO(jcarpent): check the increase of tolerance.
149
150
151

28640
  TangentVector_t vdiff = LieGroupType().difference(q1,q2);
152




28640
  BOOST_CHECK_MESSAGE(vdiff.isApprox(q1_dot,tol_test*prec), std::string("Error when differentiating " + jmodel.shortname()));
153
154
  // Check distance
155

28640
  Scalar dist = LieGroupType().distance(q1,q2);
156



28640
  BOOST_CHECK_MESSAGE(dist > 0., "distance - wrong results");
157



28640
  BOOST_CHECK_SMALL(math::fabs(dist-q1_dot.norm()), tol_test*prec);
158
159
57280
  std::string error_prefix("LieGroup");
160

28640
  error_prefix += " on joint " + jmodel.shortname();
161
162




28640
  BOOST_CHECK_MESSAGE(jmodel.nq() == LieGroupType::NQ, std::string(error_prefix + " - nq "));
163




28640
  BOOST_CHECK_MESSAGE(jmodel.nv() == LieGroupType::NV, std::string(error_prefix + " - nv "));
164
165






28640
  BOOST_CHECK_MESSAGE
166
  (jmodel.nq() ==
167
   LieGroupType().randomConfiguration(-1 * Ones, Ones).size(),
168
   std::string(error_prefix + " - RandomConfiguration dimensions "));
169
170

28640
  ConfigVector_t q_normalize(ConfigVector_t::Random());
171
57280
  Eigen::VectorXd q_normalize_ref(q_normalize);
172

28640
  if(jmodel.shortname() == "JointModelSpherical")
173
  {
174




2040
    BOOST_CHECK_MESSAGE(!LieGroupType().isNormalized(q_normalize_ref), std::string(error_prefix + " - !isNormalized "));
175

2040
    q_normalize_ref /= q_normalize_ref.norm();
176
  }
177

26600
  else if(jmodel.shortname() == "JointModelFreeFlyer")
178
  {
179




2040
    BOOST_CHECK_MESSAGE(!LieGroupType().isNormalized(q_normalize_ref), std::string(error_prefix + " - !isNormalized "));
180


2040
    q_normalize_ref.template tail<4>() /= q_normalize_ref.template tail<4>().norm();
181
  }
182

24560
  else if(boost::algorithm::istarts_with(jmodel.shortname(),"JointModelRUB"))
183
  {
184




6120
    BOOST_CHECK_MESSAGE(!LieGroupType().isNormalized(q_normalize_ref), std::string(error_prefix + " - !isNormalized "));
185

6120
    q_normalize_ref /= q_normalize_ref.norm();
186
  }
187

18440
  else if(jmodel.shortname() == "JointModelPlanar")
188
  {
189




2040
    BOOST_CHECK_MESSAGE(!LieGroupType().isNormalized(q_normalize_ref), std::string(error_prefix + " - !isNormalized "));
190


2040
    q_normalize_ref.template tail<2>() /= q_normalize_ref.template tail<2>().norm();
191
  }
192




28640
  BOOST_CHECK_MESSAGE(LieGroupType().isNormalized(q_normalize_ref), std::string(error_prefix + " - isNormalized "));
193

28640
  LieGroupType().normalize(q_normalize);
194




28640
  BOOST_CHECK_MESSAGE(q_normalize.isApprox(q_normalize_ref), std::string(error_prefix + " - normalize "));
195
28640
}
196
197
struct TestJoint{
198
199
  template <typename T>
200
560
  void operator()(const T ) const
201
  {
202
560
    T jmodel;
203
560
    jmodel.setIndexes(0,0,0);
204
560
    typename T::JointDataDerived jdata = jmodel.createData();
205
206
29120
    for (int i = 0; i <= 50; ++i)
207
    {
208
28560
      test_lie_group_methods(jmodel, jdata);
209
    }
210
560
  }
211
212
20
  void operator()(const pinocchio::JointModelRevoluteUnaligned & ) const
213
  {
214
20
    pinocchio::JointModelRevoluteUnaligned jmodel(1.5, 1., 0.);
215
20
    jmodel.setIndexes(0,0,0);
216
20
    pinocchio::JointModelRevoluteUnaligned::JointDataDerived jdata = jmodel.createData();
217
218
20
    test_lie_group_methods(jmodel, jdata);
219
20
  }
220
221
20
  void operator()(const pinocchio::JointModelPrismaticUnaligned & ) const
222
  {
223
20
    pinocchio::JointModelPrismaticUnaligned jmodel(1.5, 1., 0.);
224
20
    jmodel.setIndexes(0,0,0);
225
20
    pinocchio::JointModelPrismaticUnaligned::JointDataDerived jdata = jmodel.createData();
226
227
20
    test_lie_group_methods(jmodel, jdata);
228
20
  }
229
230
};
231
232
struct LieGroup_Jdifference{
233
  template <typename T>
234
320
  void operator()(const T ) const
235
  {
236
    typedef typename T::ConfigVector_t ConfigVector_t;
237
    typedef typename T::TangentVector_t TangentVector_t;
238
    typedef typename T::JacobianMatrix_t JacobianMatrix_t;
239
    typedef typename T::Scalar Scalar;
240
241
320
    T lg;
242



320
    BOOST_TEST_MESSAGE (lg.name());
243


1600
    ConfigVector_t q[2], q_dv[2];
244
320
    q[0] = lg.random();
245
320
    q[1] = lg.random();
246

320
    TangentVector_t va, vb, dv;
247

960
    JacobianMatrix_t J[2];
248
320
    dv.setZero();
249
250
320
    lg.difference (q[0], q[1], va);
251
320
    lg.template dDifference<ARG0> (q[0], q[1], J[0]);
252
320
    lg.template dDifference<ARG1> (q[0], q[1], J[1]);
253
254
320
    const Scalar eps = 1e-6;
255
960
    for (int k = 0; k < 2; ++k) {
256




640
      BOOST_TEST_MESSAGE ("Checking J" << k << '\n' << J[k]);
257
640
      q_dv[0] = q[0];
258
640
      q_dv[1] = q[1];
259
      // Check J[k]
260

2640
      for (int i = 0; i < dv.size(); ++i)
261
      {
262
2000
        dv[i] = eps;
263
2000
        lg.integrate (q[k], dv, q_dv[k]);
264
2000
        lg.difference (q_dv[0], q_dv[1], vb);
265
266
        // vb - va ~ J[k] * dv
267

2000
        TangentVector_t J_dv = J[k].col(i);
268

2000
        TangentVector_t vb_va = (vb - va) / eps;
269






2000
        EIGEN_VECTOR_IS_APPROX (vb_va, J_dv, 1e-2);
270
2000
        dv[i] = 0;
271
      }
272
    }
273
274

320
    specificTests(lg);
275
320
  }
276
277
  template <typename T>
278
240
  void specificTests(const T ) const
279
240
  {}
280
281
  template <typename Scalar, int Options>
282
20
  void specificTests(const SpecialEuclideanOperationTpl<3,Scalar,Options>) const
283
  {
284
    typedef SE3Tpl<Scalar> SE3;
285
    typedef SpecialEuclideanOperationTpl<3,Scalar,Options> LG_t;
286
    typedef typename LG_t::ConfigVector_t ConfigVector_t;
287
    typedef typename LG_t::JacobianMatrix_t JacobianMatrix_t;
288
    typedef typename LG_t::ConstQuaternionMap_t ConstQuaternionMap_t;
289
290
20
    LG_t lg;
291
292

60
    ConfigVector_t q[2];
293
20
    q[0] = lg.random();
294
20
    q[1] = lg.random();
295
296


20
    ConstQuaternionMap_t quat0(q[0].template tail<4>().data()), quat1(q[1].template tail<4>().data());
297

60
    JacobianMatrix_t J[2];
298
299
20
    lg.template dDifference<ARG0> (q[0], q[1], J[0]);
300
20
    lg.template dDifference<ARG1> (q[0], q[1], J[1]);
301
302


20
    SE3 om0 (typename SE3::Quaternion (q[0].template tail<4>()).matrix(), q[0].template head<3>()),
303


20
        om1 (typename SE3::Quaternion (q[1].template tail<4>()).matrix(), q[1].template head<3>()),
304
20
        _1m2 (om1.actInv (om0)) ;
305








20
    EIGEN_MATRIX_IS_APPROX (J[1] * _1m2.toActionMatrix(), - J[0], 1e-8);
306
307
    // Test against SE3::Interpolate
308
20
    const Scalar u = 0.3;
309
20
    ConfigVector_t q_interp = lg.interpolate(q[0],q[1],u);
310

20
    ConstQuaternionMap_t quat_interp(q_interp.template tail<4>().data());
311
312

20
    SE3 M0(quat0,q[0].template head<3>());
313

20
    SE3 M1(quat1,q[1].template head<3>());
314
315
20
    SE3 M_u = SE3::Interpolate(M0,M1,u);
316

20
    SE3 M_interp(quat_interp,q_interp.template head<3>());
317
318



20
    BOOST_CHECK(M_u.isApprox(M_interp));
319
20
  }
320
321
  template <typename Scalar, int Options>
322
20
    void specificTests(const CartesianProductOperation<
323
        VectorSpaceOperationTpl<3,Scalar,Options>,
324
        SpecialOrthogonalOperationTpl<3,Scalar,Options>
325
        >) const
326
  {
327
    typedef SE3Tpl<Scalar> SE3;
328
    typedef CartesianProductOperation<
329
      VectorSpaceOperationTpl<3,Scalar,Options>,
330
      SpecialOrthogonalOperationTpl<3,Scalar,Options>
331
        > LG_t;
332
    typedef typename LG_t::ConfigVector_t ConfigVector_t;
333
    typedef typename LG_t::JacobianMatrix_t JacobianMatrix_t;
334
335
20
    LG_t lg;
336
337

60
    ConfigVector_t q[2];
338
20
    q[0] = lg.random();
339
20
    q[1] = lg.random();
340

60
    JacobianMatrix_t J[2];
341
342
20
    lg.template dDifference<ARG0> (q[0], q[1], J[0]);
343
20
    lg.template dDifference<ARG1> (q[0], q[1], J[1]);
344
345
    typename SE3::Matrix3
346

20
      oR0 (typename SE3::Quaternion (q[0].template tail<4>()).matrix()),
347

20
      oR1 (typename SE3::Quaternion (q[1].template tail<4>()).matrix());
348

20
    JacobianMatrix_t X (JacobianMatrix_t::Identity());
349


20
    X.template bottomRightCorner<3,3>() = oR1.transpose() * oR0;
350







20
    EIGEN_MATRIX_IS_APPROX (J[1] * X, - J[0], 1e-8);
351
20
  }
352
};
353
354
template<bool around_identity>
355
struct LieGroup_Jintegrate{
356
  template <typename T>
357
336
  void operator()(const T ) const
358
  {
359
    typedef typename T::ConfigVector_t ConfigVector_t;
360
    typedef typename T::TangentVector_t TangentVector_t;
361
    typedef typename T::JacobianMatrix_t JacobianMatrix_t;
362
    typedef typename T::Scalar Scalar;
363
364
336
    T lg;
365
336
    ConfigVector_t q = lg.random();
366

336
    TangentVector_t v, dq, dv;
367
    if(around_identity)
368
16
      v.setZero();
369
    else
370
320
      v.setRandom();
371
372
336
    dq.setZero();
373
336
    dv.setZero();
374
375
336
    ConfigVector_t q_v = lg.integrate (q, v);
376
377

336
    JacobianMatrix_t Jq, Jv;
378
336
    lg.dIntegrate_dq (q, v, Jq);
379
336
    lg.dIntegrate_dv (q, v, Jv);
380
381
336
    const Scalar eps = 1e-6;
382

1386
    for (int i = 0; i < v.size(); ++i)
383
    {
384

1050
      dq[i] = dv[i] = eps;
385
1050
      ConfigVector_t q_dq = lg.integrate (q, dq);
386
387
1050
      ConfigVector_t q_dq_v = lg.integrate (q_dq, v);
388

1050
      TangentVector_t Jq_dq = Jq.col(i);
389
      // q_dv_v - q_v ~ Jq dv
390

1050
      TangentVector_t dI_dq = lg.difference (q_v, q_dq_v) / eps;
391






1050
      EIGEN_VECTOR_IS_APPROX (dI_dq, Jq_dq, 1e-2);
392
393

1050
      ConfigVector_t q_v_dv = lg.integrate (q, (v+dv).eval());
394

1050
      TangentVector_t Jv_dv = Jv.col(i);
395
      // q_v_dv - q_v ~ Jv dv
396

1050
      TangentVector_t dI_dv = lg.difference (q_v, q_v_dv) / eps;
397






1050
      EIGEN_VECTOR_IS_APPROX (dI_dv, Jv_dv, 1e-2);
398
399

1050
      dq[i] = dv[i] = 0;
400
    }
401
336
  }
402
};
403
404
struct LieGroup_JintegrateJdifference{
405
  template <typename T>
406
320
  void operator()(const T ) const
407
  {
408
    typedef typename T::ConfigVector_t ConfigVector_t;
409
    typedef typename T::TangentVector_t TangentVector_t;
410
    typedef typename T::JacobianMatrix_t JacobianMatrix_t;
411
412
320
    T lg;
413



320
    BOOST_TEST_MESSAGE (lg.name());
414

320
    ConfigVector_t qa, qb (lg.nq());
415
320
    qa = lg.random();
416

320
    TangentVector_t v (lg.nv());
417
320
    v.setRandom ();
418
320
    lg.integrate(qa, v, qb);
419
420

320
    JacobianMatrix_t Jd_qb, Ji_v;
421
422
320
    lg.template dDifference<ARG1> (qa, qb, Jd_qb);
423
320
    lg.template dIntegrate <ARG1> (qa, v , Ji_v );
424
425








320
    BOOST_CHECK_MESSAGE ((Jd_qb * Ji_v).isIdentity(),
426
        "Jd_qb\n" <<
427
        Jd_qb << '\n' <<
428
        "* Ji_v\n" <<
429
        Ji_v << '\n' <<
430
        "!= Identity\n" <<
431
        Jd_qb * Ji_v << '\n');
432
320
  }
433
};
434
435
struct LieGroup_JintegrateCoeffWise
436
{
437
  template <typename T>
438
320
  void operator()(const T ) const
439
  {
440
    typedef typename T::ConfigVector_t ConfigVector_t;
441
    typedef typename T::TangentVector_t TangentVector_t;
442
    typedef typename T::Scalar Scalar;
443
444
320
    T lg;
445
320
    ConfigVector_t q = lg.random();
446


320
    TangentVector_t dv(TangentVector_t::Zero(lg.nv()));
447
448



320
    BOOST_TEST_MESSAGE (lg.name());
449
    typedef Eigen::Matrix<Scalar,T::NQ,T::NV> JacobianCoeffs;
450


320
    JacobianCoeffs Jintegrate(JacobianCoeffs::Zero(lg.nq(),lg.nv()));
451
320
    lg.integrateCoeffWiseJacobian(q,Jintegrate);
452


320
    JacobianCoeffs Jintegrate_fd(JacobianCoeffs::Zero(lg.nq(),lg.nv()));
453
454
320
    const Scalar eps = 1e-8;
455

1320
    for (int i = 0; i < lg.nv(); ++i)
456
    {
457
1000
      dv[i] = eps;
458


1000
      ConfigVector_t q_next(ConfigVector_t::Zero(lg.nq()));
459
1000
      lg.integrate(q, dv,q_next);
460


1000
      Jintegrate_fd.col(i) = (q_next - q)/eps;
461
462
1000
      dv[i] = 0;
463
    }
464
465





320
    EIGEN_MATRIX_IS_APPROX(Jintegrate, Jintegrate_fd, sqrt(eps));
466
320
  }
467
};
468
469
BOOST_AUTO_TEST_SUITE ( BOOST_TEST_MODULE )
470
471
















4
BOOST_AUTO_TEST_CASE ( test_all )
472
{
473
  typedef boost::variant< JointModelRX, JointModelRY, JointModelRZ, JointModelRevoluteUnaligned
474
                          , JointModelSpherical, JointModelSphericalZYX
475
                          , JointModelPX, JointModelPY, JointModelPZ
476
                          , JointModelPrismaticUnaligned
477
                          , JointModelFreeFlyer
478
                          , JointModelPlanar
479
                          , JointModelTranslation
480
                          , JointModelRUBX, JointModelRUBY, JointModelRUBZ
481
                          > Variant;
482
42
  for (int i = 0; i < 20; ++i)
483
40
    boost::mpl::for_each<Variant::types>(TestJoint());
484
485
  // FIXME JointModelComposite does not work.
486
  // boost::mpl::for_each<JointModelVariant::types>(TestJoint());
487
488
2
}
489
490
















4
BOOST_AUTO_TEST_CASE ( Jdifference )
491
{
492
  typedef double Scalar;
493
  enum { Options = 0 };
494
495
  typedef boost::mpl::vector<  VectorSpaceOperationTpl<1,Scalar,Options>
496
                             , VectorSpaceOperationTpl<2,Scalar,Options>
497
                             , SpecialOrthogonalOperationTpl<2,Scalar,Options>
498
                             , SpecialOrthogonalOperationTpl<3,Scalar,Options>
499
                             , SpecialEuclideanOperationTpl<2,Scalar,Options>
500
                             , SpecialEuclideanOperationTpl<3,Scalar,Options>
501
                             , CartesianProductOperation<
502
                                 VectorSpaceOperationTpl<2,Scalar,Options>,
503
                                 SpecialOrthogonalOperationTpl<2,Scalar,Options>
504
                               >
505
                             , CartesianProductOperation<
506
                                 VectorSpaceOperationTpl<3,Scalar,Options>,
507
                                 SpecialOrthogonalOperationTpl<3,Scalar,Options>
508
                               >
509
                             > Types;
510
42
  for (int i = 0; i < 20; ++i)
511
40
    boost::mpl::for_each<Types>(LieGroup_Jdifference());
512
2
}
513
514
















4
BOOST_AUTO_TEST_CASE ( Jintegrate )
515
{
516
  typedef double Scalar;
517
  enum { Options = 0 };
518
519
  typedef boost::mpl::vector<  VectorSpaceOperationTpl<1,Scalar,Options>
520
                             , VectorSpaceOperationTpl<2,Scalar,Options>
521
                             , SpecialOrthogonalOperationTpl<2,Scalar,Options>
522
                             , SpecialOrthogonalOperationTpl<3,Scalar,Options>
523
                             , SpecialEuclideanOperationTpl<2,Scalar,Options>
524
                             , SpecialEuclideanOperationTpl<3,Scalar,Options>
525
                             , CartesianProductOperation<
526
                                 VectorSpaceOperationTpl<2,Scalar,Options>,
527
                                 SpecialOrthogonalOperationTpl<2,Scalar,Options>
528
                               >
529
                             , CartesianProductOperation<
530
                                 VectorSpaceOperationTpl<3,Scalar,Options>,
531
                                 SpecialOrthogonalOperationTpl<3,Scalar,Options>
532
                               >
533
                             > Types;
534
42
  for (int i = 0; i < 20; ++i)
535
40
    boost::mpl::for_each<Types>(LieGroup_Jintegrate<false>());
536
537
  // Around identity
538
2
  boost::mpl::for_each<Types>(LieGroup_Jintegrate<true>());
539
2
}
540
541
















4
BOOST_AUTO_TEST_CASE ( Jintegrate_Jdifference )
542
{
543
  typedef double Scalar;
544
  enum { Options = 0 };
545
546
  typedef boost::mpl::vector<  VectorSpaceOperationTpl<1,Scalar,Options>
547
                             , VectorSpaceOperationTpl<2,Scalar,Options>
548
                             , SpecialOrthogonalOperationTpl<2,Scalar,Options>
549
                             , SpecialOrthogonalOperationTpl<3,Scalar,Options>
550
                             , SpecialEuclideanOperationTpl<2,Scalar,Options>
551
                             , SpecialEuclideanOperationTpl<3,Scalar,Options>
552
                             , CartesianProductOperation<
553
                                 VectorSpaceOperationTpl<2,Scalar,Options>,
554
                                 SpecialOrthogonalOperationTpl<2,Scalar,Options>
555
                               >
556
                             , CartesianProductOperation<
557
                                 VectorSpaceOperationTpl<3,Scalar,Options>,
558
                                 SpecialOrthogonalOperationTpl<3,Scalar,Options>
559
                               >
560
                             > Types;
561
42
  for (int i = 0; i < 20; ++i)
562
40
    boost::mpl::for_each<Types>(LieGroup_JintegrateJdifference());
563
2
}
564
565
















4
BOOST_AUTO_TEST_CASE(JintegrateCoeffWise)
566
{
567
  typedef double Scalar;
568
  enum { Options = 0 };
569
570
  typedef boost::mpl::vector<  VectorSpaceOperationTpl<1,Scalar,Options>
571
  , VectorSpaceOperationTpl<2,Scalar,Options>
572
  , SpecialOrthogonalOperationTpl<2,Scalar,Options>
573
  , SpecialOrthogonalOperationTpl<3,Scalar,Options>
574
  , SpecialEuclideanOperationTpl<2,Scalar,Options>
575
  , SpecialEuclideanOperationTpl<3,Scalar,Options>
576
  , CartesianProductOperation<
577
  VectorSpaceOperationTpl<2,Scalar,Options>,
578
  SpecialOrthogonalOperationTpl<2,Scalar,Options>
579
  >
580
  , CartesianProductOperation<
581
  VectorSpaceOperationTpl<3,Scalar,Options>,
582
  SpecialOrthogonalOperationTpl<3,Scalar,Options>
583
  >
584
  > Types;
585
42
  for (int i = 0; i < 20; ++i)
586
40
    boost::mpl::for_each<Types>(LieGroup_JintegrateCoeffWise());
587
588
  {
589
    typedef SpecialEuclideanOperationTpl<3,Scalar,Options> LieGroup;
590
    typedef LieGroup::ConfigVector_t ConfigVector_t;
591
2
    LieGroup lg;
592
593
2
    ConfigVector_t q = lg.random();
594
//    TangentVector_t dv(TangentVector_t::Zero(lg.nv()));
595
596
    typedef Eigen::Matrix<Scalar,LieGroup::NQ,LieGroup::NV> JacobianCoeffs;
597

2
    JacobianCoeffs Jintegrate(JacobianCoeffs::Zero(lg.nq(),lg.nv()));
598
2
    lg.integrateCoeffWiseJacobian(q,Jintegrate);
599
600
601
602
  }
603
2
}
604
605
















4
BOOST_AUTO_TEST_CASE ( test_vector_space )
606
{
607
  typedef VectorSpaceOperationTpl<3,double> VSO_t;
608
2
  VSO_t::ConfigVector_t q,
609

2
    lo(VSO_t::ConfigVector_t::Constant(-std::numeric_limits<double>::infinity())),
610
    // lo(VSO_t::ConfigVector_t::Constant(                                       0)),
611
    // up(VSO_t::ConfigVector_t::Constant( std::numeric_limits<double>::infinity()));
612

2
    up(VSO_t::ConfigVector_t::Constant(                                       0));
613
614
2
  bool error = false;
615
  try {
616

2
    VSO_t ().randomConfiguration(lo, up, q);
617
2
  } catch (const std::runtime_error&) {
618
2
    error = true;
619
  }
620



2
  BOOST_CHECK_MESSAGE(error, "Random configuration between infinite bounds should return an error");
621
2
}
622
623
















4
BOOST_AUTO_TEST_CASE ( test_size )
624
{
625
  // R^1: neutral = [0]
626
2
  VectorSpaceOperationTpl <1,double> vs1;
627
4
  Eigen::VectorXd neutral;
628
2
  neutral.resize (1);
629
2
  neutral.setZero ();
630



2
  BOOST_CHECK (vs1.nq () == 1);
631



2
  BOOST_CHECK (vs1.nv () == 1);
632



2
  BOOST_CHECK (vs1.name () == "R^1");
633




2
  BOOST_CHECK (vs1.neutral () == neutral);
634
  // R^2: neutral = [0, 0]
635
2
  VectorSpaceOperationTpl <2,double> vs2;
636
2
  neutral.resize (2);
637
2
  neutral.setZero ();
638



2
  BOOST_CHECK (vs2.nq () == 2);
639



2
  BOOST_CHECK (vs2.nv () == 2);
640



2
  BOOST_CHECK (vs2.name () == "R^2");
641




2
  BOOST_CHECK (vs2.neutral () == neutral);
642
  // R^3: neutral = [0, 0, 0]
643
2
  VectorSpaceOperationTpl <3,double> vs3;
644
2
  neutral.resize (3);
645
2
  neutral.setZero ();
646



2
  BOOST_CHECK (vs3.nq () == 3);
647



2
  BOOST_CHECK (vs3.nv () == 3);
648



2
  BOOST_CHECK (vs3.name () == "R^3");
649




2
  BOOST_CHECK (vs3.neutral () == neutral);
650
  // SO(2): neutral = [1, 0]
651
2
  SpecialOrthogonalOperationTpl<2,double> so2;
652

2
  neutral.resize (2); neutral [0] = 1; neutral [1] = 0;
653



2
  BOOST_CHECK (so2.nq () == 2);
654



2
  BOOST_CHECK (so2.nv () == 1);
655



2
  BOOST_CHECK (so2.name () == "SO(2)");
656




2
  BOOST_CHECK (so2.neutral () == neutral);
657
  // SO(3): neutral = [0, 0, 0, 1]
658
2
  SpecialOrthogonalOperationTpl<3,double> so3;
659

2
  neutral.resize (4); neutral.setZero ();
660
2
  neutral [3] = 1;
661



2
  BOOST_CHECK (so3.nq () == 4);
662



2
  BOOST_CHECK (so3.nv () == 3);
663



2
  BOOST_CHECK (so3.name () == "SO(3)");
664




2
  BOOST_CHECK (so3.neutral () == neutral);
665
  // SE(2): neutral = [0, 0, 1, 0]
666
2
  SpecialEuclideanOperationTpl <2,double> se2;
667

2
  neutral.resize (4); neutral.setZero ();
668
2
  neutral [2] = 1;
669



2
  BOOST_CHECK (se2.nq () == 4);
670



2
  BOOST_CHECK (se2.nv () == 3);
671



2
  BOOST_CHECK (se2.name () == "SE(2)");
672




2
  BOOST_CHECK (se2.neutral () == neutral);
673
  // SE(3): neutral = [0, 0, 0, 0, 0, 0, 1]
674
2
  SpecialEuclideanOperationTpl <3,double> se3;
675

2
  neutral.resize (7); neutral.setZero ();
676
2
  neutral [6] = 1;
677



2
  BOOST_CHECK (se3.nq () == 7);
678



2
  BOOST_CHECK (se3.nv () == 6);
679



2
  BOOST_CHECK (se3.name () == "SE(3)");
680




2
  BOOST_CHECK (se3.neutral () == neutral);
681
  // R^2 x SO(2): neutral = [0, 0, 1, 0]
682
  CartesianProductOperation <VectorSpaceOperationTpl <2,double>,
683
2
                             SpecialOrthogonalOperationTpl <2,double> > r2xso2;
684

2
  neutral.resize (4); neutral.setZero ();
685
2
  neutral [2] = 1;
686



2
  BOOST_CHECK (r2xso2.nq () == 4);
687



2
  BOOST_CHECK (r2xso2.nv () == 3);
688



2
  BOOST_CHECK (r2xso2.name () == "R^2*SO(2)");
689




2
  BOOST_CHECK (r2xso2.neutral () == neutral);
690
  // R^3 x SO(3): neutral = [0, 0, 0, 0, 0, 0, 1]
691
  CartesianProductOperation <VectorSpaceOperationTpl <3,double>,
692
2
                             SpecialOrthogonalOperationTpl <3,double> > r3xso3;
693

2
  neutral.resize (7); neutral.setZero ();
694
2
  neutral [6] = 1;
695



2
  BOOST_CHECK (r3xso3.nq () == 7);
696



2
  BOOST_CHECK (r3xso3.nv () == 6);
697



2
  BOOST_CHECK (r3xso3.name () == "R^3*SO(3)");
698




2
  BOOST_CHECK (r3xso3.neutral () == neutral);
699
2
}
700
701
















4
BOOST_AUTO_TEST_CASE(test_dim_computation)
702
{
703
2
  int dim = eval_set_dim<1,1>::value ;
704


2
  BOOST_CHECK(dim == 2);
705
2
  dim = eval_set_dim<Eigen::Dynamic,1>::value;
706


2
  BOOST_CHECK(dim == Eigen::Dynamic);
707
2
  dim = eval_set_dim<1,Eigen::Dynamic>::value;
708


2
  BOOST_CHECK(dim == Eigen::Dynamic);
709
2
}
710
711
















4
BOOST_AUTO_TEST_CASE (small_distance_test)
712
{
713
2
  SpecialOrthogonalOperationTpl <3,double> so3;
714
4
  Eigen::VectorXd q1(so3.nq());
715
4
  Eigen::VectorXd q2(so3.nq());
716


2
  q1 << 0,0,-0.1953711450011105244,0.9807293794421349169;
717


2
  q2 << 0,0,-0.19537114500111049664,0.98072937944213492244;
718
719



2
  BOOST_CHECK_MESSAGE (so3.distance(q1,q2) > 0.,
720
                       "SO3 small distance - wrong results");
721
2
}
722
723
template<typename LieGroupCollection>
724
struct TestLieGroupVariantVisitor
725
{
726
727
  typedef LieGroupGenericTpl<LieGroupCollection> LieGroupGeneric;
728
  typedef typename LieGroupGeneric::ConfigVector_t ConfigVector_t;
729
  typedef typename LieGroupGeneric::TangentVector_t TangentVector_t;
730
731
  template<typename Derived>
732
16
  void operator() (const LieGroupBase<Derived> & lg) const
733
  {
734
32
    LieGroupGenericTpl<LieGroupCollection> lg_generic(lg.derived());
735
16
    test(lg,lg_generic);
736
16
  }
737
738
  template<typename Derived>
739
16
  static void test(const LieGroupBase<Derived> & lg,
740
                   const LieGroupGenericTpl<LieGroupCollection> & lg_generic)
741
  {
742





16
    BOOST_CHECK(lg.nq() == nq(lg_generic));
743





16
    BOOST_CHECK(lg.nv() == nv(lg_generic));
744
745




16
    BOOST_CHECK(lg.name() == name(lg_generic));
746
747




16
    BOOST_CHECK(lg.neutral() == neutral(lg_generic));
748
749
    typedef typename LieGroupGeneric::ConfigVector_t ConfigVectorGeneric;
750
    typedef typename LieGroupGeneric::TangentVector_t TangentVectorGeneric;
751
752

32
    ConfigVector_t q0 = lg.random();
753


32
    TangentVector_t v = TangentVector_t::Random(lg.nv());
754

32
    ConfigVector_t qout_ref(lg.nq());
755
16
    lg.integrate(q0, v, qout_ref);
756
757

32
    ConfigVectorGeneric qout(lg.nq());
758

16
    integrate(lg_generic, ConfigVectorGeneric(q0), TangentVectorGeneric(v), qout);
759



16
    BOOST_CHECK(qout.isApprox(qout_ref));
760
761

32
    ConfigVector_t q1 (nq(lg_generic));
762
16
    random (lg_generic, q1);
763
16
    difference(lg_generic, q0, q1, v);
764



16
    BOOST_CHECK_EQUAL(lg.distance(q0, q1), distance (lg_generic, q0, q1));
765
766

32
    ConfigVector_t q2(nq(lg_generic));
767
16
    random(lg_generic, q2);
768
16
    normalize(lg_generic, q2);
769



16
    BOOST_CHECK(isNormalized(lg_generic, q2));
770
16
  }
771
};
772
773
















4
BOOST_AUTO_TEST_CASE(test_liegroup_variant)
774
{
775
2
  boost::mpl::for_each<LieGroupCollectionDefault::LieGroupVariant::types>(TestLieGroupVariantVisitor<LieGroupCollectionDefault>());
776
2
}
777
778
template<typename Lg1, typename Lg2>
779
1
void test_liegroup_variant_equal(Lg1 lg1, Lg2 lg2)
780
{
781
  typedef LieGroupGenericTpl<LieGroupCollectionDefault> LieGroupGeneric;
782


1
  BOOST_CHECK_EQUAL(LieGroupGeneric(lg1), LieGroupGeneric(lg2));
783
1
}
784
785
template<typename Lg1, typename Lg2>
786
1
void test_liegroup_variant_not_equal(Lg1 lg1, Lg2 lg2)
787
{
788
  typedef LieGroupGenericTpl<LieGroupCollectionDefault> LieGroupGeneric;
789


1
  BOOST_CHECK_PREDICATE( std::not_equal_to<LieGroupGeneric>(),
790
      (LieGroupGeneric(lg1))(LieGroupGeneric(lg2)) );
791
1
}
792
793
















4
BOOST_AUTO_TEST_CASE(test_liegroup_variant_comparison)
794
{
795
2
  test_liegroup_variant_equal(
796
2
      VectorSpaceOperationTpl<1, double>(),
797
2
      VectorSpaceOperationTpl<Eigen::Dynamic, double>(1));
798
2
  test_liegroup_variant_not_equal(
799
2
      VectorSpaceOperationTpl<1, double>(),
800
2
      VectorSpaceOperationTpl<Eigen::Dynamic, double>(2));
801
2
}
802
803
BOOST_AUTO_TEST_SUITE_END ()