• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &parameter_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