blob: ea51c2d5c7776c4376b9f69c106719c470ad998d [file] [log] [blame]
Keir Mierle3130b3c2013-02-11 19:39:29 -08001// Ceres Solver - A fast non-linear least squares minimizer
Keir Mierle7492b0d2015-03-17 22:30:16 -07002// Copyright 2015 Google Inc. All rights reserved.
3// http://ceres-solver.org/
Keir Mierle3130b3c2013-02-11 19:39:29 -08004//
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: thadh@gmail.com (Thad Hughes)
30// mierle@gmail.com (Keir Mierle)
31// sameeragarwal@google.com (Sameer Agarwal)
32
Keir Mierle3130b3c2013-02-11 19:39:29 -080033#include <cstddef>
34
Sameer Agarwala427c872013-06-24 17:50:56 -070035#include "ceres/dynamic_autodiff_cost_function.h"
36#include "ceres/internal/scoped_ptr.h"
Keir Mierle3130b3c2013-02-11 19:39:29 -080037#include "gtest/gtest.h"
38
39namespace ceres {
40namespace internal {
41
Sameer Agarwalbcc865f2014-12-17 07:35:09 -080042using std::vector;
43
Keir Mierle3130b3c2013-02-11 19:39:29 -080044// Takes 2 parameter blocks:
45// parameters[0] is size 10.
46// parameters[1] is size 5.
47// Emits 21 residuals:
48// A: i - parameters[0][i], for i in [0,10) -- this is 10 residuals
49// B: parameters[0][i] - i, for i in [0,10) -- this is another 10.
50// C: sum(parameters[0][i]^2 - 8*parameters[0][i]) + sum(parameters[1][i])
51class MyCostFunctor {
52 public:
53 template <typename T>
54 bool operator()(T const* const* parameters, T* residuals) const {
55 const T* params0 = parameters[0];
56 int r = 0;
57 for (int i = 0; i < 10; ++i) {
58 residuals[r++] = T(i) - params0[i];
59 residuals[r++] = params0[i] - T(i);
60 }
61
62 T c_residual(0.0);
63 for (int i = 0; i < 10; ++i) {
64 c_residual += pow(params0[i], 2) - T(8) * params0[i];
65 }
66
67 const T* params1 = parameters[1];
68 for (int i = 0; i < 5; ++i) {
69 c_residual += params1[i];
70 }
71 residuals[r++] = c_residual;
72 return true;
73 }
74};
75
76TEST(DynamicAutodiffCostFunctionTest, TestResiduals) {
77 vector<double> param_block_0(10, 0.0);
78 vector<double> param_block_1(5, 0.0);
79 DynamicAutoDiffCostFunction<MyCostFunctor, 3> cost_function(
80 new MyCostFunctor());
81 cost_function.AddParameterBlock(param_block_0.size());
82 cost_function.AddParameterBlock(param_block_1.size());
83 cost_function.SetNumResiduals(21);
84
85 // Test residual computation.
86 vector<double> residuals(21, -100000);
87 vector<double*> parameter_blocks(2);
88 parameter_blocks[0] = &param_block_0[0];
89 parameter_blocks[1] = &param_block_1[0];
90 EXPECT_TRUE(cost_function.Evaluate(&parameter_blocks[0],
91 residuals.data(),
92 NULL));
93 for (int r = 0; r < 10; ++r) {
94 EXPECT_EQ(1.0 * r, residuals.at(r * 2));
95 EXPECT_EQ(-1.0 * r, residuals.at(r * 2 + 1));
96 }
97 EXPECT_EQ(0, residuals.at(20));
98}
99
100TEST(DynamicAutodiffCostFunctionTest, TestJacobian) {
101 // Test the residual counting.
102 vector<double> param_block_0(10, 0.0);
103 for (int i = 0; i < 10; ++i) {
104 param_block_0[i] = 2 * i;
105 }
106 vector<double> param_block_1(5, 0.0);
107 DynamicAutoDiffCostFunction<MyCostFunctor, 3> cost_function(
108 new MyCostFunctor());
109 cost_function.AddParameterBlock(param_block_0.size());
110 cost_function.AddParameterBlock(param_block_1.size());
111 cost_function.SetNumResiduals(21);
112
113 // Prepare the residuals.
114 vector<double> residuals(21, -100000);
115
116 // Prepare the parameters.
117 vector<double*> parameter_blocks(2);
118 parameter_blocks[0] = &param_block_0[0];
119 parameter_blocks[1] = &param_block_1[0];
120
121 // Prepare the jacobian.
122 vector<vector<double> > jacobian_vect(2);
123 jacobian_vect[0].resize(21 * 10, -100000);
124 jacobian_vect[1].resize(21 * 5, -100000);
125 vector<double*> jacobian;
126 jacobian.push_back(jacobian_vect[0].data());
127 jacobian.push_back(jacobian_vect[1].data());
128
129 // Test jacobian computation.
130 EXPECT_TRUE(cost_function.Evaluate(parameter_blocks.data(),
131 residuals.data(),
132 jacobian.data()));
133
134 for (int r = 0; r < 10; ++r) {
135 EXPECT_EQ(-1.0 * r, residuals.at(r * 2));
136 EXPECT_EQ(+1.0 * r, residuals.at(r * 2 + 1));
137 }
138 EXPECT_EQ(420, residuals.at(20));
139 for (int p = 0; p < 10; ++p) {
140 // Check "A" Jacobian.
141 EXPECT_EQ(-1.0, jacobian_vect[0][2*p * 10 + p]);
142 // Check "B" Jacobian.
143 EXPECT_EQ(+1.0, jacobian_vect[0][(2*p+1) * 10 + p]);
144 jacobian_vect[0][2*p * 10 + p] = 0.0;
145 jacobian_vect[0][(2*p+1) * 10 + p] = 0.0;
146 }
147
148 // Check "C" Jacobian for first parameter block.
149 for (int p = 0; p < 10; ++p) {
150 EXPECT_EQ(4 * p - 8, jacobian_vect[0][20 * 10 + p]);
151 jacobian_vect[0][20 * 10 + p] = 0.0;
152 }
153 for (int i = 0; i < jacobian_vect[0].size(); ++i) {
154 EXPECT_EQ(0.0, jacobian_vect[0][i]);
155 }
156
157 // Check "C" Jacobian for second parameter block.
158 for (int p = 0; p < 5; ++p) {
159 EXPECT_EQ(1.0, jacobian_vect[1][20 * 5 + p]);
160 jacobian_vect[1][20 * 5 + p] = 0.0;
161 }
162 for (int i = 0; i < jacobian_vect[1].size(); ++i) {
163 EXPECT_EQ(0.0, jacobian_vect[1][i]);
164 }
165}
166
Sameer Agarwal974513a2013-02-12 14:22:40 -0800167TEST(DynamicAutodiffCostFunctionTest, JacobianWithFirstParameterBlockConstant) {
168 // Test the residual counting.
169 vector<double> param_block_0(10, 0.0);
170 for (int i = 0; i < 10; ++i) {
171 param_block_0[i] = 2 * i;
172 }
173 vector<double> param_block_1(5, 0.0);
174 DynamicAutoDiffCostFunction<MyCostFunctor, 3> cost_function(
175 new MyCostFunctor());
176 cost_function.AddParameterBlock(param_block_0.size());
177 cost_function.AddParameterBlock(param_block_1.size());
178 cost_function.SetNumResiduals(21);
179
180 // Prepare the residuals.
181 vector<double> residuals(21, -100000);
182
183 // Prepare the parameters.
184 vector<double*> parameter_blocks(2);
185 parameter_blocks[0] = &param_block_0[0];
186 parameter_blocks[1] = &param_block_1[0];
187
188 // Prepare the jacobian.
189 vector<vector<double> > jacobian_vect(2);
190 jacobian_vect[0].resize(21 * 10, -100000);
191 jacobian_vect[1].resize(21 * 5, -100000);
192 vector<double*> jacobian;
193 jacobian.push_back(NULL);
194 jacobian.push_back(jacobian_vect[1].data());
195
196 // Test jacobian computation.
197 EXPECT_TRUE(cost_function.Evaluate(parameter_blocks.data(),
198 residuals.data(),
199 jacobian.data()));
200
201 for (int r = 0; r < 10; ++r) {
202 EXPECT_EQ(-1.0 * r, residuals.at(r * 2));
203 EXPECT_EQ(+1.0 * r, residuals.at(r * 2 + 1));
204 }
205 EXPECT_EQ(420, residuals.at(20));
206
207 // Check "C" Jacobian for second parameter block.
208 for (int p = 0; p < 5; ++p) {
209 EXPECT_EQ(1.0, jacobian_vect[1][20 * 5 + p]);
210 jacobian_vect[1][20 * 5 + p] = 0.0;
211 }
212 for (int i = 0; i < jacobian_vect[1].size(); ++i) {
213 EXPECT_EQ(0.0, jacobian_vect[1][i]);
214 }
215}
216
Sameer Agarwalbcc865f2014-12-17 07:35:09 -0800217TEST(DynamicAutodiffCostFunctionTest, JacobianWithSecondParameterBlockConstant) { // NOLINT
Sameer Agarwal974513a2013-02-12 14:22:40 -0800218 // Test the residual counting.
219 vector<double> param_block_0(10, 0.0);
220 for (int i = 0; i < 10; ++i) {
221 param_block_0[i] = 2 * i;
222 }
223 vector<double> param_block_1(5, 0.0);
224 DynamicAutoDiffCostFunction<MyCostFunctor, 3> cost_function(
225 new MyCostFunctor());
226 cost_function.AddParameterBlock(param_block_0.size());
227 cost_function.AddParameterBlock(param_block_1.size());
228 cost_function.SetNumResiduals(21);
229
230 // Prepare the residuals.
231 vector<double> residuals(21, -100000);
232
233 // Prepare the parameters.
234 vector<double*> parameter_blocks(2);
235 parameter_blocks[0] = &param_block_0[0];
236 parameter_blocks[1] = &param_block_1[0];
237
238 // Prepare the jacobian.
239 vector<vector<double> > jacobian_vect(2);
240 jacobian_vect[0].resize(21 * 10, -100000);
241 jacobian_vect[1].resize(21 * 5, -100000);
242 vector<double*> jacobian;
243 jacobian.push_back(jacobian_vect[0].data());
244 jacobian.push_back(NULL);
245
246 // Test jacobian computation.
247 EXPECT_TRUE(cost_function.Evaluate(parameter_blocks.data(),
248 residuals.data(),
249 jacobian.data()));
250
251 for (int r = 0; r < 10; ++r) {
252 EXPECT_EQ(-1.0 * r, residuals.at(r * 2));
253 EXPECT_EQ(+1.0 * r, residuals.at(r * 2 + 1));
254 }
255 EXPECT_EQ(420, residuals.at(20));
256 for (int p = 0; p < 10; ++p) {
257 // Check "A" Jacobian.
258 EXPECT_EQ(-1.0, jacobian_vect[0][2*p * 10 + p]);
259 // Check "B" Jacobian.
260 EXPECT_EQ(+1.0, jacobian_vect[0][(2*p+1) * 10 + p]);
261 jacobian_vect[0][2*p * 10 + p] = 0.0;
262 jacobian_vect[0][(2*p+1) * 10 + p] = 0.0;
263 }
264
265 // Check "C" Jacobian for first parameter block.
266 for (int p = 0; p < 10; ++p) {
267 EXPECT_EQ(4 * p - 8, jacobian_vect[0][20 * 10 + p]);
268 jacobian_vect[0][20 * 10 + p] = 0.0;
269 }
270 for (int i = 0; i < jacobian_vect[0].size(); ++i) {
271 EXPECT_EQ(0.0, jacobian_vect[0][i]);
272 }
273}
274
Richard Stebbing6dd18562013-06-17 07:27:26 +0100275// Takes 3 parameter blocks:
276// parameters[0] (x) is size 1.
277// parameters[1] (y) is size 2.
278// parameters[2] (z) is size 3.
279// Emits 7 residuals:
280// A: x[0] (= sum_x)
281// B: y[0] + 2.0 * y[1] (= sum_y)
282// C: z[0] + 3.0 * z[1] + 6.0 * z[2] (= sum_z)
283// D: sum_x * sum_y
284// E: sum_y * sum_z
285// F: sum_x * sum_z
286// G: sum_x * sum_y * sum_z
287class MyThreeParameterCostFunctor {
288 public:
289 template <typename T>
290 bool operator()(T const* const* parameters, T* residuals) const {
291 const T* x = parameters[0];
292 const T* y = parameters[1];
293 const T* z = parameters[2];
294
295 T sum_x = x[0];
296 T sum_y = y[0] + 2.0 * y[1];
297 T sum_z = z[0] + 3.0 * z[1] + 6.0 * z[2];
298
299 residuals[0] = sum_x;
300 residuals[1] = sum_y;
301 residuals[2] = sum_z;
302 residuals[3] = sum_x * sum_y;
303 residuals[4] = sum_y * sum_z;
304 residuals[5] = sum_x * sum_z;
305 residuals[6] = sum_x * sum_y * sum_z;
306 return true;
307 }
308};
309
310class ThreeParameterCostFunctorTest : public ::testing::Test {
311 protected:
312 virtual void SetUp() {
313 // Prepare the parameters.
314 x_.resize(1);
315 x_[0] = 0.0;
316
317 y_.resize(2);
318 y_[0] = 1.0;
319 y_[1] = 3.0;
320
321 z_.resize(3);
322 z_[0] = 2.0;
323 z_[1] = 4.0;
324 z_[2] = 6.0;
325
326 parameter_blocks_.resize(3);
327 parameter_blocks_[0] = &x_[0];
328 parameter_blocks_[1] = &y_[0];
329 parameter_blocks_[2] = &z_[0];
330
331 // Prepare the cost function.
332 typedef DynamicAutoDiffCostFunction<MyThreeParameterCostFunctor, 3>
333 DynamicMyThreeParameterCostFunction;
334 DynamicMyThreeParameterCostFunction * cost_function =
335 new DynamicMyThreeParameterCostFunction(
336 new MyThreeParameterCostFunctor());
337 cost_function->AddParameterBlock(1);
338 cost_function->AddParameterBlock(2);
339 cost_function->AddParameterBlock(3);
340 cost_function->SetNumResiduals(7);
341
342 cost_function_.reset(cost_function);
343
344 // Setup jacobian data.
345 jacobian_vect_.resize(3);
346 jacobian_vect_[0].resize(7 * x_.size(), -100000);
347 jacobian_vect_[1].resize(7 * y_.size(), -100000);
348 jacobian_vect_[2].resize(7 * z_.size(), -100000);
349
350 // Prepare the expected residuals.
351 const double sum_x = x_[0];
352 const double sum_y = y_[0] + 2.0 * y_[1];
353 const double sum_z = z_[0] + 3.0 * z_[1] + 6.0 * z_[2];
354
355 expected_residuals_.resize(7);
356 expected_residuals_[0] = sum_x;
357 expected_residuals_[1] = sum_y;
358 expected_residuals_[2] = sum_z;
359 expected_residuals_[3] = sum_x * sum_y;
360 expected_residuals_[4] = sum_y * sum_z;
361 expected_residuals_[5] = sum_x * sum_z;
362 expected_residuals_[6] = sum_x * sum_y * sum_z;
363
364 // Prepare the expected jacobian entries.
365 expected_jacobian_x_.resize(7);
366 expected_jacobian_x_[0] = 1.0;
367 expected_jacobian_x_[1] = 0.0;
368 expected_jacobian_x_[2] = 0.0;
369 expected_jacobian_x_[3] = sum_y;
370 expected_jacobian_x_[4] = 0.0;
371 expected_jacobian_x_[5] = sum_z;
372 expected_jacobian_x_[6] = sum_y * sum_z;
373
374 expected_jacobian_y_.resize(14);
375 expected_jacobian_y_[0] = 0.0;
376 expected_jacobian_y_[1] = 0.0;
377 expected_jacobian_y_[2] = 1.0;
378 expected_jacobian_y_[3] = 2.0;
379 expected_jacobian_y_[4] = 0.0;
380 expected_jacobian_y_[5] = 0.0;
381 expected_jacobian_y_[6] = sum_x;
382 expected_jacobian_y_[7] = 2.0 * sum_x;
383 expected_jacobian_y_[8] = sum_z;
384 expected_jacobian_y_[9] = 2.0 * sum_z;
385 expected_jacobian_y_[10] = 0.0;
386 expected_jacobian_y_[11] = 0.0;
387 expected_jacobian_y_[12] = sum_x * sum_z;
388 expected_jacobian_y_[13] = 2.0 * sum_x * sum_z;
389
390 expected_jacobian_z_.resize(21);
391 expected_jacobian_z_[0] = 0.0;
392 expected_jacobian_z_[1] = 0.0;
393 expected_jacobian_z_[2] = 0.0;
394 expected_jacobian_z_[3] = 0.0;
395 expected_jacobian_z_[4] = 0.0;
396 expected_jacobian_z_[5] = 0.0;
397 expected_jacobian_z_[6] = 1.0;
398 expected_jacobian_z_[7] = 3.0;
399 expected_jacobian_z_[8] = 6.0;
400 expected_jacobian_z_[9] = 0.0;
401 expected_jacobian_z_[10] = 0.0;
402 expected_jacobian_z_[11] = 0.0;
403 expected_jacobian_z_[12] = sum_y;
404 expected_jacobian_z_[13] = 3.0 * sum_y;
405 expected_jacobian_z_[14] = 6.0 * sum_y;
406 expected_jacobian_z_[15] = sum_x;
407 expected_jacobian_z_[16] = 3.0 * sum_x;
408 expected_jacobian_z_[17] = 6.0 * sum_x;
409 expected_jacobian_z_[18] = sum_x * sum_y;
410 expected_jacobian_z_[19] = 3.0 * sum_x * sum_y;
411 expected_jacobian_z_[20] = 6.0 * sum_x * sum_y;
412 }
413
414 protected:
415 vector<double> x_;
416 vector<double> y_;
417 vector<double> z_;
418
419 vector<double*> parameter_blocks_;
420
421 scoped_ptr<CostFunction> cost_function_;
422
423 vector<vector<double> > jacobian_vect_;
424
425 vector<double> expected_residuals_;
426
427 vector<double> expected_jacobian_x_;
428 vector<double> expected_jacobian_y_;
429 vector<double> expected_jacobian_z_;
430};
431
432TEST_F(ThreeParameterCostFunctorTest, TestThreeParameterResiduals) {
433 vector<double> residuals(7, -100000);
434 EXPECT_TRUE(cost_function_->Evaluate(parameter_blocks_.data(),
435 residuals.data(),
436 NULL));
437 for (int i = 0; i < 7; ++i) {
438 EXPECT_EQ(expected_residuals_[i], residuals[i]);
439 }
440}
441
442TEST_F(ThreeParameterCostFunctorTest, TestThreeParameterJacobian) {
443 vector<double> residuals(7, -100000);
444
445 vector<double*> jacobian;
446 jacobian.push_back(jacobian_vect_[0].data());
447 jacobian.push_back(jacobian_vect_[1].data());
448 jacobian.push_back(jacobian_vect_[2].data());
449
450 EXPECT_TRUE(cost_function_->Evaluate(parameter_blocks_.data(),
451 residuals.data(),
452 jacobian.data()));
453
454 for (int i = 0; i < 7; ++i) {
455 EXPECT_EQ(expected_residuals_[i], residuals[i]);
456 }
457
458 for (int i = 0; i < 7; ++i) {
459 EXPECT_EQ(expected_jacobian_x_[i], jacobian[0][i]);
460 }
461
462 for (int i = 0; i < 14; ++i) {
463 EXPECT_EQ(expected_jacobian_y_[i], jacobian[1][i]);
464 }
465
466 for (int i = 0; i < 21; ++i) {
467 EXPECT_EQ(expected_jacobian_z_[i], jacobian[2][i]);
468 }
469}
470
471TEST_F(ThreeParameterCostFunctorTest,
472 ThreeParameterJacobianWithFirstAndLastParameterBlockConstant) {
473 vector<double> residuals(7, -100000);
474
475 vector<double*> jacobian;
476 jacobian.push_back(NULL);
477 jacobian.push_back(jacobian_vect_[1].data());
478 jacobian.push_back(NULL);
479
480 EXPECT_TRUE(cost_function_->Evaluate(parameter_blocks_.data(),
481 residuals.data(),
482 jacobian.data()));
483
484 for (int i = 0; i < 7; ++i) {
485 EXPECT_EQ(expected_residuals_[i], residuals[i]);
486 }
487
488 for (int i = 0; i < 14; ++i) {
489 EXPECT_EQ(expected_jacobian_y_[i], jacobian[1][i]);
490 }
491}
492
493TEST_F(ThreeParameterCostFunctorTest,
494 ThreeParameterJacobianWithSecondParameterBlockConstant) {
495 vector<double> residuals(7, -100000);
496
497 vector<double*> jacobian;
498 jacobian.push_back(jacobian_vect_[0].data());
499 jacobian.push_back(NULL);
500 jacobian.push_back(jacobian_vect_[2].data());
501
502 EXPECT_TRUE(cost_function_->Evaluate(parameter_blocks_.data(),
503 residuals.data(),
504 jacobian.data()));
505
506 for (int i = 0; i < 7; ++i) {
507 EXPECT_EQ(expected_residuals_[i], residuals[i]);
508 }
509
510 for (int i = 0; i < 7; ++i) {
511 EXPECT_EQ(expected_jacobian_x_[i], jacobian[0][i]);
512 }
513
514 for (int i = 0; i < 21; ++i) {
515 EXPECT_EQ(expected_jacobian_z_[i], jacobian[2][i]);
516 }
517}
518
519// Takes 6 parameter blocks all of size 1:
520// x0, y0, y1, z0, z1, z2
521// Same 7 residuals as MyThreeParameterCostFunctor.
522// Naming convention for tests is (V)ariable and (C)onstant.
523class MySixParameterCostFunctor {
524 public:
525 template <typename T>
526 bool operator()(T const* const* parameters, T* residuals) const {
527 const T* x0 = parameters[0];
528 const T* y0 = parameters[1];
529 const T* y1 = parameters[2];
530 const T* z0 = parameters[3];
531 const T* z1 = parameters[4];
532 const T* z2 = parameters[5];
533
534 T sum_x = x0[0];
535 T sum_y = y0[0] + 2.0 * y1[0];
536 T sum_z = z0[0] + 3.0 * z1[0] + 6.0 * z2[0];
537
538 residuals[0] = sum_x;
539 residuals[1] = sum_y;
540 residuals[2] = sum_z;
541 residuals[3] = sum_x * sum_y;
542 residuals[4] = sum_y * sum_z;
543 residuals[5] = sum_x * sum_z;
544 residuals[6] = sum_x * sum_y * sum_z;
545 return true;
546 }
547};
548
549class SixParameterCostFunctorTest : public ::testing::Test {
550 protected:
551 virtual void SetUp() {
552 // Prepare the parameters.
553 x0_ = 0.0;
554 y0_ = 1.0;
555 y1_ = 3.0;
556 z0_ = 2.0;
557 z1_ = 4.0;
558 z2_ = 6.0;
559
560 parameter_blocks_.resize(6);
561 parameter_blocks_[0] = &x0_;
562 parameter_blocks_[1] = &y0_;
563 parameter_blocks_[2] = &y1_;
564 parameter_blocks_[3] = &z0_;
565 parameter_blocks_[4] = &z1_;
566 parameter_blocks_[5] = &z2_;
567
568 // Prepare the cost function.
569 typedef DynamicAutoDiffCostFunction<MySixParameterCostFunctor, 3>
570 DynamicMySixParameterCostFunction;
571 DynamicMySixParameterCostFunction * cost_function =
572 new DynamicMySixParameterCostFunction(
573 new MySixParameterCostFunctor());
574 for (int i = 0; i < 6; ++i) {
575 cost_function->AddParameterBlock(1);
576 }
577 cost_function->SetNumResiduals(7);
578
579 cost_function_.reset(cost_function);
580
581 // Setup jacobian data.
582 jacobian_vect_.resize(6);
583 for (int i = 0; i < 6; ++i) {
584 jacobian_vect_[i].resize(7, -100000);
585 }
586
587 // Prepare the expected residuals.
588 const double sum_x = x0_;
589 const double sum_y = y0_ + 2.0 * y1_;
590 const double sum_z = z0_ + 3.0 * z1_ + 6.0 * z2_;
591
592 expected_residuals_.resize(7);
593 expected_residuals_[0] = sum_x;
594 expected_residuals_[1] = sum_y;
595 expected_residuals_[2] = sum_z;
596 expected_residuals_[3] = sum_x * sum_y;
597 expected_residuals_[4] = sum_y * sum_z;
598 expected_residuals_[5] = sum_x * sum_z;
599 expected_residuals_[6] = sum_x * sum_y * sum_z;
600
601 // Prepare the expected jacobian entries.
602 expected_jacobians_.resize(6);
603 expected_jacobians_[0].resize(7);
604 expected_jacobians_[0][0] = 1.0;
605 expected_jacobians_[0][1] = 0.0;
606 expected_jacobians_[0][2] = 0.0;
607 expected_jacobians_[0][3] = sum_y;
608 expected_jacobians_[0][4] = 0.0;
609 expected_jacobians_[0][5] = sum_z;
610 expected_jacobians_[0][6] = sum_y * sum_z;
611
612 expected_jacobians_[1].resize(7);
613 expected_jacobians_[1][0] = 0.0;
614 expected_jacobians_[1][1] = 1.0;
615 expected_jacobians_[1][2] = 0.0;
616 expected_jacobians_[1][3] = sum_x;
617 expected_jacobians_[1][4] = sum_z;
618 expected_jacobians_[1][5] = 0.0;
619 expected_jacobians_[1][6] = sum_x * sum_z;
620
621 expected_jacobians_[2].resize(7);
622 expected_jacobians_[2][0] = 0.0;
623 expected_jacobians_[2][1] = 2.0;
624 expected_jacobians_[2][2] = 0.0;
625 expected_jacobians_[2][3] = 2.0 * sum_x;
626 expected_jacobians_[2][4] = 2.0 * sum_z;
627 expected_jacobians_[2][5] = 0.0;
628 expected_jacobians_[2][6] = 2.0 * sum_x * sum_z;
629
630 expected_jacobians_[3].resize(7);
631 expected_jacobians_[3][0] = 0.0;
632 expected_jacobians_[3][1] = 0.0;
633 expected_jacobians_[3][2] = 1.0;
634 expected_jacobians_[3][3] = 0.0;
635 expected_jacobians_[3][4] = sum_y;
636 expected_jacobians_[3][5] = sum_x;
637 expected_jacobians_[3][6] = sum_x * sum_y;
638
639 expected_jacobians_[4].resize(7);
640 expected_jacobians_[4][0] = 0.0;
641 expected_jacobians_[4][1] = 0.0;
642 expected_jacobians_[4][2] = 3.0;
643 expected_jacobians_[4][3] = 0.0;
644 expected_jacobians_[4][4] = 3.0 * sum_y;
645 expected_jacobians_[4][5] = 3.0 * sum_x;
646 expected_jacobians_[4][6] = 3.0 * sum_x * sum_y;
647
648 expected_jacobians_[5].resize(7);
649 expected_jacobians_[5][0] = 0.0;
650 expected_jacobians_[5][1] = 0.0;
651 expected_jacobians_[5][2] = 6.0;
652 expected_jacobians_[5][3] = 0.0;
653 expected_jacobians_[5][4] = 6.0 * sum_y;
654 expected_jacobians_[5][5] = 6.0 * sum_x;
655 expected_jacobians_[5][6] = 6.0 * sum_x * sum_y;
656 }
657
658 protected:
659 double x0_;
660 double y0_;
661 double y1_;
662 double z0_;
663 double z1_;
664 double z2_;
665
666 vector<double*> parameter_blocks_;
667
668 scoped_ptr<CostFunction> cost_function_;
669
670 vector<vector<double> > jacobian_vect_;
671
672 vector<double> expected_residuals_;
673 vector<vector<double> > expected_jacobians_;
674};
675
676TEST_F(SixParameterCostFunctorTest, TestSixParameterResiduals) {
677 vector<double> residuals(7, -100000);
678 EXPECT_TRUE(cost_function_->Evaluate(parameter_blocks_.data(),
679 residuals.data(),
680 NULL));
681 for (int i = 0; i < 7; ++i) {
682 EXPECT_EQ(expected_residuals_[i], residuals[i]);
683 }
684}
685
686TEST_F(SixParameterCostFunctorTest, TestSixParameterJacobian) {
687 vector<double> residuals(7, -100000);
688
689 vector<double*> jacobian;
690 jacobian.push_back(jacobian_vect_[0].data());
691 jacobian.push_back(jacobian_vect_[1].data());
692 jacobian.push_back(jacobian_vect_[2].data());
693 jacobian.push_back(jacobian_vect_[3].data());
694 jacobian.push_back(jacobian_vect_[4].data());
695 jacobian.push_back(jacobian_vect_[5].data());
696
697 EXPECT_TRUE(cost_function_->Evaluate(parameter_blocks_.data(),
698 residuals.data(),
699 jacobian.data()));
700
701 for (int i = 0; i < 7; ++i) {
702 EXPECT_EQ(expected_residuals_[i], residuals[i]);
703 }
704
705 for (int i = 0; i < 6; ++i) {
706 for (int j = 0; j < 7; ++j) {
707 EXPECT_EQ(expected_jacobians_[i][j], jacobian[i][j]);
708 }
709 }
710}
711
712TEST_F(SixParameterCostFunctorTest, TestSixParameterJacobianVVCVVC) {
713 vector<double> residuals(7, -100000);
714
715 vector<double*> jacobian;
716 jacobian.push_back(jacobian_vect_[0].data());
717 jacobian.push_back(jacobian_vect_[1].data());
718 jacobian.push_back(NULL);
719 jacobian.push_back(jacobian_vect_[3].data());
720 jacobian.push_back(jacobian_vect_[4].data());
721 jacobian.push_back(NULL);
722
723 EXPECT_TRUE(cost_function_->Evaluate(parameter_blocks_.data(),
724 residuals.data(),
725 jacobian.data()));
726
727 for (int i = 0; i < 7; ++i) {
728 EXPECT_EQ(expected_residuals_[i], residuals[i]);
729 }
730
731 for (int i = 0; i < 6; ++i) {
732 // Skip the constant variables.
733 if (i == 2 || i == 5) {
734 continue;
735 }
736
737 for (int j = 0; j < 7; ++j) {
738 EXPECT_EQ(expected_jacobians_[i][j], jacobian[i][j]);
739 }
740 }
741}
742
743TEST_F(SixParameterCostFunctorTest, TestSixParameterJacobianVCCVCV) {
744 vector<double> residuals(7, -100000);
745
746 vector<double*> jacobian;
747 jacobian.push_back(jacobian_vect_[0].data());
748 jacobian.push_back(NULL);
749 jacobian.push_back(NULL);
750 jacobian.push_back(jacobian_vect_[3].data());
751 jacobian.push_back(NULL);
752 jacobian.push_back(jacobian_vect_[5].data());
753
754 EXPECT_TRUE(cost_function_->Evaluate(parameter_blocks_.data(),
755 residuals.data(),
756 jacobian.data()));
757
758 for (int i = 0; i < 7; ++i) {
759 EXPECT_EQ(expected_residuals_[i], residuals[i]);
760 }
761
762 for (int i = 0; i < 6; ++i) {
763 // Skip the constant variables.
764 if (i == 1 || i == 2 || i == 4) {
765 continue;
766 }
767
768 for (int j = 0; j < 7; ++j) {
769 EXPECT_EQ(expected_jacobians_[i][j], jacobian[i][j]);
770 }
771 }
772}
773
Keir Mierle3130b3c2013-02-11 19:39:29 -0800774} // namespace internal
775} // namespace ceres