1 // 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: keir@google.com (Keir Mierle)
30
31 #include "ceres/program.h"
32
33 #include <map>
34 #include <vector>
35 #include "ceres/array_utils.h"
36 #include "ceres/casts.h"
37 #include "ceres/compressed_row_sparse_matrix.h"
38 #include "ceres/cost_function.h"
39 #include "ceres/evaluator.h"
40 #include "ceres/internal/port.h"
41 #include "ceres/local_parameterization.h"
42 #include "ceres/loss_function.h"
43 #include "ceres/map_util.h"
44 #include "ceres/parameter_block.h"
45 #include "ceres/problem.h"
46 #include "ceres/residual_block.h"
47 #include "ceres/stl_util.h"
48 #include "ceres/triplet_sparse_matrix.h"
49
50 namespace ceres {
51 namespace internal {
52
Program()53 Program::Program() {}
54
Program(const Program & program)55 Program::Program(const Program& program)
56 : parameter_blocks_(program.parameter_blocks_),
57 residual_blocks_(program.residual_blocks_) {
58 }
59
parameter_blocks() const60 const vector<ParameterBlock*>& Program::parameter_blocks() const {
61 return parameter_blocks_;
62 }
63
residual_blocks() const64 const vector<ResidualBlock*>& Program::residual_blocks() const {
65 return residual_blocks_;
66 }
67
mutable_parameter_blocks()68 vector<ParameterBlock*>* Program::mutable_parameter_blocks() {
69 return ¶meter_blocks_;
70 }
71
mutable_residual_blocks()72 vector<ResidualBlock*>* Program::mutable_residual_blocks() {
73 return &residual_blocks_;
74 }
75
StateVectorToParameterBlocks(const double * state)76 bool Program::StateVectorToParameterBlocks(const double *state) {
77 for (int i = 0; i < parameter_blocks_.size(); ++i) {
78 if (!parameter_blocks_[i]->IsConstant() &&
79 !parameter_blocks_[i]->SetState(state)) {
80 return false;
81 }
82 state += parameter_blocks_[i]->Size();
83 }
84 return true;
85 }
86
ParameterBlocksToStateVector(double * state) const87 void Program::ParameterBlocksToStateVector(double *state) const {
88 for (int i = 0; i < parameter_blocks_.size(); ++i) {
89 parameter_blocks_[i]->GetState(state);
90 state += parameter_blocks_[i]->Size();
91 }
92 }
93
CopyParameterBlockStateToUserState()94 void Program::CopyParameterBlockStateToUserState() {
95 for (int i = 0; i < parameter_blocks_.size(); ++i) {
96 parameter_blocks_[i]->GetState(parameter_blocks_[i]->mutable_user_state());
97 }
98 }
99
SetParameterBlockStatePtrsToUserStatePtrs()100 bool Program::SetParameterBlockStatePtrsToUserStatePtrs() {
101 for (int i = 0; i < parameter_blocks_.size(); ++i) {
102 if (!parameter_blocks_[i]->IsConstant() &&
103 !parameter_blocks_[i]->SetState(parameter_blocks_[i]->user_state())) {
104 return false;
105 }
106 }
107 return true;
108 }
109
Plus(const double * state,const double * delta,double * state_plus_delta) const110 bool Program::Plus(const double* state,
111 const double* delta,
112 double* state_plus_delta) const {
113 for (int i = 0; i < parameter_blocks_.size(); ++i) {
114 if (!parameter_blocks_[i]->Plus(state, delta, state_plus_delta)) {
115 return false;
116 }
117 state += parameter_blocks_[i]->Size();
118 delta += parameter_blocks_[i]->LocalSize();
119 state_plus_delta += parameter_blocks_[i]->Size();
120 }
121 return true;
122 }
123
SetParameterOffsetsAndIndex()124 void Program::SetParameterOffsetsAndIndex() {
125 // Set positions for all parameters appearing as arguments to residuals to one
126 // past the end of the parameter block array.
127 for (int i = 0; i < residual_blocks_.size(); ++i) {
128 ResidualBlock* residual_block = residual_blocks_[i];
129 for (int j = 0; j < residual_block->NumParameterBlocks(); ++j) {
130 residual_block->parameter_blocks()[j]->set_index(-1);
131 }
132 }
133 // For parameters that appear in the program, set their position and offset.
134 int state_offset = 0;
135 int delta_offset = 0;
136 for (int i = 0; i < parameter_blocks_.size(); ++i) {
137 parameter_blocks_[i]->set_index(i);
138 parameter_blocks_[i]->set_state_offset(state_offset);
139 parameter_blocks_[i]->set_delta_offset(delta_offset);
140 state_offset += parameter_blocks_[i]->Size();
141 delta_offset += parameter_blocks_[i]->LocalSize();
142 }
143 }
144
IsValid() const145 bool Program::IsValid() const {
146 for (int i = 0; i < residual_blocks_.size(); ++i) {
147 const ResidualBlock* residual_block = residual_blocks_[i];
148 if (residual_block->index() != i) {
149 LOG(WARNING) << "Residual block: " << i
150 << " has incorrect index: " << residual_block->index();
151 return false;
152 }
153 }
154
155 int state_offset = 0;
156 int delta_offset = 0;
157 for (int i = 0; i < parameter_blocks_.size(); ++i) {
158 const ParameterBlock* parameter_block = parameter_blocks_[i];
159 if (parameter_block->index() != i ||
160 parameter_block->state_offset() != state_offset ||
161 parameter_block->delta_offset() != delta_offset) {
162 LOG(WARNING) << "Parameter block: " << i
163 << "has incorrect indexing information: "
164 << parameter_block->ToString();
165 return false;
166 }
167
168 state_offset += parameter_blocks_[i]->Size();
169 delta_offset += parameter_blocks_[i]->LocalSize();
170 }
171
172 return true;
173 }
174
ParameterBlocksAreFinite(string * message) const175 bool Program::ParameterBlocksAreFinite(string* message) const {
176 CHECK_NOTNULL(message);
177 for (int i = 0; i < parameter_blocks_.size(); ++i) {
178 const ParameterBlock* parameter_block = parameter_blocks_[i];
179 const double* array = parameter_block->user_state();
180 const int size = parameter_block->Size();
181 const int invalid_index = FindInvalidValue(size, array);
182 if (invalid_index != size) {
183 *message = StringPrintf(
184 "ParameterBlock: %p with size %d has at least one invalid value.\n"
185 "First invalid value is at index: %d.\n"
186 "Parameter block values: ",
187 array, size, invalid_index);
188 AppendArrayToString(size, array, message);
189 return false;
190 }
191 }
192 return true;
193 }
194
IsBoundsConstrained() const195 bool Program::IsBoundsConstrained() const {
196 for (int i = 0; i < parameter_blocks_.size(); ++i) {
197 const ParameterBlock* parameter_block = parameter_blocks_[i];
198 if (parameter_block->IsConstant()) {
199 continue;
200 }
201 const int size = parameter_block->Size();
202 for (int j = 0; j < size; ++j) {
203 const double lower_bound = parameter_block->LowerBoundForParameter(j);
204 const double upper_bound = parameter_block->UpperBoundForParameter(j);
205 if (lower_bound > -std::numeric_limits<double>::max() ||
206 upper_bound < std::numeric_limits<double>::max()) {
207 return true;
208 }
209 }
210 }
211 return false;
212 }
213
IsFeasible(string * message) const214 bool Program::IsFeasible(string* message) const {
215 CHECK_NOTNULL(message);
216 for (int i = 0; i < parameter_blocks_.size(); ++i) {
217 const ParameterBlock* parameter_block = parameter_blocks_[i];
218 const double* parameters = parameter_block->user_state();
219 const int size = parameter_block->Size();
220 if (parameter_block->IsConstant()) {
221 // Constant parameter blocks must start in the feasible region
222 // to ultimately produce a feasible solution, since Ceres cannot
223 // change them.
224 for (int j = 0; j < size; ++j) {
225 const double lower_bound = parameter_block->LowerBoundForParameter(j);
226 const double upper_bound = parameter_block->UpperBoundForParameter(j);
227 if (parameters[j] < lower_bound || parameters[j] > upper_bound) {
228 *message = StringPrintf(
229 "ParameterBlock: %p with size %d has at least one infeasible "
230 "value."
231 "\nFirst infeasible value is at index: %d."
232 "\nLower bound: %e, value: %e, upper bound: %e"
233 "\nParameter block values: ",
234 parameters, size, j, lower_bound, parameters[j], upper_bound);
235 AppendArrayToString(size, parameters, message);
236 return false;
237 }
238 }
239 } else {
240 // Variable parameter blocks must have non-empty feasible
241 // regions, otherwise there is no way to produce a feasible
242 // solution.
243 for (int j = 0; j < size; ++j) {
244 const double lower_bound = parameter_block->LowerBoundForParameter(j);
245 const double upper_bound = parameter_block->UpperBoundForParameter(j);
246 if (lower_bound >= upper_bound) {
247 *message = StringPrintf(
248 "ParameterBlock: %p with size %d has at least one infeasible "
249 "bound."
250 "\nFirst infeasible bound is at index: %d."
251 "\nLower bound: %e, upper bound: %e"
252 "\nParameter block values: ",
253 parameters, size, j, lower_bound, upper_bound);
254 AppendArrayToString(size, parameters, message);
255 return false;
256 }
257 }
258 }
259 }
260
261 return true;
262 }
263
CreateReducedProgram(vector<double * > * removed_parameter_blocks,double * fixed_cost,string * error) const264 Program* Program::CreateReducedProgram(vector<double*>* removed_parameter_blocks,
265 double* fixed_cost,
266 string* error) const {
267 CHECK_NOTNULL(removed_parameter_blocks);
268 CHECK_NOTNULL(fixed_cost);
269 CHECK_NOTNULL(error);
270
271 scoped_ptr<Program> reduced_program(new Program(*this));
272 if (!reduced_program->RemoveFixedBlocks(removed_parameter_blocks,
273 fixed_cost,
274 error)) {
275 return NULL;
276 }
277
278 reduced_program->SetParameterOffsetsAndIndex();
279 return reduced_program.release();
280 }
281
RemoveFixedBlocks(vector<double * > * removed_parameter_blocks,double * fixed_cost,string * error)282 bool Program::RemoveFixedBlocks(vector<double*>* removed_parameter_blocks,
283 double* fixed_cost,
284 string* error) {
285 CHECK_NOTNULL(removed_parameter_blocks);
286 CHECK_NOTNULL(fixed_cost);
287 CHECK_NOTNULL(error);
288
289 scoped_array<double> residual_block_evaluate_scratch;
290 residual_block_evaluate_scratch.reset(
291 new double[MaxScratchDoublesNeededForEvaluate()]);
292 *fixed_cost = 0.0;
293
294 // Mark all the parameters as unused. Abuse the index member of the
295 // parameter blocks for the marking.
296 for (int i = 0; i < parameter_blocks_.size(); ++i) {
297 parameter_blocks_[i]->set_index(-1);
298 }
299
300 // Filter out residual that have all-constant parameters, and mark
301 // all the parameter blocks that appear in residuals.
302 int num_active_residual_blocks = 0;
303 for (int i = 0; i < residual_blocks_.size(); ++i) {
304 ResidualBlock* residual_block = residual_blocks_[i];
305 int num_parameter_blocks = residual_block->NumParameterBlocks();
306
307 // Determine if the residual block is fixed, and also mark varying
308 // parameters that appear in the residual block.
309 bool all_constant = true;
310 for (int k = 0; k < num_parameter_blocks; k++) {
311 ParameterBlock* parameter_block = residual_block->parameter_blocks()[k];
312 if (!parameter_block->IsConstant()) {
313 all_constant = false;
314 parameter_block->set_index(1);
315 }
316 }
317
318 if (!all_constant) {
319 residual_blocks_[num_active_residual_blocks++] = residual_block;
320 continue;
321 }
322
323 // The residual is constant and will be removed, so its cost is
324 // added to the variable fixed_cost.
325 double cost = 0.0;
326 if (!residual_block->Evaluate(true,
327 &cost,
328 NULL,
329 NULL,
330 residual_block_evaluate_scratch.get())) {
331 *error = StringPrintf("Evaluation of the residual %d failed during "
332 "removal of fixed residual blocks.", i);
333 return false;
334 }
335 *fixed_cost += cost;
336 }
337 residual_blocks_.resize(num_active_residual_blocks);
338
339 // Filter out unused or fixed parameter blocks.
340 int num_active_parameter_blocks = 0;
341 removed_parameter_blocks->clear();
342 for (int i = 0; i < parameter_blocks_.size(); ++i) {
343 ParameterBlock* parameter_block = parameter_blocks_[i];
344 if (parameter_block->index() == -1) {
345 removed_parameter_blocks->push_back(parameter_block->mutable_user_state());
346 } else {
347 parameter_blocks_[num_active_parameter_blocks++] = parameter_block;
348 }
349 }
350 parameter_blocks_.resize(num_active_parameter_blocks);
351
352 if (!(((NumResidualBlocks() == 0) &&
353 (NumParameterBlocks() == 0)) ||
354 ((NumResidualBlocks() != 0) &&
355 (NumParameterBlocks() != 0)))) {
356 *error = "Congratulations, you found a bug in Ceres. Please report it.";
357 return false;
358 }
359
360 return true;
361 }
362
IsParameterBlockSetIndependent(const set<double * > & independent_set) const363 bool Program::IsParameterBlockSetIndependent(const set<double*>& independent_set) const {
364 // Loop over each residual block and ensure that no two parameter
365 // blocks in the same residual block are part of
366 // parameter_block_ptrs as that would violate the assumption that it
367 // is an independent set in the Hessian matrix.
368 for (vector<ResidualBlock*>::const_iterator it = residual_blocks_.begin();
369 it != residual_blocks_.end();
370 ++it) {
371 ParameterBlock* const* parameter_blocks = (*it)->parameter_blocks();
372 const int num_parameter_blocks = (*it)->NumParameterBlocks();
373 int count = 0;
374 for (int i = 0; i < num_parameter_blocks; ++i) {
375 count += independent_set.count(
376 parameter_blocks[i]->mutable_user_state());
377 }
378 if (count > 1) {
379 return false;
380 }
381 }
382 return true;
383 }
384
CreateJacobianBlockSparsityTranspose() const385 TripletSparseMatrix* Program::CreateJacobianBlockSparsityTranspose() const {
386 // Matrix to store the block sparsity structure of the Jacobian.
387 TripletSparseMatrix* tsm =
388 new TripletSparseMatrix(NumParameterBlocks(),
389 NumResidualBlocks(),
390 10 * NumResidualBlocks());
391 int num_nonzeros = 0;
392 int* rows = tsm->mutable_rows();
393 int* cols = tsm->mutable_cols();
394 double* values = tsm->mutable_values();
395
396 for (int c = 0; c < residual_blocks_.size(); ++c) {
397 const ResidualBlock* residual_block = residual_blocks_[c];
398 const int num_parameter_blocks = residual_block->NumParameterBlocks();
399 ParameterBlock* const* parameter_blocks =
400 residual_block->parameter_blocks();
401
402 for (int j = 0; j < num_parameter_blocks; ++j) {
403 if (parameter_blocks[j]->IsConstant()) {
404 continue;
405 }
406
407 // Re-size the matrix if needed.
408 if (num_nonzeros >= tsm->max_num_nonzeros()) {
409 tsm->set_num_nonzeros(num_nonzeros);
410 tsm->Reserve(2 * num_nonzeros);
411 rows = tsm->mutable_rows();
412 cols = tsm->mutable_cols();
413 values = tsm->mutable_values();
414 }
415
416 const int r = parameter_blocks[j]->index();
417 rows[num_nonzeros] = r;
418 cols[num_nonzeros] = c;
419 values[num_nonzeros] = 1.0;
420 ++num_nonzeros;
421 }
422 }
423
424 tsm->set_num_nonzeros(num_nonzeros);
425 return tsm;
426 }
427
NumResidualBlocks() const428 int Program::NumResidualBlocks() const {
429 return residual_blocks_.size();
430 }
431
NumParameterBlocks() const432 int Program::NumParameterBlocks() const {
433 return parameter_blocks_.size();
434 }
435
NumResiduals() const436 int Program::NumResiduals() const {
437 int num_residuals = 0;
438 for (int i = 0; i < residual_blocks_.size(); ++i) {
439 num_residuals += residual_blocks_[i]->NumResiduals();
440 }
441 return num_residuals;
442 }
443
NumParameters() const444 int Program::NumParameters() const {
445 int num_parameters = 0;
446 for (int i = 0; i < parameter_blocks_.size(); ++i) {
447 num_parameters += parameter_blocks_[i]->Size();
448 }
449 return num_parameters;
450 }
451
NumEffectiveParameters() const452 int Program::NumEffectiveParameters() const {
453 int num_parameters = 0;
454 for (int i = 0; i < parameter_blocks_.size(); ++i) {
455 num_parameters += parameter_blocks_[i]->LocalSize();
456 }
457 return num_parameters;
458 }
459
MaxScratchDoublesNeededForEvaluate() const460 int Program::MaxScratchDoublesNeededForEvaluate() const {
461 // Compute the scratch space needed for evaluate.
462 int max_scratch_bytes_for_evaluate = 0;
463 for (int i = 0; i < residual_blocks_.size(); ++i) {
464 max_scratch_bytes_for_evaluate =
465 max(max_scratch_bytes_for_evaluate,
466 residual_blocks_[i]->NumScratchDoublesForEvaluate());
467 }
468 return max_scratch_bytes_for_evaluate;
469 }
470
MaxDerivativesPerResidualBlock() const471 int Program::MaxDerivativesPerResidualBlock() const {
472 int max_derivatives = 0;
473 for (int i = 0; i < residual_blocks_.size(); ++i) {
474 int derivatives = 0;
475 ResidualBlock* residual_block = residual_blocks_[i];
476 int num_parameters = residual_block->NumParameterBlocks();
477 for (int j = 0; j < num_parameters; ++j) {
478 derivatives += residual_block->NumResiduals() *
479 residual_block->parameter_blocks()[j]->LocalSize();
480 }
481 max_derivatives = max(max_derivatives, derivatives);
482 }
483 return max_derivatives;
484 }
485
MaxParametersPerResidualBlock() const486 int Program::MaxParametersPerResidualBlock() const {
487 int max_parameters = 0;
488 for (int i = 0; i < residual_blocks_.size(); ++i) {
489 max_parameters = max(max_parameters,
490 residual_blocks_[i]->NumParameterBlocks());
491 }
492 return max_parameters;
493 }
494
MaxResidualsPerResidualBlock() const495 int Program::MaxResidualsPerResidualBlock() const {
496 int max_residuals = 0;
497 for (int i = 0; i < residual_blocks_.size(); ++i) {
498 max_residuals = max(max_residuals,
499 residual_blocks_[i]->NumResiduals());
500 }
501 return max_residuals;
502 }
503
ToString() const504 string Program::ToString() const {
505 string ret = "Program dump\n";
506 ret += StringPrintf("Number of parameter blocks: %d\n", NumParameterBlocks());
507 ret += StringPrintf("Number of parameters: %d\n", NumParameters());
508 ret += "Parameters:\n";
509 for (int i = 0; i < parameter_blocks_.size(); ++i) {
510 ret += StringPrintf("%d: %s\n",
511 i, parameter_blocks_[i]->ToString().c_str());
512 }
513 return ret;
514 }
515
516 } // namespace internal
517 } // namespace ceres
518