A number of small changes.

These changes came about from testing the power bundle adjustment
integration CL.

1. Allow Solver::Options::max_linear_solver_iterations == 0.
2. Simplify the logic for when inverse(F'F) is computed.
3. norm_b -> norm_rhs in ConjugateGradientsSolver.

Change-Id: I50c19e1f24a4cc08ed60e3a3032b96b37bcada9f
diff --git a/internal/ceres/conjugate_gradients_solver.h b/internal/ceres/conjugate_gradients_solver.h
index 93f9e25..f2eea87 100644
--- a/internal/ceres/conjugate_gradients_solver.h
+++ b/internal/ceres/conjugate_gradients_solver.h
@@ -125,15 +125,15 @@
   summary.message = "Maximum number of iterations reached.";
   summary.num_iterations = 0;
 
-  const double norm_b = Norm(rhs);
-  if (norm_b == 0.0) {
+  const double norm_rhs = Norm(rhs);
+  if (norm_rhs == 0.0) {
     SetZero(solution);
     summary.termination_type = LinearSolverTerminationType::SUCCESS;
     summary.message = "Convergence. |b| = 0.";
     return summary;
   }
 
-  const double tol_r = options.r_tolerance * norm_b;
+  const double tol_r = options.r_tolerance * norm_rhs;
 
   SetZero(tmp);
   lhs.RightMultiplyAndAccumulate(solution, tmp);
diff --git a/internal/ceres/implicit_schur_complement.cc b/internal/ceres/implicit_schur_complement.cc
index 4e837f3..92631de 100644
--- a/internal/ceres/implicit_schur_complement.cc
+++ b/internal/ceres/implicit_schur_complement.cc
@@ -42,7 +42,7 @@
 
 ImplicitSchurComplement::ImplicitSchurComplement(
     const LinearSolver::Options& options)
-    : options_(options), D_(nullptr), b_(nullptr) {}
+    : options_(options) {}
 
 void ImplicitSchurComplement::Init(const BlockSparseMatrix& A,
                                    const double* D,
@@ -56,12 +56,15 @@
   D_ = D;
   b_ = b;
 
+  compute_ftf_inverse_ =
+      options_.preconditioner_type == JACOBI ||
+      options_.preconditioner_type == SCHUR_POWER_SERIES_EXPANSION;
+
   // Initialize temporary storage and compute the block diagonals of
   // E'E and F'E.
   if (block_diagonal_EtE_inverse_ == nullptr) {
     block_diagonal_EtE_inverse_ = A_->CreateBlockDiagonalEtE();
-    if (options_.preconditioner_type == JACOBI ||
-        options_.preconditioner_type == SCHUR_POWER_SERIES_EXPANSION) {
+    if (compute_ftf_inverse_) {
       block_diagonal_FtF_inverse_ = A_->CreateBlockDiagonalFtF();
     }
     rhs_.resize(A_->num_cols_f());
@@ -72,8 +75,7 @@
     tmp_f_cols_.resize(A_->num_cols_f());
   } else {
     A_->UpdateBlockDiagonalEtE(block_diagonal_EtE_inverse_.get());
-    if (options_.preconditioner_type == JACOBI ||
-        options_.preconditioner_type == SCHUR_POWER_SERIES_EXPANSION) {
+    if (compute_ftf_inverse_) {
       A_->UpdateBlockDiagonalFtF(block_diagonal_FtF_inverse_.get());
     }
   }
@@ -82,8 +84,7 @@
   // contributions from the diagonal D if it is non-null. Add that to
   // the block diagonals and invert them.
   AddDiagonalAndInvert(D_, block_diagonal_EtE_inverse_.get());
-  if (options_.preconditioner_type == JACOBI ||
-      options_.preconditioner_type == SCHUR_POWER_SERIES_EXPANSION) {
+  if (compute_ftf_inverse_) {
     AddDiagonalAndInvert((D_ == nullptr) ? nullptr : D_ + A_->num_cols_e(),
                          block_diagonal_FtF_inverse_.get());
   }
@@ -134,6 +135,7 @@
 
 void ImplicitSchurComplement::InversePowerSeriesOperatorRightMultiplyAccumulate(
     const double* x, double* y) const {
+  CHECK(compute_ftf_inverse_);
   // y1 = F x
   tmp_rows_.setZero();
   A_->RightMultiplyAndAccumulateF(x, tmp_rows_.data());
diff --git a/internal/ceres/implicit_schur_complement.h b/internal/ceres/implicit_schur_complement.h
index 435ddda..620ea8c 100644
--- a/internal/ceres/implicit_schur_complement.h
+++ b/internal/ceres/implicit_schur_complement.h
@@ -143,6 +143,7 @@
   }
 
   const BlockSparseMatrix* block_diagonal_FtF_inverse() const {
+    CHECK(compute_ftf_inverse_);
     return block_diagonal_FtF_inverse_.get();
   }
 
@@ -151,10 +152,10 @@
   void UpdateRhs();
 
   const LinearSolver::Options& options_;
-
+  bool compute_ftf_inverse_ = false;
   std::unique_ptr<PartitionedMatrixViewBase> A_;
-  const double* D_;
-  const double* b_;
+  const double* D_ = nullptr;
+  const double* b_ = nullptr;
 
   std::unique_ptr<BlockSparseMatrix> block_diagonal_EtE_inverse_;
   std::unique_ptr<BlockSparseMatrix> block_diagonal_FtF_inverse_;
diff --git a/internal/ceres/solver.cc b/internal/ceres/solver.cc
index 966a5dd..8ad0862 100644
--- a/internal/ceres/solver.cc
+++ b/internal/ceres/solver.cc
@@ -166,7 +166,7 @@
   OPTION_GE(max_num_consecutive_invalid_steps, 0);
   OPTION_GT(eta, 0.0);
   OPTION_GE(min_linear_solver_iterations, 0);
-  OPTION_GE(max_linear_solver_iterations, 1);
+  OPTION_GE(max_linear_solver_iterations, 0);
   OPTION_LE_OPTION(min_linear_solver_iterations, max_linear_solver_iterations);
 
   if (options.use_inner_iterations) {