mtkmath.hpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. // This is an advanced implementation of the algorithm described in the
  2. // following paper:
  3. // C. Hertzberg, R. Wagner, U. Frese, and L. Schroder. Integratinggeneric sensor fusion algorithms with sound state representationsthrough encapsulation of manifolds.
  4. // CoRR, vol. abs/1107.1119, 2011.[Online]. Available: http://arxiv.org/abs/1107.1119
  5. /*
  6. * Copyright (c) 2019--2023, The University of Hong Kong
  7. * All rights reserved.
  8. *
  9. * Modifier: Dongjiao HE <hdj65822@connect.hku.hk>
  10. *
  11. * Redistribution and use in source and binary forms, with or without
  12. * modification, are permitted provided that the following conditions
  13. * are met:
  14. *
  15. * * Redistributions of source code must retain the above copyright
  16. * notice, this list of conditions and the following disclaimer.
  17. * * Redistributions in binary form must reproduce the above
  18. * copyright notice, this list of conditions and the following
  19. * disclaimer in the documentation and/or other materials provided
  20. * with the distribution.
  21. * * Neither the name of the Universitaet Bremen nor the names of its
  22. * contributors may be used to endorse or promote products derived
  23. * from this software without specific prior written permission.
  24. *
  25. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  26. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  27. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  28. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  29. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  30. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  31. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  32. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  33. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  34. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  35. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36. * POSSIBILITY OF SUCH DAMAGE.
  37. */
  38. /*
  39. * Copyright (c) 2008--2011, Universitaet Bremen
  40. * All rights reserved.
  41. *
  42. * Author: Christoph Hertzberg <chtz@informatik.uni-bremen.de>
  43. *
  44. * Redistribution and use in source and binary forms, with or without
  45. * modification, are permitted provided that the following conditions
  46. * are met:
  47. *
  48. * * Redistributions of source code must retain the above copyright
  49. * notice, this list of conditions and the following disclaimer.
  50. * * Redistributions in binary form must reproduce the above
  51. * copyright notice, this list of conditions and the following
  52. * disclaimer in the documentation and/or other materials provided
  53. * with the distribution.
  54. * * Neither the name of the Universitaet Bremen nor the names of its
  55. * contributors may be used to endorse or promote products derived
  56. * from this software without specific prior written permission.
  57. *
  58. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  59. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  60. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  61. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  62. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  63. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  64. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  65. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  66. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  67. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  68. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  69. * POSSIBILITY OF SUCH DAMAGE.
  70. */
  71. /**
  72. * @file mtk/src/mtkmath.hpp
  73. * @brief several math utility functions.
  74. */
  75. #ifndef MTKMATH_H_
  76. #define MTKMATH_H_
  77. #include <cmath>
  78. #include <boost/math/tools/precision.hpp>
  79. #include "../types/vect.hpp"
  80. #ifndef M_PI
  81. #define M_PI 3.1415926535897932384626433832795
  82. #endif
  83. namespace MTK {
  84. namespace internal {
  85. template<class Manifold>
  86. struct traits {
  87. typedef typename Manifold::scalar scalar;
  88. enum {DOF = Manifold::DOF};
  89. typedef vect<DOF, scalar> vectorized_type;
  90. typedef Eigen::Matrix<scalar, DOF, DOF> matrix_type;
  91. };
  92. template<>
  93. struct traits<float> : traits<Scalar<float> > {};
  94. template<>
  95. struct traits<double> : traits<Scalar<double> > {};
  96. } // namespace internal
  97. /**
  98. * \defgroup MTKMath Mathematical helper functions
  99. */
  100. //@{
  101. //! constant @f$ \pi @f$
  102. const double pi = M_PI;
  103. template<class scalar> inline scalar tolerance();
  104. template<> inline float tolerance<float >() { return 1e-5f; }
  105. template<> inline double tolerance<double>() { return 1e-11; }
  106. /**
  107. * normalize @a x to @f$[-bound, bound] @f$.
  108. *
  109. * result for @f$ x = bound + 2\cdot n\cdot bound @f$ is arbitrary @f$\pm bound @f$.
  110. */
  111. template<class scalar>
  112. inline scalar normalize(scalar x, scalar bound){ //not used
  113. if(std::fabs(x) <= bound) return x;
  114. int r = (int)(x *(scalar(1.0)/ bound));
  115. return x - ((r + (r>>31) + 1) & ~1)*bound;
  116. }
  117. /**
  118. * Calculate cosine and sinc of sqrt(x2).
  119. * @param x2 the squared angle must be non-negative
  120. * @return a pair containing cos and sinc of sqrt(x2)
  121. */
  122. template<class scalar>
  123. std::pair<scalar, scalar> cos_sinc_sqrt(const scalar &x2){
  124. using std::sqrt;
  125. using std::cos;
  126. using std::sin;
  127. static scalar const taylor_0_bound = boost::math::tools::epsilon<scalar>();
  128. static scalar const taylor_2_bound = sqrt(taylor_0_bound);
  129. static scalar const taylor_n_bound = sqrt(taylor_2_bound);
  130. assert(x2>=0 && "argument must be non-negative");
  131. // FIXME check if bigger bounds are possible
  132. if(x2>=taylor_n_bound) {
  133. // slow fall-back solution
  134. scalar x = sqrt(x2);
  135. return std::make_pair(cos(x), sin(x)/x); // x is greater than 0.
  136. }
  137. // FIXME Replace by Horner-Scheme (4 instead of 5 FLOP/term, numerically more stable, theoretically cos and sinc can be calculated in parallel using SSE2 mulpd/addpd)
  138. // TODO Find optimal coefficients using Remez algorithm
  139. static scalar const inv[] = {1/3., 1/4., 1/5., 1/6., 1/7., 1/8., 1/9.};
  140. scalar cosi = 1., sinc=1;
  141. scalar term = -1/2. * x2;
  142. for(int i=0; i<3; ++i) {
  143. cosi += term;
  144. term *= inv[2*i];
  145. sinc += term;
  146. term *= -inv[2*i+1] * x2;
  147. }
  148. return std::make_pair(cosi, sinc);
  149. }
  150. template<typename Base>
  151. Eigen::Matrix<typename Base::scalar, 3, 3> hat(const Base& v) {
  152. Eigen::Matrix<typename Base::scalar, 3, 3> res;
  153. res << 0, -v[2], v[1],
  154. v[2], 0, -v[0],
  155. -v[1], v[0], 0;
  156. return res;
  157. }
  158. template<typename Base>
  159. Eigen::Matrix<typename Base::scalar, 3, 3> A_inv_trans(const Base& v){
  160. Eigen::Matrix<typename Base::scalar, 3, 3> res;
  161. if(v.norm() > MTK::tolerance<typename Base::scalar>())
  162. {
  163. res = Eigen::Matrix<typename Base::scalar, 3, 3>::Identity() + 0.5 * hat<Base>(v) + (1 - v.norm() * std::cos(v.norm() / 2) / 2 / std::sin(v.norm() / 2)) * hat(v) * hat(v) / v.squaredNorm();
  164. }
  165. else
  166. {
  167. res = Eigen::Matrix<typename Base::scalar, 3, 3>::Identity();
  168. }
  169. return res;
  170. }
  171. template<typename Base>
  172. Eigen::Matrix<typename Base::scalar, 3, 3> A_inv(const Base& v){
  173. Eigen::Matrix<typename Base::scalar, 3, 3> res;
  174. if(v.norm() > MTK::tolerance<typename Base::scalar>())
  175. {
  176. res = Eigen::Matrix<typename Base::scalar, 3, 3>::Identity() - 0.5 * hat<Base>(v) + (1 - v.norm() * std::cos(v.norm() / 2) / 2 / std::sin(v.norm() / 2)) * hat(v) * hat(v) / v.squaredNorm();
  177. }
  178. else
  179. {
  180. res = Eigen::Matrix<typename Base::scalar, 3, 3>::Identity();
  181. }
  182. return res;
  183. }
  184. template<typename scalar>
  185. Eigen::Matrix<scalar, 2, 3> S2_w_expw_( Eigen::Matrix<scalar, 2, 1> v, scalar length)
  186. {
  187. Eigen::Matrix<scalar, 2, 3> res;
  188. scalar norm = std::sqrt(v[0]*v[0] + v[1]*v[1]);
  189. if(norm < MTK::tolerance<scalar>()){
  190. res = Eigen::Matrix<scalar, 2, 3>::Zero();
  191. res(0, 1) = 1;
  192. res(1, 2) = 1;
  193. res /= length;
  194. }
  195. else{
  196. res << -v[0]*(1/norm-1/std::tan(norm))/std::sin(norm), norm/std::sin(norm), 0,
  197. -v[1]*(1/norm-1/std::tan(norm))/std::sin(norm), 0, norm/std::sin(norm);
  198. res /= length;
  199. }
  200. }
  201. template<typename Base>
  202. Eigen::Matrix<typename Base::scalar, 3, 3> A_matrix(const Base & v){
  203. Eigen::Matrix<typename Base::scalar, 3, 3> res;
  204. double squaredNorm = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
  205. double norm = std::sqrt(squaredNorm);
  206. if(norm < MTK::tolerance<typename Base::scalar>()){
  207. res = Eigen::Matrix<typename Base::scalar, 3, 3>::Identity();
  208. }
  209. else{
  210. res = Eigen::Matrix<typename Base::scalar, 3, 3>::Identity() + (1 - std::cos(norm)) / squaredNorm * hat(v) + (1 - std::sin(norm) / norm) / squaredNorm * hat(v) * hat(v);
  211. }
  212. return res;
  213. }
  214. template<class scalar, int n>
  215. scalar exp(vectview<scalar, n> result, vectview<const scalar, n> vec, const scalar& scale = 1) {
  216. scalar norm2 = vec.squaredNorm();
  217. std::pair<scalar, scalar> cos_sinc = cos_sinc_sqrt(scale*scale * norm2);
  218. scalar mult = cos_sinc.second * scale;
  219. result = mult * vec;
  220. return cos_sinc.first;
  221. }
  222. /**
  223. * Inverse function to @c exp.
  224. *
  225. * @param result @c vectview to the result
  226. * @param w scalar part of input
  227. * @param vec vector part of input
  228. * @param scale scale result by this value
  229. * @param plus_minus_periodicity if true values @f$[w, vec]@f$ and @f$[-w, -vec]@f$ give the same result
  230. */
  231. template<class scalar, int n>
  232. void log(vectview<scalar, n> result,
  233. const scalar &w, const vectview<const scalar, n> vec,
  234. const scalar &scale, bool plus_minus_periodicity)
  235. {
  236. // FIXME implement optimized case for vec.squaredNorm() <= tolerance() * (w*w) via Rational Remez approximation ~> only one division
  237. scalar nv = vec.norm();
  238. if(nv < tolerance<scalar>()) {
  239. if(!plus_minus_periodicity && w < 0) {
  240. // find the maximal entry:
  241. int i;
  242. nv = vec.cwiseAbs().maxCoeff(&i);
  243. result = scale * std::atan2(nv, w) * vect<n, scalar>::Unit(i);
  244. return;
  245. }
  246. nv = tolerance<scalar>();
  247. }
  248. scalar s = scale / nv * (plus_minus_periodicity ? std::atan(nv / w) : std::atan2(nv, w) );
  249. result = s * vec;
  250. }
  251. } // namespace MTK
  252. #endif /* MTKMATH_H_ */