| 
					
				 | 
			
			
				@@ -28,8 +28,8 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // Author: sameeragarwal@google.com (Sameer Agarwal) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "ceres/block_sparse_matrix.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "ceres/casts.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-#include "ceres/compressed_row_sparse_matrix.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "ceres/internal/scoped_ptr.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "ceres/linear_least_squares_problems.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "ceres/linear_solver.h" 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -38,12 +38,14 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "glog/logging.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "gtest/gtest.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "Eigen/Cholesky" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 namespace ceres { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 namespace internal { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // TODO(sameeragarwal): These tests needs to be re-written, since 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // SparseNormalCholeskySolver is a composition of two classes now, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-// OuterProduct and SparseCholesky. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// InnerProductComputer and SparseCholesky. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // So the test should exercise the composition, rather than the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // numerics of the solver, which are well covered by tests for those 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -52,88 +54,55 @@ class SparseNormalCholeskyLinearSolverTest : public ::testing::Test { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  protected: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   virtual void SetUp() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     scoped_ptr<LinearLeastSquaresProblem> problem( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        CreateLinearLeastSquaresProblemFromId(0)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        CreateLinearLeastSquaresProblemFromId(2)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     CHECK_NOTNULL(problem.get()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    A_.reset(down_cast<TripletSparseMatrix*>(problem->A.release())); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    A_.reset(down_cast<BlockSparseMatrix*>(problem->A.release())); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     b_.reset(problem->b.release()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     D_.reset(problem->D.release()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    sol_unregularized_.reset(problem->x.release()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    sol_regularized_.reset(problem->x_D.release()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  void TestSolver(const LinearSolver::Options& 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()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    scoped_ptr<SparseMatrix> transformed_A; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    CompressedRowSparseMatrix* crsm = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        CompressedRowSparseMatrix::FromTripletSparseMatrix(*A_); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // Add row/column blocks structure. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    for (int i = 0; i < A_->num_rows(); ++i) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      crsm->mutable_row_blocks()->push_back(1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  void TestSolver(const LinearSolver::Options& options, double* D) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Matrix dense_A; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    A_->ToDenseMatrix(&dense_A); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Matrix lhs = dense_A.transpose() * dense_A; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (D != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      lhs += (ConstVectorRef(D, A_->num_cols()).array() * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              ConstVectorRef(D, A_->num_cols()).array()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                 .matrix() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                 .asDiagonal(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    for (int i = 0; i < A_->num_cols(); ++i) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      crsm->mutable_col_blocks()->push_back(1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Vector rhs(A_->num_cols()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    rhs.setZero(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    A_->LeftMultiply(b_.get(), rhs.data()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Vector expected_solution = lhs.llt().solve(rhs); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // With all blocks of size 1, crsb_rows and crsb_cols are equivalent to 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // rows and cols. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    std::copy(crsm->rows(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              crsm->rows() + crsm->num_rows() + 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              std::back_inserter(*crsm->mutable_crsb_rows())); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    std::copy(crsm->cols(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              crsm->cols() + crsm->num_nonzeros(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              std::back_inserter(*crsm->mutable_crsb_cols())); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    transformed_A.reset(crsm); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // Unregularized 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     scoped_ptr<LinearSolver> solver(LinearSolver::Create(options)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    unregularized_solve_summary = solver->Solve(transformed_A.get(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                                b_.get(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                                per_solve_options, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                                x_unregularized.data()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // Sparsity structure is changing, reset the solver. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    solver.reset(LinearSolver::Create(options)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // Regularized solution 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    per_solve_options.D = D_.get(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    regularized_solve_summary = solver->Solve( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        transformed_A.get(), b_.get(), per_solve_options, x_regularized.data()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    LinearSolver::PerSolveOptions per_solve_options; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    per_solve_options.D = D; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Vector actual_solution(A_->num_cols()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    LinearSolver::Summary summary; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    summary = solver->Solve( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        A_.get(), b_.get(), per_solve_options, actual_solution.data()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    EXPECT_EQ(unregularized_solve_summary.termination_type, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              LINEAR_SOLVER_SUCCESS); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    EXPECT_EQ(summary.termination_type, LINEAR_SOLVER_SUCCESS); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     for (int i = 0; i < A_->num_cols(); ++i) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      EXPECT_NEAR(sol_unregularized_[i], x_unregularized[i], 1e-8) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          << "\nExpected: " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          << ConstVectorRef(sol_unregularized_.get(), A_->num_cols()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                 .transpose() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          << "\nActual: " << x_unregularized.transpose(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      EXPECT_NEAR(expected_solution(i), actual_solution(i), 1e-8) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          << "\nExpected: " << expected_solution.transpose() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          << "\nActual: " << actual_solution.transpose(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    EXPECT_EQ(regularized_solve_summary.termination_type, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              LINEAR_SOLVER_SUCCESS); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    for (int i = 0; i < A_->num_cols(); ++i) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      EXPECT_NEAR(sol_regularized_[i], x_regularized[i], 1e-8) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          << "\nExpected: " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          << ConstVectorRef(sol_regularized_.get(), A_->num_cols()).transpose() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          << "\nActual: " << x_regularized.transpose(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  void TestSolver(const LinearSolver::Options& options) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    TestSolver(options, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    TestSolver(options, D_.get()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  scoped_ptr<TripletSparseMatrix> A_; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  scoped_ptr<BlockSparseMatrix> A_; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   scoped_array<double> b_; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   scoped_array<double> D_; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  scoped_array<double> sol_unregularized_; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  scoped_array<double> sol_regularized_; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #ifndef CERES_NO_SUITESPARSE 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -154,15 +123,6 @@ TEST_F(SparseNormalCholeskyLinearSolverTest, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   options.use_postordering = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   TestSolver(options); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-TEST_F(SparseNormalCholeskyLinearSolverTest, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-       SparseNormalCholeskyUsingSuiteSparseDynamicSparsity) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  LinearSolver::Options options; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  options.sparse_linear_algebra_library_type = SUITE_SPARSE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  options.type = SPARSE_NORMAL_CHOLESKY; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  options.dynamic_sparsity = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  TestSolver(options); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #ifndef CERES_NO_CXSPARSE 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -183,15 +143,6 @@ TEST_F(SparseNormalCholeskyLinearSolverTest, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   options.use_postordering = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   TestSolver(options); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-TEST_F(SparseNormalCholeskyLinearSolverTest, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-       SparseNormalCholeskyUsingCXSparseDynamicSparsity) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  LinearSolver::Options options; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  options.sparse_linear_algebra_library_type = CX_SPARSE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  options.type = SPARSE_NORMAL_CHOLESKY; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  options.dynamic_sparsity = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  TestSolver(options); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #ifdef CERES_USE_EIGEN_SPARSE 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -212,15 +163,6 @@ TEST_F(SparseNormalCholeskyLinearSolverTest, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   options.use_postordering = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   TestSolver(options); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-TEST_F(SparseNormalCholeskyLinearSolverTest, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-       SparseNormalCholeskyUsingEigenDynamicSparsity) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  LinearSolver::Options options; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  options.sparse_linear_algebra_library_type = EIGEN_SPARSE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  options.type = SPARSE_NORMAL_CHOLESKY; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  options.dynamic_sparsity = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  TestSolver(options); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #endif  // CERES_USE_EIGEN_SPARSE 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 }  // namespace internal 
			 |