blob: c186f527be874f6af6b274fb6b479176f159988a [file] [log] [blame]
Keir Mierle8ebb0732012-04-30 23:09:08 -07001// Ceres Solver - A fast non-linear least squares minimizer
2// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
3// http://code.google.com/p/ceres-solver/
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// keir@google.com (Keir Mierle)
31
32#include "ceres/problem_impl.h"
33
34#include <algorithm>
35#include <cstddef>
36#include <set>
37#include <string>
38#include <utility>
39#include <vector>
Sameer Agarwal0beab862012-08-13 15:12:01 -070040#include "ceres/cost_function.h"
41#include "ceres/loss_function.h"
42#include "ceres/map_util.h"
Keir Mierle8ebb0732012-04-30 23:09:08 -070043#include "ceres/parameter_block.h"
44#include "ceres/program.h"
45#include "ceres/residual_block.h"
46#include "ceres/stl_util.h"
Keir Mierle8ebb0732012-04-30 23:09:08 -070047#include "ceres/stringprintf.h"
Sameer Agarwal0beab862012-08-13 15:12:01 -070048#include "glog/logging.h"
Keir Mierle8ebb0732012-04-30 23:09:08 -070049
50namespace ceres {
51namespace internal {
52
53typedef map<double*, internal::ParameterBlock*> ParameterMap;
54
55// Returns true if two regions of memory, a and b, with sizes size_a and size_b
56// respectively, overlap.
57static bool RegionsAlias(const double* a, int size_a,
58 const double* b, int size_b) {
59 return (a < b) ? b < (a + size_a)
60 : a < (b + size_b);
61}
62
63static void CheckForNoAliasing(double* existing_block,
64 int existing_block_size,
65 double* new_block,
66 int new_block_size) {
67 CHECK(!RegionsAlias(existing_block, existing_block_size,
68 new_block, new_block_size))
69 << "Aliasing detected between existing parameter block at memory "
70 << "location " << existing_block
71 << " and has size " << existing_block_size << " with new parameter "
72 << "block that has memory adderss " << new_block << " and would have "
73 << "size " << new_block_size << ".";
74}
75
76static ParameterBlock* InternalAddParameterBlock(
77 double* values,
78 int size,
79 ParameterMap* parameter_map,
80 vector<ParameterBlock*>* parameter_blocks) {
81 CHECK(values) << "Null pointer passed to AddParameterBlock for a parameter "
82 << "with size " << size;
83
84 // Ignore the request if there is a block for the given pointer already.
85 ParameterMap::iterator it = parameter_map->find(values);
86 if (it != parameter_map->end()) {
87 int existing_size = it->second->Size();
88 CHECK(size == existing_size)
89 << "Tried adding a parameter block with the same double pointer, "
90 << values << ", twice, but with different block sizes. Original "
91 << "size was " << existing_size << " but new size is "
92 << size;
93 return it->second;
94 }
95 // Before adding the parameter block, also check that it doesn't alias any
96 // other parameter blocks.
97 if (!parameter_map->empty()) {
98 ParameterMap::iterator lb = parameter_map->lower_bound(values);
99
100 // If lb is not the first block, check the previous block for aliasing.
101 if (lb != parameter_map->begin()) {
102 ParameterMap::iterator previous = lb;
103 --previous;
104 CheckForNoAliasing(previous->first,
105 previous->second->Size(),
106 values,
107 size);
108 }
109
110 // If lb is not off the end, check lb for aliasing.
111 if (lb != parameter_map->end()) {
112 CheckForNoAliasing(lb->first,
113 lb->second->Size(),
114 values,
115 size);
116 }
117 }
118 ParameterBlock* new_parameter_block = new ParameterBlock(values, size);
119 (*parameter_map)[values] = new_parameter_block;
120 parameter_blocks->push_back(new_parameter_block);
121 return new_parameter_block;
122}
123
124ProblemImpl::ProblemImpl() : program_(new internal::Program) {}
125ProblemImpl::ProblemImpl(const Problem::Options& options)
126 : options_(options),
127 program_(new internal::Program) {}
128
129ProblemImpl::~ProblemImpl() {
130 // Collect the unique cost/loss functions and delete the residuals.
131 set<CostFunction*> cost_functions;
132 set<LossFunction*> loss_functions;
133 for (int i = 0; i < program_->residual_blocks_.size(); ++i) {
134 ResidualBlock* residual_block = program_->residual_blocks_[i];
135
136 // The const casts here are legit, since ResidualBlock holds these
137 // pointers as const pointers but we have ownership of them and
138 // have the right to destroy them when the destructor is called.
139 if (options_.cost_function_ownership == TAKE_OWNERSHIP) {
140 cost_functions.insert(
141 const_cast<CostFunction*>(residual_block->cost_function()));
142 }
143 if (options_.loss_function_ownership == TAKE_OWNERSHIP) {
144 loss_functions.insert(
145 const_cast<LossFunction*>(residual_block->loss_function()));
146 }
147
148 delete residual_block;
149 }
150
151 // Collect the unique parameterizations and delete the parameters.
152 set<LocalParameterization*> local_parameterizations;
153 for (int i = 0; i < program_->parameter_blocks_.size(); ++i) {
154 ParameterBlock* parameter_block = program_->parameter_blocks_[i];
155
156 if (options_.local_parameterization_ownership == TAKE_OWNERSHIP) {
157 local_parameterizations.insert(parameter_block->local_parameterization_);
158 }
159
160 delete parameter_block;
161 }
162
163 // Delete the owned cost/loss functions and parameterizations.
164 STLDeleteContainerPointers(local_parameterizations.begin(),
165 local_parameterizations.end());
166 STLDeleteContainerPointers(cost_functions.begin(),
167 cost_functions.end());
168 STLDeleteContainerPointers(loss_functions.begin(),
169 loss_functions.end());
170}
171
172const ResidualBlock* ProblemImpl::AddResidualBlock(
173 CostFunction* cost_function,
174 LossFunction* loss_function,
175 const vector<double*>& parameter_blocks) {
176 CHECK_NOTNULL(cost_function);
177 CHECK_EQ(parameter_blocks.size(),
178 cost_function->parameter_block_sizes().size());
179
180 // Check the sizes match.
181 const vector<int16>& parameter_block_sizes =
182 cost_function->parameter_block_sizes();
183 CHECK_EQ(parameter_block_sizes.size(), parameter_blocks.size())
184 << "Number of blocks input is different than the number of blocks "
185 << "that the cost function expects.";
186
187 // Check for duplicate parameter blocks.
188 vector<double*> sorted_parameter_blocks(parameter_blocks);
189 sort(sorted_parameter_blocks.begin(), sorted_parameter_blocks.end());
190 vector<double*>::const_iterator duplicate_items =
191 unique(sorted_parameter_blocks.begin(),
192 sorted_parameter_blocks.end());
193 if (duplicate_items != sorted_parameter_blocks.end()) {
194 string blocks;
195 for (int i = 0; i < parameter_blocks.size(); ++i) {
196 blocks += internal::StringPrintf(" %p ", parameter_blocks[i]);
197 }
198
199 LOG(FATAL) << "Duplicate parameter blocks in a residual parameter "
200 << "are not allowed. Parameter block pointers: ["
201 << blocks << "]";
202 }
203
204 // Add parameter blocks and convert the double*'s to parameter blocks.
205 vector<ParameterBlock*> parameter_block_ptrs(parameter_blocks.size());
206 for (int i = 0; i < parameter_blocks.size(); ++i) {
207 parameter_block_ptrs[i] =
208 InternalAddParameterBlock(parameter_blocks[i],
209 parameter_block_sizes[i],
210 &parameter_block_map_,
211 &program_->parameter_blocks_);
212 }
213
214 // Check that the block sizes match the block sizes expected by the
215 // cost_function.
216 for (int i = 0; i < parameter_block_ptrs.size(); ++i) {
217 CHECK_EQ(cost_function->parameter_block_sizes()[i],
218 parameter_block_ptrs[i]->Size())
219 << "The cost function expects parameter block " << i
220 << " of size " << cost_function->parameter_block_sizes()[i]
221 << " but was given a block of size "
222 << parameter_block_ptrs[i]->Size();
223 }
224
225 ResidualBlock* new_residual_block =
226 new ResidualBlock(cost_function,
227 loss_function,
228 parameter_block_ptrs);
229 program_->residual_blocks_.push_back(new_residual_block);
230 return new_residual_block;
231}
232
233// Unfortunately, macros don't help much to reduce this code, and var args don't
234// work because of the ambiguous case that there is no loss function.
235const ResidualBlock* ProblemImpl::AddResidualBlock(
236 CostFunction* cost_function,
237 LossFunction* loss_function,
238 double* x0) {
239 vector<double*> residual_parameters;
240 residual_parameters.push_back(x0);
241 return AddResidualBlock(cost_function, loss_function, residual_parameters);
242}
243
244const ResidualBlock* ProblemImpl::AddResidualBlock(
245 CostFunction* cost_function,
246 LossFunction* loss_function,
247 double* x0, double* x1) {
248 vector<double*> residual_parameters;
249 residual_parameters.push_back(x0);
250 residual_parameters.push_back(x1);
251 return AddResidualBlock(cost_function, loss_function, residual_parameters);
252}
253
254const ResidualBlock* ProblemImpl::AddResidualBlock(
255 CostFunction* cost_function,
256 LossFunction* loss_function,
257 double* x0, double* x1, double* x2) {
258 vector<double*> residual_parameters;
259 residual_parameters.push_back(x0);
260 residual_parameters.push_back(x1);
261 residual_parameters.push_back(x2);
262 return AddResidualBlock(cost_function, loss_function, residual_parameters);
263}
264
265const ResidualBlock* ProblemImpl::AddResidualBlock(
266 CostFunction* cost_function,
267 LossFunction* loss_function,
268 double* x0, double* x1, double* x2, double* x3) {
269 vector<double*> residual_parameters;
270 residual_parameters.push_back(x0);
271 residual_parameters.push_back(x1);
272 residual_parameters.push_back(x2);
273 residual_parameters.push_back(x3);
274 return AddResidualBlock(cost_function, loss_function, residual_parameters);
275}
276
277const ResidualBlock* ProblemImpl::AddResidualBlock(
278 CostFunction* cost_function,
279 LossFunction* loss_function,
280 double* x0, double* x1, double* x2, double* x3, double* x4) {
281 vector<double*> residual_parameters;
282 residual_parameters.push_back(x0);
283 residual_parameters.push_back(x1);
284 residual_parameters.push_back(x2);
285 residual_parameters.push_back(x3);
286 residual_parameters.push_back(x4);
287 return AddResidualBlock(cost_function, loss_function, residual_parameters);
288}
289
290const ResidualBlock* ProblemImpl::AddResidualBlock(
291 CostFunction* cost_function,
292 LossFunction* loss_function,
293 double* x0, double* x1, double* x2, double* x3, double* x4, double* x5) {
294 vector<double*> residual_parameters;
295 residual_parameters.push_back(x0);
296 residual_parameters.push_back(x1);
297 residual_parameters.push_back(x2);
298 residual_parameters.push_back(x3);
299 residual_parameters.push_back(x4);
300 residual_parameters.push_back(x5);
301 return AddResidualBlock(cost_function, loss_function, residual_parameters);
302}
303
304
305void ProblemImpl::AddParameterBlock(double* values, int size) {
306 InternalAddParameterBlock(values,
307 size,
308 &parameter_block_map_,
309 &program_->parameter_blocks_);
310}
311
312void ProblemImpl::AddParameterBlock(
313 double* values,
314 int size,
315 LocalParameterization* local_parameterization) {
316 ParameterBlock* parameter_block =
317 InternalAddParameterBlock(values,
318 size,
319 &parameter_block_map_,
320 &program_->parameter_blocks_);
321 if (local_parameterization != NULL) {
322 parameter_block->SetParameterization(local_parameterization);
323 }
324}
325
326void ProblemImpl::SetParameterBlockConstant(double* values) {
327 FindOrDie(parameter_block_map_, values)->SetConstant();
328}
329
330void ProblemImpl::SetParameterBlockVariable(double* values) {
331 FindOrDie(parameter_block_map_, values)->SetVarying();
332}
333
334void ProblemImpl::SetParameterization(
335 double* values,
336 LocalParameterization* local_parameterization) {
337 FindOrDie(parameter_block_map_, values)
338 ->SetParameterization(local_parameterization);
339}
340
341int ProblemImpl::NumParameterBlocks() const {
342 return program_->NumParameterBlocks();
343}
344
345int ProblemImpl::NumParameters() const {
346 return program_->NumParameters();
347}
348
349int ProblemImpl::NumResidualBlocks() const {
350 return program_->NumResidualBlocks();
351}
352
353int ProblemImpl::NumResiduals() const {
354 return program_->NumResiduals();
355}
356
357} // namespace internal
358} // namespace ceres