Multiple sparse linear algebra backends.

1. Added support for CXSparse - SparseNormalCholesky and
   SchurComplementSolver support SuiteSparse and CXSparse now.
   I am not sure I will add suport for visibility based
   preconditioning using CXSparse. Its not a high priority.

2. New enum SparseLinearAlgebraLibraryType which allows the user
   to indicate which sparse linear algebra library should be used.

3. Updated tests for SolverImpl and system_test.

4. Build system changes to automatically detect CXSparse and
   link to it by default -- just like SuiteSparse.

5. Minor bug fixes dealing in the cmake files and VBP.

6. Changed the order of the system test.

7. Deduped the unsymmetric linear solver test.

Change-Id: I33252a103c87b722ecb7ed7b5f0ae7fd91249244
diff --git a/internal/ceres/schur_complement_solver.cc b/internal/ceres/schur_complement_solver.cc
index 4db7c31..b30d6ed 100644
--- a/internal/ceres/schur_complement_solver.cc
+++ b/internal/ceres/schur_complement_solver.cc
@@ -32,6 +32,11 @@
 #include <ctime>
 #include <set>
 #include <vector>
+
+#ifndef CERES_NO_CXSPARSE
+#include "cs.h"
+#endif  // CERES_NO_CXSPARSE
+
 #include "Eigen/Dense"
 #include "ceres/block_random_access_dense_matrix.h"
 #include "ceres/block_random_access_matrix.h"
@@ -48,6 +53,7 @@
 #include "ceres/internal/scoped_ptr.h"
 #include "ceres/types.h"
 
+
 namespace ceres {
 namespace internal {
 
@@ -139,18 +145,22 @@
   return true;
 }
 
-#ifndef CERES_NO_SUITESPARSE
+
 SparseSchurComplementSolver::SparseSchurComplementSolver(
     const LinearSolver::Options& options)
-    : SchurComplementSolver(options),
-      symbolic_factor_(NULL) {
+    : SchurComplementSolver(options) {
+#ifndef CERES_NO_SUITESPARSE
+  symbolic_factor_ = NULL;
+#endif  // CERES_NO_SUITESPARSE
 }
 
 SparseSchurComplementSolver::~SparseSchurComplementSolver() {
+#ifndef CERES_NO_SUITESPARSE
   if (symbolic_factor_ != NULL) {
     ss_.Free(symbolic_factor_);
     symbolic_factor_ = NULL;
   }
+#endif  // CERES_NO_SUITESPARSE
 }
 
 // Determine the non-zero blocks in the Schur Complement matrix, and
@@ -224,10 +234,28 @@
   set_rhs(new double[lhs()->num_rows()]);
 }
 
+bool SparseSchurComplementSolver::SolveReducedLinearSystem(double* solution) {
+  switch (options().sparse_linear_algebra_library) {
+    case SUITE_SPARSE:
+      return SolveReducedLinearSystemUsingSuiteSparse(solution);
+    case CX_SPARSE:
+      return SolveReducedLinearSystemUsingCXSparse(solution);
+    default:
+      LOG(FATAL) << "Unknown sparse linear algebra library : "
+                 << options().sparse_linear_algebra_library;
+  }
+
+  LOG(FATAL) << "Unknown sparse linear algebra library : "
+             << options().sparse_linear_algebra_library;
+  return false;
+}
+
+#ifndef CERES_NO_SUITESPARSE
 // Solve the system Sx = r, assuming that the matrix S is stored in a
 // BlockRandomAccessSparseMatrix.  The linear system is solved using
 // CHOLMOD's sparse cholesky factorization routines.
-bool SparseSchurComplementSolver::SolveReducedLinearSystem(double* solution) {
+bool SparseSchurComplementSolver::SolveReducedLinearSystemUsingSuiteSparse(
+    double* solution) {
   // Extract the TripletSparseMatrix that is used for actually storing S.
   TripletSparseMatrix* tsm =
       const_cast<TripletSparseMatrix*>(
@@ -272,7 +300,58 @@
   ss_.Free(cholmod_solution);
   return true;
 }
+#else
+bool SparseSchurComplementSolver::SolveReducedLinearSystemUsingSuiteSparse(
+    double* solution) {
+  LOG(FATAL) << "No SuiteSparse support in Ceres.";
+  return false;
+}
 #endif  // CERES_NO_SUITESPARSE
 
+#ifndef CERES_NO_CXSPARSE
+// Solve the system Sx = r, assuming that the matrix S is stored in a
+// BlockRandomAccessSparseMatrix.  The linear system is solved using
+// CXSparse's sparse cholesky factorization routines.
+bool SparseSchurComplementSolver::SolveReducedLinearSystemUsingCXSparse(
+    double* solution) {
+  // Extract the TripletSparseMatrix that is used for actually storing S.
+  TripletSparseMatrix* tsm =
+      const_cast<TripletSparseMatrix*>(
+          down_cast<const BlockRandomAccessSparseMatrix*>(lhs())->matrix());
+
+  const int num_rows = tsm->num_rows();
+
+  // The case where there are no f blocks, and the system is block
+  // diagonal.
+  if (num_rows == 0) {
+    return true;
+  }
+
+  cs_di_sparse tsm_wrapper;
+  tsm_wrapper.nzmax = tsm->num_nonzeros();
+  tsm_wrapper.m = num_rows;
+  tsm_wrapper.n = num_rows;
+  tsm_wrapper.p = tsm->mutable_cols();
+  tsm_wrapper.i = tsm->mutable_rows();
+  tsm_wrapper.x = tsm->mutable_values();
+  tsm_wrapper.nz = tsm->num_nonzeros();
+
+  cs_di_sparse* lhs = cs_compress(&tsm_wrapper);
+  VectorRef(solution, num_rows) = ConstVectorRef(rhs(), num_rows);
+
+  // It maybe worth caching the ordering here, but for now we are
+  // going to go with the simple cholsol based implementation.
+  int ok = cs_di_cholsol(1, lhs, solution);
+  cs_free(lhs);
+  return ok;
+}
+#else
+bool SparseSchurComplementSolver::SolveReducedLinearSystemUsingCXSparse(
+    double* solution) {
+  LOG(FATAL) << "No CXSparse support in Ceres.";
+  return false;
+}
+#endif  // CERES_NO_CXPARSE
+
 }  // namespace internal
 }  // namespace ceres