10ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Ceres Solver - A fast non-linear least squares minimizer
20ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Copyright 2010, 2011, 2012 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//
320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// System level tests for Ceres. The current suite of two tests. The
330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// first test is a small test based on Powell's Function. It is a
340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// scalar problem with 4 variables. The second problem is a bundle
350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// adjustment problem with 16 cameras and two thousand cameras. The
360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// first problem is to test the sanity test the factorization based
370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// solvers. The second problem is used to test the various
380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// combinations of solvers, orderings, preconditioners and
390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// multithreading.
400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include <cmath>
420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include <cstdio>
430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include <cstdlib>
440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include <string>
450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
4679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#include "ceres/internal/port.h"
4779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/autodiff_cost_function.h"
490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/ordered_groups.h"
500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/problem.h"
510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/rotation.h"
520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/solver.h"
530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/stringprintf.h"
540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/test_util.h"
550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/types.h"
560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "gflags/gflags.h"
570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "glog/logging.h"
580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "gtest/gtest.h"
590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
600ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongnamespace ceres {
610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongnamespace internal {
620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongconst bool kAutomaticOrdering = true;
640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongconst bool kUserOrdering = false;
650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Struct used for configuring the solver.
670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongstruct SolverConfig {
6879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  SolverConfig(
6979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      LinearSolverType linear_solver_type,
7079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
7179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      bool use_automatic_ordering)
720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      : linear_solver_type(linear_solver_type),
73399f7d09e0c45af54b77b4ab9508d6f23759b927Scott Ettinger        sparse_linear_algebra_library_type(sparse_linear_algebra_library_type),
740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        use_automatic_ordering(use_automatic_ordering),
750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        preconditioner_type(IDENTITY),
760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        num_threads(1) {
770ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  }
780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
7979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  SolverConfig(
8079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      LinearSolverType linear_solver_type,
8179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
8279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      bool use_automatic_ordering,
8379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      PreconditionerType preconditioner_type)
840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      : linear_solver_type(linear_solver_type),
85399f7d09e0c45af54b77b4ab9508d6f23759b927Scott Ettinger        sparse_linear_algebra_library_type(sparse_linear_algebra_library_type),
860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        use_automatic_ordering(use_automatic_ordering),
870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        preconditioner_type(preconditioner_type),
880ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        num_threads(1) {
890ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  }
900ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  string ToString() const {
920ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    return StringPrintf(
930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        "(%s, %s, %s, %s, %d)",
940ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        LinearSolverTypeToString(linear_solver_type),
9579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez        SparseLinearAlgebraLibraryTypeToString(
9679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez            sparse_linear_algebra_library_type),
970ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        use_automatic_ordering ? "AUTOMATIC" : "USER",
980ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        PreconditionerTypeToString(preconditioner_type),
990ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        num_threads);
1000ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  }
1010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1020ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  LinearSolverType linear_solver_type;
103399f7d09e0c45af54b77b4ab9508d6f23759b927Scott Ettinger  SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type;
1040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  bool use_automatic_ordering;
1050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  PreconditionerType preconditioner_type;
1060ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  int num_threads;
1070ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong};
1080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1090ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Templated function that given a set of solver configurations,
1100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// instantiates a new copy of SystemTestProblem for each configuration
1110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// and solves it. The solutions are expected to have residuals with
1120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// coordinate-wise maximum absolute difference less than or equal to
1130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// max_abs_difference.
1140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//
1150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// The template parameter SystemTestProblem is expected to implement
1160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// the following interface.
1170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//
1180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//   class SystemTestProblem {
1190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//     public:
1200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//       SystemTestProblem();
1210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//       Problem* mutable_problem();
1220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//       Solver::Options* mutable_solver_options();
1230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//   };
1240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongtemplate <typename SystemTestProblem>
1250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongvoid RunSolversAndCheckTheyMatch(const vector<SolverConfig>& configurations,
1260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                                 const double max_abs_difference) {
1270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  int num_configurations = configurations.size();
1280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  vector<SystemTestProblem*> problems;
1291d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  vector<vector<double> > final_residuals(num_configurations);
1300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  for (int i = 0; i < num_configurations; ++i) {
1320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    SystemTestProblem* system_test_problem = new SystemTestProblem();
1330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    const SolverConfig& config = configurations[i];
1350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    Solver::Options& options = *(system_test_problem->mutable_solver_options());
1370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    options.linear_solver_type = config.linear_solver_type;
138399f7d09e0c45af54b77b4ab9508d6f23759b927Scott Ettinger    options.sparse_linear_algebra_library_type =
139399f7d09e0c45af54b77b4ab9508d6f23759b927Scott Ettinger        config.sparse_linear_algebra_library_type;
1400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    options.preconditioner_type = config.preconditioner_type;
1410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    options.num_threads = config.num_threads;
1420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    options.num_linear_solver_threads = config.num_threads;
1430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    if (config.use_automatic_ordering) {
14579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez      options.linear_solver_ordering.reset();
1460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
1470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    LOG(INFO) << "Running solver configuration: "
1490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong              << config.ToString();
1500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1511d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    Solver::Summary summary;
1520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    Solve(options,
1530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong          system_test_problem->mutable_problem(),
1541d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling          &summary);
1550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1561d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    system_test_problem
1571d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling        ->mutable_problem()
1581d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling        ->Evaluate(Problem::EvaluateOptions(),
1591d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                   NULL,
1601d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                   &final_residuals[i],
1611d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                   NULL,
1621d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                   NULL);
1631d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
16479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    CHECK_NE(summary.termination_type, ceres::FAILURE)
1650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        << "Solver configuration " << i << " failed.";
1660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    problems.push_back(system_test_problem);
1670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // Compare the resulting solutions to each other. Arbitrarily take
1690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // SPARSE_NORMAL_CHOLESKY as the golden solve. We compare
1700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // solutions by comparing their residual vectors. We do not
1710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // compare parameter vectors because it is much more brittle and
1720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // error prone to do so, since the same problem can have nearly
1730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // the same residuals at two completely different positions in
1740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // parameter space.
1750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    if (i > 0) {
1761d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      const vector<double>& reference_residuals = final_residuals[0];
1771d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling      const vector<double>& current_residuals = final_residuals[i];
1780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1790ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      for (int j = 0; j < reference_residuals.size(); ++j) {
1800ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        EXPECT_NEAR(current_residuals[j],
1810ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                    reference_residuals[j],
1820ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                    max_abs_difference)
1830ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong            << "Not close enough residual:" << j
1840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong            << " reference " << reference_residuals[j]
1850ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong            << " current " << current_residuals[j];
1860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      }
1870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
1880ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  }
1890ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1900ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  for (int i = 0; i < num_configurations; ++i) {
1910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    delete problems[i];
1920ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  }
1930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong}
1940ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1950ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// This class implements the SystemTestProblem interface and provides
1960ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// access to an implementation of Powell's singular function.
1970ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//
1980ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//   F = 1/2 (f1^2 + f2^2 + f3^2 + f4^2)
1990ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//
2000ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//   f1 = x1 + 10*x2;
2010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//   f2 = sqrt(5) * (x3 - x4)
2020ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//   f3 = (x2 - 2*x3)^2
2030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//   f4 = sqrt(10) * (x1 - x4)^2
2040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//
2050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// The starting values are x1 = 3, x2 = -1, x3 = 0, x4 = 1.
2060ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// The minimum is 0 at (x1, x2, x3, x4) = 0.
2070ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//
2080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// From: Testing Unconstrained Optimization Software by Jorge J. More, Burton S.
2090ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Garbow and Kenneth E. Hillstrom in ACM Transactions on Mathematical Software,
2100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Vol 7(1), March 1981.
2110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongclass PowellsFunction {
2120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong public:
2130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  PowellsFunction() {
2140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    x_[0] =  3.0;
2150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    x_[1] = -1.0;
2160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    x_[2] =  0.0;
2170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    x_[3] =  1.0;
2180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
2190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    problem_.AddResidualBlock(
2200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        new AutoDiffCostFunction<F1, 1, 1, 1>(new F1), NULL, &x_[0], &x_[1]);
2210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    problem_.AddResidualBlock(
2220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        new AutoDiffCostFunction<F2, 1, 1, 1>(new F2), NULL, &x_[2], &x_[3]);
2230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    problem_.AddResidualBlock(
2240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        new AutoDiffCostFunction<F3, 1, 1, 1>(new F3), NULL, &x_[1], &x_[2]);
2250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    problem_.AddResidualBlock(
2260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        new AutoDiffCostFunction<F4, 1, 1, 1>(new F4), NULL, &x_[0], &x_[3]);
2270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
2280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    options_.max_num_iterations = 10;
2290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  }
2300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
2310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  Problem* mutable_problem() { return &problem_; }
2320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  Solver::Options* mutable_solver_options() { return &options_; }
2330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
2340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong private:
2350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // Templated functions used for automatically differentiated cost
2360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // functions.
2370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  class F1 {
2380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong   public:
2390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    template <typename T> bool operator()(const T* const x1,
2400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                                          const T* const x2,
2410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                                          T* residual) const {
2420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      // f1 = x1 + 10 * x2;
2430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      *residual = *x1 + T(10.0) * *x2;
2440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      return true;
2450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
2460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  };
2470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
2480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  class F2 {
2490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong   public:
2500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    template <typename T> bool operator()(const T* const x3,
2510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                                          const T* const x4,
2520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                                          T* residual) const {
2530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      // f2 = sqrt(5) (x3 - x4)
2540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      *residual = T(sqrt(5.0)) * (*x3 - *x4);
2550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      return true;
2560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
2570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  };
2580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
2590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  class F3 {
2600ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong   public:
2610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    template <typename T> bool operator()(const T* const x2,
2620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                                          const T* const x4,
2630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                                          T* residual) const {
2640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      // f3 = (x2 - 2 x3)^2
2650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      residual[0] = (x2[0] - T(2.0) * x4[0]) * (x2[0] - T(2.0) * x4[0]);
2660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      return true;
2670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
2680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  };
2690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
2700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  class F4 {
2710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong   public:
2720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    template <typename T> bool operator()(const T* const x1,
2730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                                          const T* const x4,
2740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                                          T* residual) const {
2750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      // f4 = sqrt(10) (x1 - x4)^2
2760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      residual[0] = T(sqrt(10.0)) * (x1[0] - x4[0]) * (x1[0] - x4[0]);
2770ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      return true;
2780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
2790ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  };
2800ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
2810ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  double x_[4];
2820ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  Problem problem_;
2830ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  Solver::Options options_;
2840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong};
2850ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
2860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(SystemTest, PowellsFunction) {
2870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  vector<SolverConfig> configs;
288399f7d09e0c45af54b77b4ab9508d6f23759b927Scott Ettinger#define CONFIGURE(linear_solver, sparse_linear_algebra_library_type, ordering) \
289399f7d09e0c45af54b77b4ab9508d6f23759b927Scott Ettinger  configs.push_back(SolverConfig(linear_solver,                         \
290399f7d09e0c45af54b77b4ab9508d6f23759b927Scott Ettinger                                 sparse_linear_algebra_library_type,    \
2910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                                 ordering))
2920ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
2930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  CONFIGURE(DENSE_QR,               SUITE_SPARSE, kAutomaticOrdering);
2940ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  CONFIGURE(DENSE_NORMAL_CHOLESKY,  SUITE_SPARSE, kAutomaticOrdering);
2950ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  CONFIGURE(DENSE_SCHUR,            SUITE_SPARSE, kAutomaticOrdering);
2960ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
2970ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#ifndef CERES_NO_SUITESPARSE
2980ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  CONFIGURE(SPARSE_NORMAL_CHOLESKY, SUITE_SPARSE, kAutomaticOrdering);
2990ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#endif  // CERES_NO_SUITESPARSE
3000ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#ifndef CERES_NO_CXSPARSE
3020ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  CONFIGURE(SPARSE_NORMAL_CHOLESKY, CX_SPARSE,    kAutomaticOrdering);
3030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#endif  // CERES_NO_CXSPARSE
3040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  CONFIGURE(ITERATIVE_SCHUR,        SUITE_SPARSE, kAutomaticOrdering);
3060ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3070ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#undef CONFIGURE
3080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3090ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  const double kMaxAbsoluteDifference = 1e-8;
3100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  RunSolversAndCheckTheyMatch<PowellsFunction>(configs, kMaxAbsoluteDifference);
3110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong}
3120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// This class implements the SystemTestProblem interface and provides
3140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// access to a bundle adjustment problem. It is based on
3150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// examples/bundle_adjustment_example.cc. Currently a small 16 camera
3160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// problem is hard coded in the constructor. Going forward we may
3170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// extend this to a larger number of problems.
3180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongclass BundleAdjustmentProblem {
3190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong public:
3200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  BundleAdjustmentProblem() {
3210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    const string input_file = TestFileAbsolutePath("problem-16-22106-pre.txt");
3220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    ReadData(input_file);
3230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    BuildProblem();
3240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  }
3250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  ~BundleAdjustmentProblem() {
3270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    delete []point_index_;
3280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    delete []camera_index_;
3290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    delete []observations_;
3300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    delete []parameters_;
3310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  }
3320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  Problem* mutable_problem() { return &problem_; }
3340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  Solver::Options* mutable_solver_options() { return &options_; }
3350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  int num_cameras()            const { return num_cameras_;        }
3370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  int num_points()             const { return num_points_;         }
3380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  int num_observations()       const { return num_observations_;   }
3390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  const int* point_index()     const { return point_index_;  }
3400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  const int* camera_index()    const { return camera_index_; }
3410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  const double* observations() const { return observations_; }
3420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  double* mutable_cameras() { return parameters_; }
3430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  double* mutable_points() { return parameters_  + 9 * num_cameras_; }
3440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong private:
3460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  void ReadData(const string& filename) {
3470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    FILE * fptr = fopen(filename.c_str(), "r");
3480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    if (!fptr) {
3500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      LOG(FATAL) << "File Error: unable to open file " << filename;
3510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    };
3520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // This will die horribly on invalid files. Them's the breaks.
3540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    FscanfOrDie(fptr, "%d", &num_cameras_);
3550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    FscanfOrDie(fptr, "%d", &num_points_);
3560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    FscanfOrDie(fptr, "%d", &num_observations_);
3570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    VLOG(1) << "Header: " << num_cameras_
3590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong            << " " << num_points_
3600ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong            << " " << num_observations_;
3610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    point_index_ = new int[num_observations_];
3630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    camera_index_ = new int[num_observations_];
3640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    observations_ = new double[2 * num_observations_];
3650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    num_parameters_ = 9 * num_cameras_ + 3 * num_points_;
3670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    parameters_ = new double[num_parameters_];
3680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    for (int i = 0; i < num_observations_; ++i) {
3700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      FscanfOrDie(fptr, "%d", camera_index_ + i);
3710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      FscanfOrDie(fptr, "%d", point_index_ + i);
3720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      for (int j = 0; j < 2; ++j) {
3730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        FscanfOrDie(fptr, "%lf", observations_ + 2*i + j);
3740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      }
3750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
3760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3770ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    for (int i = 0; i < num_parameters_; ++i) {
3780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      FscanfOrDie(fptr, "%lf", parameters_ + i);
3790ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
3800ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  }
3810ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3820ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  void BuildProblem() {
3830ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    double* points = mutable_points();
3840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    double* cameras = mutable_cameras();
3850ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    for (int i = 0; i < num_observations(); ++i) {
3870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      // Each Residual block takes a point and a camera as input and
3880ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      // outputs a 2 dimensional residual.
3890ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      CostFunction* cost_function =
3900ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong          new AutoDiffCostFunction<BundlerResidual, 2, 9, 3>(
3910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong              new BundlerResidual(observations_[2*i + 0],
3920ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                                  observations_[2*i + 1]));
3930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
3940ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      // Each observation correponds to a pair of a camera and a point
3950ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      // which are identified by camera_index()[i] and
3960ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      // point_index()[i] respectively.
3970ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      double* camera = cameras + 9 * camera_index_[i];
3980ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      double* point = points + 3 * point_index()[i];
3990ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      problem_.AddResidualBlock(cost_function, NULL, camera, point);
4000ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
4010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
40279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez    options_.linear_solver_ordering.reset(new ParameterBlockOrdering);
4030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
4040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // The points come before the cameras.
4050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    for (int i = 0; i < num_points_; ++i) {
4060ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      options_.linear_solver_ordering->AddElementToGroup(points + 3 * i, 0);
4070ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
4080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
4090ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    for (int i = 0; i < num_cameras_; ++i) {
4100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      options_.linear_solver_ordering->AddElementToGroup(cameras + 9 * i, 1);
4110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
4120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
4130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    options_.max_num_iterations = 25;
4140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    options_.function_tolerance = 1e-10;
4150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    options_.gradient_tolerance = 1e-10;
4160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    options_.parameter_tolerance = 1e-10;
4170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  }
4180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
4190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  template<typename T>
4200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  void FscanfOrDie(FILE *fptr, const char *format, T *value) {
4210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    int num_scanned = fscanf(fptr, format, value);
4220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    if (num_scanned != 1) {
4230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      LOG(FATAL) << "Invalid UW data file.";
4240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
4250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  }
4260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
4270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // Templated pinhole camera model.  The camera is parameterized
4280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // using 9 parameters. 3 for rotation, 3 for translation, 1 for
4290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // focal length and 2 for radial distortion. The principal point is
4300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // not modeled (i.e. it is assumed be located at the image center).
4310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  struct BundlerResidual {
4320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // (u, v): the position of the observation with respect to the image
4330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // center point.
4340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    BundlerResidual(double u, double v): u(u), v(v) {}
4350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
4360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    template <typename T>
4370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    bool operator()(const T* const camera,
4380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                    const T* const point,
4390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                    T* residuals) const {
4400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      T p[3];
4410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      AngleAxisRotatePoint(camera, point, p);
4420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
4430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      // Add the translation vector
4440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      p[0] += camera[3];
4450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      p[1] += camera[4];
4460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      p[2] += camera[5];
4470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
4480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      const T& focal = camera[6];
4490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      const T& l1 = camera[7];
4500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      const T& l2 = camera[8];
4510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
4520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      // Compute the center of distortion.  The sign change comes from
4530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      // the camera model that Noah Snavely's Bundler assumes, whereby
4540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      // the camera coordinate system has a negative z axis.
4550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      T xp = - focal * p[0] / p[2];
4560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      T yp = - focal * p[1] / p[2];
4570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
4580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      // Apply second and fourth order radial distortion.
4590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      T r2 = xp*xp + yp*yp;
4600ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      T distortion = T(1.0) + r2  * (l1 + l2  * r2);
4610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
4620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      residuals[0] = distortion * xp - T(u);
4630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      residuals[1] = distortion * yp - T(v);
4640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
4650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      return true;
4660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
4670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
4680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    double u;
4690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    double v;
4700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  };
4710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
4720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
4730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  Problem problem_;
4740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  Solver::Options options_;
4750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
4760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  int num_cameras_;
4770ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  int num_points_;
4780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  int num_observations_;
4790ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  int num_parameters_;
4800ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
4810ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  int* point_index_;
4820ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  int* camera_index_;
4830ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  double* observations_;
4840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // The parameter vector is laid out as follows
4850ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // [camera_1, ..., camera_n, point_1, ..., point_m]
4860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  double* parameters_;
4870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong};
4880ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
4890ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(SystemTest, BundleAdjustmentProblem) {
4900ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  vector<SolverConfig> configs;
4910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
492399f7d09e0c45af54b77b4ab9508d6f23759b927Scott Ettinger#define CONFIGURE(linear_solver, sparse_linear_algebra_library_type, ordering, preconditioner) \
4930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  configs.push_back(SolverConfig(linear_solver,                         \
494399f7d09e0c45af54b77b4ab9508d6f23759b927Scott Ettinger                                 sparse_linear_algebra_library_type,    \
4950ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                                 ordering,                              \
4960ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                                 preconditioner))
4970ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
4980ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  CONFIGURE(DENSE_SCHUR,            SUITE_SPARSE, kAutomaticOrdering, IDENTITY);
4990ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  CONFIGURE(DENSE_SCHUR,            SUITE_SPARSE, kUserOrdering,      IDENTITY);
5000ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
5010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  CONFIGURE(CGNR,                   SUITE_SPARSE, kAutomaticOrdering, JACOBI);
50279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
5030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  CONFIGURE(ITERATIVE_SCHUR,        SUITE_SPARSE, kUserOrdering,      JACOBI);
50479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  CONFIGURE(ITERATIVE_SCHUR,        SUITE_SPARSE, kAutomaticOrdering, JACOBI);
50579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
5061d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  CONFIGURE(ITERATIVE_SCHUR,        SUITE_SPARSE, kUserOrdering,      SCHUR_JACOBI);
50779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  CONFIGURE(ITERATIVE_SCHUR,        SUITE_SPARSE, kAutomaticOrdering, SCHUR_JACOBI);
5080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
5090ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#ifndef CERES_NO_SUITESPARSE
51079397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  CONFIGURE(SPARSE_NORMAL_CHOLESKY, SUITE_SPARSE, kAutomaticOrdering, IDENTITY);
51179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  CONFIGURE(SPARSE_NORMAL_CHOLESKY, SUITE_SPARSE, kUserOrdering,      IDENTITY);
51279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
51379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  CONFIGURE(SPARSE_SCHUR,           SUITE_SPARSE, kAutomaticOrdering, IDENTITY);
51479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  CONFIGURE(SPARSE_SCHUR,           SUITE_SPARSE, kUserOrdering,      IDENTITY);
5151d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
51679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  CONFIGURE(ITERATIVE_SCHUR,        SUITE_SPARSE, kAutomaticOrdering, CLUSTER_JACOBI);
5170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  CONFIGURE(ITERATIVE_SCHUR,        SUITE_SPARSE, kUserOrdering,      CLUSTER_JACOBI);
51879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez
51979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  CONFIGURE(ITERATIVE_SCHUR,        SUITE_SPARSE, kAutomaticOrdering, CLUSTER_TRIDIAGONAL);
5200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  CONFIGURE(ITERATIVE_SCHUR,        SUITE_SPARSE, kUserOrdering,      CLUSTER_TRIDIAGONAL);
5210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#endif  // CERES_NO_SUITESPARSE
5220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
52379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#ifndef CERES_NO_CXSPARSE
52479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  CONFIGURE(SPARSE_NORMAL_CHOLESKY, CX_SPARSE,    kAutomaticOrdering, IDENTITY);
52579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  CONFIGURE(SPARSE_NORMAL_CHOLESKY, CX_SPARSE,    kUserOrdering,      IDENTITY);
5260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
52779397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  CONFIGURE(SPARSE_SCHUR,           CX_SPARSE,    kAutomaticOrdering, IDENTITY);
52879397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  CONFIGURE(SPARSE_SCHUR,           CX_SPARSE,    kUserOrdering,      IDENTITY);
52979397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#endif  // CERES_NO_CXSPARSE
5301d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
53179397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#ifdef CERES_USE_EIGEN_SPARSE
53279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  CONFIGURE(SPARSE_SCHUR,           EIGEN_SPARSE, kAutomaticOrdering, IDENTITY);
53379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  CONFIGURE(SPARSE_SCHUR,           EIGEN_SPARSE, kUserOrdering,      IDENTITY);
53479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  CONFIGURE(SPARSE_NORMAL_CHOLESKY, EIGEN_SPARSE, kAutomaticOrdering, IDENTITY);
53579397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez  CONFIGURE(SPARSE_NORMAL_CHOLESKY, EIGEN_SPARSE, kUserOrdering,      IDENTITY);
53679397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#endif  // CERES_USE_EIGEN_SPARSE
5370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
5380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#undef CONFIGURE
5390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
5400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // Single threaded evaluators and linear solvers.
5410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  const double kMaxAbsoluteDifference = 1e-4;
5420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  RunSolversAndCheckTheyMatch<BundleAdjustmentProblem>(configs,
5430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                                                       kMaxAbsoluteDifference);
5440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
5450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#ifdef CERES_USE_OPENMP
5460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // Multithreaded evaluators and linear solvers.
5470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  for (int i = 0; i < configs.size(); ++i) {
5480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    configs[i].num_threads = 2;
5490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  }
5500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  RunSolversAndCheckTheyMatch<BundleAdjustmentProblem>(configs,
5510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                                                       kMaxAbsoluteDifference);
5520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#endif  // CERES_USE_OPENMP
5530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong}
5540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
5550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong}  // namespace internal
5560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong}  // namespace ceres
557