30 #include <gtest/gtest.h> 31 #include <Eigen/Dense> 33 #if EIGEN_VERSION_AT_LEAST(3, 3, 0) 47 constexpr
int N = 1000;
48 constexpr
double THRESHOLD_ANALYTIC = 1e-5;
49 constexpr
double THRESHOLD_FINITE_DIFFERENCES = 1e-3;
50 constexpr
double THRESHOLD_FINITE_DIFFERENCES_HESSIAN = 5e-1;
51 constexpr
double INPUT_VECTOR_SCALE = 2.0;
55 template <
class FunctorType>
56 struct Function1 :
public FunctorType
66 void operator()(
const Eigen::Matrix<T, FunctorType::InputType::RowsAtCompileTime, 1> &x, Eigen::Matrix<T, FunctorType::ValueType::RowsAtCompileTime, 1> &
y)
const 68 Eigen::Matrix<T, FunctorType::ValueType::RowsAtCompileTime, 1> tmp(y.rows());
71 for (
int i = 0; i < 4; ++i)
73 y(i, 0) = (Eigen::AngleAxis<T>(x(i, 0), Eigen::Vector3d::UnitZ().cast<T>()).toRotationMatrix() * Eigen::Vector3d::UnitX().cast<T>()).dot(Eigen::Vector3d::UnitX().cast<T>());
75 if (i > 0)
y(i, 0) += tmp(i - 1, 0);
82 template <
class FunctorType>
83 struct Function2 :
public FunctorType
93 void operator()(
const Eigen::Matrix<T, FunctorType::InputType::RowsAtCompileTime, 1> &x, Eigen::Matrix<T, FunctorType::ValueType::RowsAtCompileTime, 1> &y)
const 95 Eigen::Matrix<T, FunctorType::ValueType::RowsAtCompileTime, 1> tmp(y.rows());
96 for (
int i = 0; i < 4; ++i)
98 y.block(i * 3, 0, 3, 1) = Eigen::AngleAxis<T>(x(i, 0), Eigen::Vector3d::UnitZ().cast<T>()).toRotationMatrix() * Eigen::Vector3d::UnitX().cast<T>();
105 template <
class FunctorType>
106 struct Function3 :
public FunctorType
115 template <
typename T>
116 void operator()(
const Eigen::Matrix<T, FunctorType::InputType::RowsAtCompileTime, 1> &x, Eigen::Matrix<T, FunctorType::ValueType::RowsAtCompileTime, 1> &y)
const 118 Eigen::Matrix<T, FunctorType::ValueType::RowsAtCompileTime, 1> tmp(y.rows());
119 for (
int i = 0; i < 4; ++i)
121 y(i, 0) = Eigen::Vector3d::UnitX().cast<T>().
dot(x.block(i * 3, 0, 3, 1));
123 if (i > 0)
y(i, 0) += tmp(i - 1, 0);
129 template <
template <
typename>
class DiffType,
typename _FunctorType,
template <
typename>
class FunctionType>
132 typedef _FunctorType FunctorType;
133 typedef FunctionType<FunctorType> Function;
134 typedef DiffType<Function> Diff;
135 typedef typename Diff::InputType InputType;
136 typedef typename Diff::ValueType ValueType;
137 typedef typename Diff::JacobianType JacobianType;
142 struct JacobianFull :
public T
144 void operator()(
const typename T::InputType &x,
typename T::ValueType &y,
145 typename T::JacobianType &j)
147 typename T::Function
f;
148 typename T::Diff autoj(f);
150 if (T::ValueType::RowsAtCompileTime == Eigen::Dynamic)
151 y.resize(T::Function::Values, 1);
152 if (T::JacobianType::RowsAtCompileTime == Eigen::Dynamic)
153 j.resize(T::Function::Values, T::Function::JacobianCols);
162 struct JacobianCompound :
public T
164 void operator()(
const typename T::InputType &x,
typename T::ValueType &y,
165 typename T::JacobianType &j,
const typename T::Diff::InputJacobianType &ij)
167 typename T::Function f;
168 typename T::Diff autoj(f);
170 if (T::ValueType::RowsAtCompileTime == Eigen::Dynamic)
171 y.resize(T::Function::Values, 1);
172 if (T::JacobianType::RowsAtCompileTime == Eigen::Dynamic)
173 j.resize(T::Function::Values, T::Function::JacobianCols);
182 template <
class T, Eigen::NumericalDiffMode mode>
183 struct JacobianFullFinite :
public T
187 int operator()(
const typename T::InputType &x,
typename T::ValueType &y,
188 typename T::JacobianType &j)
190 typename T::Function f;
193 if (T::ValueType::RowsAtCompileTime == Eigen::Dynamic)
194 y.resize(T::Function::Values, 1);
195 if (T::JacobianType::RowsAtCompileTime == Eigen::Dynamic)
196 j.resize(T::Function::Values, T::Function::JacobianCols);
199 return autoj(x, y, j);
206 template <
class T,
class T2, Eigen::NumericalDiffMode mode>
207 struct JacobianCompoundFinite :
public T
210 typedef typename T2::Function F2;
212 int operator()(
const typename diff::InputJacobianRowType &x,
typename T::ValueType &y,
213 typename T::JacobianType &j)
215 typename T::Function f;
217 auto compute_intermediate = [](
const typename diff::InputJacobianRowType &jx,
typename T::InputType &_x) {
218 if (T::InputType::RowsAtCompileTime == Eigen::Dynamic) _x.resize(F2::Values);
223 diff autoj(f, compute_intermediate);
225 if (T::ValueType::RowsAtCompileTime == Eigen::Dynamic)
226 y.resize(T::Function::Values, 1);
227 if (T::JacobianType::RowsAtCompileTime == Eigen::Dynamic)
228 j.resize(T::Function::Values, T::Function::JacobianCols);
231 return autoj(x, y, j);
237 struct HessianFull :
public T
239 void operator()(
const typename T::InputType &x,
typename T::ValueType &y,
240 typename T::JacobianType &j,
typename T::Diff::HessianType &hess)
242 typename T::Function f;
243 typename T::Diff autoj(f);
245 if (T::ValueType::RowsAtCompileTime == Eigen::Dynamic)
247 y.resize(T::Function::Values, 1);
248 hess.resize(T::Function::Values);
250 if (T::JacobianType::RowsAtCompileTime == Eigen::Dynamic)
252 j.resize(T::Function::Values, T::Function::JacobianCols);
253 for (
int i = 0; i < hess.rows(); ++i)
255 hess[i].resize(T::Function::JacobianCols, T::Function::JacobianCols);
260 autoj(x, y, j, hess);
266 struct HessianCompound :
public T
268 void operator()(
const typename T::InputType &x,
typename T::ValueType &y,
269 typename T::JacobianType &j,
typename T::Diff::HessianType &hess,
270 const typename T::Diff::InputJacobianType &ij,
const typename T::Diff::InputHessianType &ihess)
272 typename T::Function f;
273 typename T::Diff autoj(f);
275 if (T::ValueType::RowsAtCompileTime == Eigen::Dynamic)
277 y.resize(T::Function::Values, 1);
278 hess.resize(T::Function::Values);
280 if (T::JacobianType::RowsAtCompileTime == Eigen::Dynamic)
282 j.resize(T::Function::Values, T::Function::JacobianCols);
283 for (
int i = 0; i < hess.rows(); ++i)
285 hess[i].resize(T::Function::JacobianCols, T::Function::JacobianCols);
290 autoj(x, y, j, hess, ij, ihess);
296 template <
class T, Eigen::NumericalDiffMode mode>
297 struct HessianFullFinite :
public T
301 int operator()(
const typename T::InputType &x,
typename T::ValueType &y,
302 typename T::JacobianType &j,
typename T::Diff::HessianType &hess)
304 typename T::Function f;
307 if (T::ValueType::RowsAtCompileTime == Eigen::Dynamic)
309 y.resize(T::Function::Values, 1);
310 hess.resize(T::Function::Values);
312 if (T::JacobianType::RowsAtCompileTime == Eigen::Dynamic)
314 j.resize(T::Function::Values, T::Function::JacobianCols);
315 for (
int i = 0; i < hess.rows(); ++i)
317 hess[i].resize(T::Function::JacobianCols, T::Function::JacobianCols);
322 return autoj(x, y, j, hess);
329 template <
class T,
class T2, Eigen::NumericalDiffMode mode>
330 struct HessianCompoundFinite :
public T
333 typedef typename T2::Function F2;
335 int operator()(
const typename diff::InputJacobianRowType &x,
typename T::ValueType &y,
336 typename T::JacobianType &j,
typename T::Diff::HessianType &hess)
338 typename T::Function f;
340 auto compute_intermediate = [](
const typename diff::InputJacobianRowType &jx,
typename T::InputType &_x) {
341 if (T::InputType::RowsAtCompileTime == Eigen::Dynamic) _x.resize(F2::Values);
346 diff autoj(f, compute_intermediate);
348 if (T::ValueType::RowsAtCompileTime == Eigen::Dynamic)
350 y.resize(T::Function::Values, 1);
351 hess.resize(T::Function::Values);
353 if (T::JacobianType::RowsAtCompileTime == Eigen::Dynamic)
355 j.resize(T::Function::Values, T::Function::JacobianCols);
356 for (
int i = 0; i < hess.rows(); ++i)
358 hess[i].resize(T::Function::JacobianCols, T::Function::JacobianCols);
363 return autoj(x, y, j, hess);
368 struct TestStaticTrait
385 struct TestDynamicTrait
389 Inputs1 = Eigen::Dynamic,
390 Values1 = Eigen::Dynamic,
391 JacobianCols1 = Eigen::Dynamic,
392 Inputs2 = Eigen::Dynamic,
393 Values2 = Eigen::Dynamic,
394 JacobianCols2 = Eigen::Dynamic,
395 Inputs3 = Eigen::Dynamic,
396 Values3 = Eigen::Dynamic,
397 JacobianCols3 = Eigen::Dynamic
405 for (
int i = 0; i < N; ++i)
412 typedef TestingBase<DiffType, MyFunctor1, Function1> Test1;
413 typedef TestingBase<DiffType, MyFunctor2, Function2> Test2;
414 typedef TestingBase<DiffType, MyFunctor3, Function3> Test3;
416 typename Test1::InputType x1;
417 if (Test1::InputType::RowsAtCompileTime == Eigen::Dynamic)
419 x1 = Test1::InputType::Random(4) * INPUT_VECTOR_SCALE;
423 x1 = Test1::InputType::Random() * INPUT_VECTOR_SCALE;
426 typename Test1::ValueType y1;
427 typename Test1::JacobianType j1;
429 typename Test2::ValueType y2;
430 typename Test2::JacobianType j2;
432 typename Test3::ValueType y3;
433 typename Test3::JacobianType j3;
436 JacobianFull<Test1>()(x1, y1, j1);
438 JacobianFull<Test2>()(x1, y2, j2);
440 JacobianCompound<Test3>()(y2, y3, j3, j2);
442 typename Test1::ValueType y1fd;
443 typename Test1::JacobianType j1fd;
444 typename Test3::ValueType y3fd;
445 typename Test3::JacobianType j3fd;
448 JacobianFullFinite<Test1, mode>()(x1, y1fd, j1fd);
450 JacobianCompoundFinite<Test3, Test2, mode>()(x1, y3fd, j3fd);
452 EXPECT_TRUE((y1 - y3).norm() < THRESHOLD_ANALYTIC);
453 EXPECT_TRUE((j1 - j1fd).norm() < THRESHOLD_FINITE_DIFFERENCES);
454 EXPECT_TRUE((j3 - j3fd).norm() < THRESHOLD_FINITE_DIFFERENCES);
455 EXPECT_TRUE((y1fd - y3fd).norm() < THRESHOLD_FINITE_DIFFERENCES);
456 EXPECT_TRUE((y1 - y1fd).norm() < THRESHOLD_FINITE_DIFFERENCES);
461 template <
template <
typename>
class DiffType,
typename Dynamic>
462 void TestJacobiansSparse()
464 for (
int i = 0; i < N; ++i)
471 typedef TestingBase<DiffType, MyFunctor1, Function1> Test1;
472 typedef TestingBase<DiffType, MyFunctor2, Function2> Test2;
473 typedef TestingBase<DiffType, MyFunctor3, Function3> Test3;
475 typename Test1::InputType x1;
476 if (Test1::InputType::RowsAtCompileTime == Eigen::Dynamic)
478 x1 = Test1::InputType::Random(4) * INPUT_VECTOR_SCALE;
482 x1 = Test1::InputType::Random() * INPUT_VECTOR_SCALE;
485 typename Test1::ValueType y1;
486 typename Test1::JacobianType j1;
488 typename Test2::ValueType y2;
489 typename Test2::JacobianType j2;
491 typename Test3::ValueType y3;
492 typename Test3::JacobianType j3;
495 JacobianFull<Test1>()(x1, y1, j1);
497 JacobianFull<Test2>()(x1, y2, j2);
499 JacobianCompound<Test3>()(y2, y3, j3, j2);
502 typedef TestingBase<Eigen::AutoDiffChainJacobian, MyFunctor1, Function1> Test1D;
503 typedef TestingBase<Eigen::AutoDiffChainJacobian, MyFunctor2, Function2> Test2D;
504 typedef TestingBase<Eigen::AutoDiffChainJacobian, MyFunctor3, Function3> Test3D;
505 typename Test1D::ValueType y1d;
506 typename Test1D::JacobianType j1d;
507 typename Test2D::ValueType y2d;
508 typename Test2D::JacobianType j2d;
509 typename Test3D::ValueType y3d;
510 typename Test3D::JacobianType j3d;
513 JacobianFull<Test1D>()(x1, y1d, j1d);
515 JacobianFull<Test2D>()(x1, y2d, j2d);
517 JacobianCompound<Test3D>()(y2d, y3d, j3d, j2d);
519 EXPECT_TRUE((y1 - y3).norm() < THRESHOLD_ANALYTIC);
520 EXPECT_TRUE((j1 - j1d).norm() < THRESHOLD_ANALYTIC);
521 EXPECT_TRUE((j3 - j3d).norm() < THRESHOLD_ANALYTIC);
522 EXPECT_TRUE((y1d - y3d).norm() < THRESHOLD_ANALYTIC);
523 EXPECT_TRUE((y1 - y1d).norm() < THRESHOLD_ANALYTIC);
529 template <
typename HessianType1,
typename HessianType2>
530 double diffNorm(
const HessianType1 &
A,
const HessianType2 &B)
534 for (
int i = 0; i < A.rows(); ++i)
536 tmp = (A[i] - B[i]).norm();
539 return ret /
static_cast<double>(A.rows());
545 for (
int i = 0; i < N; ++i)
552 typedef TestingBase<DiffType, MyFunctor1, Function1> Test1;
553 typedef TestingBase<DiffType, MyFunctor2, Function2> Test2;
554 typedef TestingBase<DiffType, MyFunctor3, Function3> Test3;
556 typename Test1::InputType x1;
557 if (Test1::InputType::RowsAtCompileTime == Eigen::Dynamic)
559 x1 = Test1::InputType::Random(4) * INPUT_VECTOR_SCALE;
563 x1 = Test1::InputType::Random() * INPUT_VECTOR_SCALE;
566 typename Test1::ValueType y1;
567 typename Test1::JacobianType j1;
568 typename Test1::Diff::HessianType hess1;
570 typename Test1::ValueType y1fd;
571 typename Test1::JacobianType j1fd;
572 typename Test1::Diff::HessianType hess1fd;
574 typename Test2::ValueType y2;
575 typename Test2::JacobianType j2;
576 typename Test2::Diff::HessianType hess2;
578 typename Test3::ValueType y3;
579 typename Test3::JacobianType j3;
580 typename Test3::Diff::HessianType hess3;
582 typename Test3::ValueType y3fd;
583 typename Test3::JacobianType j3fd;
584 typename Test3::Diff::HessianType hess3fd;
587 HessianFull<Test1>()(x1, y1, j1, hess1);
589 HessianFull<Test2>()(x1, y2, j2, hess2);
591 HessianCompound<Test3>()(y2, y3, j3, hess3, j2, hess2);
594 HessianFullFinite<Test1, mode>()(x1, y1fd, j1fd, hess1fd);
596 HessianCompoundFinite<Test3, Test2, mode>()(x1, y3fd, j3fd, hess3fd);
598 EXPECT_TRUE((y1 - y3).norm() < THRESHOLD_ANALYTIC);
599 EXPECT_TRUE((j1 - j1fd).norm() < THRESHOLD_FINITE_DIFFERENCES);
600 EXPECT_TRUE((j3 - j3fd).norm() < THRESHOLD_FINITE_DIFFERENCES);
601 EXPECT_TRUE((y1fd - y3fd).norm() < THRESHOLD_FINITE_DIFFERENCES);
602 EXPECT_TRUE((y1 - y1fd).norm() < THRESHOLD_FINITE_DIFFERENCES);
604 EXPECT_TRUE(diffNorm(hess1, hess3) < THRESHOLD_ANALYTIC);
605 EXPECT_TRUE(diffNorm(hess1, hess1fd) < THRESHOLD_FINITE_DIFFERENCES_HESSIAN);
606 EXPECT_TRUE(diffNorm(hess3, hess3fd) < THRESHOLD_FINITE_DIFFERENCES_HESSIAN);
607 EXPECT_TRUE(diffNorm(hess1, hess3fd) < THRESHOLD_FINITE_DIFFERENCES_HESSIAN);
612 template <
template <
typename>
class DiffType,
typename Dynamic>
613 void TestHessiansSparse()
615 for (
int i = 0; i < N; ++i)
622 typedef TestingBase<DiffType, MyFunctor1, Function1> Test1;
623 typedef TestingBase<DiffType, MyFunctor2, Function2> Test2;
624 typedef TestingBase<DiffType, MyFunctor3, Function3> Test3;
626 typename Test1::InputType x1;
627 if (Test1::InputType::RowsAtCompileTime == Eigen::Dynamic)
629 x1 = Test1::InputType::Random(4) * INPUT_VECTOR_SCALE;
633 x1 = Test1::InputType::Random() * INPUT_VECTOR_SCALE;
636 typename Test1::ValueType y1;
637 typename Test1::JacobianType j1;
638 typename Test1::Diff::HessianType hess1;
640 typename Test2::ValueType y2;
641 typename Test2::JacobianType j2;
642 typename Test2::Diff::HessianType hess2;
644 typename Test3::ValueType y3;
645 typename Test3::JacobianType j3;
646 typename Test3::Diff::HessianType hess3;
649 HessianFull<Test1>()(x1, y1, j1, hess1);
651 HessianFull<Test2>()(x1, y2, j2, hess2);
653 HessianCompound<Test3>()(y2, y3, j3, hess3, j2, hess2);
656 typedef TestingBase<Eigen::AutoDiffChainHessian, MyFunctor1, Function1> Test1D;
657 typedef TestingBase<Eigen::AutoDiffChainHessian, MyFunctor2, Function2> Test2D;
658 typedef TestingBase<Eigen::AutoDiffChainHessian, MyFunctor3, Function3> Test3D;
660 typename Test1D::ValueType y1d;
661 typename Test1D::JacobianType j1d;
662 typename Test1D::Diff::HessianType hess1d;
664 typename Test2D::ValueType y2d;
665 typename Test2D::JacobianType j2d;
666 typename Test2D::Diff::HessianType hess2d;
668 typename Test3D::ValueType y3d;
669 typename Test3D::JacobianType j3d;
670 typename Test3D::Diff::HessianType hess3d;
673 HessianFull<Test1D>()(x1, y1d, j1d, hess1d);
675 HessianFull<Test2D>()(x1, y2d, j2d, hess2d);
677 HessianCompound<Test3D>()(y2d, y3d, j3d, hess3d, j2d, hess2d);
679 EXPECT_TRUE((y1 - y3).norm() < THRESHOLD_ANALYTIC);
680 EXPECT_TRUE((j1 - j1d).norm() < THRESHOLD_ANALYTIC);
681 EXPECT_TRUE((j3 - j3d).norm() < THRESHOLD_ANALYTIC);
682 EXPECT_TRUE((y1d - y3d).norm() < THRESHOLD_ANALYTIC);
683 EXPECT_TRUE((y1 - y1d).norm() < THRESHOLD_ANALYTIC);
685 EXPECT_TRUE(diffNorm(hess1, hess3) < THRESHOLD_ANALYTIC);
686 EXPECT_TRUE(diffNorm(hess1, hess1d) < THRESHOLD_ANALYTIC);
687 EXPECT_TRUE(diffNorm(hess3, hess3d) < THRESHOLD_ANALYTIC);
688 EXPECT_TRUE(diffNorm(hess1, hess3d) < THRESHOLD_ANALYTIC);
703 TEST(AutoDiffJacobian, JacobianComputationDynamicMatrix)
705 TestJacobians<Eigen::AutoDiffChainJacobian, TestDynamicTrait, Eigen::Forward>();
708 TEST(AutoDiffJacobian, JacobianComputationDynamicMatrixCentralDifferences)
710 TestJacobians<Eigen::AutoDiffChainJacobian, TestDynamicTrait, Eigen::Central>();
713 TEST(AutoDiffJacobian, JacobianComputationTemplatedMatrix)
715 TestJacobians<Eigen::AutoDiffChainJacobian, TestStaticTrait, Eigen::Forward>();
718 TEST(AutoDiffJacobian, JacobianComputationTemplatedMatrixCentralDifferences)
720 TestJacobians<Eigen::AutoDiffChainJacobian, TestStaticTrait, Eigen::Central>();
723 TEST(AutoDiffHessian, JacobianComputationDynamicMatrix)
725 TestJacobians<Eigen::AutoDiffChainHessian, TestDynamicTrait, Eigen::Forward>();
728 TEST(AutoDiffHessian, JacobianComputationDynamicMatrixCentralDifferences)
730 TestJacobians<Eigen::AutoDiffChainHessian, TestDynamicTrait, Eigen::Central>();
733 TEST(AutoDiffHessian, JacobianComputationTemplatedMatrix)
735 TestJacobians<Eigen::AutoDiffChainHessian, TestStaticTrait, Eigen::Forward>();
738 TEST(AutoDiffHessian, JacobianComputationTemplatedMatrixCentralDifferences)
740 TestJacobians<Eigen::AutoDiffChainHessian, TestStaticTrait, Eigen::Central>();
743 TEST(AutoDiffHessian, HessianComputationDynamicMatrix)
745 TestHessians<Eigen::AutoDiffChainHessian, TestDynamicTrait, Eigen::Forward>();
748 TEST(AutoDiffHessian, HessianComputationDynamicMatrixCentralDifferences)
750 TestHessians<Eigen::AutoDiffChainHessian, TestDynamicTrait, Eigen::Central>();
753 TEST(AutoDiffHessian, HessianComputationTemplatedMatrix)
755 TestHessians<Eigen::AutoDiffChainHessian, TestStaticTrait, Eigen::Forward>();
758 TEST(AutoDiffHessian, HessianComputationTemplatedMatrixCentralDifferences)
760 TestHessians<Eigen::AutoDiffChainHessian, TestStaticTrait, Eigen::Central>();
763 TEST(AutoDiffJacobianSparse, JacobianComputationDynamicMatrix)
765 TestJacobiansSparse<Eigen::AutoDiffChainJacobianSparse, TestDynamicTrait>();
768 TEST(AutoDiffJacobianSparse, JacobianComputationTemplatedMatrix)
770 TestJacobiansSparse<Eigen::AutoDiffChainJacobianSparse, TestStaticTrait>();
773 TEST(AutoDiffHessianSparse, HessianComputationDynamicMatrix)
775 TestHessiansSparse<Eigen::AutoDiffChainHessianSparse, TestDynamicTrait>();
778 TEST(AutoDiffHessianSparse, HessianComputationTemplatedMatrix)
780 TestHessiansSparse<Eigen::AutoDiffChainHessianSparse, TestStaticTrait>();
785 int main(
int argc,
char **argv)
787 testing::InitGoogleTest(&argc, argv);
788 int ret = RUN_ALL_TESTS();
IMETHOD Vector diff(const Vector &p_w_a, const Vector &p_w_b, double dt=1)
int main(int argc, char **argv)
TFSIMD_FORCE_INLINE tfScalar dot(const Quaternion &q1, const Quaternion &q2)
TEST(ExoticaCore, testKinematicJacobian)
#define EXPECT_TRUE(args)