Add the first unit test for Block-Jacobi Preconditioner
							parent
							
								
									85d6456a69
								
							
						
					
					
						commit
						7bbd0513f4
					
				|  | @ -0,0 +1,115 @@ | |||
| /* ----------------------------------------------------------------------------
 | ||||
| 
 | ||||
|  * GTSAM Copyright 2010, Georgia Tech Research Corporation, | ||||
|  * Atlanta, Georgia 30332-0415 | ||||
|  * All Rights Reserved | ||||
|  * Authors: Frank Dellaert, et al. (see THANKS for the full author list) | ||||
| 
 | ||||
|  * See LICENSE for the license information | ||||
| 
 | ||||
|  * -------------------------------------------------------------------------- */ | ||||
| 
 | ||||
| /**
 | ||||
|  *  @file   testPreconditioner.cpp | ||||
|  *  @brief  Unit tests for Preconditioners | ||||
|  *  @author Sungtae An | ||||
|  *  @date   Nov 6, 2014 | ||||
|  **/ | ||||
| 
 | ||||
| #include <CppUnitLite/TestHarness.h> | ||||
| 
 | ||||
| #include <gtsam/linear/GaussianFactorGraph.h> | ||||
| #include <gtsam/linear/Preconditioner.h> | ||||
| #include <gtsam/nonlinear/Values.h> | ||||
| #include <gtsam/geometry/Point2.h> | ||||
| #include <gtsam/linear/PCGSolver.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace gtsam; | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| static GaussianFactorGraph createSimpleGaussianFactorGraph() { | ||||
|   GaussianFactorGraph fg; | ||||
|   SharedDiagonal unit2 = noiseModel::Unit::Create(2); | ||||
|   // linearized prior on x1: c[_x1_]+x1=0 i.e. x1=-c[_x1_]
 | ||||
|   fg += JacobianFactor(2, 10*eye(2), -1.0*ones(2), unit2); | ||||
|   // odometry between x1 and x2: x2-x1=[0.2;-0.1]
 | ||||
|   fg += JacobianFactor(2, -10*eye(2), 0, 10*eye(2), (Vector(2) << 2.0, -1.0), unit2); | ||||
|   // measurement between x1 and l1: l1-x1=[0.0;0.2]
 | ||||
|   fg += JacobianFactor(2, -5*eye(2), 1, 5*eye(2), (Vector(2) << 0.0, 1.0), unit2); | ||||
|   // measurement between x2 and l1: l1-x2=[-0.2;0.3]
 | ||||
|   fg += JacobianFactor(0, -5*eye(2), 1, 5*eye(2), (Vector(2) << -1.0, 1.5), unit2); | ||||
|   return fg; | ||||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| // Copy of BlockJacobiPreconditioner::build
 | ||||
| std::vector<Matrix> buildBlocks( const GaussianFactorGraph &gfg, const KeyInfo &keyInfo) | ||||
| { | ||||
|   const size_t n = keyInfo.size(); | ||||
|   std::vector<size_t> dims_ = keyInfo.colSpec(); | ||||
| 
 | ||||
|   /* prepare the buffer of block diagonals */ | ||||
|   std::vector<Matrix> blocks; blocks.reserve(n); | ||||
| 
 | ||||
|   /* allocate memory for the factorization of block diagonals */ | ||||
|   size_t nnz = 0; | ||||
|   for ( size_t i = 0 ; i < n ; ++i ) { | ||||
|     const size_t dim = dims_[i]; | ||||
|     blocks.push_back(Matrix::Zero(dim, dim)); | ||||
|     // nnz += (((dim)*(dim+1)) >> 1); // d*(d+1) / 2  ;
 | ||||
|     nnz += dim*dim; | ||||
|   } | ||||
| 
 | ||||
|   /* compute the block diagonal by scanning over the factors */ | ||||
|   BOOST_FOREACH ( const GaussianFactor::shared_ptr &gf, gfg ) { | ||||
|     if ( JacobianFactor::shared_ptr jf = boost::dynamic_pointer_cast<JacobianFactor>(gf) ) { | ||||
|       for ( JacobianFactor::const_iterator it = jf->begin() ; it != jf->end() ; ++it ) { | ||||
|         const KeyInfoEntry &entry =  keyInfo.find(*it)->second; | ||||
|         const Matrix &Ai = jf->getA(it); | ||||
|         blocks[entry.index()] += (Ai.transpose() * Ai); | ||||
|       } | ||||
|     } | ||||
|     else if ( HessianFactor::shared_ptr hf = boost::dynamic_pointer_cast<HessianFactor>(gf) ) { | ||||
|       for ( HessianFactor::const_iterator it = hf->begin() ; it != hf->end() ; ++it ) { | ||||
|         const KeyInfoEntry &entry =  keyInfo.find(*it)->second; | ||||
|         const Matrix &Hii = hf->info(it, it).selfadjointView(); | ||||
|         blocks[entry.index()] += Hii; | ||||
|       } | ||||
|     } | ||||
|     else { | ||||
|       throw invalid_argument("BlockJacobiPreconditioner::build gfg contains a factor that is neither a JacobianFactor nor a HessianFactor."); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return blocks; | ||||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| TEST( Preconditioner, buildBlocks ) { | ||||
|   // Create simple Gaussian factor graph and initial values
 | ||||
|   GaussianFactorGraph gfg = createSimpleGaussianFactorGraph(); | ||||
|   Values initial; | ||||
|   initial.insert(0,Point2(4, 5)); | ||||
|   initial.insert(1,Point2(0,  1)); | ||||
|   initial.insert(2,Point2(-5, 7)); | ||||
| 
 | ||||
|   // Expected Hessian block diagonal matrices
 | ||||
|   std::map<Key, Matrix> expectedHessian =gfg.hessianBlockDiagonal(); | ||||
| 
 | ||||
|   // Actual Hessian block diagonal matrices from BlockJacobiPreconditioner::build
 | ||||
|   std::vector<Matrix> actualHessian = buildBlocks(gfg, KeyInfo(gfg)); | ||||
| 
 | ||||
|   // Compare the number of block diagonal matrices
 | ||||
|   EXPECT_LONGS_EQUAL(expectedHessian.size(), actualHessian.size()); | ||||
| 
 | ||||
|   // Compare the values of matrices
 | ||||
|   std::map<Key, Matrix>::const_iterator it1 = expectedHessian.begin(); | ||||
|   std::vector<Matrix>::const_iterator it2 = actualHessian.begin(); | ||||
|   for(; it1!=expectedHessian.end(); it1++, it2++) | ||||
|     EXPECT(assert_equal(it1->second, *it2)); | ||||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| int main() { TestResult tr; return TestRegistry::runAllTests(tr); } | ||||
| /* ************************************************************************* */ | ||||
		Loading…
	
		Reference in New Issue