• 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/solver_impl.h"
32 
33 #include <cstdio>
34 #include <iostream>  // NOLINT
35 #include <numeric>
36 #include "ceres/coordinate_descent_minimizer.h"
37 #include "ceres/evaluator.h"
38 #include "ceres/gradient_checking_cost_function.h"
39 #include "ceres/iteration_callback.h"
40 #include "ceres/levenberg_marquardt_strategy.h"
41 #include "ceres/linear_solver.h"
42 #include "ceres/map_util.h"
43 #include "ceres/minimizer.h"
44 #include "ceres/ordered_groups.h"
45 #include "ceres/parameter_block.h"
46 #include "ceres/parameter_block_ordering.h"
47 #include "ceres/problem.h"
48 #include "ceres/problem_impl.h"
49 #include "ceres/program.h"
50 #include "ceres/residual_block.h"
51 #include "ceres/stringprintf.h"
52 #include "ceres/trust_region_minimizer.h"
53 #include "ceres/wall_time.h"
54 
55 namespace ceres {
56 namespace internal {
57 namespace {
58 
59 // Callback for updating the user's parameter blocks. Updates are only
60 // done if the step is successful.
61 class StateUpdatingCallback : public IterationCallback {
62  public:
StateUpdatingCallback(Program * program,double * parameters)63   StateUpdatingCallback(Program* program, double* parameters)
64       : program_(program), parameters_(parameters) {}
65 
operator ()(const IterationSummary & summary)66   CallbackReturnType operator()(const IterationSummary& summary) {
67     if (summary.step_is_successful) {
68       program_->StateVectorToParameterBlocks(parameters_);
69       program_->CopyParameterBlockStateToUserState();
70     }
71     return SOLVER_CONTINUE;
72   }
73 
74  private:
75   Program* program_;
76   double* parameters_;
77 };
78 
79 // Callback for logging the state of the minimizer to STDERR or STDOUT
80 // depending on the user's preferences and logging level.
81 class LoggingCallback : public IterationCallback {
82  public:
LoggingCallback(bool log_to_stdout)83   explicit LoggingCallback(bool log_to_stdout)
84       : log_to_stdout_(log_to_stdout) {}
85 
~LoggingCallback()86   ~LoggingCallback() {}
87 
operator ()(const IterationSummary & summary)88   CallbackReturnType operator()(const IterationSummary& summary) {
89     const char* kReportRowFormat =
90         "% 4d: f:% 8e d:% 3.2e g:% 3.2e h:% 3.2e "
91         "rho:% 3.2e mu:% 3.2e li:% 3d it:% 3.2e tt:% 3.2e";
92     string output = StringPrintf(kReportRowFormat,
93                                  summary.iteration,
94                                  summary.cost,
95                                  summary.cost_change,
96                                  summary.gradient_max_norm,
97                                  summary.step_norm,
98                                  summary.relative_decrease,
99                                  summary.trust_region_radius,
100                                  summary.linear_solver_iterations,
101                                  summary.iteration_time_in_seconds,
102                                  summary.cumulative_time_in_seconds);
103     if (log_to_stdout_) {
104       cout << output << endl;
105     } else {
106       VLOG(1) << output;
107     }
108     return SOLVER_CONTINUE;
109   }
110 
111  private:
112   const bool log_to_stdout_;
113 };
114 
115 // Basic callback to record the execution of the solver to a file for
116 // offline analysis.
117 class FileLoggingCallback : public IterationCallback {
118  public:
FileLoggingCallback(const string & filename)119   explicit FileLoggingCallback(const string& filename)
120       : fptr_(NULL) {
121     fptr_ = fopen(filename.c_str(), "w");
122     CHECK_NOTNULL(fptr_);
123   }
124 
~FileLoggingCallback()125   virtual ~FileLoggingCallback() {
126     if (fptr_ != NULL) {
127       fclose(fptr_);
128     }
129   }
130 
operator ()(const IterationSummary & summary)131   virtual CallbackReturnType operator()(const IterationSummary& summary) {
132     fprintf(fptr_,
133             "%4d %e %e\n",
134             summary.iteration,
135             summary.cost,
136             summary.cumulative_time_in_seconds);
137     return SOLVER_CONTINUE;
138   }
139  private:
140     FILE* fptr_;
141 };
142 
143 }  // namespace
144 
Minimize(const Solver::Options & options,Program * program,CoordinateDescentMinimizer * inner_iteration_minimizer,Evaluator * evaluator,LinearSolver * linear_solver,double * parameters,Solver::Summary * summary)145 void SolverImpl::Minimize(const Solver::Options& options,
146                           Program* program,
147                           CoordinateDescentMinimizer* inner_iteration_minimizer,
148                           Evaluator* evaluator,
149                           LinearSolver* linear_solver,
150                           double* parameters,
151                           Solver::Summary* summary) {
152   Minimizer::Options minimizer_options(options);
153 
154   // TODO(sameeragarwal): Add support for logging the configuration
155   // and more detailed stats.
156   scoped_ptr<IterationCallback> file_logging_callback;
157   if (!options.solver_log.empty()) {
158     file_logging_callback.reset(new FileLoggingCallback(options.solver_log));
159     minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(),
160                                        file_logging_callback.get());
161   }
162 
163   LoggingCallback logging_callback(options.minimizer_progress_to_stdout);
164   if (options.logging_type != SILENT) {
165     minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(),
166                                        &logging_callback);
167   }
168 
169   StateUpdatingCallback updating_callback(program, parameters);
170   if (options.update_state_every_iteration) {
171     // This must get pushed to the front of the callbacks so that it is run
172     // before any of the user callbacks.
173     minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(),
174                                        &updating_callback);
175   }
176 
177   minimizer_options.evaluator = evaluator;
178   scoped_ptr<SparseMatrix> jacobian(evaluator->CreateJacobian());
179   minimizer_options.jacobian = jacobian.get();
180   minimizer_options.inner_iteration_minimizer = inner_iteration_minimizer;
181 
182   TrustRegionStrategy::Options trust_region_strategy_options;
183   trust_region_strategy_options.linear_solver = linear_solver;
184   trust_region_strategy_options.initial_radius =
185       options.initial_trust_region_radius;
186   trust_region_strategy_options.max_radius = options.max_trust_region_radius;
187   trust_region_strategy_options.lm_min_diagonal = options.lm_min_diagonal;
188   trust_region_strategy_options.lm_max_diagonal = options.lm_max_diagonal;
189   trust_region_strategy_options.trust_region_strategy_type =
190       options.trust_region_strategy_type;
191   trust_region_strategy_options.dogleg_type = options.dogleg_type;
192   scoped_ptr<TrustRegionStrategy> strategy(
193       TrustRegionStrategy::Create(trust_region_strategy_options));
194   minimizer_options.trust_region_strategy = strategy.get();
195 
196   TrustRegionMinimizer minimizer;
197   double minimizer_start_time = WallTimeInSeconds();
198   minimizer.Minimize(minimizer_options, parameters, summary);
199   summary->minimizer_time_in_seconds =
200       WallTimeInSeconds() - minimizer_start_time;
201 }
202 
Solve(const Solver::Options & original_options,ProblemImpl * original_problem_impl,Solver::Summary * summary)203 void SolverImpl::Solve(const Solver::Options& original_options,
204                        ProblemImpl* original_problem_impl,
205                        Solver::Summary* summary) {
206   double solver_start_time = WallTimeInSeconds();
207 
208   Program* original_program = original_problem_impl->mutable_program();
209   ProblemImpl* problem_impl = original_problem_impl;
210 
211   // Reset the summary object to its default values.
212   *CHECK_NOTNULL(summary) = Solver::Summary();
213 
214   summary->num_parameter_blocks = problem_impl->NumParameterBlocks();
215   summary->num_parameters = problem_impl->NumParameters();
216   summary->num_residual_blocks = problem_impl->NumResidualBlocks();
217   summary->num_residuals = problem_impl->NumResiduals();
218 
219   // Empty programs are usually a user error.
220   if (summary->num_parameter_blocks == 0) {
221     summary->error = "Problem contains no parameter blocks.";
222     LOG(ERROR) << summary->error;
223     return;
224   }
225 
226   if (summary->num_residual_blocks == 0) {
227     summary->error = "Problem contains no residual blocks.";
228     LOG(ERROR) << summary->error;
229     return;
230   }
231 
232   Solver::Options options(original_options);
233   options.linear_solver_ordering = NULL;
234   options.inner_iteration_ordering = NULL;
235 
236 #ifndef CERES_USE_OPENMP
237   if (options.num_threads > 1) {
238     LOG(WARNING)
239         << "OpenMP support is not compiled into this binary; "
240         << "only options.num_threads=1 is supported. Switching "
241         << "to single threaded mode.";
242     options.num_threads = 1;
243   }
244   if (options.num_linear_solver_threads > 1) {
245     LOG(WARNING)
246         << "OpenMP support is not compiled into this binary; "
247         << "only options.num_linear_solver_threads=1 is supported. Switching "
248         << "to single threaded mode.";
249     options.num_linear_solver_threads = 1;
250   }
251 #endif
252 
253   summary->num_threads_given = original_options.num_threads;
254   summary->num_threads_used = options.num_threads;
255 
256   if (options.lsqp_iterations_to_dump.size() > 0) {
257     LOG(WARNING) << "Dumping linear least squares problems to disk is"
258         " currently broken. Ignoring Solver::Options::lsqp_iterations_to_dump";
259   }
260 
261   // Evaluate the initial cost, residual vector and the jacobian
262   // matrix if requested by the user. The initial cost needs to be
263   // computed on the original unpreprocessed problem, as it is used to
264   // determine the value of the "fixed" part of the objective function
265   // after the problem has undergone reduction.
266   if (!Evaluator::Evaluate(original_program,
267                            options.num_threads,
268                            &(summary->initial_cost),
269                            options.return_initial_residuals
270                            ? &summary->initial_residuals
271                            : NULL,
272                            options.return_initial_gradient
273                            ? &summary->initial_gradient
274                            : NULL,
275                            options.return_initial_jacobian
276                            ? &summary->initial_jacobian
277                            : NULL)) {
278     summary->termination_type = NUMERICAL_FAILURE;
279     summary->error = "Unable to evaluate the initial cost.";
280     LOG(ERROR) << summary->error;
281     return;
282   }
283 
284   original_program->SetParameterBlockStatePtrsToUserStatePtrs();
285 
286   // If the user requests gradient checking, construct a new
287   // ProblemImpl by wrapping the CostFunctions of problem_impl inside
288   // GradientCheckingCostFunction and replacing problem_impl with
289   // gradient_checking_problem_impl.
290   scoped_ptr<ProblemImpl> gradient_checking_problem_impl;
291   if (options.check_gradients) {
292     VLOG(1) << "Checking Gradients";
293     gradient_checking_problem_impl.reset(
294         CreateGradientCheckingProblemImpl(
295             problem_impl,
296             options.numeric_derivative_relative_step_size,
297             options.gradient_check_relative_precision));
298 
299     // From here on, problem_impl will point to the gradient checking
300     // version.
301     problem_impl = gradient_checking_problem_impl.get();
302   }
303 
304   if (original_options.linear_solver_ordering != NULL) {
305     if (!IsOrderingValid(original_options, problem_impl, &summary->error)) {
306       LOG(ERROR) << summary->error;
307       return;
308     }
309     options.linear_solver_ordering =
310         new ParameterBlockOrdering(*original_options.linear_solver_ordering);
311   } else {
312     options.linear_solver_ordering = new ParameterBlockOrdering;
313     const ProblemImpl::ParameterMap& parameter_map =
314         problem_impl->parameter_map();
315     for (ProblemImpl::ParameterMap::const_iterator it = parameter_map.begin();
316          it != parameter_map.end();
317          ++it) {
318       options.linear_solver_ordering->AddElementToGroup(it->first, 0);
319     }
320   }
321 
322   // Create the three objects needed to minimize: the transformed program, the
323   // evaluator, and the linear solver.
324   scoped_ptr<Program> reduced_program(CreateReducedProgram(&options,
325                                                            problem_impl,
326                                                            &summary->fixed_cost,
327                                                            &summary->error));
328   if (reduced_program == NULL) {
329     return;
330   }
331 
332   summary->num_parameter_blocks_reduced = reduced_program->NumParameterBlocks();
333   summary->num_parameters_reduced = reduced_program->NumParameters();
334   summary->num_residual_blocks_reduced = reduced_program->NumResidualBlocks();
335   summary->num_residuals_reduced = reduced_program->NumResiduals();
336 
337   if (summary->num_parameter_blocks_reduced == 0) {
338     summary->preprocessor_time_in_seconds =
339         WallTimeInSeconds() - solver_start_time;
340 
341     LOG(INFO) << "Terminating: FUNCTION_TOLERANCE reached. "
342               << "No non-constant parameter blocks found.";
343 
344     // FUNCTION_TOLERANCE is the right convergence here, as we know
345     // that the objective function is constant and cannot be changed
346     // any further.
347     summary->termination_type = FUNCTION_TOLERANCE;
348 
349     double post_process_start_time = WallTimeInSeconds();
350     // Evaluate the final cost, residual vector and the jacobian
351     // matrix if requested by the user.
352     if (!Evaluator::Evaluate(original_program,
353                              options.num_threads,
354                              &summary->final_cost,
355                              options.return_final_residuals
356                              ? &summary->final_residuals
357                              : NULL,
358                              options.return_final_gradient
359                              ? &summary->final_gradient
360                              : NULL,
361                              options.return_final_jacobian
362                              ? &summary->final_jacobian
363                              : NULL)) {
364       summary->termination_type = NUMERICAL_FAILURE;
365       summary->error = "Unable to evaluate the final cost.";
366       LOG(ERROR) << summary->error;
367       return;
368     }
369 
370     // Ensure the program state is set to the user parameters on the way out.
371     original_program->SetParameterBlockStatePtrsToUserStatePtrs();
372 
373     summary->postprocessor_time_in_seconds =
374         WallTimeInSeconds() - post_process_start_time;
375     return;
376   }
377 
378   scoped_ptr<LinearSolver>
379       linear_solver(CreateLinearSolver(&options, &summary->error));
380   if (linear_solver == NULL) {
381     return;
382   }
383 
384   summary->linear_solver_type_given = original_options.linear_solver_type;
385   summary->linear_solver_type_used = options.linear_solver_type;
386 
387   summary->preconditioner_type = options.preconditioner_type;
388 
389   summary->num_linear_solver_threads_given =
390       original_options.num_linear_solver_threads;
391   summary->num_linear_solver_threads_used = options.num_linear_solver_threads;
392 
393   summary->sparse_linear_algebra_library =
394       options.sparse_linear_algebra_library;
395 
396   summary->trust_region_strategy_type = options.trust_region_strategy_type;
397   summary->dogleg_type = options.dogleg_type;
398 
399   // Only Schur types require the lexicographic reordering.
400   if (IsSchurType(options.linear_solver_type)) {
401     const int num_eliminate_blocks =
402         options.linear_solver_ordering
403         ->group_to_elements().begin()
404         ->second.size();
405     if (!LexicographicallyOrderResidualBlocks(num_eliminate_blocks,
406                                               reduced_program.get(),
407                                               &summary->error)) {
408       return;
409     }
410   }
411 
412   scoped_ptr<Evaluator> evaluator(CreateEvaluator(options,
413                                                   problem_impl->parameter_map(),
414                                                   reduced_program.get(),
415                                                   &summary->error));
416   if (evaluator == NULL) {
417     return;
418   }
419 
420   scoped_ptr<CoordinateDescentMinimizer> inner_iteration_minimizer;
421   if (options.use_inner_iterations) {
422     if (reduced_program->parameter_blocks().size() < 2) {
423       LOG(WARNING) << "Reduced problem only contains one parameter block."
424                    << "Disabling inner iterations.";
425     } else {
426       inner_iteration_minimizer.reset(
427           CreateInnerIterationMinimizer(original_options,
428                                         *reduced_program,
429                                         problem_impl->parameter_map(),
430                                         &summary->error));
431       if (inner_iteration_minimizer == NULL) {
432         LOG(ERROR) << summary->error;
433         return;
434       }
435     }
436   }
437 
438   // The optimizer works on contiguous parameter vectors; allocate some.
439   Vector parameters(reduced_program->NumParameters());
440 
441   // Collect the discontiguous parameters into a contiguous state vector.
442   reduced_program->ParameterBlocksToStateVector(parameters.data());
443 
444   Vector original_parameters = parameters;
445 
446   double minimizer_start_time = WallTimeInSeconds();
447   summary->preprocessor_time_in_seconds =
448       minimizer_start_time - solver_start_time;
449 
450   // Run the optimization.
451   Minimize(options,
452            reduced_program.get(),
453            inner_iteration_minimizer.get(),
454            evaluator.get(),
455            linear_solver.get(),
456            parameters.data(),
457            summary);
458 
459   // If the user aborted mid-optimization or the optimization
460   // terminated because of a numerical failure, then return without
461   // updating user state.
462   if (summary->termination_type == USER_ABORT ||
463       summary->termination_type == NUMERICAL_FAILURE) {
464     return;
465   }
466 
467   double post_process_start_time = WallTimeInSeconds();
468 
469   // Push the contiguous optimized parameters back to the user's parameters.
470   reduced_program->StateVectorToParameterBlocks(parameters.data());
471   reduced_program->CopyParameterBlockStateToUserState();
472 
473   // Evaluate the final cost, residual vector and the jacobian
474   // matrix if requested by the user.
475   if (!Evaluator::Evaluate(original_program,
476                            options.num_threads,
477                            &summary->final_cost,
478                            options.return_final_residuals
479                            ? &summary->final_residuals
480                            : NULL,
481                            options.return_final_gradient
482                            ? &summary->final_gradient
483                            : NULL,
484                            options.return_final_jacobian
485                            ? &summary->final_jacobian
486                            : NULL)) {
487     // This failure requires careful handling.
488     //
489     // At this point, we have modified the user's state, but the
490     // evaluation failed and we inform him of NUMERICAL_FAILURE. Ceres
491     // guarantees that user's state is not modified if the solver
492     // returns with NUMERICAL_FAILURE. Thus, we need to restore the
493     // user's state to their original values.
494 
495     reduced_program->StateVectorToParameterBlocks(original_parameters.data());
496     reduced_program->CopyParameterBlockStateToUserState();
497 
498     summary->termination_type = NUMERICAL_FAILURE;
499     summary->error = "Unable to evaluate the final cost.";
500     LOG(ERROR) << summary->error;
501     return;
502   }
503 
504   // Ensure the program state is set to the user parameters on the way out.
505   original_program->SetParameterBlockStatePtrsToUserStatePtrs();
506 
507   // Stick a fork in it, we're done.
508   summary->postprocessor_time_in_seconds =
509       WallTimeInSeconds() - post_process_start_time;
510 }
511 
IsOrderingValid(const Solver::Options & options,const ProblemImpl * problem_impl,string * error)512 bool SolverImpl::IsOrderingValid(const Solver::Options& options,
513                                  const ProblemImpl* problem_impl,
514                                  string* error) {
515   if (options.linear_solver_ordering->NumElements() !=
516       problem_impl->NumParameterBlocks()) {
517       *error = "Number of parameter blocks in user supplied ordering "
518           "does not match the number of parameter blocks in the problem";
519     return false;
520   }
521 
522   const Program& program = problem_impl->program();
523   const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
524   for (vector<ParameterBlock*>::const_iterator it = parameter_blocks.begin();
525        it != parameter_blocks.end();
526        ++it) {
527     if (!options.linear_solver_ordering
528         ->IsMember(const_cast<double*>((*it)->user_state()))) {
529       *error = "Problem contains a parameter block that is not in "
530           "the user specified ordering.";
531       return false;
532     }
533   }
534 
535   if (IsSchurType(options.linear_solver_type) &&
536       options.linear_solver_ordering->NumGroups() > 1) {
537     const vector<ResidualBlock*>& residual_blocks = program.residual_blocks();
538     const set<double*>& e_blocks  =
539         options.linear_solver_ordering->group_to_elements().begin()->second;
540     if (!IsParameterBlockSetIndependent(e_blocks, residual_blocks)) {
541       *error = "The user requested the use of a Schur type solver. "
542           "But the first elimination group in the ordering is not an "
543           "independent set.";
544       return false;
545     }
546   }
547   return true;
548 }
549 
IsParameterBlockSetIndependent(const set<double * > & parameter_block_ptrs,const vector<ResidualBlock * > & residual_blocks)550 bool SolverImpl::IsParameterBlockSetIndependent(const set<double*>& parameter_block_ptrs,
551                                                 const vector<ResidualBlock*>& residual_blocks) {
552   // Loop over each residual block and ensure that no two parameter
553   // blocks in the same residual block are part of
554   // parameter_block_ptrs as that would violate the assumption that it
555   // is an independent set in the Hessian matrix.
556   for (vector<ResidualBlock*>::const_iterator it = residual_blocks.begin();
557        it != residual_blocks.end();
558        ++it) {
559     ParameterBlock* const* parameter_blocks = (*it)->parameter_blocks();
560     const int num_parameter_blocks = (*it)->NumParameterBlocks();
561     int count = 0;
562     for (int i = 0; i < num_parameter_blocks; ++i) {
563       count += parameter_block_ptrs.count(
564           parameter_blocks[i]->mutable_user_state());
565     }
566     if (count > 1) {
567       return false;
568     }
569   }
570   return true;
571 }
572 
573 
574 // Strips varying parameters and residuals, maintaining order, and updating
575 // num_eliminate_blocks.
RemoveFixedBlocksFromProgram(Program * program,ParameterBlockOrdering * ordering,double * fixed_cost,string * error)576 bool SolverImpl::RemoveFixedBlocksFromProgram(Program* program,
577                                               ParameterBlockOrdering* ordering,
578                                               double* fixed_cost,
579                                               string* error) {
580   vector<ParameterBlock*>* parameter_blocks =
581       program->mutable_parameter_blocks();
582 
583   scoped_array<double> residual_block_evaluate_scratch;
584   if (fixed_cost != NULL) {
585     residual_block_evaluate_scratch.reset(
586         new double[program->MaxScratchDoublesNeededForEvaluate()]);
587     *fixed_cost = 0.0;
588   }
589 
590   // Mark all the parameters as unused. Abuse the index member of the parameter
591   // blocks for the marking.
592   for (int i = 0; i < parameter_blocks->size(); ++i) {
593     (*parameter_blocks)[i]->set_index(-1);
594   }
595 
596   // Filter out residual that have all-constant parameters, and mark all the
597   // parameter blocks that appear in residuals.
598   {
599     vector<ResidualBlock*>* residual_blocks =
600         program->mutable_residual_blocks();
601     int j = 0;
602     for (int i = 0; i < residual_blocks->size(); ++i) {
603       ResidualBlock* residual_block = (*residual_blocks)[i];
604       int num_parameter_blocks = residual_block->NumParameterBlocks();
605 
606       // Determine if the residual block is fixed, and also mark varying
607       // parameters that appear in the residual block.
608       bool all_constant = true;
609       for (int k = 0; k < num_parameter_blocks; k++) {
610         ParameterBlock* parameter_block = residual_block->parameter_blocks()[k];
611         if (!parameter_block->IsConstant()) {
612           all_constant = false;
613           parameter_block->set_index(1);
614         }
615       }
616 
617       if (!all_constant) {
618         (*residual_blocks)[j++] = (*residual_blocks)[i];
619       } else if (fixed_cost != NULL) {
620         // The residual is constant and will be removed, so its cost is
621         // added to the variable fixed_cost.
622         double cost = 0.0;
623         if (!residual_block->Evaluate(
624               &cost, NULL, NULL, residual_block_evaluate_scratch.get())) {
625           *error = StringPrintf("Evaluation of the residual %d failed during "
626                                 "removal of fixed residual blocks.", i);
627           return false;
628         }
629         *fixed_cost += cost;
630       }
631     }
632     residual_blocks->resize(j);
633   }
634 
635   // Filter out unused or fixed parameter blocks, and update
636   // the ordering.
637   {
638     vector<ParameterBlock*>* parameter_blocks =
639         program->mutable_parameter_blocks();
640     int j = 0;
641     for (int i = 0; i < parameter_blocks->size(); ++i) {
642       ParameterBlock* parameter_block = (*parameter_blocks)[i];
643       if (parameter_block->index() == 1) {
644         (*parameter_blocks)[j++] = parameter_block;
645       } else {
646         ordering->Remove(parameter_block->mutable_user_state());
647       }
648     }
649     parameter_blocks->resize(j);
650   }
651 
652   CHECK(((program->NumResidualBlocks() == 0) &&
653          (program->NumParameterBlocks() == 0)) ||
654         ((program->NumResidualBlocks() != 0) &&
655          (program->NumParameterBlocks() != 0)))
656       << "Congratulations, you found a bug in Ceres. Please report it.";
657   return true;
658 }
659 
CreateReducedProgram(Solver::Options * options,ProblemImpl * problem_impl,double * fixed_cost,string * error)660 Program* SolverImpl::CreateReducedProgram(Solver::Options* options,
661                                           ProblemImpl* problem_impl,
662                                           double* fixed_cost,
663                                           string* error) {
664   CHECK_NOTNULL(options->linear_solver_ordering);
665   Program* original_program = problem_impl->mutable_program();
666   scoped_ptr<Program> transformed_program(new Program(*original_program));
667   ParameterBlockOrdering* linear_solver_ordering =
668       options->linear_solver_ordering;
669 
670   const int min_group_id =
671       linear_solver_ordering->group_to_elements().begin()->first;
672   const int original_num_groups = linear_solver_ordering->NumGroups();
673 
674   if (!RemoveFixedBlocksFromProgram(transformed_program.get(),
675                                     linear_solver_ordering,
676                                     fixed_cost,
677                                     error)) {
678     return NULL;
679   }
680 
681   if (transformed_program->NumParameterBlocks() == 0) {
682     if (transformed_program->NumResidualBlocks() > 0) {
683       *error = "Zero parameter blocks but non-zero residual blocks"
684           " in the reduced program. Congratulations, you found a "
685           "Ceres bug! Please report this error to the developers.";
686       return NULL;
687     }
688 
689     LOG(WARNING) << "No varying parameter blocks to optimize; "
690                  << "bailing early.";
691     return transformed_program.release();
692   }
693 
694   // If the user supplied an linear_solver_ordering with just one
695   // group, it is equivalent to the user supplying NULL as
696   // ordering. Ceres is completely free to choose the parameter block
697   // ordering as it sees fit. For Schur type solvers, this means that
698   // the user wishes for Ceres to identify the e_blocks, which we do
699   // by computing a maximal independent set.
700   if (original_num_groups == 1 && IsSchurType(options->linear_solver_type)) {
701     vector<ParameterBlock*> schur_ordering;
702     const int num_eliminate_blocks = ComputeSchurOrdering(*transformed_program,
703                                                           &schur_ordering);
704     CHECK_EQ(schur_ordering.size(), transformed_program->NumParameterBlocks())
705         << "Congratulations, you found a Ceres bug! Please report this error "
706         << "to the developers.";
707 
708     for (int i = 0; i < schur_ordering.size(); ++i) {
709       linear_solver_ordering->AddElementToGroup(
710           schur_ordering[i]->mutable_user_state(),
711           (i < num_eliminate_blocks) ? 0 : 1);
712     }
713   }
714 
715   if (!ApplyUserOrdering(problem_impl->parameter_map(),
716                          linear_solver_ordering,
717                          transformed_program.get(),
718                          error)) {
719     return NULL;
720   }
721 
722   // If the user requested the use of a Schur type solver, and
723   // supplied a non-NULL linear_solver_ordering object with more than
724   // one elimination group, then it can happen that after all the
725   // parameter blocks which are fixed or unused have been removed from
726   // the program and the ordering, there are no more parameter blocks
727   // in the first elimination group.
728   //
729   // In such a case, the use of a Schur type solver is not possible,
730   // as they assume there is at least one e_block. Thus, we
731   // automatically switch to one of the other solvers, depending on
732   // the user's indicated preferences.
733   if (IsSchurType(options->linear_solver_type) &&
734       original_num_groups > 1 &&
735       linear_solver_ordering->GroupSize(min_group_id) == 0) {
736     string msg = "No e_blocks remaining. Switching from ";
737     if (options->linear_solver_type == SPARSE_SCHUR) {
738       options->linear_solver_type = SPARSE_NORMAL_CHOLESKY;
739       msg += "SPARSE_SCHUR to SPARSE_NORMAL_CHOLESKY.";
740     } else if (options->linear_solver_type == DENSE_SCHUR) {
741       // TODO(sameeragarwal): This is probably not a great choice.
742       // Ideally, we should have a DENSE_NORMAL_CHOLESKY, that can
743       // take a BlockSparseMatrix as input.
744       options->linear_solver_type = DENSE_QR;
745       msg += "DENSE_SCHUR to DENSE_QR.";
746     } else if (options->linear_solver_type == ITERATIVE_SCHUR) {
747       msg += StringPrintf("ITERATIVE_SCHUR with %s preconditioner "
748                           "to CGNR with JACOBI preconditioner.",
749                           PreconditionerTypeToString(
750                               options->preconditioner_type));
751       options->linear_solver_type = CGNR;
752       if (options->preconditioner_type != IDENTITY) {
753         // CGNR currently only supports the JACOBI preconditioner.
754         options->preconditioner_type = JACOBI;
755       }
756     }
757 
758     LOG(WARNING) << msg;
759   }
760 
761   // Since the transformed program is the "active" program, and it is mutated,
762   // update the parameter offsets and indices.
763   transformed_program->SetParameterOffsetsAndIndex();
764   return transformed_program.release();
765 }
766 
CreateLinearSolver(Solver::Options * options,string * error)767 LinearSolver* SolverImpl::CreateLinearSolver(Solver::Options* options,
768                                              string* error) {
769   CHECK_NOTNULL(options);
770   CHECK_NOTNULL(options->linear_solver_ordering);
771   CHECK_NOTNULL(error);
772 
773   if (options->trust_region_strategy_type == DOGLEG) {
774     if (options->linear_solver_type == ITERATIVE_SCHUR ||
775         options->linear_solver_type == CGNR) {
776       *error = "DOGLEG only supports exact factorization based linear "
777                "solvers. If you want to use an iterative solver please "
778                "use LEVENBERG_MARQUARDT as the trust_region_strategy_type";
779       return NULL;
780     }
781   }
782 
783 #ifdef CERES_NO_SUITESPARSE
784   if (options->linear_solver_type == SPARSE_NORMAL_CHOLESKY &&
785       options->sparse_linear_algebra_library == SUITE_SPARSE) {
786     *error = "Can't use SPARSE_NORMAL_CHOLESKY with SUITESPARSE because "
787              "SuiteSparse was not enabled when Ceres was built.";
788     return NULL;
789   }
790 
791   if (options->preconditioner_type == SCHUR_JACOBI) {
792     *error =  "SCHUR_JACOBI preconditioner not suppored. Please build Ceres "
793         "with SuiteSparse support.";
794     return NULL;
795   }
796 
797   if (options->preconditioner_type == CLUSTER_JACOBI) {
798     *error =  "CLUSTER_JACOBI preconditioner not suppored. Please build Ceres "
799         "with SuiteSparse support.";
800     return NULL;
801   }
802 
803   if (options->preconditioner_type == CLUSTER_TRIDIAGONAL) {
804     *error =  "CLUSTER_TRIDIAGONAL preconditioner not suppored. Please build "
805         "Ceres with SuiteSparse support.";
806     return NULL;
807   }
808 #endif
809 
810 #ifdef CERES_NO_CXSPARSE
811   if (options->linear_solver_type == SPARSE_NORMAL_CHOLESKY &&
812       options->sparse_linear_algebra_library == CX_SPARSE) {
813     *error = "Can't use SPARSE_NORMAL_CHOLESKY with CXSPARSE because "
814              "CXSparse was not enabled when Ceres was built.";
815     return NULL;
816   }
817 #endif
818 
819 #if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE)
820   if (options->linear_solver_type == SPARSE_SCHUR) {
821     *error = "Can't use SPARSE_SCHUR because neither SuiteSparse nor"
822         "CXSparse was enabled when Ceres was compiled.";
823     return NULL;
824   }
825 #endif
826 
827   if (options->linear_solver_max_num_iterations <= 0) {
828     *error = "Solver::Options::linear_solver_max_num_iterations is 0.";
829     return NULL;
830   }
831   if (options->linear_solver_min_num_iterations <= 0) {
832     *error = "Solver::Options::linear_solver_min_num_iterations is 0.";
833     return NULL;
834   }
835   if (options->linear_solver_min_num_iterations >
836       options->linear_solver_max_num_iterations) {
837     *error = "Solver::Options::linear_solver_min_num_iterations > "
838         "Solver::Options::linear_solver_max_num_iterations.";
839     return NULL;
840   }
841 
842   LinearSolver::Options linear_solver_options;
843   linear_solver_options.min_num_iterations =
844         options->linear_solver_min_num_iterations;
845   linear_solver_options.max_num_iterations =
846       options->linear_solver_max_num_iterations;
847   linear_solver_options.type = options->linear_solver_type;
848   linear_solver_options.preconditioner_type = options->preconditioner_type;
849   linear_solver_options.sparse_linear_algebra_library =
850       options->sparse_linear_algebra_library;
851 
852   linear_solver_options.num_threads = options->num_linear_solver_threads;
853   // The matrix used for storing the dense Schur complement has a
854   // single lock guarding the whole matrix. Running the
855   // SchurComplementSolver with multiple threads leads to maximum
856   // contention and slowdown. If the problem is large enough to
857   // benefit from a multithreaded schur eliminator, you should be
858   // using a SPARSE_SCHUR solver anyways.
859   if ((linear_solver_options.num_threads > 1) &&
860       (linear_solver_options.type == DENSE_SCHUR)) {
861     LOG(WARNING) << "Warning: Solver::Options::num_linear_solver_threads = "
862                  << options->num_linear_solver_threads
863                  << " with DENSE_SCHUR will result in poor performance; "
864                  << "switching to single-threaded.";
865     linear_solver_options.num_threads = 1;
866   }
867   options->num_linear_solver_threads = linear_solver_options.num_threads;
868 
869   linear_solver_options.use_block_amd = options->use_block_amd;
870   const map<int, set<double*> >& groups =
871       options->linear_solver_ordering->group_to_elements();
872   for (map<int, set<double*> >::const_iterator it = groups.begin();
873        it != groups.end();
874        ++it) {
875     linear_solver_options.elimination_groups.push_back(it->second.size());
876   }
877   // Schur type solvers, expect at least two elimination groups. If
878   // there is only one elimination group, then CreateReducedProgram
879   // guarantees that this group only contains e_blocks. Thus we add a
880   // dummy elimination group with zero blocks in it.
881   if (IsSchurType(linear_solver_options.type) &&
882       linear_solver_options.elimination_groups.size() == 1) {
883     linear_solver_options.elimination_groups.push_back(0);
884   }
885 
886   return LinearSolver::Create(linear_solver_options);
887 }
888 
ApplyUserOrdering(const ProblemImpl::ParameterMap & parameter_map,const ParameterBlockOrdering * ordering,Program * program,string * error)889 bool SolverImpl::ApplyUserOrdering(const ProblemImpl::ParameterMap& parameter_map,
890                                    const ParameterBlockOrdering* ordering,
891                                    Program* program,
892                                    string* error) {
893   if (ordering->NumElements() != program->NumParameterBlocks()) {
894     *error = StringPrintf("User specified ordering does not have the same "
895                           "number of parameters as the problem. The problem"
896                           "has %d blocks while the ordering has %d blocks.",
897                           program->NumParameterBlocks(),
898                           ordering->NumElements());
899     return false;
900   }
901 
902   vector<ParameterBlock*>* parameter_blocks =
903       program->mutable_parameter_blocks();
904   parameter_blocks->clear();
905 
906   const map<int, set<double*> >& groups =
907       ordering->group_to_elements();
908 
909   for (map<int, set<double*> >::const_iterator group_it = groups.begin();
910        group_it != groups.end();
911        ++group_it) {
912     const set<double*>& group = group_it->second;
913     for (set<double*>::const_iterator parameter_block_ptr_it = group.begin();
914          parameter_block_ptr_it != group.end();
915          ++parameter_block_ptr_it) {
916       ProblemImpl::ParameterMap::const_iterator parameter_block_it =
917           parameter_map.find(*parameter_block_ptr_it);
918       if (parameter_block_it == parameter_map.end()) {
919         *error = StringPrintf("User specified ordering contains a pointer "
920                               "to a double that is not a parameter block in the "
921                               "problem. The invalid double is in group: %d",
922                               group_it->first);
923         return false;
924       }
925       parameter_blocks->push_back(parameter_block_it->second);
926     }
927   }
928   return true;
929 }
930 
931 // Find the minimum index of any parameter block to the given residual.
932 // Parameter blocks that have indices greater than num_eliminate_blocks are
933 // considered to have an index equal to num_eliminate_blocks.
MinParameterBlock(const ResidualBlock * residual_block,int num_eliminate_blocks)934 int MinParameterBlock(const ResidualBlock* residual_block,
935                       int num_eliminate_blocks) {
936   int min_parameter_block_position = num_eliminate_blocks;
937   for (int i = 0; i < residual_block->NumParameterBlocks(); ++i) {
938     ParameterBlock* parameter_block = residual_block->parameter_blocks()[i];
939     if (!parameter_block->IsConstant()) {
940       CHECK_NE(parameter_block->index(), -1)
941           << "Did you forget to call Program::SetParameterOffsetsAndIndex()? "
942           << "This is a Ceres bug; please contact the developers!";
943       min_parameter_block_position = std::min(parameter_block->index(),
944                                               min_parameter_block_position);
945     }
946   }
947   return min_parameter_block_position;
948 }
949 
950 // Reorder the residuals for program, if necessary, so that the residuals
951 // involving each E block occur together. This is a necessary condition for the
952 // Schur eliminator, which works on these "row blocks" in the jacobian.
LexicographicallyOrderResidualBlocks(const int num_eliminate_blocks,Program * program,string * error)953 bool SolverImpl::LexicographicallyOrderResidualBlocks(const int num_eliminate_blocks,
954                                                       Program* program,
955                                                       string* error) {
956   CHECK_GE(num_eliminate_blocks, 1)
957       << "Congratulations, you found a Ceres bug! Please report this error "
958       << "to the developers.";
959 
960   // Create a histogram of the number of residuals for each E block. There is an
961   // extra bucket at the end to catch all non-eliminated F blocks.
962   vector<int> residual_blocks_per_e_block(num_eliminate_blocks + 1);
963   vector<ResidualBlock*>* residual_blocks = program->mutable_residual_blocks();
964   vector<int> min_position_per_residual(residual_blocks->size());
965   for (int i = 0; i < residual_blocks->size(); ++i) {
966     ResidualBlock* residual_block = (*residual_blocks)[i];
967     int position = MinParameterBlock(residual_block, num_eliminate_blocks);
968     min_position_per_residual[i] = position;
969     DCHECK_LE(position, num_eliminate_blocks);
970     residual_blocks_per_e_block[position]++;
971   }
972 
973   // Run a cumulative sum on the histogram, to obtain offsets to the start of
974   // each histogram bucket (where each bucket is for the residuals for that
975   // E-block).
976   vector<int> offsets(num_eliminate_blocks + 1);
977   std::partial_sum(residual_blocks_per_e_block.begin(),
978                    residual_blocks_per_e_block.end(),
979                    offsets.begin());
980   CHECK_EQ(offsets.back(), residual_blocks->size())
981       << "Congratulations, you found a Ceres bug! Please report this error "
982       << "to the developers.";
983 
984   CHECK(find(residual_blocks_per_e_block.begin(),
985              residual_blocks_per_e_block.end() - 1, 0) !=
986         residual_blocks_per_e_block.end())
987       << "Congratulations, you found a Ceres bug! Please report this error "
988       << "to the developers.";
989 
990   // Fill in each bucket with the residual blocks for its corresponding E block.
991   // Each bucket is individually filled from the back of the bucket to the front
992   // of the bucket. The filling order among the buckets is dictated by the
993   // residual blocks. This loop uses the offsets as counters; subtracting one
994   // from each offset as a residual block is placed in the bucket. When the
995   // filling is finished, the offset pointerts should have shifted down one
996   // entry (this is verified below).
997   vector<ResidualBlock*> reordered_residual_blocks(
998       (*residual_blocks).size(), static_cast<ResidualBlock*>(NULL));
999   for (int i = 0; i < residual_blocks->size(); ++i) {
1000     int bucket = min_position_per_residual[i];
1001 
1002     // Decrement the cursor, which should now point at the next empty position.
1003     offsets[bucket]--;
1004 
1005     // Sanity.
1006     CHECK(reordered_residual_blocks[offsets[bucket]] == NULL)
1007         << "Congratulations, you found a Ceres bug! Please report this error "
1008         << "to the developers.";
1009 
1010     reordered_residual_blocks[offsets[bucket]] = (*residual_blocks)[i];
1011   }
1012 
1013   // Sanity check #1: The difference in bucket offsets should match the
1014   // histogram sizes.
1015   for (int i = 0; i < num_eliminate_blocks; ++i) {
1016     CHECK_EQ(residual_blocks_per_e_block[i], offsets[i + 1] - offsets[i])
1017         << "Congratulations, you found a Ceres bug! Please report this error "
1018         << "to the developers.";
1019   }
1020   // Sanity check #2: No NULL's left behind.
1021   for (int i = 0; i < reordered_residual_blocks.size(); ++i) {
1022     CHECK(reordered_residual_blocks[i] != NULL)
1023         << "Congratulations, you found a Ceres bug! Please report this error "
1024         << "to the developers.";
1025   }
1026 
1027   // Now that the residuals are collected by E block, swap them in place.
1028   swap(*program->mutable_residual_blocks(), reordered_residual_blocks);
1029   return true;
1030 }
1031 
CreateEvaluator(const Solver::Options & options,const ProblemImpl::ParameterMap & parameter_map,Program * program,string * error)1032 Evaluator* SolverImpl::CreateEvaluator(const Solver::Options& options,
1033                                        const ProblemImpl::ParameterMap& parameter_map,
1034                                        Program* program,
1035                                        string* error) {
1036   Evaluator::Options evaluator_options;
1037   evaluator_options.linear_solver_type = options.linear_solver_type;
1038   evaluator_options.num_eliminate_blocks =
1039       (options.linear_solver_ordering->NumGroups() > 0 &&
1040        IsSchurType(options.linear_solver_type))
1041       ? (options.linear_solver_ordering
1042          ->group_to_elements().begin()
1043          ->second.size())
1044       : 0;
1045   evaluator_options.num_threads = options.num_threads;
1046   return Evaluator::Create(evaluator_options, program, error);
1047 }
1048 
CreateInnerIterationMinimizer(const Solver::Options & options,const Program & program,const ProblemImpl::ParameterMap & parameter_map,string * error)1049 CoordinateDescentMinimizer* SolverImpl::CreateInnerIterationMinimizer(
1050     const Solver::Options& options,
1051     const Program& program,
1052     const ProblemImpl::ParameterMap& parameter_map,
1053     string* error) {
1054   scoped_ptr<CoordinateDescentMinimizer> inner_iteration_minimizer(
1055       new CoordinateDescentMinimizer);
1056   scoped_ptr<ParameterBlockOrdering> inner_iteration_ordering;
1057   ParameterBlockOrdering* ordering_ptr  = NULL;
1058 
1059   if (options.inner_iteration_ordering == NULL) {
1060     // Find a recursive decomposition of the Hessian matrix as a set
1061     // of independent sets of decreasing size and invert it. This
1062     // seems to work better in practice, i.e., Cameras before
1063     // points.
1064     inner_iteration_ordering.reset(new ParameterBlockOrdering);
1065     ComputeRecursiveIndependentSetOrdering(program,
1066                                            inner_iteration_ordering.get());
1067     inner_iteration_ordering->Reverse();
1068     ordering_ptr = inner_iteration_ordering.get();
1069   } else {
1070     const map<int, set<double*> >& group_to_elements =
1071         options.inner_iteration_ordering->group_to_elements();
1072 
1073     // Iterate over each group and verify that it is an independent
1074     // set.
1075     map<int, set<double*> >::const_iterator it = group_to_elements.begin();
1076     for ( ;it != group_to_elements.end(); ++it) {
1077       if (!IsParameterBlockSetIndependent(it->second,
1078                                           program.residual_blocks())) {
1079         *error =
1080             StringPrintf("The user-provided "
1081                          "parameter_blocks_for_inner_iterations does not "
1082                          "form an independent set. Group Id: %d", it->first);
1083         return NULL;
1084       }
1085     }
1086     ordering_ptr = options.inner_iteration_ordering;
1087   }
1088 
1089   if (!inner_iteration_minimizer->Init(program,
1090                                        parameter_map,
1091                                        *ordering_ptr,
1092                                        error)) {
1093     return NULL;
1094   }
1095 
1096   return inner_iteration_minimizer.release();
1097 }
1098 
1099 }  // namespace internal
1100 }  // namespace ceres
1101