PageRenderTime 42ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/include/roboptim/core/detail/utility.hh

https://github.com/roboptim/roboptim-core
C++ Header | 361 lines | 180 code | 38 blank | 143 comment | 2 complexity | c9c306bfbc03e320ced363dd6c640f47 MD5 | raw file
  1. // Copyright (C) 2014 by Benjamin Chretien, CNRS-LIRMM.
  2. //
  3. // This file is part of the roboptim.
  4. //
  5. // roboptim is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU Lesser General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. //
  10. // roboptim is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. // GNU Lesser General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU Lesser General Public License
  16. // along with roboptim. If not, see <http://www.gnu.org/licenses/>.
  17. #ifndef ROBOPTIM_CORE_DETAIL_UTILITY_HH
  18. # define ROBOPTIM_CORE_DETAIL_UTILITY_HH
  19. # include <boost/mpl/assert.hpp>
  20. # include <boost/mpl/back_inserter.hpp>
  21. # include <boost/mpl/copy.hpp>
  22. # include <boost/mpl/count_if.hpp>
  23. # include <boost/mpl/fold.hpp>
  24. # include <boost/mpl/greater.hpp>
  25. # include <boost/mpl/has_xxx.hpp>
  26. # include <boost/mpl/logical.hpp>
  27. # include <boost/mpl/transform.hpp>
  28. # include <boost/mpl/vector.hpp>
  29. # include <boost/variant.hpp>
  30. # include <boost/shared_ptr.hpp>
  31. # include <boost/type_traits/is_base_of.hpp>
  32. # include <vector>
  33. # include <Eigen/Core>
  34. # include <Eigen/StdVector>
  35. namespace roboptim
  36. {
  37. namespace detail
  38. {
  39. /// \brief Transform a types list into a types list of shared pointers.
  40. ///
  41. /// If the input list is:
  42. /// \code
  43. /// boost::mpl::vector<int, long>
  44. /// \endcode
  45. ///
  46. /// then the result (type) will be:
  47. /// \code
  48. /// boost::mpl::vector<boost::shared_ptr<int>,
  49. /// boost::shared_ptr<long> >
  50. /// \endcode
  51. ///
  52. /// \tparam CLIST list that will be transformed
  53. template <typename CLIST>
  54. struct add_shared_ptr
  55. {
  56. /// \brief Result.
  57. typedef typename boost::mpl::transform
  58. <CLIST, typename boost::shared_ptr<boost::mpl::_1> >::type type;
  59. };
  60. /// \brief Generate a Boost.Variant of shared pointers from the static
  61. /// constraints types list.
  62. ///
  63. /// For instance, if one instantiates
  64. /// \code
  65. /// Problem<QuadraticFunction, vector<LinearFunction, QuadraticFunction> >
  66. /// \endcode
  67. /// then this type will be set to:
  68. /// \code
  69. /// boost::variant<boost::shared_ptr<LinearFunction>,
  70. /// boost::shared_ptr<QuadraticFunction> >
  71. /// \endcode
  72. ///
  73. /// \tparam CLIST vector of types
  74. template <typename CLIST>
  75. struct shared_ptr_variant :
  76. boost::make_variant_over<typename detail::add_shared_ptr<CLIST>::type>
  77. {};
  78. BOOST_MPL_HAS_XXX_TRAIT_DEF (Scalar)
  79. BOOST_MPL_HAS_XXX_TRAIT_DEF (Index)
  80. BOOST_MPL_HAS_XXX_TRAIT_DEF (StorageKind)
  81. /// \brief Check whether the type provided is an Eigen type.
  82. ///
  83. /// This solution comes from a post in the Eigen forums:
  84. /// https://forum.kde.org/viewtopic.php?f=74&t=121280
  85. ///
  86. /// \tparam T
  87. template<typename T>
  88. struct is_eigen_type
  89. : boost::mpl::and_<has_Scalar<T>,
  90. has_Index<T>,
  91. has_StorageKind<T> >
  92. {};
  93. /// \brief Return an Eigen-aligned std::vector if required, else use the
  94. /// default allocator.
  95. /// \tparam V type of the elements.
  96. template <typename V>
  97. struct aligned_vector_type
  98. : boost::mpl::if_<
  99. is_eigen_type<V>,
  100. typename boost::mpl::if_c<(sizeof (V) % 16) == 0,
  101. std::vector<V, Eigen::aligned_allocator<V> >,
  102. std::vector<V> >::type,
  103. std::vector<V> >
  104. {};
  105. /// \brief Return the type of a const reference to an Eigen matrix, using
  106. /// Eigen's Ref.
  107. ///
  108. /// \tparam T Eigen dense matrix/vector type.
  109. template <typename T>
  110. struct const_eigen_ref
  111. {
  112. typedef const Eigen::Ref<const T>& type;
  113. };
  114. /// \brief Return the proper const reference type of a given type.
  115. ///
  116. /// For instance:
  117. /// * const_ref<float>::value_t == const float&
  118. /// * const_ref<argument_t>::value_t == const_argument_ref
  119. ///
  120. /// This returns a const Eigen::Ref for dense Eigen matrices, else a
  121. /// simple const reference.
  122. ///
  123. /// Note: this currently does not cover all cases (e.g. sparse
  124. /// vectors), but should work for argument_t/vector_t (dense
  125. /// vectors).
  126. ///
  127. /// \tparam T type.
  128. template <typename T>
  129. struct const_ref
  130. {
  131. typedef typename
  132. boost::mpl::if_<is_eigen_type<T>,
  133. const_eigen_ref<T>,
  134. boost::add_reference<typename boost::add_const<T>::type> >
  135. ::type::type type;
  136. };
  137. /// \brief Get the matrix stride type for a row vector, given a matrix
  138. /// storage order.
  139. ///
  140. /// This solves compiler errors in Eigen when dealing with Eigen::Refs,
  141. /// row vectors and different storage orders.
  142. ///
  143. /// \tparam SO storage order (Eigen::ColMajor or Eigen::RowMajor).
  144. template <int SO>
  145. struct row_vector_stride
  146. {
  147. typedef Eigen::InnerStride<(SO == Eigen::RowMajor)? 1:-1> type;
  148. };
  149. /// \brief Converts CLIST to a boost::mpl::vector to ensure a similar
  150. /// behavior for codes using different random access sequences (vector,
  151. /// list, etc.).
  152. ///
  153. /// In the case of boost::mpl::vector, this ensures a normalized
  154. /// representation of the vector (boost::mpl::vector converted to
  155. /// boost::mpl::v_item) and orders the constraints in a proper way. This
  156. /// makes the use of typeid comparison possible.
  157. ///
  158. /// \tparam CLIST vector of types
  159. template <typename CLIST>
  160. struct list_converter :
  161. boost::mpl::copy
  162. <CLIST, boost::mpl::back_inserter<boost::mpl::vector<> > >
  163. {};
  164. /// \brief Whether a sequence of types contains a base of a given type.
  165. /// \tparam Sequence sequence of types.
  166. /// \tparam Type type.
  167. template <typename Sequence, typename Type>
  168. struct contains_base_of
  169. : boost::mpl::greater<
  170. boost::mpl::int_<
  171. boost::mpl::count_if<Sequence,
  172. boost::is_base_of<boost::mpl::_, Type> >
  173. ::value>,
  174. boost::mpl::int_<0> >
  175. {};
  176. /// \brief Get the descendant among two relatives.
  177. /// Type1 and Type2 are expected to be base/derivative of one another.
  178. /// \tparam Type1 first relative.
  179. /// \tparam Type2 second relative.
  180. template <typename Type1, typename Type2>
  181. struct get_descendant
  182. : boost::mpl::if_<boost::is_base_of<Type1, Type2>, Type2, Type1>
  183. {
  184. BOOST_MPL_ASSERT_MSG((boost::mpl::or_<boost::is_base_of<Type1, Type2>,
  185. boost::is_base_of<Type2, Type1> >::value),
  186. ONE_SHOULD_INHERIT_FROM_THE_OTHER, (Type1&, Type2&));
  187. };
  188. /// \brief Checks whether C is a valid constraint type in CLIST.
  189. /// \tparam C constraint type.
  190. /// \tparam CLIST a vector of constraint types.
  191. template <typename C, typename CLIST>
  192. struct check_constraint_type
  193. : boost::mpl::fold<CLIST,
  194. boost::mpl::bool_<false>,
  195. boost::mpl::if_<boost::is_base_of<boost::mpl::_2, C>,
  196. boost::mpl::bool_<true>,
  197. boost::mpl::_1>
  198. >
  199. {};
  200. /// \brief Get the constraint type of CLIST that best match C.
  201. /// \tparam C constraint type.
  202. /// \tparam CLIST a vector of constraint types.
  203. template <typename C, typename CLIST>
  204. struct cast_constraint_type
  205. {
  206. typedef typename
  207. boost::mpl::fold <CLIST,
  208. void,
  209. boost::mpl::if_<boost::is_base_of<boost::mpl::_2, C>,
  210. boost::mpl::if_<boost::is_void<boost::mpl::_1>,
  211. boost::mpl::_2,
  212. detail::get_descendant<boost::mpl::_1, boost::mpl::_2> >,
  213. boost::mpl::_1>
  214. >::type type;
  215. };
  216. /// \brief Checks whether the function types derives from Function or
  217. /// SparseFunction.
  218. ///
  219. /// \tparam F function type.
  220. template <typename F>
  221. struct derives_from_function :
  222. boost::mpl::or_<boost::is_base_of<Function, F>,
  223. boost::is_base_of<SparseFunction, F> >
  224. {};
  225. /// \brief Checks whether the function type derives from
  226. /// DifferentiableFunction or DifferentiableSparseFunction.
  227. ///
  228. /// \tparam F function type.
  229. template <typename F>
  230. struct derives_from_differentiable_function :
  231. boost::mpl::or_<boost::is_base_of<DifferentiableFunction, F>,
  232. boost::is_base_of<DifferentiableSparseFunction, F> >
  233. {};
  234. /// \brief Checks whether the function type derives from
  235. /// TwiceDifferentiableFunction or TwiceDifferentiableSparseFunction.
  236. ///
  237. /// \tparam F function type.
  238. template <typename F>
  239. struct derives_from_twice_differentiable_function :
  240. boost::mpl::or_<boost::is_base_of<TwiceDifferentiableFunction, F>,
  241. boost::is_base_of<TwiceDifferentiableSparseFunction, F> >
  242. {};
  243. /// \brief Checks whether the function type derives from
  244. /// NTimesDerivableFunction.
  245. ///
  246. /// \tparam F function type.
  247. template <typename F>
  248. struct derives_from_ntimes_derivable_function :
  249. boost::is_base_of<NTimesDerivableFunction<2>, F>
  250. {};
  251. /// \brief Checks whether all the constraints derive from Function or
  252. /// SparseFunction.
  253. ///
  254. /// \tparam CLIST a vector of constraint types.
  255. template <typename CLIST>
  256. struct list_derives_from_function :
  257. boost::mpl::fold<CLIST,
  258. boost::mpl::bool_<true>,
  259. boost::mpl::if_<
  260. derives_from_function<boost::mpl::_2>,
  261. boost::mpl::_1,
  262. boost::mpl::bool_<false> >
  263. >
  264. {};
  265. /// \brief Check that CLIST_ is a subset of CLIST (i.e. all the
  266. /// functions of CLIST_ derive from functions of CLIST).
  267. /// \tparam CLIST_ a vector of constraint types.
  268. /// \tparam CLIST a vector of constraint types.
  269. template <typename CLIST_, typename CLIST>
  270. struct is_compatible_list
  271. {
  272. // The algorithm is as follows:
  273. // (0) outer_ok = true
  274. // (1) for c_ in FLIST_:
  275. // (2) inner_ok = false
  276. // (3) for c in FLIST:
  277. // (4) if c is_base_of c_:
  278. // (5) inner_ok = true
  279. // (6) if not inner_ok:
  280. // (7) outer_ok = false
  281. // (8) return outer_ok
  282. typedef typename
  283. boost::mpl::fold<CLIST_, // (1)
  284. boost::mpl::bool_<true>, // (0)
  285. boost::mpl::if_< // (6)
  286. contains_base_of<CLIST,boost::mpl::_2>, // (2,3,4,5)
  287. boost::mpl::_1,
  288. boost::mpl::bool_<false> // (7)
  289. >
  290. >::type type;
  291. };
  292. /// \brief Convert a constraint to a proper type.
  293. /// \tparam CLIST a vector of valid constraint types.
  294. template <typename CLIST>
  295. struct ConvertConstraint
  296. {
  297. template <typename C>
  298. boost::shared_ptr<typename cast_constraint_type<C, CLIST>::type>
  299. operator () (const boost::shared_ptr<C>& c) const
  300. {
  301. return boost::static_pointer_cast
  302. <typename cast_constraint_type<C, CLIST>::type> (c);
  303. }
  304. };
  305. /// \brief Convert a constraint from a Boost.Variant to
  306. /// an adequate constraint type depending on the problem's
  307. /// constraints type.
  308. ///
  309. /// \tparam P problem type.
  310. template <typename P>
  311. struct ConvertConstraintVariant
  312. : public boost::static_visitor<typename P::constraint_t>
  313. {
  314. template <typename U>
  315. typename P::constraint_t operator () (const U& c) const
  316. {
  317. ConvertConstraint<typename P::constraintsList_t> converter;
  318. return converter (c);
  319. }
  320. };
  321. } // end of namespace detail.
  322. } // end of namespace roboptim.
  323. #endif //! ROBOPTIM_CORE_DETAIL_UTILITY_HH