10ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Ceres Solver - A fast non-linear least squares minimizer
279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez// Copyright 2014 Google Inc. All rights reserved.
30ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// http://code.google.com/p/ceres-solver/
40ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//
50ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Redistribution and use in source and binary forms, with or without
60ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// modification, are permitted provided that the following conditions are met:
70ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//
80ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// * Redistributions of source code must retain the above copyright notice,
90ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//   this list of conditions and the following disclaimer.
100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// * Redistributions in binary form must reproduce the above copyright notice,
110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//   this list of conditions and the following disclaimer in the documentation
120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//   and/or other materials provided with the distribution.
130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// * Neither the name of Google Inc. nor the names of its contributors may be
140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//   used to endorse or promote products derived from this software without
150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//   specific prior written permission.
160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//
170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// POSSIBILITY OF SUCH DAMAGE.
280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//
290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Author: keir@google.com (Keir Mierle)
300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//         sameeragarwal@google.com (Sameer Agarwal)
310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#include "ceres/internal/port.h"
330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/solver.h"
340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#include <sstream>   // NOLINT
360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include <vector>
3779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/problem.h"
390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/problem_impl.h"
400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/program.h"
410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/solver_impl.h"
420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/stringprintf.h"
4379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#include "ceres/types.h"
4479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#include "ceres/version.h"
450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/wall_time.h"
460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongnamespace ceres {
481d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberlingnamespace {
491d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
5079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#define OPTION_OP(x, y, OP)                                             \
5179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  if (!(options.x OP y)) {                                              \
5279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    std::stringstream ss;                                               \
5379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    ss << "Invalid configuration. ";                                    \
5479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    ss << string("Solver::Options::" #x " = ") << options.x << ". ";    \
5579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    ss << "Violated constraint: ";                                      \
5679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    ss << string("Solver::Options::" #x " " #OP " "#y);                 \
5779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    *error = ss.str();                                                  \
5879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    return false;                                                       \
5979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  }
6079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
6179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#define OPTION_OP_OPTION(x, y, OP)                                      \
6279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  if (!(options.x OP options.y)) {                                      \
6379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    std::stringstream ss;                                               \
6479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    ss << "Invalid configuration. ";                                    \
6579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    ss << string("Solver::Options::" #x " = ") << options.x << ". ";    \
6679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    ss << string("Solver::Options::" #y " = ") << options.y << ". ";    \
6779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    ss << "Violated constraint: ";                                      \
6879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    ss << string("Solver::Options::" #x );                              \
6979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    ss << string(#OP " Solver::Options::" #y ".");                      \
7079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    *error = ss.str();                                                  \
7179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    return false;                                                       \
7279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  }
7379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
7479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#define OPTION_GE(x, y) OPTION_OP(x, y, >=);
7579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#define OPTION_GT(x, y) OPTION_OP(x, y, >);
7679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#define OPTION_LE(x, y) OPTION_OP(x, y, <=);
7779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#define OPTION_LT(x, y) OPTION_OP(x, y, <);
7879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#define OPTION_LE_OPTION(x, y) OPTION_OP_OPTION(x ,y, <=)
7979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#define OPTION_LT_OPTION(x, y) OPTION_OP_OPTION(x ,y, <)
8079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
8179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandezbool CommonOptionsAreValid(const Solver::Options& options, string* error) {
8279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_GE(max_num_iterations, 0);
8379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_GE(max_solver_time_in_seconds, 0.0);
8479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_GE(function_tolerance, 0.0);
8579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_GE(gradient_tolerance, 0.0);
8679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_GE(parameter_tolerance, 0.0);
8779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_GT(num_threads, 0);
8879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_GT(num_linear_solver_threads, 0);
8979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  if (options.check_gradients) {
9079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    OPTION_GT(gradient_check_relative_precision, 0.0);
9179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    OPTION_GT(numeric_derivative_relative_step_size, 0.0);
9279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  }
9379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  return true;
9479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez}
9579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
9679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandezbool TrustRegionOptionsAreValid(const Solver::Options& options, string* error) {
9779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_GT(initial_trust_region_radius, 0.0);
9879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_GT(min_trust_region_radius, 0.0);
9979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_GT(max_trust_region_radius, 0.0);
10079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_LE_OPTION(min_trust_region_radius, max_trust_region_radius);
10179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_LE_OPTION(min_trust_region_radius, initial_trust_region_radius);
10279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_LE_OPTION(initial_trust_region_radius, max_trust_region_radius);
10379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_GE(min_relative_decrease, 0.0);
10479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_GE(min_lm_diagonal, 0.0);
10579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_GE(max_lm_diagonal, 0.0);
10679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_LE_OPTION(min_lm_diagonal, max_lm_diagonal);
10779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_GE(max_num_consecutive_invalid_steps, 0);
10879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_GT(eta, 0.0);
10979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_GE(min_linear_solver_iterations, 1);
11079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_GE(max_linear_solver_iterations, 1);
11179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_LE_OPTION(min_linear_solver_iterations, max_linear_solver_iterations);
11279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
11379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  if (options.use_inner_iterations) {
11479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    OPTION_GE(inner_iteration_tolerance, 0.0);
11579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  }
11679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
11779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  if (options.use_nonmonotonic_steps) {
11879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    OPTION_GT(max_consecutive_nonmonotonic_steps, 0);
11979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  }
12079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
12179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  if (options.preconditioner_type == CLUSTER_JACOBI &&
12279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      options.sparse_linear_algebra_library_type != SUITE_SPARSE) {
12379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    *error =  "CLUSTER_JACOBI requires "
12479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez        "Solver::Options::sparse_linear_algebra_library_type to be "
12579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez        "SUITE_SPARSE";
12679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    return false;
12779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  }
12879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
12979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  if (options.preconditioner_type == CLUSTER_TRIDIAGONAL &&
13079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      options.sparse_linear_algebra_library_type != SUITE_SPARSE) {
13179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    *error =  "CLUSTER_TRIDIAGONAL requires "
13279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez        "Solver::Options::sparse_linear_algebra_library_type to be "
13379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez        "SUITE_SPARSE";
13479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    return false;
13579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  }
13679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
13779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#ifdef CERES_NO_LAPACK
13879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  if (options.dense_linear_algebra_library_type == LAPACK) {
13979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    if (options.linear_solver_type == DENSE_NORMAL_CHOLESKY) {
14079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      *error = "Can't use DENSE_NORMAL_CHOLESKY with LAPACK because "
14179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez          "LAPACK was not enabled when Ceres was built.";
14279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      return false;
14379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    }
14479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
14579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    if (options.linear_solver_type == DENSE_QR) {
14679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      *error = "Can't use DENSE_QR with LAPACK because "
14779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez          "LAPACK was not enabled when Ceres was built.";
14879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      return false;
14979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    }
15079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
15179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    if (options.linear_solver_type == DENSE_SCHUR) {
15279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      *error = "Can't use DENSE_SCHUR with LAPACK because "
15379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez          "LAPACK was not enabled when Ceres was built.";
15479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      return false;
15579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    }
15679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  }
15779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#endif
15879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
15979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#ifdef CERES_NO_SUITESPARSE
16079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  if (options.sparse_linear_algebra_library_type == SUITE_SPARSE) {
16179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    if (options.linear_solver_type == SPARSE_NORMAL_CHOLESKY) {
16279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      *error = "Can't use SPARSE_NORMAL_CHOLESKY with SUITESPARSE because "
16379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez             "SuiteSparse was not enabled when Ceres was built.";
16479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      return false;
16579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    }
16679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
16779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    if (options.linear_solver_type == SPARSE_SCHUR) {
16879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      *error = "Can't use SPARSE_SCHUR with SUITESPARSE because "
16979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez          "SuiteSparse was not enabled when Ceres was built.";
17079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      return false;
17179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    }
17279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
17379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    if (options.preconditioner_type == CLUSTER_JACOBI) {
17479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      *error =  "CLUSTER_JACOBI preconditioner not supported. "
17579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez          "SuiteSparse was not enabled when Ceres was built.";
17679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      return false;
17779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    }
17879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
17979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    if (options.preconditioner_type == CLUSTER_TRIDIAGONAL) {
18079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      *error =  "CLUSTER_TRIDIAGONAL preconditioner not supported. "
18179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez          "SuiteSparse was not enabled when Ceres was built.";
18279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    return false;
18379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    }
18479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  }
18579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#endif
18679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
18779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#ifdef CERES_NO_CXSPARSE
18879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  if (options.sparse_linear_algebra_library_type == CX_SPARSE) {
18979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    if (options.linear_solver_type == SPARSE_NORMAL_CHOLESKY) {
19079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      *error = "Can't use SPARSE_NORMAL_CHOLESKY with CX_SPARSE because "
19179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez             "CXSparse was not enabled when Ceres was built.";
19279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      return false;
19379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    }
19479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
19579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    if (options.linear_solver_type == SPARSE_SCHUR) {
19679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      *error = "Can't use SPARSE_SCHUR with CX_SPARSE because "
19779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez          "CXSparse was not enabled when Ceres was built.";
19879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      return false;
19979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    }
20079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  }
20179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#endif
20279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
20379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  if (options.trust_region_strategy_type == DOGLEG) {
20479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    if (options.linear_solver_type == ITERATIVE_SCHUR ||
20579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez        options.linear_solver_type == CGNR) {
20679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      *error = "DOGLEG only supports exact factorization based linear "
20779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez          "solvers. If you want to use an iterative solver please "
20879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez          "use LEVENBERG_MARQUARDT as the trust_region_strategy_type";
20979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      return false;
21079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    }
21179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  }
21279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
21379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  if (options.trust_region_minimizer_iterations_to_dump.size() > 0 &&
21479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      options.trust_region_problem_dump_format_type != CONSOLE &&
21579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      options.trust_region_problem_dump_directory.empty()) {
21679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    *error = "Solver::Options::trust_region_problem_dump_directory is empty.";
21779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    return false;
21879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  }
21979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
22079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  if (options.dynamic_sparsity &&
22179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      options.linear_solver_type != SPARSE_NORMAL_CHOLESKY) {
22279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    *error = "Dynamic sparsity is only supported with SPARSE_NORMAL_CHOLESKY.";
22379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    return false;
22479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  }
22579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
22679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  return true;
22779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez}
22879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
22979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandezbool LineSearchOptionsAreValid(const Solver::Options& options, string* error) {
23079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_GT(max_lbfgs_rank, 0);
23179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_GT(min_line_search_step_size, 0.0);
23279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_GT(max_line_search_step_contraction, 0.0);
23379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_LT(max_line_search_step_contraction, 1.0);
23479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_LT_OPTION(max_line_search_step_contraction,
23579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez                   min_line_search_step_contraction);
23679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_LE(min_line_search_step_contraction, 1.0);
23779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_GT(max_num_line_search_step_size_iterations, 0);
23879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_GT(line_search_sufficient_function_decrease, 0.0);
23979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_LT_OPTION(line_search_sufficient_function_decrease,
24079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez                   line_search_sufficient_curvature_decrease);
24179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_LT(line_search_sufficient_curvature_decrease, 1.0);
24279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  OPTION_GT(max_line_search_step_expansion, 1.0);
24379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
24479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  if ((options.line_search_direction_type == ceres::BFGS ||
24579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez       options.line_search_direction_type == ceres::LBFGS) &&
24679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      options.line_search_type != ceres::WOLFE) {
24779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
24879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    *error =
24979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez        string("Invalid configuration: Solver::Options::line_search_type = ")
25079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez        + string(LineSearchTypeToString(options.line_search_type))
25179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez        + string(". When using (L)BFGS, "
25279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez                 "Solver::Options::line_search_type must be set to WOLFE.");
25379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    return false;
25479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  }
25579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
25679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  // Warn user if they have requested BISECTION interpolation, but constraints
25779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  // on max/min step size change during line search prevent bisection scaling
25879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  // from occurring. Warn only, as this is likely a user mistake, but one which
25979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  // does not prevent us from continuing.
26079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  LOG_IF(WARNING,
26179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez         (options.line_search_interpolation_type == ceres::BISECTION &&
26279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez          (options.max_line_search_step_contraction > 0.5 ||
26379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez           options.min_line_search_step_contraction < 0.5)))
26479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      << "Line search interpolation type is BISECTION, but specified "
26579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      << "max_line_search_step_contraction: "
26679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      << options.max_line_search_step_contraction << ", and "
26779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      << "min_line_search_step_contraction: "
26879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      << options.min_line_search_step_contraction
26979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      << ", prevent bisection (0.5) scaling, continuing with solve regardless.";
27079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
27179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  return true;
27279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez}
27379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
27479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#undef OPTION_OP
27579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#undef OPTION_OP_OPTION
27679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#undef OPTION_GT
27779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#undef OPTION_GE
27879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#undef OPTION_LE
27979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#undef OPTION_LT
28079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#undef OPTION_LE_OPTION
28179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#undef OPTION_LT_OPTION
28279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
2831d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberlingvoid StringifyOrdering(const vector<int>& ordering, string* report) {
2841d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  if (ordering.size() == 0) {
2851d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    internal::StringAppendF(report, "AUTOMATIC");
2861d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    return;
2871d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  }
2881d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
2891d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  for (int i = 0; i < ordering.size() - 1; ++i) {
2901d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    internal::StringAppendF(report, "%d, ", ordering[i]);
2911d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  }
2921d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  internal::StringAppendF(report, "%d", ordering.back());
2931d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling}
2941d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
29579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez} // namespace
29679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
29779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandezbool Solver::Options::IsValid(string* error) const {
29879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  if (!CommonOptionsAreValid(*this, error)) {
29979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    return false;
30079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  }
3010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
30279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  if (minimizer_type == TRUST_REGION) {
30379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    return TrustRegionOptionsAreValid(*this, error);
30479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  }
30579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
30679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  CHECK_EQ(minimizer_type, LINE_SEARCH);
30779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  return LineSearchOptionsAreValid(*this, error);
3080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong}
3090ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongSolver::~Solver() {}
3110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongvoid Solver::Solve(const Solver::Options& options,
3130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                   Problem* problem,
3140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                   Solver::Summary* summary) {
3150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  double start_time_seconds = internal::WallTimeInSeconds();
31679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  CHECK_NOTNULL(problem);
31779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  CHECK_NOTNULL(summary);
31879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
31979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  *summary = Summary();
32079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  if (!options.IsValid(&summary->message)) {
32179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    LOG(ERROR) << "Terminating: " << summary->message;
32279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    return;
32379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  }
32479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
32579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  internal::ProblemImpl* problem_impl = problem->problem_impl_.get();
3260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  internal::SolverImpl::Solve(options, problem_impl, summary);
3270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  summary->total_time_in_seconds =
3280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      internal::WallTimeInSeconds() - start_time_seconds;
3290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong}
3300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongvoid Solve(const Solver::Options& options,
3320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong           Problem* problem,
3330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong           Solver::Summary* summary) {
3340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  Solver solver;
3350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  solver.Solve(options, problem, summary);
3360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong}
3370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongSolver::Summary::Summary()
3390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // Invalid values for most fields, to ensure that we are not
3400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // accidentally reporting default values.
3411d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    : minimizer_type(TRUST_REGION),
34279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      termination_type(FAILURE),
34379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      message("ceres::Solve was not called."),
3440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      initial_cost(-1.0),
3450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      final_cost(-1.0),
3460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      fixed_cost(-1.0),
3470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      num_successful_steps(-1),
3480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      num_unsuccessful_steps(-1),
3491d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      num_inner_iteration_steps(-1),
3500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      preprocessor_time_in_seconds(-1.0),
3510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      minimizer_time_in_seconds(-1.0),
3520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      postprocessor_time_in_seconds(-1.0),
3530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      total_time_in_seconds(-1.0),
3541d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      linear_solver_time_in_seconds(-1.0),
3551d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      residual_evaluation_time_in_seconds(-1.0),
3561d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      jacobian_evaluation_time_in_seconds(-1.0),
3571d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      inner_iteration_time_in_seconds(-1.0),
3580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      num_parameter_blocks(-1),
3590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      num_parameters(-1),
3601d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      num_effective_parameters(-1),
3610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      num_residual_blocks(-1),
3620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      num_residuals(-1),
3630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      num_parameter_blocks_reduced(-1),
3640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      num_parameters_reduced(-1),
3651d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      num_effective_parameters_reduced(-1),
3660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      num_residual_blocks_reduced(-1),
3670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      num_residuals_reduced(-1),
3680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      num_threads_given(-1),
3690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      num_threads_used(-1),
3700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      num_linear_solver_threads_given(-1),
3710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      num_linear_solver_threads_used(-1),
3720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      linear_solver_type_given(SPARSE_NORMAL_CHOLESKY),
3730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      linear_solver_type_used(SPARSE_NORMAL_CHOLESKY),
3741d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      inner_iterations_given(false),
3751d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      inner_iterations_used(false),
3760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      preconditioner_type(IDENTITY),
37779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      visibility_clustering_type(CANONICAL_VIEWS),
3780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      trust_region_strategy_type(LEVENBERG_MARQUARDT),
379399f7d09e0c45af54b77b4ab9508d6f23759b927Scott Ettinger      dense_linear_algebra_library_type(EIGEN),
380399f7d09e0c45af54b77b4ab9508d6f23759b927Scott Ettinger      sparse_linear_algebra_library_type(SUITE_SPARSE),
3811d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      line_search_direction_type(LBFGS),
38279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      line_search_type(ARMIJO),
38379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      line_search_interpolation_type(BISECTION),
38479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      nonlinear_conjugate_gradient_type(FLETCHER_REEVES),
38579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      max_lbfgs_rank(-1) {
3860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong}
3870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3881d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberlingusing internal::StringAppendF;
3891d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberlingusing internal::StringPrintf;
3901d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
39179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandezstring Solver::Summary::BriefReport() const {
39279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  return StringPrintf("Ceres Solver Report: "
39379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez                      "Iterations: %d, "
39479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez                      "Initial cost: %e, "
39579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez                      "Final cost: %e, "
39679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez                      "Termination: %s",
39779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez                      num_successful_steps + num_unsuccessful_steps,
39879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez                      initial_cost,
39979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez                      final_cost,
40079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez                      TerminationTypeToString(termination_type));
40179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez};
40279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
4030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongstring Solver::Summary::FullReport() const {
4040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  string report =
4050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      "\n"
40679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      "Ceres Solver v" CERES_VERSION_STRING " Solve Report\n"
40779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      "----------------------------------\n";
40879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
40979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  StringAppendF(&report, "%45s    %21s\n", "Original", "Reduced");
41079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  StringAppendF(&report, "Parameter blocks    % 25d% 25d\n",
41179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez                num_parameter_blocks, num_parameter_blocks_reduced);
41279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  StringAppendF(&report, "Parameters          % 25d% 25d\n",
41379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez                num_parameters, num_parameters_reduced);
41479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  if (num_effective_parameters_reduced != num_parameters_reduced) {
41579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    StringAppendF(&report, "Effective parameters% 25d% 25d\n",
41679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez                  num_effective_parameters, num_effective_parameters_reduced);
4170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  }
41879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  StringAppendF(&report, "Residual blocks     % 25d% 25d\n",
41979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez                num_residual_blocks, num_residual_blocks_reduced);
42079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  StringAppendF(&report, "Residual            % 25d% 25d\n",
42179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez                num_residuals, num_residuals_reduced);
4220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
4231d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  if (minimizer_type == TRUST_REGION) {
4241d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    // TRUST_SEARCH HEADER
4251d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    StringAppendF(&report, "\nMinimizer                 %19s\n",
4261d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                  "TRUST_REGION");
427399f7d09e0c45af54b77b4ab9508d6f23759b927Scott Ettinger
428399f7d09e0c45af54b77b4ab9508d6f23759b927Scott Ettinger    if (linear_solver_type_used == DENSE_NORMAL_CHOLESKY ||
429399f7d09e0c45af54b77b4ab9508d6f23759b927Scott Ettinger        linear_solver_type_used == DENSE_SCHUR ||
430399f7d09e0c45af54b77b4ab9508d6f23759b927Scott Ettinger        linear_solver_type_used == DENSE_QR) {
431399f7d09e0c45af54b77b4ab9508d6f23759b927Scott Ettinger      StringAppendF(&report, "\nDense linear algebra library  %15s\n",
432399f7d09e0c45af54b77b4ab9508d6f23759b927Scott Ettinger                    DenseLinearAlgebraLibraryTypeToString(
433399f7d09e0c45af54b77b4ab9508d6f23759b927Scott Ettinger                        dense_linear_algebra_library_type));
434399f7d09e0c45af54b77b4ab9508d6f23759b927Scott Ettinger    }
435399f7d09e0c45af54b77b4ab9508d6f23759b927Scott Ettinger
4361d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    if (linear_solver_type_used == SPARSE_NORMAL_CHOLESKY ||
4371d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling        linear_solver_type_used == SPARSE_SCHUR ||
4381d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling        (linear_solver_type_used == ITERATIVE_SCHUR &&
4391d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling         (preconditioner_type == CLUSTER_JACOBI ||
4401d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling          preconditioner_type == CLUSTER_TRIDIAGONAL))) {
4411d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      StringAppendF(&report, "\nSparse linear algebra library %15s\n",
4421d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                    SparseLinearAlgebraLibraryTypeToString(
443399f7d09e0c45af54b77b4ab9508d6f23759b927Scott Ettinger                        sparse_linear_algebra_library_type));
4441d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    }
4450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
4461d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    StringAppendF(&report, "Trust region strategy     %19s",
4471d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                  TrustRegionStrategyTypeToString(
4481d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                      trust_region_strategy_type));
4491d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    if (trust_region_strategy_type == DOGLEG) {
4501d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      if (dogleg_type == TRADITIONAL_DOGLEG) {
4511d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling        StringAppendF(&report, " (TRADITIONAL)");
4521d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      } else {
4531d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling        StringAppendF(&report, " (SUBSPACE)");
4541d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      }
4551d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    }
4561d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    StringAppendF(&report, "\n");
4571d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    StringAppendF(&report, "\n");
4581d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
4591d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    StringAppendF(&report, "%45s    %21s\n", "Given",  "Used");
4601d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    StringAppendF(&report, "Linear solver       %25s%25s\n",
4611d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                  LinearSolverTypeToString(linear_solver_type_given),
4621d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                  LinearSolverTypeToString(linear_solver_type_used));
4631d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
4641d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    if (linear_solver_type_given == CGNR ||
4651d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling        linear_solver_type_given == ITERATIVE_SCHUR) {
4661d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      StringAppendF(&report, "Preconditioner      %25s%25s\n",
4671d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                    PreconditionerTypeToString(preconditioner_type),
4681d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                    PreconditionerTypeToString(preconditioner_type));
4691d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    }
4701d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
47179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    if (preconditioner_type == CLUSTER_JACOBI ||
47279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez        preconditioner_type == CLUSTER_TRIDIAGONAL) {
47379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      StringAppendF(&report, "Visibility clustering%24s%25s\n",
47479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez                    VisibilityClusteringTypeToString(
47579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez                        visibility_clustering_type),
47679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez                    VisibilityClusteringTypeToString(
47779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez                        visibility_clustering_type));
47879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    }
4791d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    StringAppendF(&report, "Threads             % 25d% 25d\n",
4801d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                  num_threads_given, num_threads_used);
4811d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    StringAppendF(&report, "Linear solver threads % 23d% 25d\n",
4821d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                  num_linear_solver_threads_given,
4831d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                  num_linear_solver_threads_used);
4841d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
4851d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    if (IsSchurType(linear_solver_type_used)) {
4861d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      string given;
4871d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      StringifyOrdering(linear_solver_ordering_given, &given);
4881d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      string used;
4891d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      StringifyOrdering(linear_solver_ordering_used, &used);
4901d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      StringAppendF(&report,
4911d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                    "Linear solver ordering %22s %24s\n",
4921d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                    given.c_str(),
4931d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                    used.c_str());
4941d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    }
4951d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
4961d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    if (inner_iterations_given) {
4971d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      StringAppendF(&report,
4981d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                    "Use inner iterations     %20s     %20s\n",
4991d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                    inner_iterations_given ? "True" : "False",
5001d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                    inner_iterations_used ? "True" : "False");
5011d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    }
5021d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
5031d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    if (inner_iterations_used) {
5041d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      string given;
5051d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      StringifyOrdering(inner_iteration_ordering_given, &given);
5061d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      string used;
5071d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      StringifyOrdering(inner_iteration_ordering_used, &used);
5081d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    StringAppendF(&report,
5091d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                  "Inner iteration ordering %20s %24s\n",
5101d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                  given.c_str(),
5111d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                  used.c_str());
5121d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    }
5130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  } else {
5141d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    // LINE_SEARCH HEADER
5151d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    StringAppendF(&report, "\nMinimizer                 %19s\n", "LINE_SEARCH");
5160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
5170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
5181d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    string line_search_direction_string;
5191d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    if (line_search_direction_type == LBFGS) {
5201d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      line_search_direction_string = StringPrintf("LBFGS (%d)", max_lbfgs_rank);
5211d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    } else if (line_search_direction_type == NONLINEAR_CONJUGATE_GRADIENT) {
5221d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      line_search_direction_string =
5231d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling          NonlinearConjugateGradientTypeToString(
5241d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling              nonlinear_conjugate_gradient_type);
5250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    } else {
5261d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      line_search_direction_string =
5271d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling          LineSearchDirectionTypeToString(line_search_direction_type);
5280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
5290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
5301d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    StringAppendF(&report, "Line search direction     %19s\n",
5311d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                  line_search_direction_string.c_str());
5321d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
5331d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    const string line_search_type_string =
5341d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling        StringPrintf("%s %s",
5351d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                     LineSearchInterpolationTypeToString(
5361d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                         line_search_interpolation_type),
5371d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                     LineSearchTypeToString(line_search_type));
5381d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    StringAppendF(&report, "Line search type          %19s\n",
5391d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                  line_search_type_string.c_str());
5401d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    StringAppendF(&report, "\n");
5411d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
5421d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    StringAppendF(&report, "%45s    %21s\n", "Given",  "Used");
5431d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    StringAppendF(&report, "Threads             % 25d% 25d\n",
5441d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                  num_threads_given, num_threads_used);
5451d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  }
5460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
5471d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  StringAppendF(&report, "\nCost:\n");
5481d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  StringAppendF(&report, "Initial        % 30e\n", initial_cost);
54979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  if (termination_type != FAILURE &&
55079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      termination_type != USER_FAILURE) {
5511d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    StringAppendF(&report, "Final          % 30e\n", final_cost);
5521d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    StringAppendF(&report, "Change         % 30e\n",
5531d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                  initial_cost - final_cost);
5540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  }
5550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
5561d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  StringAppendF(&report, "\nMinimizer iterations         % 16d\n",
5571d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                num_successful_steps + num_unsuccessful_steps);
5581d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
5591d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  // Successful/Unsuccessful steps only matter in the case of the
5601d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  // trust region solver. Line search terminates when it encounters
5611d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  // the first unsuccessful step.
5621d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  if (minimizer_type == TRUST_REGION) {
5631d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    StringAppendF(&report, "Successful steps               % 14d\n",
5641d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                  num_successful_steps);
5651d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    StringAppendF(&report, "Unsuccessful steps             % 14d\n",
5661d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                  num_unsuccessful_steps);
5671d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  }
5681d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  if (inner_iterations_used) {
5691d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    StringAppendF(&report, "Steps with inner iterations    % 14d\n",
5701d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                  num_inner_iteration_steps);
5711d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  }
5721d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
5731d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  StringAppendF(&report, "\nTime (in seconds):\n");
5741d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  StringAppendF(&report, "Preprocessor        %25.3f\n",
5751d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                preprocessor_time_in_seconds);
5761d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
5771d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  StringAppendF(&report, "\n  Residual evaluation %23.3f\n",
5781d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                residual_evaluation_time_in_seconds);
5791d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  StringAppendF(&report, "  Jacobian evaluation %23.3f\n",
5801d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                jacobian_evaluation_time_in_seconds);
5811d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
5821d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  if (minimizer_type == TRUST_REGION) {
5831d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    StringAppendF(&report, "  Linear solver       %23.3f\n",
5841d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                  linear_solver_time_in_seconds);
5851d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  }
5861d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
5871d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  if (inner_iterations_used) {
5881d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    StringAppendF(&report, "  Inner iterations    %23.3f\n",
5891d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                  inner_iteration_time_in_seconds);
5901d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  }
5911d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
5921d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  StringAppendF(&report, "Minimizer           %25.3f\n\n",
5931d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                minimizer_time_in_seconds);
5941d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
5951d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  StringAppendF(&report, "Postprocessor        %24.3f\n",
5961d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                postprocessor_time_in_seconds);
5971d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
5981d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  StringAppendF(&report, "Total               %25.3f\n\n",
5991d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                total_time_in_seconds);
6001d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
60179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  StringAppendF(&report, "Termination:        %25s (%s)\n",
60279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez                TerminationTypeToString(termination_type), message.c_str());
6030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  return report;
6040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong};
6050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
60679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandezbool Solver::Summary::IsSolutionUsable() const {
60779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  return (termination_type == CONVERGENCE ||
60879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez          termination_type == NO_CONVERGENCE ||
60979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez          termination_type == USER_SUCCESS);
61079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez}
61179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
6120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong}  // namespace ceres
613