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/unsymmetric_linear_solver_test.cc b/internal/ceres/unsymmetric_linear_solver_test.cc
index be91056..a7ee23e 100644
--- a/internal/ceres/unsymmetric_linear_solver_test.cc
+++ b/internal/ceres/unsymmetric_linear_solver_test.cc
@@ -52,109 +52,82 @@
     A_.reset(down_cast<TripletSparseMatrix*>(problem->A.release()));
     b_.reset(problem->b.release());
     D_.reset(problem->D.release());
-    sol1_.reset(problem->x.release());
-    sol2_.reset(problem->x_D.release());
-    x_.reset(new double[A_->num_cols()]);
+    sol_unregularized_.reset(problem->x.release());
+    sol_regularized_.reset(problem->x_D.release());
   }
 
-  void TestSolver(LinearSolverType linear_solver_type) {
+  void TestSolver(
+      LinearSolverType linear_solver_type,
+      SparseLinearAlgebraLibraryType sparse_linear_algebra_library) {
     LinearSolver::Options options;
     options.type = linear_solver_type;
+    options.sparse_linear_algebra_library = sparse_linear_algebra_library;
     scoped_ptr<LinearSolver> solver(LinearSolver::Create(options));
 
     LinearSolver::PerSolveOptions per_solve_options;
+    LinearSolver::Summary unregularized_solve_summary;
+    LinearSolver::Summary regularized_solve_summary;
+    Vector x_unregularized(A_->num_cols());
+    Vector x_regularized(A_->num_cols());
 
-    // Unregularized
-    LinearSolver::Summary summary =
-        solver->Solve(A_.get(), b_.get(), per_solve_options, x_.get());
+    scoped_ptr<SparseMatrix> transformed_A;
 
-    EXPECT_EQ(summary.termination_type, TOLERANCE);
-
-    for (int i = 0; i < A_->num_cols(); ++i) {
-      EXPECT_NEAR(sol1_[i], x_[i], 1e-8);
+    if (linear_solver_type == DENSE_QR) {
+      transformed_A.reset(new DenseSparseMatrix(*A_));
+    } else if (linear_solver_type == SPARSE_NORMAL_CHOLESKY) {
+      transformed_A.reset(new   CompressedRowSparseMatrix(*A_));
+    } else {
+      LOG(FATAL) << "Unknown linear solver : " << linear_solver_type;
     }
+    // Unregularized
+    unregularized_solve_summary =
+        solver->Solve(transformed_A.get(),
+                      b_.get(),
+                      per_solve_options,
+                      x_unregularized.data());
 
     // Regularized solution
     per_solve_options.D = D_.get();
-    summary = solver->Solve(A_.get(), b_.get(), per_solve_options, x_.get());
+    regularized_solve_summary =
+        solver->Solve(transformed_A.get(),
+                      b_.get(),
+                      per_solve_options,
+                      x_regularized.data());
 
-    EXPECT_EQ(summary.termination_type, TOLERANCE);
+    EXPECT_EQ(unregularized_solve_summary.termination_type, TOLERANCE);
 
     for (int i = 0; i < A_->num_cols(); ++i) {
-      EXPECT_NEAR(sol2_[i], x_[i], 1e-8);
+      EXPECT_NEAR(sol_unregularized_[i], x_unregularized[i], 1e-8);
+    }
+
+    EXPECT_EQ(regularized_solve_summary.termination_type, TOLERANCE);
+    for (int i = 0; i < A_->num_cols(); ++i) {
+      EXPECT_NEAR(sol_regularized_[i], x_regularized[i], 1e-8);
     }
   }
 
   scoped_ptr<TripletSparseMatrix> A_;
   scoped_array<double> b_;
   scoped_array<double> D_;
-  scoped_array<double> sol1_;
-  scoped_array<double> sol2_;
-
-  scoped_array<double> x_;
+  scoped_array<double> sol_unregularized_;
+  scoped_array<double> sol_regularized_;
 };
 
-// TODO(keir): Reduce duplication.
 TEST_F(UnsymmetricLinearSolverTest, DenseQR) {
-  LinearSolver::Options options;
-  options.type = DENSE_QR;
-  scoped_ptr<LinearSolver> solver(LinearSolver::Create(options));
-
-  LinearSolver::PerSolveOptions per_solve_options;
-  DenseSparseMatrix A(*A_);
-
-  // Unregularized
-  LinearSolver::Summary summary =
-      solver->Solve(&A, b_.get(), per_solve_options, x_.get());
-
-  EXPECT_EQ(summary.termination_type, TOLERANCE);
-  for (int i = 0; i < A_->num_cols(); ++i) {
-    EXPECT_NEAR(sol1_[i], x_[i], 1e-8);
-  }
-
-  VectorRef x(x_.get(), A_->num_cols());
-  VectorRef b(b_.get(), A_->num_rows());
-  Vector r = A.matrix()*x - b;
-  LOG(INFO) << "r = A*x - b: \n" << r;
-
-  // Regularized solution
-  per_solve_options.D = D_.get();
-  summary = solver->Solve(&A, b_.get(), per_solve_options, x_.get());
-
-  EXPECT_EQ(summary.termination_type, TOLERANCE);
-  for (int i = 0; i < A_->num_cols(); ++i) {
-    EXPECT_NEAR(sol2_[i], x_[i], 1e-8);
-  }
+  TestSolver(DENSE_QR, SUITE_SPARSE);
 }
 
 #ifndef CERES_NO_SUITESPARSE
-TEST_F(UnsymmetricLinearSolverTest, SparseNormalCholesky) {
-  LinearSolver::Options options;
-  options.type = SPARSE_NORMAL_CHOLESKY;
-  scoped_ptr<LinearSolver>solver(LinearSolver::Create(options));
-
-  LinearSolver::PerSolveOptions per_solve_options;
-  CompressedRowSparseMatrix A(*A_);
-
-  // Unregularized
-  LinearSolver::Summary summary =
-      solver->Solve(&A, b_.get(), per_solve_options, x_.get());
-
-  EXPECT_EQ(summary.termination_type, TOLERANCE);
-  for (int i = 0; i < A_->num_cols(); ++i) {
-    EXPECT_NEAR(sol1_[i], x_[i], 1e-8);
-  }
-
-  // Regularized solution
-  per_solve_options.D = D_.get();
-  summary = solver->Solve(&A, b_.get(), per_solve_options, x_.get());
-
-  EXPECT_EQ(summary.termination_type, TOLERANCE);
-  for (int i = 0; i < A_->num_cols(); ++i) {
-    EXPECT_NEAR(sol2_[i], x_[i], 1e-8);
-  }
+TEST_F(UnsymmetricLinearSolverTest, SparseNormalCholeskyUsingSuiteSparse) {
+  TestSolver(SPARSE_NORMAL_CHOLESKY, SUITE_SPARSE);
 }
-#endif  // CERES_NO_SUITESPARSE
+#endif
+
+#ifndef CERES_NO_CXSPARSE
+TEST_F(UnsymmetricLinearSolverTest, SparseNormalCholeskyUsingCXSparse) {
+  TestSolver(SPARSE_NORMAL_CHOLESKY, CX_SPARSE);
+}
+#endif
 
 }  // namespace internal
 }  // namespace ceres