Add a templated TypedPreconditioner class.

This sets the stage of preconditioners that can utilize
different kinds of matrix layouts, just like the LinearSolver
class hierarchy.

Change-Id: I3579cf344bcd2eeeecb1ae621cab02a3c9a0f920
diff --git a/internal/ceres/block_jacobi_preconditioner.cc b/internal/ceres/block_jacobi_preconditioner.cc
index 5525d4c..749e0b6 100644
--- a/internal/ceres/block_jacobi_preconditioner.cc
+++ b/internal/ceres/block_jacobi_preconditioner.cc
@@ -66,8 +66,8 @@
 
 BlockJacobiPreconditioner::~BlockJacobiPreconditioner() {}
 
-bool BlockJacobiPreconditioner::Update(const BlockSparseMatrix& A,
-                                       const double* D) {
+bool BlockJacobiPreconditioner::UpdateImpl(const BlockSparseMatrix& A,
+                                           const double* D) {
   const CompressedRowBlockStructure* bs = A.block_structure();
 
   // Compute the diagonal blocks by block inner products.
diff --git a/internal/ceres/block_jacobi_preconditioner.h b/internal/ceres/block_jacobi_preconditioner.h
index dc291bf..3505a01 100644
--- a/internal/ceres/block_jacobi_preconditioner.h
+++ b/internal/ceres/block_jacobi_preconditioner.h
@@ -51,20 +51,21 @@
 // update the matrix by running Update(A, D). The values of the matrix A are
 // inspected to construct the preconditioner. The vector D is applied as the
 // D^TD diagonal term.
-class BlockJacobiPreconditioner : public Preconditioner {
+class BlockJacobiPreconditioner : public BlockSparseMatrixPreconditioner {
  public:
   // A must remain valid while the BlockJacobiPreconditioner is.
   explicit BlockJacobiPreconditioner(const BlockSparseMatrix& A);
   virtual ~BlockJacobiPreconditioner();
 
   // Preconditioner interface
-  virtual bool Update(const BlockSparseMatrix& A, const double* D);
   virtual void RightMultiply(const double* x, double* y) const;
   virtual void LeftMultiply(const double* x, double* y) const;
   virtual int num_rows() const { return num_rows_; }
   virtual int num_cols() const { return num_rows_; }
 
  private:
+  virtual bool UpdateImpl(const BlockSparseMatrix& A, const double* D);
+
   std::vector<double*> blocks_;
   std::vector<double> block_storage_;
   int num_rows_;
diff --git a/internal/ceres/preconditioner.cc b/internal/ceres/preconditioner.cc
index 19e58fc..505a47d 100644
--- a/internal/ceres/preconditioner.cc
+++ b/internal/ceres/preconditioner.cc
@@ -45,8 +45,8 @@
 SparseMatrixPreconditionerWrapper::~SparseMatrixPreconditionerWrapper() {
 }
 
-bool SparseMatrixPreconditionerWrapper::Update(const BlockSparseMatrix& A,
-                                               const double* D) {
+bool SparseMatrixPreconditionerWrapper::UpdateImpl(const SparseMatrix& A,
+                                                   const double* D) {
   return true;
 }
 
diff --git a/internal/ceres/preconditioner.h b/internal/ceres/preconditioner.h
index 7206536..cb0a381 100644
--- a/internal/ceres/preconditioner.h
+++ b/internal/ceres/preconditioner.h
@@ -32,6 +32,8 @@
 #define CERES_INTERNAL_PRECONDITIONER_H_
 
 #include <vector>
+#include "ceres/casts.h"
+#include "ceres/compressed_row_sparse_matrix.h"
 #include "ceres/linear_operator.h"
 #include "ceres/sparse_matrix.h"
 
@@ -105,7 +107,7 @@
   //
   // D can be NULL, in which case its interpreted as a diagonal matrix
   // of size zero.
-  virtual bool Update(const BlockSparseMatrix& A, const double* D) = 0;
+  virtual bool Update(const LinearOperator& A, const double* D) = 0;
 
   // LinearOperator interface. Since the operator is symmetric,
   // LeftMultiply and num_cols are just calls to RightMultiply and
@@ -122,19 +124,40 @@
   }
 };
 
+// This templated subclass of Preconditioner serves as a base class for
+// other preconditioners that depend on the particular matrix layout of
+// the underlying linear operator.
+template <typename MatrixType>
+class TypedPreconditioner : public Preconditioner {
+ public:
+  virtual ~TypedPreconditioner() {}
+  virtual bool Update(const LinearOperator& A, const double* D) {
+    return UpdateImpl(*down_cast<const MatrixType*>(&A), D);
+  }
+
+ private:
+  virtual bool UpdateImpl(const MatrixType& A, const double* D) = 0;
+};
+
+// Preconditioners that depend on acccess to the low level structure
+// of a SparseMatrix.
+typedef TypedPreconditioner<SparseMatrix>              SparseMatrixPreconditioner;               // NOLINT
+typedef TypedPreconditioner<BlockSparseMatrix>         BlockSparseMatrixPreconditioner;          // NOLINT
+typedef TypedPreconditioner<CompressedRowSparseMatrix> CompressedRowSparseMatrixPreconditioner;  // NOLINT
+
 // Wrap a SparseMatrix object as a preconditioner.
-class SparseMatrixPreconditionerWrapper : public Preconditioner {
+class SparseMatrixPreconditionerWrapper : public SparseMatrixPreconditioner {
  public:
   // Wrapper does NOT take ownership of the matrix pointer.
   explicit SparseMatrixPreconditionerWrapper(const SparseMatrix* matrix);
   virtual ~SparseMatrixPreconditionerWrapper();
 
   // Preconditioner interface
-  virtual bool Update(const BlockSparseMatrix& A, const double* D);
   virtual void RightMultiply(const double* x, double* y) const;
   virtual int num_rows() const;
 
  private:
+  virtual bool UpdateImpl(const SparseMatrix& A, const double* D);
   const SparseMatrix* matrix_;
 };
 
diff --git a/internal/ceres/schur_jacobi_preconditioner.cc b/internal/ceres/schur_jacobi_preconditioner.cc
index 780795b..aa840c5 100644
--- a/internal/ceres/schur_jacobi_preconditioner.cc
+++ b/internal/ceres/schur_jacobi_preconditioner.cc
@@ -91,8 +91,8 @@
 }
 
 // Update the values of the preconditioner matrix and factorize it.
-bool SchurJacobiPreconditioner::Update(const BlockSparseMatrix& A,
-                                       const double* D) {
+bool SchurJacobiPreconditioner::UpdateImpl(const BlockSparseMatrix& A,
+                                           const double* D) {
   const int num_rows = m_->num_rows();
   CHECK_GT(num_rows, 0);
 
diff --git a/internal/ceres/schur_jacobi_preconditioner.h b/internal/ceres/schur_jacobi_preconditioner.h
index b80a249..f6e7b0d 100644
--- a/internal/ceres/schur_jacobi_preconditioner.h
+++ b/internal/ceres/schur_jacobi_preconditioner.h
@@ -73,7 +73,7 @@
 //   preconditioner.Update(A, NULL);
 //   preconditioner.RightMultiply(x, y);
 //
-class SchurJacobiPreconditioner : public Preconditioner {
+class SchurJacobiPreconditioner : public BlockSparseMatrixPreconditioner {
  public:
   // Initialize the symbolic structure of the preconditioner. bs is
   // the block structure of the linear system to be solved. It is used
@@ -86,12 +86,12 @@
   virtual ~SchurJacobiPreconditioner();
 
   // Preconditioner interface.
-  virtual bool Update(const BlockSparseMatrix& A, const double* D);
   virtual void RightMultiply(const double* x, double* y) const;
   virtual int num_rows() const;
 
  private:
   void InitEliminator(const CompressedRowBlockStructure& bs);
+  virtual bool UpdateImpl(const BlockSparseMatrix& A, const double* D);
 
   Preconditioner::Options options_;
 
diff --git a/internal/ceres/visibility_based_preconditioner.cc b/internal/ceres/visibility_based_preconditioner.cc
index 94266e5..7af1339 100644
--- a/internal/ceres/visibility_based_preconditioner.cc
+++ b/internal/ceres/visibility_based_preconditioner.cc
@@ -324,8 +324,8 @@
 }
 
 // Update the values of the preconditioner matrix and factorize it.
-bool VisibilityBasedPreconditioner::Update(const BlockSparseMatrix& A,
-                                           const double* D) {
+bool VisibilityBasedPreconditioner::UpdateImpl(const BlockSparseMatrix& A,
+                                               const double* D) {
   const time_t start_time = time(NULL);
   const int num_rows = m_->num_rows();
   CHECK_GT(num_rows, 0);
diff --git a/internal/ceres/visibility_based_preconditioner.h b/internal/ceres/visibility_based_preconditioner.h
index 54a03e6..c58b1a7 100644
--- a/internal/ceres/visibility_based_preconditioner.h
+++ b/internal/ceres/visibility_based_preconditioner.h
@@ -123,7 +123,7 @@
 //   preconditioner.RightMultiply(x, y);
 //
 #ifndef CERES_NO_SUITESPARSE
-class VisibilityBasedPreconditioner : public Preconditioner {
+class VisibilityBasedPreconditioner : public BlockSparseMatrixPreconditioner {
  public:
   // Initialize the symbolic structure of the preconditioner. bs is
   // the block structure of the linear system to be solved. It is used
@@ -136,12 +136,13 @@
   virtual ~VisibilityBasedPreconditioner();
 
   // Preconditioner interface
-  virtual bool Update(const BlockSparseMatrix& A, const double* D);
   virtual void RightMultiply(const double* x, double* y) const;
   virtual int num_rows() const;
 
   friend class VisibilityBasedPreconditionerTest;
+
  private:
+  virtual bool UpdateImpl(const BlockSparseMatrix& A, const double* D);
   void ComputeClusterJacobiSparsity(const CompressedRowBlockStructure& bs);
   void ComputeClusterTridiagonalSparsity(const CompressedRowBlockStructure& bs);
   void InitStorage(const CompressedRowBlockStructure& bs);
@@ -203,7 +204,7 @@
 #else  // SuiteSparse
 // If SuiteSparse is not compiled in, the preconditioner is not
 // available.
-class VisibilityBasedPreconditioner : public Preconditioner {
+class VisibilityBasedPreconditioner : public BlockSparseMatrixPreconditioner {
  public:
   VisibilityBasedPreconditioner(const CompressedRowBlockStructure& bs,
                                 const Preconditioner::Options& options) {
@@ -215,7 +216,9 @@
   virtual void LeftMultiply(const double* x, double* y) const {}
   virtual int num_rows() const { return -1; }
   virtual int num_cols() const { return -1; }
-  bool Update(const BlockSparseMatrix& A, const double* D) {
+
+ private:
+  bool UpdateImpl(const BlockSparseMatrix& A, const double* D) {
     return false;
   }
 };