blob: a5a4230dc6c055a134aaaf5eada6e3a54967459f [file] [log] [blame]
Austin Schuh70cc9552019-01-21 19:46:48 -08001// Ceres Solver - A fast non-linear least squares minimizer
2// Copyright 2015 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: keir@google.com (Keir Mierle)
30
31#include "ceres/parameter_block.h"
32
Austin Schuh70cc9552019-01-21 19:46:48 -080033#include "ceres/internal/eigen.h"
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080034#include "gtest/gtest.h"
Austin Schuh70cc9552019-01-21 19:46:48 -080035
36namespace ceres {
37namespace internal {
38
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080039TEST(ParameterBlock, SetParameterizationDiesOnSizeMismatch) {
Austin Schuh70cc9552019-01-21 19:46:48 -080040 double x[3] = {1.0, 2.0, 3.0};
41 ParameterBlock parameter_block(x, 3, -1);
42 std::vector<int> indices;
43 indices.push_back(1);
44 SubsetParameterization subset_wrong_size(4, indices);
45 EXPECT_DEATH_IF_SUPPORTED(
46 parameter_block.SetParameterization(&subset_wrong_size), "global");
47}
48
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080049TEST(ParameterBlock, SetParameterizationWithSameExistingParameterization) {
Austin Schuh70cc9552019-01-21 19:46:48 -080050 double x[3] = {1.0, 2.0, 3.0};
51 ParameterBlock parameter_block(x, 3, -1);
52 std::vector<int> indices;
53 indices.push_back(1);
54 SubsetParameterization subset(3, indices);
55 parameter_block.SetParameterization(&subset);
56 parameter_block.SetParameterization(&subset);
57}
58
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080059TEST(ParameterBlock, SetParameterizationAllowsResettingToNull) {
Austin Schuh70cc9552019-01-21 19:46:48 -080060 double x[3] = {1.0, 2.0, 3.0};
61 ParameterBlock parameter_block(x, 3, -1);
62 std::vector<int> indices;
63 indices.push_back(1);
64 SubsetParameterization subset(3, indices);
65 parameter_block.SetParameterization(&subset);
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080066 EXPECT_EQ(parameter_block.local_parameterization(), &subset);
67 parameter_block.SetParameterization(nullptr);
68 EXPECT_EQ(parameter_block.local_parameterization(), nullptr);
Austin Schuh70cc9552019-01-21 19:46:48 -080069}
70
71TEST(ParameterBlock,
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080072 SetParameterizationAllowsResettingToDifferentParameterization) {
Austin Schuh70cc9552019-01-21 19:46:48 -080073 double x[3] = {1.0, 2.0, 3.0};
74 ParameterBlock parameter_block(x, 3, -1);
75 std::vector<int> indices;
76 indices.push_back(1);
77 SubsetParameterization subset(3, indices);
78 parameter_block.SetParameterization(&subset);
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080079 EXPECT_EQ(parameter_block.local_parameterization(), &subset);
80
Austin Schuh70cc9552019-01-21 19:46:48 -080081 SubsetParameterization subset_different(3, indices);
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080082 parameter_block.SetParameterization(&subset_different);
83 EXPECT_EQ(parameter_block.local_parameterization(), &subset_different);
Austin Schuh70cc9552019-01-21 19:46:48 -080084}
85
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080086TEST(ParameterBlock, SetParameterizationAndNormalOperation) {
Austin Schuh70cc9552019-01-21 19:46:48 -080087 double x[3] = {1.0, 2.0, 3.0};
88 ParameterBlock parameter_block(x, 3, -1);
89 std::vector<int> indices;
90 indices.push_back(1);
Austin Schuh70cc9552019-01-21 19:46:48 -080091 SubsetParameterization subset(3, indices);
92 parameter_block.SetParameterization(&subset);
93
94 // Ensure the local parameterization jacobian result is correctly computed.
95 ConstMatrixRef local_parameterization_jacobian(
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080096 parameter_block.LocalParameterizationJacobian(), 3, 2);
Austin Schuh70cc9552019-01-21 19:46:48 -080097 ASSERT_EQ(1.0, local_parameterization_jacobian(0, 0));
98 ASSERT_EQ(0.0, local_parameterization_jacobian(0, 1));
99 ASSERT_EQ(0.0, local_parameterization_jacobian(1, 0));
100 ASSERT_EQ(0.0, local_parameterization_jacobian(1, 1));
101 ASSERT_EQ(0.0, local_parameterization_jacobian(2, 0));
102 ASSERT_EQ(1.0, local_parameterization_jacobian(2, 1));
103
104 // Check that updating works as expected.
105 double x_plus_delta[3];
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800106 double delta[2] = {0.5, 0.3};
Austin Schuh70cc9552019-01-21 19:46:48 -0800107 parameter_block.Plus(x, delta, x_plus_delta);
108 ASSERT_EQ(1.5, x_plus_delta[0]);
109 ASSERT_EQ(2.0, x_plus_delta[1]);
110 ASSERT_EQ(3.3, x_plus_delta[2]);
111}
112
113struct TestParameterization : public LocalParameterization {
114 public:
115 virtual ~TestParameterization() {}
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800116 bool Plus(const double* x,
117 const double* delta,
118 double* x_plus_delta) const final {
Austin Schuh70cc9552019-01-21 19:46:48 -0800119 LOG(FATAL) << "Shouldn't get called.";
120 return true;
121 }
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800122 bool ComputeJacobian(const double* x, double* jacobian) const final {
Austin Schuh70cc9552019-01-21 19:46:48 -0800123 jacobian[0] = *x * 2;
124 return true;
125 }
126
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800127 int GlobalSize() const final { return 1; }
128 int LocalSize() const final { return 1; }
Austin Schuh70cc9552019-01-21 19:46:48 -0800129};
130
131TEST(ParameterBlock, SetStateUpdatesLocalParameterizationJacobian) {
132 TestParameterization test_parameterization;
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800133 double x[1] = {1.0};
Austin Schuh70cc9552019-01-21 19:46:48 -0800134 ParameterBlock parameter_block(x, 1, -1, &test_parameterization);
135
136 EXPECT_EQ(2.0, *parameter_block.LocalParameterizationJacobian());
137
138 x[0] = 5.5;
139 parameter_block.SetState(x);
140 EXPECT_EQ(11.0, *parameter_block.LocalParameterizationJacobian());
141}
142
143TEST(ParameterBlock, PlusWithNoLocalParameterization) {
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800144 double x[2] = {1.0, 2.0};
Austin Schuh70cc9552019-01-21 19:46:48 -0800145 ParameterBlock parameter_block(x, 2, -1);
146
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800147 double delta[2] = {0.2, 0.3};
Austin Schuh70cc9552019-01-21 19:46:48 -0800148 double x_plus_delta[2];
149 parameter_block.Plus(x, delta, x_plus_delta);
150 EXPECT_EQ(1.2, x_plus_delta[0]);
151 EXPECT_EQ(2.3, x_plus_delta[1]);
152}
153
154// Stops computing the jacobian after the first time.
155class BadLocalParameterization : public LocalParameterization {
156 public:
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800157 BadLocalParameterization() : calls_(0) {}
Austin Schuh70cc9552019-01-21 19:46:48 -0800158
159 virtual ~BadLocalParameterization() {}
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800160 bool Plus(const double* x,
161 const double* delta,
162 double* x_plus_delta) const final {
Austin Schuh70cc9552019-01-21 19:46:48 -0800163 *x_plus_delta = *x + *delta;
164 return true;
165 }
166
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800167 bool ComputeJacobian(const double* x, double* jacobian) const final {
Austin Schuh70cc9552019-01-21 19:46:48 -0800168 if (calls_ == 0) {
169 jacobian[0] = 0;
170 }
171 ++calls_;
172 return true;
173 }
174
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800175 int GlobalSize() const final { return 1; }
176 int LocalSize() const final { return 1; }
Austin Schuh70cc9552019-01-21 19:46:48 -0800177
178 private:
179 mutable int calls_;
180};
181
182TEST(ParameterBlock, DetectBadLocalParameterization) {
183 double x = 1;
184 BadLocalParameterization bad_parameterization;
185 ParameterBlock parameter_block(&x, 1, -1, &bad_parameterization);
186 double y = 2;
187 EXPECT_FALSE(parameter_block.SetState(&y));
188}
189
190TEST(ParameterBlock, DefaultBounds) {
191 double x[2];
192 ParameterBlock parameter_block(x, 2, -1, nullptr);
193 EXPECT_EQ(parameter_block.UpperBoundForParameter(0),
194 std::numeric_limits<double>::max());
195 EXPECT_EQ(parameter_block.UpperBoundForParameter(1),
196 std::numeric_limits<double>::max());
197 EXPECT_EQ(parameter_block.LowerBoundForParameter(0),
198 -std::numeric_limits<double>::max());
199 EXPECT_EQ(parameter_block.LowerBoundForParameter(1),
200 -std::numeric_limits<double>::max());
201}
202
203TEST(ParameterBlock, SetBounds) {
204 double x[2];
205 ParameterBlock parameter_block(x, 2, -1, nullptr);
206 parameter_block.SetLowerBound(0, 1);
207 parameter_block.SetUpperBound(1, 1);
208
209 EXPECT_EQ(parameter_block.LowerBoundForParameter(0), 1.0);
210 EXPECT_EQ(parameter_block.LowerBoundForParameter(1),
211 -std::numeric_limits<double>::max());
212
213 EXPECT_EQ(parameter_block.UpperBoundForParameter(0),
214 std::numeric_limits<double>::max());
215 EXPECT_EQ(parameter_block.UpperBoundForParameter(1), 1.0);
216}
217
218TEST(ParameterBlock, PlusWithBoundsConstraints) {
219 double x[] = {1.0, 0.0};
220 double delta[] = {2.0, -10.0};
221 ParameterBlock parameter_block(x, 2, -1, nullptr);
222 parameter_block.SetUpperBound(0, 2.0);
223 parameter_block.SetLowerBound(1, -1.0);
224 double x_plus_delta[2];
225 parameter_block.Plus(x, delta, x_plus_delta);
226 EXPECT_EQ(x_plus_delta[0], 2.0);
227 EXPECT_EQ(x_plus_delta[1], -1.0);
228}
229
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800230TEST(ParameterBlock, ResetLocalParameterizationToNull) {
231 double x[3] = {1.0, 2.0, 3.0};
232 ParameterBlock parameter_block(x, 3, -1);
233 std::vector<int> indices;
234 indices.push_back(1);
235 SubsetParameterization subset(3, indices);
236 parameter_block.SetParameterization(&subset);
237 EXPECT_EQ(parameter_block.local_parameterization(), &subset);
238 parameter_block.SetParameterization(nullptr);
239 EXPECT_EQ(parameter_block.local_parameterization(), nullptr);
240}
241
242TEST(ParameterBlock, ResetLocalParameterizationToNotNull) {
243 double x[3] = {1.0, 2.0, 3.0};
244 ParameterBlock parameter_block(x, 3, -1);
245 std::vector<int> indices;
246 indices.push_back(1);
247 SubsetParameterization subset(3, indices);
248 parameter_block.SetParameterization(&subset);
249 EXPECT_EQ(parameter_block.local_parameterization(), &subset);
250
251 SubsetParameterization subset_different(3, indices);
252 parameter_block.SetParameterization(&subset_different);
253 EXPECT_EQ(parameter_block.local_parameterization(), &subset_different);
254}
255
256TEST(ParameterBlock, SetNullLocalParameterization) {
257 double x[3] = {1.0, 2.0, 3.0};
258 ParameterBlock parameter_block(x, 3, -1);
259 EXPECT_EQ(parameter_block.local_parameterization(), nullptr);
260
261 parameter_block.SetParameterization(nullptr);
262 EXPECT_EQ(parameter_block.local_parameterization(), nullptr);
263}
264
Austin Schuh70cc9552019-01-21 19:46:48 -0800265} // namespace internal
266} // namespace ceres