cost_function_to_functor_test.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. // Ceres Solver - A fast non-linear least squares minimizer
  2. // Copyright 2023 Google Inc. All rights reserved.
  3. // http://ceres-solver.org/
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are met:
  7. //
  8. // * Redistributions of source code must retain the above copyright notice,
  9. // this list of conditions and the following disclaimer.
  10. // * Redistributions in binary form must reproduce the above copyright notice,
  11. // this list of conditions and the following disclaimer in the documentation
  12. // and/or other materials provided with the distribution.
  13. // * Neither the name of Google Inc. nor the names of its contributors may be
  14. // used to endorse or promote products derived from this software without
  15. // specific prior written permission.
  16. //
  17. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  18. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  21. // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  22. // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  23. // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  24. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  25. // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  26. // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  27. // POSSIBILITY OF SUCH DAMAGE.
  28. //
  29. // Author: sameeragarwal@google.com (Sameer Agarwal)
  30. #include "ceres/cost_function_to_functor.h"
  31. #include <cstdint>
  32. #include <memory>
  33. #include <vector>
  34. #include "ceres/autodiff_cost_function.h"
  35. #include "ceres/dynamic_autodiff_cost_function.h"
  36. #include "ceres/dynamic_cost_function_to_functor.h"
  37. #include "gtest/gtest.h"
  38. namespace ceres::internal {
  39. const double kTolerance = 1e-18;
  40. static void ExpectCostFunctionsAreEqual(
  41. const CostFunction& cost_function,
  42. const CostFunction& actual_cost_function) {
  43. EXPECT_EQ(cost_function.num_residuals(),
  44. actual_cost_function.num_residuals());
  45. const int num_residuals = cost_function.num_residuals();
  46. const std::vector<int32_t>& parameter_block_sizes =
  47. cost_function.parameter_block_sizes();
  48. const std::vector<int32_t>& actual_parameter_block_sizes =
  49. actual_cost_function.parameter_block_sizes();
  50. EXPECT_EQ(parameter_block_sizes.size(), actual_parameter_block_sizes.size());
  51. int num_parameters = 0;
  52. for (int i = 0; i < parameter_block_sizes.size(); ++i) {
  53. EXPECT_EQ(parameter_block_sizes[i], actual_parameter_block_sizes[i]);
  54. num_parameters += parameter_block_sizes[i];
  55. }
  56. std::unique_ptr<double[]> parameters(new double[num_parameters]);
  57. for (int i = 0; i < num_parameters; ++i) {
  58. parameters[i] = static_cast<double>(i) + 1.0;
  59. }
  60. std::unique_ptr<double[]> residuals(new double[num_residuals]);
  61. std::unique_ptr<double[]> jacobians(
  62. new double[num_parameters * num_residuals]);
  63. std::unique_ptr<double[]> actual_residuals(new double[num_residuals]);
  64. std::unique_ptr<double[]> actual_jacobians(
  65. new double[num_parameters * num_residuals]);
  66. std::unique_ptr<double*[]> parameter_blocks(
  67. new double*[parameter_block_sizes.size()]);
  68. std::unique_ptr<double*[]> jacobian_blocks(
  69. new double*[parameter_block_sizes.size()]);
  70. std::unique_ptr<double*[]> actual_jacobian_blocks(
  71. new double*[parameter_block_sizes.size()]);
  72. num_parameters = 0;
  73. for (int i = 0; i < parameter_block_sizes.size(); ++i) {
  74. parameter_blocks[i] = parameters.get() + num_parameters;
  75. jacobian_blocks[i] = jacobians.get() + num_parameters * num_residuals;
  76. actual_jacobian_blocks[i] =
  77. actual_jacobians.get() + num_parameters * num_residuals;
  78. num_parameters += parameter_block_sizes[i];
  79. }
  80. EXPECT_TRUE(
  81. cost_function.Evaluate(parameter_blocks.get(), residuals.get(), nullptr));
  82. EXPECT_TRUE(actual_cost_function.Evaluate(
  83. parameter_blocks.get(), actual_residuals.get(), nullptr));
  84. for (int i = 0; i < num_residuals; ++i) {
  85. EXPECT_NEAR(residuals[i], actual_residuals[i], kTolerance)
  86. << "residual id: " << i;
  87. }
  88. EXPECT_TRUE(cost_function.Evaluate(
  89. parameter_blocks.get(), residuals.get(), jacobian_blocks.get()));
  90. EXPECT_TRUE(actual_cost_function.Evaluate(parameter_blocks.get(),
  91. actual_residuals.get(),
  92. actual_jacobian_blocks.get()));
  93. for (int i = 0; i < num_residuals; ++i) {
  94. EXPECT_NEAR(residuals[i], actual_residuals[i], kTolerance)
  95. << "residual : " << i;
  96. }
  97. for (int i = 0; i < num_residuals * num_parameters; ++i) {
  98. EXPECT_NEAR(jacobians[i], actual_jacobians[i], kTolerance)
  99. << "jacobian : " << i << " " << jacobians[i] << " "
  100. << actual_jacobians[i];
  101. }
  102. }
  103. struct OneParameterBlockFunctor {
  104. public:
  105. template <typename T>
  106. bool operator()(const T* x1, T* residuals) const {
  107. residuals[0] = x1[0] * x1[0];
  108. residuals[1] = x1[1] * x1[1];
  109. return true;
  110. }
  111. };
  112. struct TwoParameterBlockFunctor {
  113. public:
  114. template <typename T>
  115. bool operator()(const T* x1, const T* x2, T* residuals) const {
  116. residuals[0] = x1[0] * x1[0] + x2[0] * x2[0];
  117. residuals[1] = x1[1] * x1[1] + x2[1] * x2[1];
  118. return true;
  119. }
  120. };
  121. struct ThreeParameterBlockFunctor {
  122. public:
  123. template <typename T>
  124. bool operator()(const T* x1, const T* x2, const T* x3, T* residuals) const {
  125. residuals[0] = x1[0] * x1[0] + x2[0] * x2[0] + x3[0] * x3[0];
  126. residuals[1] = x1[1] * x1[1] + x2[1] * x2[1] + x3[1] * x3[1];
  127. return true;
  128. }
  129. };
  130. struct FourParameterBlockFunctor {
  131. public:
  132. template <typename T>
  133. bool operator()(
  134. const T* x1, const T* x2, const T* x3, const T* x4, T* residuals) const {
  135. residuals[0] =
  136. x1[0] * x1[0] + x2[0] * x2[0] + x3[0] * x3[0] + x4[0] * x4[0];
  137. residuals[1] =
  138. x1[1] * x1[1] + x2[1] * x2[1] + x3[1] * x3[1] + x4[1] * x4[1];
  139. return true;
  140. }
  141. };
  142. struct FiveParameterBlockFunctor {
  143. public:
  144. template <typename T>
  145. bool operator()(const T* x1,
  146. const T* x2,
  147. const T* x3,
  148. const T* x4,
  149. const T* x5,
  150. T* residuals) const {
  151. residuals[0] = x1[0] * x1[0] + x2[0] * x2[0] + x3[0] * x3[0] +
  152. x4[0] * x4[0] + x5[0] * x5[0];
  153. residuals[1] = x1[1] * x1[1] + x2[1] * x2[1] + x3[1] * x3[1] +
  154. x4[1] * x4[1] + x5[1] * x5[1];
  155. return true;
  156. }
  157. };
  158. struct SixParameterBlockFunctor {
  159. public:
  160. template <typename T>
  161. bool operator()(const T* x1,
  162. const T* x2,
  163. const T* x3,
  164. const T* x4,
  165. const T* x5,
  166. const T* x6,
  167. T* residuals) const {
  168. residuals[0] = x1[0] * x1[0] + x2[0] * x2[0] + x3[0] * x3[0] +
  169. x4[0] * x4[0] + x5[0] * x5[0] + x6[0] * x6[0];
  170. residuals[1] = x1[1] * x1[1] + x2[1] * x2[1] + x3[1] * x3[1] +
  171. x4[1] * x4[1] + x5[1] * x5[1] + x6[1] * x6[1];
  172. return true;
  173. }
  174. };
  175. struct SevenParameterBlockFunctor {
  176. public:
  177. template <typename T>
  178. bool operator()(const T* x1,
  179. const T* x2,
  180. const T* x3,
  181. const T* x4,
  182. const T* x5,
  183. const T* x6,
  184. const T* x7,
  185. T* residuals) const {
  186. residuals[0] = x1[0] * x1[0] + x2[0] * x2[0] + x3[0] * x3[0] +
  187. x4[0] * x4[0] + x5[0] * x5[0] + x6[0] * x6[0] +
  188. x7[0] * x7[0];
  189. residuals[1] = x1[1] * x1[1] + x2[1] * x2[1] + x3[1] * x3[1] +
  190. x4[1] * x4[1] + x5[1] * x5[1] + x6[1] * x6[1] +
  191. x7[1] * x7[1];
  192. return true;
  193. }
  194. };
  195. struct EightParameterBlockFunctor {
  196. public:
  197. template <typename T>
  198. bool operator()(const T* x1,
  199. const T* x2,
  200. const T* x3,
  201. const T* x4,
  202. const T* x5,
  203. const T* x6,
  204. const T* x7,
  205. const T* x8,
  206. T* residuals) const {
  207. residuals[0] = x1[0] * x1[0] + x2[0] * x2[0] + x3[0] * x3[0] +
  208. x4[0] * x4[0] + x5[0] * x5[0] + x6[0] * x6[0] +
  209. x7[0] * x7[0] + x8[0] * x8[0];
  210. residuals[1] = x1[1] * x1[1] + x2[1] * x2[1] + x3[1] * x3[1] +
  211. x4[1] * x4[1] + x5[1] * x5[1] + x6[1] * x6[1] +
  212. x7[1] * x7[1] + x8[1] * x8[1];
  213. return true;
  214. }
  215. };
  216. struct NineParameterBlockFunctor {
  217. public:
  218. template <typename T>
  219. bool operator()(const T* x1,
  220. const T* x2,
  221. const T* x3,
  222. const T* x4,
  223. const T* x5,
  224. const T* x6,
  225. const T* x7,
  226. const T* x8,
  227. const T* x9,
  228. T* residuals) const {
  229. residuals[0] = x1[0] * x1[0] + x2[0] * x2[0] + x3[0] * x3[0] +
  230. x4[0] * x4[0] + x5[0] * x5[0] + x6[0] * x6[0] +
  231. x7[0] * x7[0] + x8[0] * x8[0] + x9[0] * x9[0];
  232. residuals[1] = x1[1] * x1[1] + x2[1] * x2[1] + x3[1] * x3[1] +
  233. x4[1] * x4[1] + x5[1] * x5[1] + x6[1] * x6[1] +
  234. x7[1] * x7[1] + x8[1] * x8[1] + x9[1] * x9[1];
  235. return true;
  236. }
  237. };
  238. struct TenParameterBlockFunctor {
  239. public:
  240. template <typename T>
  241. bool operator()(const T* x1,
  242. const T* x2,
  243. const T* x3,
  244. const T* x4,
  245. const T* x5,
  246. const T* x6,
  247. const T* x7,
  248. const T* x8,
  249. const T* x9,
  250. const T* x10,
  251. T* residuals) const {
  252. residuals[0] = x1[0] * x1[0] + x2[0] * x2[0] + x3[0] * x3[0] +
  253. x4[0] * x4[0] + x5[0] * x5[0] + x6[0] * x6[0] +
  254. x7[0] * x7[0] + x8[0] * x8[0] + x9[0] * x9[0] +
  255. x10[0] * x10[0];
  256. residuals[1] = x1[1] * x1[1] + x2[1] * x2[1] + x3[1] * x3[1] +
  257. x4[1] * x4[1] + x5[1] * x5[1] + x6[1] * x6[1] +
  258. x7[1] * x7[1] + x8[1] * x8[1] + x9[1] * x9[1] +
  259. x10[1] * x10[1];
  260. return true;
  261. }
  262. };
  263. class DynamicTwoParameterBlockFunctor {
  264. public:
  265. template <typename T>
  266. bool operator()(T const* const* parameters, T* residuals) const {
  267. for (int i = 0; i < 2; ++i) {
  268. residuals[0] = parameters[i][0] * parameters[i][0];
  269. residuals[1] = parameters[i][1] * parameters[i][1];
  270. }
  271. return true;
  272. }
  273. };
  274. // Check that AutoDiff(Functor1) == AutoDiff(CostToFunctor(AutoDiff(Functor1)))
  275. #define TEST_BODY(Functor1) \
  276. TEST(CostFunctionToFunctor, Functor1) { \
  277. using CostFunction1 = \
  278. AutoDiffCostFunction<Functor1, 2, PARAMETER_BLOCK_SIZES>; \
  279. using FunctionToFunctor = CostFunctionToFunctor<2, PARAMETER_BLOCK_SIZES>; \
  280. using CostFunction2 = \
  281. AutoDiffCostFunction<FunctionToFunctor, 2, PARAMETER_BLOCK_SIZES>; \
  282. \
  283. std::unique_ptr<CostFunction> cost_function(new CostFunction2( \
  284. new FunctionToFunctor(new CostFunction1(new Functor1)))); \
  285. \
  286. std::unique_ptr<CostFunction> actual_cost_function( \
  287. new CostFunction1(new Functor1)); \
  288. ExpectCostFunctionsAreEqual(*cost_function, *actual_cost_function); \
  289. }
  290. #define PARAMETER_BLOCK_SIZES 2
  291. TEST_BODY(OneParameterBlockFunctor)
  292. #undef PARAMETER_BLOCK_SIZES
  293. #define PARAMETER_BLOCK_SIZES 2, 2
  294. TEST_BODY(TwoParameterBlockFunctor)
  295. #undef PARAMETER_BLOCK_SIZES
  296. #define PARAMETER_BLOCK_SIZES 2, 2, 2
  297. TEST_BODY(ThreeParameterBlockFunctor)
  298. #undef PARAMETER_BLOCK_SIZES
  299. #define PARAMETER_BLOCK_SIZES 2, 2, 2, 2
  300. TEST_BODY(FourParameterBlockFunctor)
  301. #undef PARAMETER_BLOCK_SIZES
  302. #define PARAMETER_BLOCK_SIZES 2, 2, 2, 2, 2
  303. TEST_BODY(FiveParameterBlockFunctor)
  304. #undef PARAMETER_BLOCK_SIZES
  305. #define PARAMETER_BLOCK_SIZES 2, 2, 2, 2, 2, 2
  306. TEST_BODY(SixParameterBlockFunctor)
  307. #undef PARAMETER_BLOCK_SIZES
  308. #define PARAMETER_BLOCK_SIZES 2, 2, 2, 2, 2, 2, 2
  309. TEST_BODY(SevenParameterBlockFunctor)
  310. #undef PARAMETER_BLOCK_SIZES
  311. #define PARAMETER_BLOCK_SIZES 2, 2, 2, 2, 2, 2, 2, 2
  312. TEST_BODY(EightParameterBlockFunctor)
  313. #undef PARAMETER_BLOCK_SIZES
  314. #define PARAMETER_BLOCK_SIZES 2, 2, 2, 2, 2, 2, 2, 2, 2
  315. TEST_BODY(NineParameterBlockFunctor)
  316. #undef PARAMETER_BLOCK_SIZES
  317. #define PARAMETER_BLOCK_SIZES 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
  318. TEST_BODY(TenParameterBlockFunctor)
  319. #undef PARAMETER_BLOCK_SIZES
  320. #undef TEST_BODY
  321. TEST(CostFunctionToFunctor, DynamicNumberOfResiduals) {
  322. std::unique_ptr<CostFunction> cost_function(
  323. new AutoDiffCostFunction<CostFunctionToFunctor<ceres::DYNAMIC, 2, 2>,
  324. ceres::DYNAMIC,
  325. 2,
  326. 2>(
  327. new CostFunctionToFunctor<ceres::DYNAMIC, 2, 2>(
  328. new AutoDiffCostFunction<TwoParameterBlockFunctor, 2, 2, 2>(
  329. new TwoParameterBlockFunctor)),
  330. 2));
  331. std::unique_ptr<CostFunction> actual_cost_function(
  332. new AutoDiffCostFunction<TwoParameterBlockFunctor, 2, 2, 2>(
  333. new TwoParameterBlockFunctor));
  334. ExpectCostFunctionsAreEqual(*cost_function, *actual_cost_function);
  335. }
  336. TEST(CostFunctionToFunctor, DynamicCostFunctionToFunctor) {
  337. auto* actual_cost_function(
  338. new DynamicAutoDiffCostFunction<DynamicTwoParameterBlockFunctor>(
  339. new DynamicTwoParameterBlockFunctor));
  340. actual_cost_function->AddParameterBlock(2);
  341. actual_cost_function->AddParameterBlock(2);
  342. actual_cost_function->SetNumResiduals(2);
  343. DynamicAutoDiffCostFunction<DynamicCostFunctionToFunctor> cost_function(
  344. new DynamicCostFunctionToFunctor(actual_cost_function));
  345. cost_function.AddParameterBlock(2);
  346. cost_function.AddParameterBlock(2);
  347. cost_function.SetNumResiduals(2);
  348. ExpectCostFunctionsAreEqual(cost_function, *actual_cost_function);
  349. }
  350. } // namespace ceres::internal