Squashed 'third_party/ceres/' content from commit e51e9b4

Change-Id: I763587619d57e594d3fa158dc3a7fe0b89a1743b
git-subtree-dir: third_party/ceres
git-subtree-split: e51e9b46f6ca88ab8b2266d0e362771db6d98067
diff --git a/internal/ceres/iterative_schur_complement_solver.cc b/internal/ceres/iterative_schur_complement_solver.cc
new file mode 100644
index 0000000..6076c38
--- /dev/null
+++ b/internal/ceres/iterative_schur_complement_solver.cc
@@ -0,0 +1,176 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/iterative_schur_complement_solver.h"
+
+#include <algorithm>
+#include <cstring>
+#include <vector>
+
+#include "Eigen/Dense"
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/block_structure.h"
+#include "ceres/conjugate_gradients_solver.h"
+#include "ceres/detect_structure.h"
+#include "ceres/implicit_schur_complement.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/linear_solver.h"
+#include "ceres/preconditioner.h"
+#include "ceres/schur_jacobi_preconditioner.h"
+#include "ceres/triplet_sparse_matrix.h"
+#include "ceres/types.h"
+#include "ceres/visibility_based_preconditioner.h"
+#include "ceres/wall_time.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+IterativeSchurComplementSolver::IterativeSchurComplementSolver(
+    const LinearSolver::Options& options)
+    : options_(options) {
+}
+
+IterativeSchurComplementSolver::~IterativeSchurComplementSolver() {}
+
+LinearSolver::Summary IterativeSchurComplementSolver::SolveImpl(
+    BlockSparseMatrix* A,
+    const double* b,
+    const LinearSolver::PerSolveOptions& per_solve_options,
+    double* x) {
+  EventLogger event_logger("IterativeSchurComplementSolver::Solve");
+
+  CHECK(A->block_structure() != nullptr);
+  const int num_eliminate_blocks = options_.elimination_groups[0];
+  // Initialize a ImplicitSchurComplement object.
+  if (schur_complement_ == NULL) {
+    DetectStructure(*(A->block_structure()),
+                    num_eliminate_blocks,
+                    &options_.row_block_size,
+                    &options_.e_block_size,
+                    &options_.f_block_size);
+    schur_complement_.reset(new ImplicitSchurComplement(options_));
+  }
+  schur_complement_->Init(*A, per_solve_options.D, b);
+
+  const int num_schur_complement_blocks =
+      A->block_structure()->cols.size() - num_eliminate_blocks;
+  if (num_schur_complement_blocks == 0) {
+    VLOG(2) << "No parameter blocks left in the schur complement.";
+    LinearSolver::Summary summary;
+    summary.num_iterations = 0;
+    summary.termination_type = LINEAR_SOLVER_SUCCESS;
+    schur_complement_->BackSubstitute(NULL, x);
+    return summary;
+  }
+
+  // Initialize the solution to the Schur complement system to zero.
+  reduced_linear_system_solution_.resize(schur_complement_->num_rows());
+  reduced_linear_system_solution_.setZero();
+
+  LinearSolver::Options cg_options;
+  cg_options.min_num_iterations = options_.min_num_iterations;
+  cg_options.max_num_iterations = options_.max_num_iterations;
+  ConjugateGradientsSolver cg_solver(cg_options);
+
+  LinearSolver::PerSolveOptions cg_per_solve_options;
+  cg_per_solve_options.r_tolerance = per_solve_options.r_tolerance;
+  cg_per_solve_options.q_tolerance = per_solve_options.q_tolerance;
+
+  CreatePreconditioner(A);
+  if (preconditioner_.get() != NULL) {
+    if (!preconditioner_->Update(*A, per_solve_options.D)) {
+      LinearSolver::Summary summary;
+      summary.num_iterations = 0;
+      summary.termination_type = LINEAR_SOLVER_FAILURE;
+      summary.message = "Preconditioner update failed.";
+      return summary;
+    }
+
+    cg_per_solve_options.preconditioner = preconditioner_.get();
+  }
+
+  event_logger.AddEvent("Setup");
+  LinearSolver::Summary summary =
+      cg_solver.Solve(schur_complement_.get(),
+                      schur_complement_->rhs().data(),
+                      cg_per_solve_options,
+                      reduced_linear_system_solution_.data());
+  if (summary.termination_type != LINEAR_SOLVER_FAILURE &&
+      summary.termination_type != LINEAR_SOLVER_FATAL_ERROR) {
+    schur_complement_->BackSubstitute(reduced_linear_system_solution_.data(),
+                                      x);
+  }
+  event_logger.AddEvent("Solve");
+  return summary;
+}
+
+void IterativeSchurComplementSolver::CreatePreconditioner(
+    BlockSparseMatrix* A) {
+  if (options_.preconditioner_type == IDENTITY ||
+      preconditioner_.get() != NULL) {
+    return;
+  }
+
+  Preconditioner::Options preconditioner_options;
+  preconditioner_options.type = options_.preconditioner_type;
+  preconditioner_options.visibility_clustering_type =
+      options_.visibility_clustering_type;
+  preconditioner_options.sparse_linear_algebra_library_type =
+      options_.sparse_linear_algebra_library_type;
+  preconditioner_options.num_threads = options_.num_threads;
+  preconditioner_options.row_block_size = options_.row_block_size;
+  preconditioner_options.e_block_size = options_.e_block_size;
+  preconditioner_options.f_block_size = options_.f_block_size;
+  preconditioner_options.elimination_groups = options_.elimination_groups;
+  CHECK(options_.context != NULL);
+  preconditioner_options.context = options_.context;
+
+  switch (options_.preconditioner_type) {
+    case JACOBI:
+      preconditioner_.reset(new SparseMatrixPreconditionerWrapper(
+          schur_complement_->block_diagonal_FtF_inverse()));
+      break;
+    case SCHUR_JACOBI:
+      preconditioner_.reset(new SchurJacobiPreconditioner(
+          *A->block_structure(), preconditioner_options));
+      break;
+    case CLUSTER_JACOBI:
+    case CLUSTER_TRIDIAGONAL:
+      preconditioner_.reset(new VisibilityBasedPreconditioner(
+          *A->block_structure(), preconditioner_options));
+      break;
+    default:
+      LOG(FATAL) << "Unknown Preconditioner Type";
+  }
+};
+
+}  // namespace internal
+}  // namespace ceres