residual_block_test.cc revision 0ae28bd5885b5daa526898fcf7c323dc2c3e1963
1f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// Ceres Solver - A fast non-linear least squares minimizer
2f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
3f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// http://code.google.com/p/ceres-solver/
4f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org//
5f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// Redistribution and use in source and binary forms, with or without
6f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// modification, are permitted provided that the following conditions are met:
7f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org//
8f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// * Redistributions of source code must retain the above copyright notice,
9f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org//   this list of conditions and the following disclaimer.
10f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// * Redistributions in binary form must reproduce the above copyright notice,
11f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org//   this list of conditions and the following disclaimer in the documentation
12f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org//   and/or other materials provided with the distribution.
13f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// * Neither the name of Google Inc. nor the names of its contributors may be
14f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org//   used to endorse or promote products derived from this software without
15f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org//   specific prior written permission.
16f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org//
17f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// POSSIBILITY OF SUCH DAMAGE.
28f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org//
29f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// Author: keir@google.com (Keir Mierle)
30f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
31f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "ceres/residual_block.h"
32f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
33f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "gtest/gtest.h"
34f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "ceres/parameter_block.h"
35f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "ceres/sized_cost_function.h"
36f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "ceres/internal/eigen.h"
37f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "ceres/local_parameterization.h"
38f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
39f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgnamespace ceres {
40f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgnamespace internal {
41f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
42f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// Trivial cost function that accepts three arguments.
43f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgclass TernaryCostFunction: public CostFunction {
44f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org public:
45f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  TernaryCostFunction(int num_residuals,
46f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                      int16 parameter_block1_size,
47f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                      int16 parameter_block2_size,
48f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                      int16 parameter_block3_size) {
49f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    set_num_residuals(num_residuals);
50f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    mutable_parameter_block_sizes()->push_back(parameter_block1_size);
51f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    mutable_parameter_block_sizes()->push_back(parameter_block2_size);
52f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    mutable_parameter_block_sizes()->push_back(parameter_block3_size);
53f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  }
54f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
55f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual bool Evaluate(double const* const* parameters,
56f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                        double* residuals,
57f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                        double** jacobians) const {
58f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    for (int i = 0; i < num_residuals(); ++i) {
59f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      residuals[i] = i;
60f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    }
61f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    if (jacobians) {
62f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      for (int k = 0; k < 3; ++k) {
63f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        if (jacobians[k] != NULL) {
64f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org          MatrixRef jacobian(jacobians[k],
65f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                             num_residuals(),
66f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                             parameter_block_sizes()[k]);
67f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org          jacobian.setConstant(k);
68f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        }
69f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      }
70f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    }
71f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    return true;
72f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  }
73f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org};
74f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
75f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgTEST(ResidualBlock, EvaluteWithNoLossFunctionOrLocalParameterizations) {
76f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  double scratch[64];
77f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
78f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  // Prepare the parameter blocks.
79f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  double values_x[2];
80f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  ParameterBlock x(values_x, 2);
81f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
82f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  double values_y[3];
83f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  ParameterBlock y(values_y, 3);
84f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
85f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  double values_z[4];
86f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  ParameterBlock z(values_z, 4);
87f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
88f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  vector<ParameterBlock*> parameters;
89f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  parameters.push_back(&x);
90f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  parameters.push_back(&y);
91f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  parameters.push_back(&z);
92f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
93f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  TernaryCostFunction cost_function(3, 2, 3, 4);
94f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
95f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  // Create the object under tests.
96f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  ResidualBlock residual_block(&cost_function, NULL, parameters);
97f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
98f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  // Verify getters.
99f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(&cost_function, residual_block.cost_function());
100f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(NULL, residual_block.loss_function());
101f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(parameters[0], residual_block.parameter_blocks()[0]);
102f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(parameters[1], residual_block.parameter_blocks()[1]);
103f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(parameters[2], residual_block.parameter_blocks()[2]);
104f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(3, residual_block.NumScratchDoublesForEvaluate());
105f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
106f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  // Verify cost-only evaluation.
107f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  double cost;
108f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  residual_block.Evaluate(&cost, NULL, NULL, scratch);
109f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(0.5 * (0*0 + 1*1 + 2*2), cost);
110f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
111f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  // Verify cost and residual evaluation.
112f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  double residuals[3];
113f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  residual_block.Evaluate(&cost, residuals, NULL, scratch);
114f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(0.5 * (0*0 + 1*1 + 2*2), cost);
115f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(0.0, residuals[0]);
116f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(1.0, residuals[1]);
117f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(2.0, residuals[2]);
118f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
119f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  // Verify cost, residual, and jacobian evaluation.
120f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  cost = 0.0;
121f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  VectorRef(residuals, 3).setConstant(0.0);
122f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
123f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  Matrix jacobian_rx(3, 2);
124f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  Matrix jacobian_ry(3, 3);
125f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  Matrix jacobian_rz(3, 4);
126f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
127f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  jacobian_rx.setConstant(-1.0);
128f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  jacobian_ry.setConstant(-1.0);
129f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  jacobian_rz.setConstant(-1.0);
130f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
131f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  double *jacobian_ptrs[3] = {
132f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    jacobian_rx.data(),
133f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    jacobian_ry.data(),
134f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    jacobian_rz.data()
135f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  };
136f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
137f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  residual_block.Evaluate(&cost, residuals, jacobian_ptrs, scratch);
138f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(0.5 * (0*0 + 1*1 + 2*2), cost);
139f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(0.0, residuals[0]);
140f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(1.0, residuals[1]);
141f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(2.0, residuals[2]);
142f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
143f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_TRUE((jacobian_rx.array() == 0.0).all()) << "\n" << jacobian_rx;
144f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_TRUE((jacobian_ry.array() == 1.0).all()) << "\n" << jacobian_ry;
145f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_TRUE((jacobian_rz.array() == 2.0).all()) << "\n" << jacobian_rz;
146f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
147f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  // Verify cost, residual, and partial jacobian evaluation.
148f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  cost = 0.0;
149f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  VectorRef(residuals, 3).setConstant(0.0);
150f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  jacobian_rx.setConstant(-1.0);
151f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  jacobian_ry.setConstant(-1.0);
152f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  jacobian_rz.setConstant(-1.0);
153f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
154f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  jacobian_ptrs[1] = NULL;  // Don't compute the jacobian for y.
155f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
156f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  residual_block.Evaluate(&cost, residuals, jacobian_ptrs, scratch);
157f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(0.5 * (0*0 + 1*1 + 2*2), cost);
158f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(0.0, residuals[0]);
159f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(1.0, residuals[1]);
160f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(2.0, residuals[2]);
161f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
162f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_TRUE((jacobian_rx.array() ==  0.0).all()) << "\n" << jacobian_rx;
163f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_TRUE((jacobian_ry.array() == -1.0).all()) << "\n" << jacobian_ry;
164f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_TRUE((jacobian_rz.array() ==  2.0).all()) << "\n" << jacobian_rz;
165f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
166f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
167f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// Trivial cost function that accepts three arguments.
168f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgclass LocallyParameterizedCostFunction: public SizedCostFunction<3, 2, 3, 4> {
169f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org public:
170f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual bool Evaluate(double const* const* parameters,
171f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                        double* residuals,
172f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                        double** jacobians) const {
173f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    for (int i = 0; i < num_residuals(); ++i) {
174f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      residuals[i] = i;
175f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    }
176f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    if (jacobians) {
177f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      for (int k = 0; k < 3; ++k) {
178f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        // The jacobians here are full sized, but they are transformed in the
179f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        // evaluator into the "local" jacobian. In the tests, the "subset
180f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        // constant" parameterization is used, which should pick out columns
181f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        // from these jacobians. Put values in the jacobian that make this
182f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        // obvious; in particular, make the jacobians like this:
183f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        //
184f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        //   0 1 2 3 4 ...
185f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        //   0 1 2 3 4 ...
186f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        //   0 1 2 3 4 ...
187f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        //
188f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        if (jacobians[k] != NULL) {
189f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org          MatrixRef jacobian(jacobians[k],
190f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                             num_residuals(),
191f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                             parameter_block_sizes()[k]);
192f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org          for (int j = 0; j < k + 2; ++j) {
193f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            jacobian.col(j).setConstant(j);
194f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org          }
195f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        }
196f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      }
197f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    }
198f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    return true;
199f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  }
200f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org};
201f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
202f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgTEST(ResidualBlock, EvaluteWithLocalParameterizations) {
203f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  double scratch[64];
204f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
205f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  // Prepare the parameter blocks.
206f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  double values_x[2];
207f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  ParameterBlock x(values_x, 2);
208f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
209f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  double values_y[3];
210f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  ParameterBlock y(values_y, 3);
211f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
212f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  double values_z[4];
213f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  ParameterBlock z(values_z, 4);
214f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
215f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  vector<ParameterBlock*> parameters;
216f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  parameters.push_back(&x);
217f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  parameters.push_back(&y);
218f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  parameters.push_back(&z);
219f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
220f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  // Make x have the first component fixed.
221f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  vector<int> x_fixed;
222f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  x_fixed.push_back(0);
223f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  SubsetParameterization x_parameterization(2, x_fixed);
224f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  x.SetParameterization(&x_parameterization);
225f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
226f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  // Make z have the last and last component fixed.
227f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  vector<int> z_fixed;
228f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  z_fixed.push_back(2);
229f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  SubsetParameterization z_parameterization(4, z_fixed);
230f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  z.SetParameterization(&z_parameterization);
231f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
232f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  LocallyParameterizedCostFunction cost_function;
233f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
234f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  // Create the object under tests.
235f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  ResidualBlock residual_block(&cost_function, NULL, parameters);
236f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
237f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  // Verify getters.
238f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(&cost_function, residual_block.cost_function());
239f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(NULL, residual_block.loss_function());
240f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(parameters[0], residual_block.parameter_blocks()[0]);
241f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(parameters[1], residual_block.parameter_blocks()[1]);
242f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(parameters[2], residual_block.parameter_blocks()[2]);
243f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(3*(2 + 4) + 3, residual_block.NumScratchDoublesForEvaluate());
244f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
245f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  // Verify cost-only evaluation.
246f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  double cost;
247f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  residual_block.Evaluate(&cost, NULL, NULL, scratch);
248f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(0.5 * (0*0 + 1*1 + 2*2), cost);
249f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
250f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  // Verify cost and residual evaluation.
251f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  double residuals[3];
252f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  residual_block.Evaluate(&cost, residuals, NULL, scratch);
253f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(0.5 * (0*0 + 1*1 + 2*2), cost);
254f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(0.0, residuals[0]);
255f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(1.0, residuals[1]);
256f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(2.0, residuals[2]);
257f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
258f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  // Verify cost, residual, and jacobian evaluation.
259f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  cost = 0.0;
260f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  VectorRef(residuals, 3).setConstant(0.0);
261f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
262f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  Matrix jacobian_rx(3, 1);  // Since the first element is fixed.
263f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  Matrix jacobian_ry(3, 3);
264f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  Matrix jacobian_rz(3, 3);  // Since the third element is fixed.
265f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
266f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  jacobian_rx.setConstant(-1.0);
267f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  jacobian_ry.setConstant(-1.0);
268f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  jacobian_rz.setConstant(-1.0);
269f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
270f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  double *jacobian_ptrs[3] = {
271f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    jacobian_rx.data(),
272f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    jacobian_ry.data(),
273f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    jacobian_rz.data()
274f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  };
275f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
276f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  residual_block.Evaluate(&cost, residuals, jacobian_ptrs, scratch);
277f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(0.5 * (0*0 + 1*1 + 2*2), cost);
278f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(0.0, residuals[0]);
279f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(1.0, residuals[1]);
280f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(2.0, residuals[2]);
281f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
282f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  Matrix expected_jacobian_rx(3, 1);
283f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  expected_jacobian_rx << 1.0, 1.0, 1.0;
284f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
285f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  Matrix expected_jacobian_ry(3, 3);
286f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  expected_jacobian_ry << 0.0, 1.0, 2.0,
287f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                          0.0, 1.0, 2.0,
288f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                          0.0, 1.0, 2.0;
289f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
290f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  Matrix expected_jacobian_rz(3, 3);
291f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  expected_jacobian_rz << 0.0, 1.0, /* 2.0, */ 3.0,  // 3rd parameter constant.
292f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                          0.0, 1.0, /* 2.0, */ 3.0,
293f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                          0.0, 1.0, /* 2.0, */ 3.0;
294f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
295f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(expected_jacobian_rx, jacobian_rx)
296f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      << "\nExpected:\n" << expected_jacobian_rx
297f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      << "\nActual:\n"   << jacobian_rx;
298f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(expected_jacobian_ry, jacobian_ry)
299f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      << "\nExpected:\n" << expected_jacobian_ry
300f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      << "\nActual:\n"   << jacobian_ry;
301f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(expected_jacobian_rz, jacobian_rz)
302f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      << "\nExpected:\n " << expected_jacobian_rz
303f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      << "\nActual:\n"   << jacobian_rz;
304f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
305f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  // Verify cost, residual, and partial jacobian evaluation.
306f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  cost = 0.0;
307f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  VectorRef(residuals, 3).setConstant(0.0);
308f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  jacobian_rx.setConstant(-1.0);
309f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  jacobian_ry.setConstant(-1.0);
310f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  jacobian_rz.setConstant(-1.0);
311f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
312f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  jacobian_ptrs[1] = NULL;  // Don't compute the jacobian for y.
313f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
314f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  residual_block.Evaluate(&cost, residuals, jacobian_ptrs, scratch);
315f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(0.5 * (0*0 + 1*1 + 2*2), cost);
316f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(0.0, residuals[0]);
317f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(1.0, residuals[1]);
318f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(2.0, residuals[2]);
319f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
320f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(expected_jacobian_rx, jacobian_rx);
321f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_TRUE((jacobian_ry.array() == -1.0).all()) << "\n" << jacobian_ry;
322f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  EXPECT_EQ(expected_jacobian_rz, jacobian_rz);
323f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
324f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
325f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}  // namespace internal
326f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}  // namespace ceres
327f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org