/tests/kernel/testLinearizer.cpp

https://github.com/nnormand/DGtal · C++ · 349 lines · 262 code · 27 blank · 60 comment · 34 complexity · 50fa22cbe48ce61baa5dca192cc71886 MD5 · raw file

  1. /**
  2. * This program is free software: you can redistribute it and/or modify
  3. * it under the terms of the GNU Lesser General Public License as
  4. * published by the Free Software Foundation, either version 3 of the
  5. * License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. *
  15. **/
  16. /**
  17. * @file testLinearizer.cpp
  18. * @ingroup Tests
  19. * @author Roland Denis (\c roland.denis@univ-smb.fr )
  20. *
  21. *
  22. * @date 2015/09/10
  23. *
  24. * This file is part of the DGtal library
  25. */
  26. /**
  27. * Description of testLinearizer.cpp <p>
  28. * Aim: Tests of linearization (point to index) et reverse process (index to point) for HyperRectDomain.
  29. */
  30. #include <cstddef>
  31. #include <cmath>
  32. #include "DGtalCatch.h"
  33. #include <DGtal/kernel/SpaceND.h>
  34. #include <DGtal/kernel/domains/HyperRectDomain.h>
  35. #include <DGtal/kernel/domains/Linearizer.h>
  36. using namespace DGtal;
  37. // Previous version of the linearizer, used here for reference results.
  38. namespace
  39. {
  40. /**
  41. * Class template for linearization of the coordinates of a Point.
  42. * This class template is to be specialized for efficiency for dimensions 1,
  43. * 2 and 3 to prevent the use of a loop in these cases.
  44. *
  45. * @tparam Domain an instance of HyperRectDomain
  46. * @tparam dimension domain dimension
  47. */
  48. template < typename Domain, int dimension>
  49. struct linearizer
  50. {
  51. typedef typename Domain::Point Point;
  52. typedef typename Domain::Size Size;
  53. /**
  54. * Compute the linearized offset of a point in a vector container.
  55. *
  56. * @param aPoint a point
  57. * @param lowerBound lower bound of the image domain.
  58. * @param extent extension of the image domain.
  59. *
  60. * @return the index
  61. */
  62. static Size apply( const Point & aPoint, const Point & lowerBound,
  63. const Point & extent )
  64. {
  65. Size pos = aPoint[ 0 ] - lowerBound[ 0 ] ;
  66. Size multiplier = 1;
  67. for (typename Domain::Dimension k = 1 ; k < dimension ; ++k)
  68. {
  69. multiplier *= extent[ k-1 ];
  70. pos += multiplier * ( aPoint[ k ] - lowerBound[ k ] );
  71. }
  72. return pos;
  73. }
  74. };
  75. /**
  76. * Specialization of the linearizer class for dimension 1.
  77. *
  78. */
  79. template < typename Domain >
  80. struct linearizer< Domain, 1 >
  81. {
  82. typedef typename Domain::Point Point;
  83. typedef typename Domain::Size Size;
  84. static Size apply( const Point & aPoint,
  85. const Point & lowerBound,
  86. const Point & /*extent*/ )
  87. {
  88. return aPoint[ 0 ] - lowerBound[ 0 ];
  89. }
  90. };
  91. /**
  92. * Specialization of the linearizer class for dimension 2.
  93. *
  94. */
  95. template < typename Domain >
  96. struct linearizer< Domain, 2 >
  97. {
  98. typedef typename Domain::Point Point;
  99. typedef typename Domain::Size Size;
  100. static Size apply( const Point & aPoint,
  101. const Point & lowerBound,
  102. const Point & extent )
  103. {
  104. return ( aPoint[ 0 ] - lowerBound[ 0 ] ) + extent[ 0 ] *
  105. (aPoint[ 1 ] - lowerBound[ 1 ] );
  106. }
  107. };
  108. /**
  109. * Specialization of the linearizer class for dimension 3.
  110. *
  111. */
  112. template < typename Domain >
  113. struct linearizer< Domain, 3 >
  114. {
  115. typedef typename Domain::Point Point;
  116. typedef typename Domain::Size Size;
  117. static Size apply( const Point & aPoint,
  118. const Point & lowerBound,
  119. const Point & extent )
  120. {
  121. Size res = aPoint[ 0 ] - lowerBound[ 0 ];
  122. Size multiplier = extent[ 0 ];
  123. res += multiplier * ( aPoint[ 1 ] - lowerBound[ 1 ] );
  124. multiplier *= extent[ 1 ];
  125. res += multiplier * ( aPoint[ 2 ] - lowerBound[ 2 ] );
  126. return res;
  127. }
  128. };
  129. }
  130. /// Converter between col-major and row-major storage order.
  131. template < typename StorageOrder >
  132. struct PointConverter;
  133. template <>
  134. struct PointConverter<ColMajorStorage>
  135. {
  136. template < typename TPoint >
  137. static inline
  138. TPoint apply( TPoint const& aPoint )
  139. {
  140. return aPoint;
  141. }
  142. };
  143. template <>
  144. struct PointConverter<RowMajorStorage>
  145. {
  146. template < typename TPoint >
  147. static inline
  148. TPoint apply( TPoint const& aPoint )
  149. {
  150. TPoint result;
  151. for ( std::size_t i = 0 ; i < TPoint::dimension ; ++i )
  152. result[i] = aPoint[ TPoint::dimension - i - 1 ];
  153. return result;
  154. }
  155. };
  156. #define TEST_LINEARIZER( N , ORDER ) \
  157. TEST_CASE( "Testing Linearizer in dimension " #N " with " #ORDER, "[test][dim" #N "][" #ORDER "]" )\
  158. {\
  159. \
  160. typedef SpaceND<N> Space;\
  161. typedef HyperRectDomain<Space> Domain;\
  162. typedef Space::Point Point;\
  163. \
  164. typedef linearizer<Domain, N> RefLinearizer;\
  165. typedef Linearizer<Domain, ORDER> NewLinearizer;\
  166. \
  167. typedef PointConverter<ORDER> RefConverter;\
  168. \
  169. std::size_t size = 1e3;\
  170. \
  171. Point lowerBound;\
  172. for ( std::size_t i = 0 ; i < N ; ++i )\
  173. lowerBound[i] = 1 + 7*i;\
  174. \
  175. std::size_t dim_size = std::size_t( std::pow( double(size), 1./N ) + 0.5 );\
  176. Point upperBound;\
  177. for ( std::size_t i = 0; i < N ; ++i )\
  178. upperBound[i] = lowerBound[i] + dim_size + i;\
  179. \
  180. Domain domain( lowerBound, upperBound );\
  181. Point extent = upperBound - lowerBound + Point::diagonal(1);\
  182. \
  183. Point refLowerBound = RefConverter::apply(lowerBound);\
  184. Point refExtent = RefConverter::apply(extent);\
  185. \
  186. SECTION( "Testing getIndex(Point, Point, Extent) syntax" )\
  187. {\
  188. for ( Domain::ConstIterator it = domain.begin(), it_end = domain.end(); it != it_end ; ++it )\
  189. REQUIRE( RefLinearizer::apply( RefConverter::apply(*it), refLowerBound, refExtent ) == NewLinearizer::getIndex( *it, lowerBound, extent ) );\
  190. }\
  191. \
  192. SECTION( "Testing getIndex(Point, Extent) syntax" )\
  193. {\
  194. for ( Domain::ConstIterator it = domain.begin(), it_end = domain.end(); it != it_end ; ++it )\
  195. REQUIRE( RefLinearizer::apply( RefConverter::apply(*it), refLowerBound, refExtent ) == NewLinearizer::getIndex( *it - lowerBound, extent ) );\
  196. }\
  197. \
  198. SECTION( "Testing getIndex(Point, Domain) syntax" )\
  199. {\
  200. for ( Domain::ConstIterator it = domain.begin(), it_end = domain.end(); it != it_end ; ++it )\
  201. REQUIRE( RefLinearizer::apply( RefConverter::apply(*it), refLowerBound, refExtent ) == NewLinearizer::getIndex( *it, domain ) );\
  202. }\
  203. \
  204. SECTION( "Testing getPoint(Index, Point, Extent) syntax" )\
  205. {\
  206. for ( std::size_t i = 0; i < domain.size(); ++i )\
  207. REQUIRE( RefLinearizer::apply( RefConverter::apply( NewLinearizer::getPoint( i, lowerBound, extent ) ), refLowerBound, refExtent ) == i );\
  208. }\
  209. \
  210. SECTION( "Testing getPoint(Index, Extent) syntax" )\
  211. {\
  212. for ( std::size_t i = 0; i < domain.size(); ++i )\
  213. REQUIRE( RefLinearizer::apply( RefConverter::apply( NewLinearizer::getPoint( i, extent ) + lowerBound ), refLowerBound, refExtent ) == i );\
  214. }\
  215. \
  216. SECTION( "Testing getPoint(Index, Domain) syntax" )\
  217. {\
  218. for ( std::size_t i = 0; i < domain.size(); ++i )\
  219. REQUIRE( RefLinearizer::apply( RefConverter::apply( NewLinearizer::getPoint( i, domain ) ), refLowerBound, refExtent ) == i );\
  220. }\
  221. }
  222. #define BENCH_LINEARIZER( N , ORDER ) \
  223. TEST_CASE( "Benchmarking Linearizer in dimension " #N " with " #ORDER, "[.bench][dim" #N "][" #ORDER "]" )\
  224. {\
  225. \
  226. typedef SpaceND<N> Space;\
  227. typedef HyperRectDomain<Space> Domain;\
  228. typedef Space::Point Point;\
  229. \
  230. typedef linearizer<Domain, N> RefLinearizer;\
  231. typedef Linearizer<Domain, ORDER> NewLinearizer;\
  232. \
  233. typedef PointConverter<ORDER> RefConverter;\
  234. \
  235. std::size_t size = 1e8;\
  236. \
  237. Point lowerBound;\
  238. for ( std::size_t i = 0 ; i < N ; ++i )\
  239. lowerBound[i] = 1 + 7*i;\
  240. \
  241. std::size_t dim_size = std::size_t( std::pow( double(size), 1./N ) + 0.5 );\
  242. Point upperBound;\
  243. for ( std::size_t i = 0; i < N ; ++i )\
  244. upperBound[i] = lowerBound[i] + dim_size + i;\
  245. \
  246. Domain domain( lowerBound, upperBound );\
  247. Point extent = upperBound - lowerBound + Point::diagonal(1);\
  248. \
  249. Point refLowerBound = RefConverter::apply(lowerBound);\
  250. Point refExtent = RefConverter::apply(extent);\
  251. \
  252. std::size_t sum = 0;\
  253. \
  254. for ( Domain::ConstIterator it = domain.begin(), it_end = domain.end(); it != it_end ; ++it )\
  255. sum += RefLinearizer::apply( RefConverter::apply(*it), refLowerBound, refExtent );\
  256. REQUIRE( sum > 0 );\
  257. sum = 0;\
  258. \
  259. SECTION( "Benchmarking reference linearizer" )\
  260. {\
  261. for ( Domain::ConstIterator it = domain.begin(), it_end = domain.end(); it != it_end ; ++it )\
  262. sum += RefLinearizer::apply( RefConverter::apply(*it), refLowerBound, refExtent );\
  263. }\
  264. \
  265. SECTION( "Benchmarking getIndex(Point, Point, Extent) syntax" )\
  266. {\
  267. for ( Domain::ConstIterator it = domain.begin(), it_end = domain.end(); it != it_end ; ++it )\
  268. sum += NewLinearizer::getIndex( *it, lowerBound, extent );\
  269. }\
  270. \
  271. SECTION( "Benchmarking getIndex(Point, Extent) syntax" )\
  272. {\
  273. for ( Domain::ConstIterator it = domain.begin(), it_end = domain.end(); it != it_end ; ++it )\
  274. sum += NewLinearizer::getIndex( *it, extent );\
  275. }\
  276. \
  277. SECTION( "Benchmarking getIndex(Point, Domain) syntax" )\
  278. {\
  279. for ( Domain::ConstIterator it = domain.begin(), it_end = domain.end(); it != it_end ; ++it )\
  280. sum += NewLinearizer::getIndex( *it, domain );\
  281. }\
  282. \
  283. SECTION( "Benchmarking getPoint(Index, Point, Extent) syntax" )\
  284. {\
  285. for ( std::size_t i = 0; i < domain.size(); ++i )\
  286. sum += NewLinearizer::getPoint( i, lowerBound, extent )[N-1];\
  287. }\
  288. \
  289. SECTION( "Benchmarking getPoint(Index, Extent) syntax" )\
  290. {\
  291. for ( std::size_t i = 0; i < domain.size(); ++i )\
  292. sum += NewLinearizer::getPoint( i, extent )[N-1];\
  293. }\
  294. \
  295. SECTION( "Benchmarking getPoint(Index, Domain) syntax" )\
  296. {\
  297. for ( std::size_t i = 0; i < domain.size(); ++i )\
  298. sum += NewLinearizer::getPoint( i, domain )[N-1];\
  299. }\
  300. \
  301. REQUIRE( sum > 0 );\
  302. }
  303. TEST_LINEARIZER( 1, ColMajorStorage )
  304. TEST_LINEARIZER( 2, ColMajorStorage )
  305. TEST_LINEARIZER( 3, ColMajorStorage )
  306. TEST_LINEARIZER( 4, ColMajorStorage )
  307. TEST_LINEARIZER( 5, ColMajorStorage )
  308. TEST_LINEARIZER( 1, RowMajorStorage )
  309. TEST_LINEARIZER( 2, RowMajorStorage )
  310. TEST_LINEARIZER( 3, RowMajorStorage )
  311. TEST_LINEARIZER( 4, RowMajorStorage )
  312. TEST_LINEARIZER( 5, RowMajorStorage )
  313. BENCH_LINEARIZER( 1, ColMajorStorage )
  314. BENCH_LINEARIZER( 2, ColMajorStorage )
  315. BENCH_LINEARIZER( 3, ColMajorStorage )
  316. BENCH_LINEARIZER( 4, ColMajorStorage )
  317. BENCH_LINEARIZER( 5, ColMajorStorage )
  318. BENCH_LINEARIZER( 1, RowMajorStorage )
  319. BENCH_LINEARIZER( 2, RowMajorStorage )
  320. BENCH_LINEARIZER( 3, RowMajorStorage )
  321. BENCH_LINEARIZER( 4, RowMajorStorage )
  322. BENCH_LINEARIZER( 5, RowMajorStorage )