Add a general sparse iterative solver: CGNR

This adds a new LinearOperator which implements symmetric
products of a matrix, and a new CGNR solver to leverage
CG to directly solve the normal equations. This also
includes a block diagonal preconditioner. In experiments
on problem-16, the non-preconditioned version is about
1/5 the speed of SPARSE_SCHUR, and the preconditioned
version using block cholesky is about 20% slower than
SPARSE_SCHUR.
diff --git a/internal/ceres/CMakeLists.txt b/internal/ceres/CMakeLists.txt
index 7891138..03d650a 100644
--- a/internal/ceres/CMakeLists.txt
+++ b/internal/ceres/CMakeLists.txt
@@ -29,6 +29,7 @@
 # Author: keir@google.com (Keir Mierle)
 
 SET(CERES_INTERNAL_SRC
+    block_diagonal_preconditioner.cc
     block_evaluate_preparer.cc
     block_jacobian_writer.cc
     block_random_access_dense_matrix.cc
@@ -37,6 +38,7 @@
     block_sparse_matrix.cc
     block_structure.cc
     canonical_views_clustering.cc
+    cgnr_solver.cc
     compressed_row_jacobian_writer.cc
     compressed_row_sparse_matrix.cc
     conditioned_cost_function.cc
diff --git a/internal/ceres/block_diagonal_preconditioner.cc b/internal/ceres/block_diagonal_preconditioner.cc
new file mode 100644
index 0000000..0779a91
--- /dev/null
+++ b/internal/ceres/block_diagonal_preconditioner.cc
@@ -0,0 +1,118 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2012 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// 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: keir@google.com (Keir Mierle)
+
+#include "ceres/block_diagonal_preconditioner.h"
+
+#include "Eigen/Cholesky"
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/block_structure.h"
+#include "ceres/casts.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+BlockDiagonalPreconditioner::BlockDiagonalPreconditioner(
+    const LinearOperator& A)
+    : block_structure_(
+        *(down_cast<const BlockSparseMatrix*>(&A)->block_structure())) {
+
+  // Calculate the amount of storage needed.
+  int storage_needed = 0;
+  for (int c = 0; c < block_structure_.cols.size(); ++c) {
+    int size = block_structure_.cols[c].size;
+    storage_needed += size * size;
+  }
+
+  // Size the offsets and storage.
+  blocks_.resize(block_structure_.cols.size());
+  block_storage_.resize(storage_needed);
+
+  // Put pointers to the storage in the offsets.
+  double *block_cursor = &block_storage_[0];
+  for (int c = 0; c < block_structure_.cols.size(); ++c) {
+    int size = block_structure_.cols[c].size;
+    blocks_[c] = block_cursor;
+    block_cursor += size * size;
+  }
+}
+
+BlockDiagonalPreconditioner::~BlockDiagonalPreconditioner() {
+}
+
+void BlockDiagonalPreconditioner::Update(const LinearOperator& matrix) {
+  const BlockSparseMatrix& A = *(down_cast<const BlockSparseMatrix*>(&matrix));
+  const CompressedRowBlockStructure* bs = A.block_structure();
+
+  // Compute the diagonal blocks by block inner products.
+  std::fill(block_storage_.begin(), block_storage_.end(), 0.0);
+  for (int r = 0; r < bs->rows.size(); ++r) {
+    const int row_block_size = bs->rows[r].block.size;
+    const vector<Cell>& cells = bs->rows[r].cells;
+    const double* row_values = A.RowBlockValues(r);
+    for (int c = 0; c < cells.size(); ++c) {
+      const int col_block_size = bs->cols[cells[c].block_id].size;
+      ConstMatrixRef m(row_values + cells[c].position,
+                       row_block_size,
+                       col_block_size);
+
+      MatrixRef(blocks_[cells[c].block_id],
+                col_block_size,
+                col_block_size).noalias() += m.transpose() * m;
+    }
+  }
+
+  // Invert each block.
+  for (int c = 0; c < bs->cols.size(); ++c) {
+    const int size = block_structure_.cols[c].size;
+    MatrixRef D(blocks_[c], size, size);
+    D = D.selfadjointView<Eigen::Upper>()
+         .ldlt()
+         .solve(Matrix::Identity(size, size));
+  }
+}
+
+void BlockDiagonalPreconditioner::RightMultiply(const double* x, double* y) const {
+  for (int c = 0; c < block_structure_.cols.size(); ++c) {
+    const int size = block_structure_.cols[c].size;
+    const int position = block_structure_.cols[c].position;
+    ConstMatrixRef D(blocks_[c], size, size);
+    ConstVectorRef x_block(x + position, size);
+    VectorRef y_block(y + position, size);
+    y_block += D * x_block;
+  }
+}
+
+void BlockDiagonalPreconditioner::LeftMultiply(const double* x, double* y) const {
+  RightMultiply(x, y);
+}
+
+}  // namespace internal
+}  // namespace ceres
diff --git a/internal/ceres/block_diagonal_preconditioner.h b/internal/ceres/block_diagonal_preconditioner.h
new file mode 100644
index 0000000..561b0db
--- /dev/null
+++ b/internal/ceres/block_diagonal_preconditioner.h
@@ -0,0 +1,68 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2012 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// 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: keir@google.com (Keir Mierle)
+
+#ifndef CERES_INTERNAL_BLOCK_DIAGONAL_PRECONDITIONER_H_
+#define CERES_INTERNAL_BLOCK_DIAGONAL_PRECONDITIONER_H_
+
+#include <vector>
+#include "ceres/linear_operator.h"
+
+namespace ceres {
+namespace internal {
+
+class CompressedRowBlockStructure;
+class LinearOperator;
+class SparseMatrix;
+
+// A block diagonal preconditioner; also known as block-Jacobi.
+class BlockDiagonalPreconditioner : public LinearOperator {
+ public:
+  BlockDiagonalPreconditioner(const LinearOperator& A);
+  virtual ~BlockDiagonalPreconditioner();
+
+  void Update(const LinearOperator& matrix);
+
+  virtual void RightMultiply(const double* x, double* y) const;
+  virtual void LeftMultiply(const double* x, double* y) const;
+
+  virtual int num_rows() const { return size_; }
+  virtual int num_cols() const { return size_; }
+
+ private:
+  std::vector<double*> blocks_;
+  std::vector<double> block_storage_;
+  int size_;
+  const CompressedRowBlockStructure& block_structure_;
+};
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_INTERNAL_LINEAR_OPERATOR_H_
diff --git a/internal/ceres/cgnr_linear_operator.h b/internal/ceres/cgnr_linear_operator.h
new file mode 100644
index 0000000..94767fb
--- /dev/null
+++ b/internal/ceres/cgnr_linear_operator.h
@@ -0,0 +1,122 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2012 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// 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: keir@google.com (Keir Mierle)
+
+#ifndef CERES_INTERNAL_CGNR_LINEAR_OPERATOR_H_
+#define CERES_INTERNAL_CGNR_LINEAR_OPERATOR_H_
+
+#include <algorithm>
+#include "ceres/linear_operator.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+class SparseMatrix;
+
+// A linear operator which takes a matrix A and a diagonal vector D and
+// performs products of the form
+//
+//   (A^T A + D^T D)x
+//
+// This is used to implement iterative general sparse linear solving with
+// conjugate gradients, where A is the Jacobian and D is a regularizing
+// parameter. A brief proof that D^T D is the correct regularizer:
+//
+// Given a regularized least squares problem:
+//
+//   min  ||Ax - b||^2 + ||Dx||^2
+//    x
+//
+// First expand into matrix notation:
+//
+//   (Ax - b)^T (Ax - b) + xD^TDx
+//
+// Then multiply out to get:
+//
+//   = xA^TAx - 2xA^T b + b^Tb + xD^TDx
+//   = xA^TAx - 2b^T Ax + b^Tb + xD^TDx
+//
+// Take the derivative:
+//
+//   0 = 2A^TAx - 2b^T A + b^Tb + 2 D^TDx
+//   0 = A^TAx - A^T b + D^TDx
+//   0 = (A^TA + D^TD)x - A^T b
+//
+// Thus, the symmetric system we need to solve for CGNR is
+//
+//   Sx = z
+//
+// with S = A^TA + D^TD
+//  and z = A^T b
+//
+// Note: This class is not thread safe, since it uses some temporary storage.
+class CgnrLinearOperator : public LinearOperator {
+ public:
+  CgnrLinearOperator(LinearOperator* A, double *D)
+      : A_(A), D_(D), z_(new double[A->num_rows()]) {
+  }
+  virtual ~CgnrLinearOperator() {}
+
+  virtual void RightMultiply(const double* x, double* y) const {
+    std::fill(z_.get(), z_.get() + A_->num_rows(), 0.0);
+
+    // z = Ax
+    A_->RightMultiply(x, z_.get());
+
+    // y = y + Atz
+    A_->LeftMultiply(z_.get(), y);
+
+    // y = y + DtDx
+    if (D_ != NULL) {
+      int n = A_->num_cols();
+      for (int i = 0; i < n; ++i) {
+        y[i] += D_[i] * D_[i] * x[i];
+      }
+    }
+  }
+
+  virtual void LeftMultiply(const double* x, double* y) const {
+    RightMultiply(x, y);
+  }
+
+  virtual int num_rows() const { return A_->num_cols(); }
+  virtual int num_cols() const { return A_->num_cols(); }
+
+ private:
+  LinearOperator* A_;
+  double* D_;
+  scoped_array<double> z_;
+};
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_INTERNAL_CGNR_LINEAR_OPERATOR_H_
diff --git a/internal/ceres/cgnr_solver.cc b/internal/ceres/cgnr_solver.cc
new file mode 100644
index 0000000..2c88e33
--- /dev/null
+++ b/internal/ceres/cgnr_solver.cc
@@ -0,0 +1,79 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2012 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// 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: keir@google.com (Keir Mierle)
+
+#include "ceres/cgnr_solver.h"
+
+#include "ceres/linear_solver.h"
+#include "ceres/cgnr_linear_operator.h"
+#include "ceres/conjugate_gradients_solver.h"
+#include "ceres/block_diagonal_preconditioner.h"
+
+namespace ceres {
+namespace internal {
+
+CgnrSolver::CgnrSolver(const LinearSolver::Options& options)
+  : options_(options),
+    jacobi_preconditioner_(NULL) {
+}
+
+LinearSolver::Summary CgnrSolver::Solve(
+    LinearOperator* A,
+    const double* b,
+    const LinearSolver::PerSolveOptions& per_solve_options,
+    double* x) {
+  // Form z = Atb.
+  scoped_array<double> z(new double[A->num_cols()]);
+  std::fill(z.get(), z.get() + A->num_cols(), 0.0);
+  A->LeftMultiply(b, z.get());
+
+  // Precondition if necessary.
+  LinearSolver::PerSolveOptions cg_per_solve_options = per_solve_options;
+  if (options_.preconditioner_type == JACOBI) {
+    if (jacobi_preconditioner_.get() == NULL) {
+      jacobi_preconditioner_.reset(new BlockDiagonalPreconditioner(*A));
+    }
+    jacobi_preconditioner_->Update(*A);
+    cg_per_solve_options.preconditioner = jacobi_preconditioner_.get();
+  } else if (options_.preconditioner_type != IDENTITY) {
+    // TODO(keir): This should die somehow.
+  }
+
+  // Solve (AtA + DtD)x = z (= Atb).
+  std::fill(x, x + A->num_cols(), 0.0);
+  CgnrLinearOperator AtApDtD(A, per_solve_options.D);
+  ConjugateGradientsSolver conjugate_gradient_solver(options_);
+  return conjugate_gradient_solver.Solve(&AtApDtD,
+                                         z.get(),
+                                         cg_per_solve_options,
+                                         x);
+}
+
+}  // namespace internal
+}  // namespace ceres
diff --git a/internal/ceres/cgnr_solver.h b/internal/ceres/cgnr_solver.h
new file mode 100644
index 0000000..db49b07
--- /dev/null
+++ b/internal/ceres/cgnr_solver.h
@@ -0,0 +1,66 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2012 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// 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: keir@google.com (Keir Mierle)
+
+#ifndef CERES_INTERNAL_CGNR_SOLVER_H_
+#define CERES_INTERNAL_CGNR_SOLVER_H_
+
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/linear_solver.h"
+
+namespace ceres {
+namespace internal {
+
+class BlockDiagonalPreconditioner;
+
+// A conjugate gradients on the normal equations solver. This directly solves
+// for the solution to
+//
+//   (A^T A + D^T D)x = A^T b
+//
+// as required for solving for x in the least squares sense. Currently only
+// block diagonal preconditioning is supported.
+class CgnrSolver : public LinearSolver {
+ public:
+  explicit CgnrSolver(const LinearSolver::Options& options);
+  virtual Summary Solve(LinearOperator* A,
+                        const double* b,
+                        const LinearSolver::PerSolveOptions& per_solve_options,
+                        double* x);
+
+ private:
+  const LinearSolver::Options options_;
+  scoped_ptr<BlockDiagonalPreconditioner> jacobi_preconditioner_;
+  DISALLOW_COPY_AND_ASSIGN(CgnrSolver);
+};
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_INTERNAL_CGNR_SOLVER_H_
diff --git a/internal/ceres/evaluator.cc b/internal/ceres/evaluator.cc
index 38c3fdb..7ceb7ac 100644
--- a/internal/ceres/evaluator.cc
+++ b/internal/ceres/evaluator.cc
@@ -53,6 +53,7 @@
     case DENSE_SCHUR:
     case SPARSE_SCHUR:
     case ITERATIVE_SCHUR:
+    case CONJUGATE_GRADIENTS:
       return new ProgramEvaluator<BlockEvaluatePreparer,
                                   BlockJacobianWriter>(options,
                                                        program);
@@ -60,11 +61,6 @@
       return new ProgramEvaluator<ScratchEvaluatePreparer,
                                   CompressedRowJacobianWriter>(options,
                                                                program);
-    case CONJUGATE_GRADIENTS:
-      *error = "CONJUGATE_GRADIENTS is not supported as a linear "
-          "solver. If you want to use an iterative linear solver, "
-          "use ITERATIVE_SCHUR instead.";
-      return NULL;
     default:
       *error = "Invalid Linear Solver Type. Unable to create evaluator.";
       return NULL;
diff --git a/internal/ceres/iterative_schur_complement_solver.cc b/internal/ceres/iterative_schur_complement_solver.cc
index 48d8453..4379ebd 100644
--- a/internal/ceres/iterative_schur_complement_solver.cc
+++ b/internal/ceres/iterative_schur_complement_solver.cc
@@ -38,13 +38,14 @@
 #include "Eigen/Dense"
 #include "ceres/block_sparse_matrix.h"
 #include "ceres/block_structure.h"
+#include "ceres/conjugate_gradients_solver.h"
 #include "ceres/implicit_schur_complement.h"
-#include "ceres/linear_solver.h"
-#include "ceres/triplet_sparse_matrix.h"
-#include "ceres/visibility_based_preconditioner.h"
 #include "ceres/internal/eigen.h"
 #include "ceres/internal/scoped_ptr.h"
+#include "ceres/linear_solver.h"
+#include "ceres/triplet_sparse_matrix.h"
 #include "ceres/types.h"
+#include "ceres/visibility_based_preconditioner.h"
 
 namespace ceres {
 namespace internal {
@@ -85,7 +86,7 @@
   LinearSolver::Options cg_options;
   cg_options.type = CONJUGATE_GRADIENTS;
   cg_options.max_num_iterations = options_.max_num_iterations;
-  scoped_ptr<LinearSolver> cg_solver(LinearSolver::Create(cg_options));
+  ConjugateGradientsSolver cg_solver(cg_options);
   LinearSolver::PerSolveOptions cg_per_solve_options;
 
   cg_per_solve_options.r_tolerance = per_solve_options.r_tolerance;
@@ -129,10 +130,10 @@
   cg_summary.termination_type = FAILURE;
 
   if (is_preconditioner_good) {
-    cg_summary = cg_solver->Solve(schur_complement_.get(),
-                                  schur_complement_->rhs().data(),
-                                  cg_per_solve_options,
-                                  reduced_linear_system_solution_.data());
+    cg_summary = cg_solver.Solve(schur_complement_.get(),
+                                 schur_complement_->rhs().data(),
+                                 cg_per_solve_options,
+                                 reduced_linear_system_solution_.data());
     if (cg_summary.termination_type != FAILURE) {
       schur_complement_->BackSubstitute(
           reduced_linear_system_solution_.data(), x);
diff --git a/internal/ceres/linear_solver.cc b/internal/ceres/linear_solver.cc
index e3912eb..fd40252 100644
--- a/internal/ceres/linear_solver.cc
+++ b/internal/ceres/linear_solver.cc
@@ -31,7 +31,7 @@
 #include "ceres/linear_solver.h"
 
 #include <glog/logging.h>
-#include "ceres/conjugate_gradients_solver.h"
+#include "ceres/cgnr_solver.h"
 #include "ceres/dense_qr_solver.h"
 #include "ceres/iterative_schur_complement_solver.h"
 #include "ceres/schur_complement_solver.h"
@@ -47,7 +47,7 @@
 LinearSolver* LinearSolver::Create(const LinearSolver::Options& options) {
   switch (options.type) {
     case CONJUGATE_GRADIENTS:
-      return new ConjugateGradientsSolver(options);
+      return new CgnrSolver(options);
 
     case SPARSE_NORMAL_CHOLESKY:
 #ifndef CERES_NO_SUITESPARSE
diff --git a/internal/ceres/linear_solver.h b/internal/ceres/linear_solver.h
index d287813..5860ecc 100644
--- a/internal/ceres/linear_solver.h
+++ b/internal/ceres/linear_solver.h
@@ -154,7 +154,7 @@
     // In either case, x is the vector that solves the following
     // optimization problem.
     //
-    //   arg min_x ||Ax -b||^2 + ||Dx||^2
+    //   arg min_x ||Ax - b||^2 + ||Dx||^2
     //
     // Here A is a matrix of size m x n, with full column rank. If A
     // does not have full column rank, the results returned by the
diff --git a/internal/ceres/solver.cc b/internal/ceres/solver.cc
index c54668e..c45c55f 100644
--- a/internal/ceres/solver.cc
+++ b/internal/ceres/solver.cc
@@ -155,7 +155,8 @@
                           LinearSolverTypeToString(linear_solver_type_given),
                           LinearSolverTypeToString(linear_solver_type_used));
 
-  if (linear_solver_type_given == ITERATIVE_SCHUR) {
+  if (linear_solver_type_given == CONJUGATE_GRADIENTS ||
+      linear_solver_type_given == ITERATIVE_SCHUR) {
     internal::StringAppendF(&report, "Preconditioner      %25s%25s\n",
                             PreconditionerTypeToString(preconditioner_type),
                             PreconditionerTypeToString(preconditioner_type));
diff --git a/internal/ceres/solver_impl.cc b/internal/ceres/solver_impl.cc
index ff2f5ea..ed07d9d 100644
--- a/internal/ceres/solver_impl.cc
+++ b/internal/ceres/solver_impl.cc
@@ -431,12 +431,6 @@
 
 LinearSolver* SolverImpl::CreateLinearSolver(Solver::Options* options,
                                              string* error) {
-  if (options->linear_solver_type ==  CONJUGATE_GRADIENTS) {
-    *error = "CONJUGATE_GRADIENTS is not a valid solver for "
-        "linear least squares problems.";
-    return NULL;
-  }
-
 #ifdef CERES_NO_SUITESPARSE
   if (options->linear_solver_type == SPARSE_NORMAL_CHOLESKY) {
     *error = "Can't use SPARSE_NORMAL_CHOLESKY because SuiteSparse was not "