2012-03-17 04:55:21 +08:00
/* ----------------------------------------------------------------------------
* 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 ISAM2 - inl . h
* @ brief Incremental update functionality ( ISAM2 ) for BayesTree , with fluid relinearization .
* @ author Michael Kaess , Richard Roberts
*/
2013-08-02 05:57:43 +08:00
#if 0
2012-03-17 04:55:21 +08:00
# include <boost/foreach.hpp>
# include <boost/assign/std/list.hpp> // for operator +=
using namespace boost : : assign ;
2012-03-25 00:52:55 +08:00
# include <boost/range/adaptors.hpp>
# include <boost/range/algorithm.hpp>
2012-07-20 03:50:00 +08:00
# include <boost/algorithm/string.hpp>
2012-03-17 04:55:21 +08:00
# include <gtsam/base/timing.h>
# include <gtsam/base/debug.h>
2013-08-06 06:31:33 +08:00
# include <gtsam/inference/BayesTree.h>
# include <gtsam/linear/GaussianJunctionTree.h>
# include <gtsam/linear/HessianFactor.h>
# include <gtsam/linear/GaussianFactorGraph.h>
2012-03-17 04:55:21 +08:00
# include <gtsam/nonlinear/ISAM2.h>
# include <gtsam/nonlinear/DoglegOptimizerImpl.h>
2013-02-25 03:09:54 +08:00
# include <gtsam/nonlinear/nonlinearExceptions.h>
# include <gtsam/nonlinear/LinearContainerFactor.h>
2012-03-17 04:55:21 +08:00
namespace gtsam {
using namespace std ;
static const bool disableReordering = false ;
static const double batchThreshold = 0.65 ;
2012-07-20 03:50:00 +08:00
/* ************************************************************************* */
std : : string ISAM2DoglegParams : : adaptationModeTranslator ( const DoglegOptimizerImpl : : TrustRegionAdaptationMode & adaptationMode ) const {
std : : string s ;
switch ( adaptationMode ) {
case DoglegOptimizerImpl : : SEARCH_EACH_ITERATION : s = " SEARCH_EACH_ITERATION " ; break ;
case DoglegOptimizerImpl : : ONE_STEP_PER_ITERATION : s = " ONE_STEP_PER_ITERATION " ; break ;
default : s = " UNDEFINED " ; break ;
}
return s ;
}
/* ************************************************************************* */
DoglegOptimizerImpl : : TrustRegionAdaptationMode ISAM2DoglegParams : : adaptationModeTranslator ( const std : : string & adaptationMode ) const {
std : : string s = adaptationMode ; boost : : algorithm : : to_upper ( s ) ;
if ( s = = " SEARCH_EACH_ITERATION " ) return DoglegOptimizerImpl : : SEARCH_EACH_ITERATION ;
if ( s = = " ONE_STEP_PER_ITERATION " ) return DoglegOptimizerImpl : : ONE_STEP_PER_ITERATION ;
/* default is SEARCH_EACH_ITERATION */
return DoglegOptimizerImpl : : SEARCH_EACH_ITERATION ;
}
/* ************************************************************************* */
ISAM2Params : : Factorization ISAM2Params : : factorizationTranslator ( const std : : string & str ) const {
std : : string s = str ; boost : : algorithm : : to_upper ( s ) ;
if ( s = = " QR " ) return ISAM2Params : : QR ;
if ( s = = " CHOLESKY " ) return ISAM2Params : : CHOLESKY ;
/* default is CHOLESKY */
return ISAM2Params : : CHOLESKY ;
}
/* ************************************************************************* */
std : : string ISAM2Params : : factorizationTranslator ( const ISAM2Params : : Factorization & value ) const {
std : : string s ;
switch ( value ) {
case ISAM2Params : : QR : s = " QR " ; break ;
case ISAM2Params : : CHOLESKY : s = " CHOLESKY " ; break ;
default : s = " UNDEFINED " ; break ;
}
return s ;
}
2012-03-17 04:55:21 +08:00
/* ************************************************************************* */
ISAM2 : : ISAM2 ( const ISAM2Params & params ) :
2012-03-19 22:32:37 +08:00
deltaDoglegUptodate_ ( true ) , deltaUptodate_ ( true ) , params_ ( params ) {
2012-03-17 04:55:21 +08:00
if ( params_ . optimizationParams . type ( ) = = typeid ( ISAM2DoglegParams ) )
doglegDelta_ = boost : : get < ISAM2DoglegParams > ( params_ . optimizationParams ) . initialDelta ;
}
/* ************************************************************************* */
ISAM2 : : ISAM2 ( ) :
2012-03-19 22:32:37 +08:00
deltaDoglegUptodate_ ( true ) , deltaUptodate_ ( true ) {
2012-03-17 04:55:21 +08:00
if ( params_ . optimizationParams . type ( ) = = typeid ( ISAM2DoglegParams ) )
doglegDelta_ = boost : : get < ISAM2DoglegParams > ( params_ . optimizationParams ) . initialDelta ;
}
2012-04-07 02:56:07 +08:00
/* ************************************************************************* */
2012-06-30 09:45:21 +08:00
ISAM2 : : ISAM2 ( const ISAM2 & other ) {
2012-04-07 02:56:07 +08:00
* this = other ;
}
/* ************************************************************************* */
ISAM2 & ISAM2 : : operator = ( const ISAM2 & rhs ) {
// Copy BayesTree
this - > Base : : operator = ( rhs ) ;
// Copy our variables
// When we have Permuted<...>, it is only necessary to copy this permuted
// view and not the original, because copying the permuted view automatically
// copies the original.
theta_ = rhs . theta_ ;
variableIndex_ = rhs . variableIndex_ ;
delta_ = rhs . delta_ ;
deltaNewton_ = rhs . deltaNewton_ ;
RgProd_ = rhs . RgProd_ ;
deltaDoglegUptodate_ = rhs . deltaDoglegUptodate_ ;
deltaUptodate_ = rhs . deltaUptodate_ ;
deltaReplacedMask_ = rhs . deltaReplacedMask_ ;
nonlinearFactors_ = rhs . nonlinearFactors_ ;
2012-04-11 22:17:59 +08:00
2013-08-06 06:31:44 +08:00
linearFactors_ = GaussianFactorGraph ( ) ;
2012-04-11 22:17:59 +08:00
linearFactors_ . reserve ( rhs . linearFactors_ . size ( ) ) ;
2013-08-06 06:31:44 +08:00
BOOST_FOREACH ( const GaussianFactor : : shared_ptr & linearFactor , rhs . linearFactors_ ) {
linearFactors_ . push_back ( linearFactor ? linearFactor - > clone ( ) : GaussianFactor : : shared_ptr ( ) ) ; }
2012-04-11 22:17:59 +08:00
2012-04-07 02:56:07 +08:00
ordering_ = rhs . ordering_ ;
params_ = rhs . params_ ;
doglegDelta_ = rhs . doglegDelta_ ;
lastAffectedVariableCount = rhs . lastAffectedVariableCount ;
lastAffectedFactorCount = rhs . lastAffectedFactorCount ;
lastAffectedCliqueCount = rhs . lastAffectedCliqueCount ;
lastAffectedMarkedCount = rhs . lastAffectedMarkedCount ;
lastBacksubVariableCount = rhs . lastBacksubVariableCount ;
lastNnzTop = rhs . lastNnzTop ;
return * this ;
}
2012-03-17 04:55:21 +08:00
/* ************************************************************************* */
FastList < size_t > ISAM2 : : getAffectedFactors ( const FastList < Index > & keys ) const {
static const bool debug = false ;
if ( debug ) cout < < " Getting affected factors for " ;
if ( debug ) { BOOST_FOREACH ( const Index key , keys ) { cout < < key < < " " ; } }
if ( debug ) cout < < endl ;
2013-08-06 06:31:44 +08:00
FactorGraph < NonlinearFactor > allAffected ;
2012-03-17 04:55:21 +08:00
FastList < size_t > indices ;
BOOST_FOREACH ( const Index key , keys ) {
// const list<size_t> l = nonlinearFactors_.factors(key);
// indices.insert(indices.begin(), l.begin(), l.end());
2013-08-06 06:31:44 +08:00
const VariableIndex : : Factors & factors ( variableIndex_ [ key ] ) ;
2012-03-17 04:55:21 +08:00
BOOST_FOREACH ( size_t factor , factors ) {
if ( debug ) cout < < " Variable " < < key < < " affects factor " < < factor < < endl ;
indices . push_back ( factor ) ;
}
}
indices . sort ( ) ;
indices . unique ( ) ;
if ( debug ) cout < < " Affected factors are: " ;
if ( debug ) { BOOST_FOREACH ( const size_t index , indices ) { cout < < index < < " " ; } }
if ( debug ) cout < < endl ;
return indices ;
}
/* ************************************************************************* */
// retrieve all factors that ONLY contain the affected variables
// (note that the remaining stuff is summarized in the cached factors)
2013-08-06 06:31:44 +08:00
FactorGraph < GaussianFactor > : : shared_ptr
2012-04-11 22:17:59 +08:00
ISAM2 : : relinearizeAffectedFactors ( const FastList < Index > & affectedKeys , const FastSet < Index > & relinKeys ) const {
2012-03-17 04:55:21 +08:00
2012-10-03 04:18:41 +08:00
gttic ( getAffectedFactors ) ;
2012-03-17 04:55:21 +08:00
FastList < size_t > candidates = getAffectedFactors ( affectedKeys ) ;
2012-10-03 04:18:41 +08:00
gttoc ( getAffectedFactors ) ;
2012-03-17 04:55:21 +08:00
NonlinearFactorGraph nonlinearAffectedFactors ;
2012-10-03 04:18:41 +08:00
gttic ( affectedKeysSet ) ;
2012-03-17 04:55:21 +08:00
// for fast lookup below
FastSet < Index > affectedKeysSet ;
affectedKeysSet . insert ( affectedKeys . begin ( ) , affectedKeys . end ( ) ) ;
2012-10-03 04:18:41 +08:00
gttoc ( affectedKeysSet ) ;
2012-03-17 04:55:21 +08:00
2012-10-03 04:18:41 +08:00
gttic ( check_candidates_and_linearize ) ;
2013-08-06 06:31:44 +08:00
FactorGraph < GaussianFactor > : : shared_ptr linearized = boost : : make_shared < FactorGraph < GaussianFactor > > ( ) ;
2012-03-17 04:55:21 +08:00
BOOST_FOREACH ( size_t idx , candidates ) {
bool inside = true ;
2012-04-11 22:17:59 +08:00
bool useCachedLinear = params_ . cacheLinearizedFactors ;
2012-03-17 04:55:21 +08:00
BOOST_FOREACH ( Key key , nonlinearFactors_ [ idx ] - > keys ( ) ) {
Index var = ordering_ [ key ] ;
2012-04-11 22:17:59 +08:00
if ( affectedKeysSet . find ( var ) = = affectedKeysSet . end ( ) ) {
2012-03-17 04:55:21 +08:00
inside = false ;
break ;
}
2012-04-11 22:17:59 +08:00
if ( useCachedLinear & & relinKeys . find ( var ) ! = relinKeys . end ( ) )
useCachedLinear = false ;
}
if ( inside ) {
if ( useCachedLinear ) {
2013-05-21 01:26:53 +08:00
# ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS
2012-04-11 22:17:59 +08:00
assert ( linearFactors_ [ idx ] ) ;
assert ( linearFactors_ [ idx ] - > keys ( ) = = nonlinearFactors_ [ idx ] - > symbolic ( ordering_ ) - > keys ( ) ) ;
2013-05-21 01:26:53 +08:00
# endif
linearized - > push_back ( linearFactors_ [ idx ] ) ;
2012-04-11 22:17:59 +08:00
} else {
2013-08-06 06:31:44 +08:00
GaussianFactor : : shared_ptr linearFactor = nonlinearFactors_ [ idx ] - > linearize ( theta_ , ordering_ ) ;
2012-04-11 22:17:59 +08:00
linearized - > push_back ( linearFactor ) ;
if ( params_ . cacheLinearizedFactors ) {
2013-05-21 01:26:53 +08:00
# ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS
2012-04-11 22:17:59 +08:00
assert ( linearFactors_ [ idx ] - > keys ( ) = = linearFactor - > keys ( ) ) ;
2013-05-21 01:26:53 +08:00
# endif
2012-04-11 22:17:59 +08:00
linearFactors_ [ idx ] = linearFactor ;
}
}
2012-03-17 04:55:21 +08:00
}
}
2012-10-03 04:18:41 +08:00
gttoc ( check_candidates_and_linearize ) ;
2012-03-17 04:55:21 +08:00
return linearized ;
}
/* ************************************************************************* */
// find intermediate (linearized) factors from cache that are passed into the affected area
2013-08-06 06:31:44 +08:00
GaussianFactorGraph ISAM2 : : getCachedBoundaryFactors ( Cliques & orphans ) {
2012-03-17 04:55:21 +08:00
static const bool debug = false ;
2013-08-06 06:31:44 +08:00
GaussianFactorGraph cachedBoundary ;
2012-03-17 04:55:21 +08:00
BOOST_FOREACH ( sharedClique orphan , orphans ) {
// find the last variable that was eliminated
Index key = ( * orphan ) - > frontals ( ) . back ( ) ;
// retrieve the cached factor and add to boundary
2012-03-28 07:30:19 +08:00
cachedBoundary . push_back ( orphan - > cachedFactor ( ) ) ;
2012-03-17 04:55:21 +08:00
if ( debug ) { cout < < " Cached factor for variable " < < key ; orphan - > cachedFactor ( ) - > print ( " " ) ; }
}
return cachedBoundary ;
}
2012-07-07 02:33:01 +08:00
boost : : shared_ptr < FastSet < Index > > ISAM2 : : recalculate ( const FastSet < Index > & markedKeys ,
2012-10-02 22:40:07 +08:00
const FastSet < Index > & relinKeys , const FastVector < Index > & observedKeys , const FastSet < Index > & unusedIndices ,
2012-03-25 00:52:55 +08:00
const boost : : optional < FastMap < Index , int > > & constrainKeys , ISAM2Result & result ) {
2012-03-17 04:55:21 +08:00
// TODO: new factors are linearized twice, the newFactors passed in are not used.
2012-03-25 00:52:55 +08:00
const bool debug = ISDEBUG ( " ISAM2 recalculate " ) ;
2012-03-17 04:55:21 +08:00
// Input: BayesTree(this), newFactors
//#define PRINT_STATS // figures for paper, disable for timing
# ifdef PRINT_STATS
static int counter = 0 ;
int maxClique = 0 ;
double avgClique = 0 ;
int numCliques = 0 ;
int nnzR = 0 ;
if ( counter > 0 ) { // cannot call on empty tree
GaussianISAM2_P : : CliqueData cdata = this - > getCliqueData ( ) ;
GaussianISAM2_P : : CliqueStats cstats = cdata . getStats ( ) ;
maxClique = cstats . maxCONDITIONALSize ;
avgClique = cstats . avgCONDITIONALSize ;
numCliques = cdata . conditionalSizes . size ( ) ;
nnzR = calculate_nnz ( this - > root ( ) ) ;
}
counter + + ;
# endif
if ( debug ) {
cout < < " markedKeys: " ;
BOOST_FOREACH ( const Index key , markedKeys ) { cout < < key < < " " ; }
cout < < endl ;
2012-04-12 11:04:32 +08:00
cout < < " observedKeys: " ;
BOOST_FOREACH ( const Index key , observedKeys ) { cout < < key < < " " ; }
2012-03-17 04:55:21 +08:00
cout < < endl ;
}
// 1. Remove top of Bayes tree and convert to a factor graph:
// (a) For each affected variable, remove the corresponding clique and all parents up to the root.
// (b) Store orphaned sub-trees \BayesTree_{O} of removed cliques.
2012-10-03 04:18:41 +08:00
gttic ( removetop ) ;
2012-03-17 04:55:21 +08:00
Cliques orphans ;
2013-08-06 06:31:44 +08:00
BayesNet < GaussianConditional > affectedBayesNet ;
2012-03-17 04:55:21 +08:00
this - > removeTop ( markedKeys , affectedBayesNet , orphans ) ;
2012-10-03 04:18:41 +08:00
gttoc ( removetop ) ;
2012-03-17 04:55:21 +08:00
if ( debug ) affectedBayesNet . print ( " Removed top: " ) ;
if ( debug ) orphans . print ( " Orphans: " ) ;
2013-08-06 06:31:44 +08:00
// FactorGraph<GaussianFactor> factors(affectedBayesNet);
2012-03-17 04:55:21 +08:00
// bug was here: we cannot reuse the original factors, because then the cached factors get messed up
// [all the necessary data is actually contained in the affectedBayesNet, including what was passed in from the boundaries,
// so this would be correct; however, in the process we also generate new cached_ entries that will be wrong (ie. they don't
// contain what would be passed up at a certain point if batch elimination was done, but that's what we need); we could choose
// not to update cached_ from here, but then the new information (and potentially different variable ordering) is not reflected
// in the cached_ values which again will be wrong]
// so instead we have to retrieve the original linearized factors AND add the cached factors from the boundary
// BEGIN OF COPIED CODE
// ordering provides all keys in conditionals, there cannot be others because path to root included
2012-10-03 04:18:41 +08:00
gttic ( affectedKeys ) ;
2012-03-17 04:55:21 +08:00
FastList < Index > affectedKeys = affectedBayesNet . ordering ( ) ;
2012-10-03 04:18:41 +08:00
gttoc ( affectedKeys ) ;
2012-03-17 04:55:21 +08:00
2012-04-12 11:04:32 +08:00
boost : : shared_ptr < FastSet < Index > > affectedKeysSet ( new FastSet < Index > ( ) ) ; // Will return this result
2012-03-17 04:55:21 +08:00
if ( affectedKeys . size ( ) > = theta_ . size ( ) * batchThreshold ) {
2012-10-03 04:18:41 +08:00
gttic ( batch ) ;
2012-03-17 04:55:21 +08:00
2012-10-03 04:18:41 +08:00
gttic ( add_keys ) ;
2013-08-06 06:31:44 +08:00
BOOST_FOREACH ( const Ordering : : value_type & key_index , ordering_ ) { affectedKeysSet - > insert ( key_index . second ) ; }
2012-10-03 04:18:41 +08:00
gttoc ( add_keys ) ;
2012-03-17 04:55:21 +08:00
2012-10-03 04:18:41 +08:00
gttic ( reorder ) ;
gttic ( CCOLAMD ) ;
2012-03-17 04:55:21 +08:00
// Do a batch step - reorder and relinearize all variables
vector < int > cmember ( theta_ . size ( ) , 0 ) ;
2012-03-25 00:52:55 +08:00
if ( constrainKeys ) {
if ( ! constrainKeys - > empty ( ) ) {
typedef std : : pair < const Index , int > Index_Group ;
if ( theta_ . size ( ) > constrainKeys - > size ( ) ) { // Only if some variables are unconstrained
BOOST_FOREACH ( const Index_Group & index_group , * constrainKeys ) {
cmember [ index_group . first ] = index_group . second ; }
} else {
int minGroup = * boost : : range : : min_element ( boost : : adaptors : : values ( * constrainKeys ) ) ;
BOOST_FOREACH ( const Index_Group & index_group , * constrainKeys ) {
cmember [ index_group . first ] = index_group . second - minGroup ; }
}
}
} else {
2012-04-12 11:04:32 +08:00
if ( theta_ . size ( ) > observedKeys . size ( ) ) { // Only if some variables are unconstrained
BOOST_FOREACH ( Index var , observedKeys ) { cmember [ var ] = 1 ; }
2012-04-03 04:04:43 +08:00
}
2012-03-17 04:55:21 +08:00
}
Permutation : : shared_ptr colamd ( inference : : PermutationCOLAMD_ ( variableIndex_ , cmember ) ) ;
Permutation : : shared_ptr colamdInverse ( colamd - > inverse ( ) ) ;
2012-10-03 04:18:41 +08:00
gttoc ( CCOLAMD ) ;
2012-03-17 04:55:21 +08:00
// Reorder
2012-10-03 04:18:41 +08:00
gttic ( permute_global_variable_index ) ;
2012-06-30 09:45:21 +08:00
variableIndex_ . permuteInPlace ( * colamd ) ;
2012-10-03 04:18:41 +08:00
gttoc ( permute_global_variable_index ) ;
gttic ( permute_delta ) ;
2012-12-18 22:21:02 +08:00
delta_ . permuteInPlace ( * colamd ) ;
deltaNewton_ . permuteInPlace ( * colamd ) ;
RgProd_ . permuteInPlace ( * colamd ) ;
2012-10-03 04:18:41 +08:00
gttoc ( permute_delta ) ;
gttic ( permute_ordering ) ;
2013-01-09 07:31:06 +08:00
ordering_ . permuteInPlace ( * colamd ) ;
2012-10-03 04:18:41 +08:00
gttoc ( permute_ordering ) ;
gttoc ( reorder ) ;
2012-03-17 04:55:21 +08:00
2012-10-03 04:18:41 +08:00
gttic ( linearize ) ;
2013-08-06 06:31:44 +08:00
GaussianFactorGraph linearized = * nonlinearFactors_ . linearize ( theta_ , ordering_ ) ;
2012-07-06 02:59:10 +08:00
if ( params_ . cacheLinearizedFactors )
linearFactors_ = linearized ;
2012-10-03 04:18:41 +08:00
gttoc ( linearize ) ;
2012-03-17 04:55:21 +08:00
2012-10-03 04:18:41 +08:00
gttic ( eliminate ) ;
2013-08-06 06:31:44 +08:00
JunctionTree < GaussianFactorGraph , Base : : Clique > jt ( linearized , variableIndex_ ) ;
2012-03-28 07:30:19 +08:00
sharedClique newRoot ;
2012-05-15 23:49:14 +08:00
if ( params_ . factorization = = ISAM2Params : : CHOLESKY )
2013-08-06 06:31:44 +08:00
newRoot = jt . eliminate ( EliminatePreferCholesky ) ;
2012-03-28 07:30:19 +08:00
else if ( params_ . factorization = = ISAM2Params : : QR )
2013-08-06 06:31:44 +08:00
newRoot = jt . eliminate ( EliminateQR ) ;
2012-03-28 07:30:19 +08:00
else assert ( false ) ;
2012-03-17 04:55:21 +08:00
if ( debug ) newRoot - > print ( " Eliminated: " ) ;
2012-10-03 04:18:41 +08:00
gttoc ( eliminate ) ;
2012-03-17 04:55:21 +08:00
2012-10-03 04:18:41 +08:00
gttic ( insert ) ;
2012-03-17 04:55:21 +08:00
this - > clear ( ) ;
this - > insert ( newRoot ) ;
2012-10-03 04:18:41 +08:00
gttoc ( insert ) ;
2012-03-17 04:55:21 +08:00
result . variablesReeliminated = affectedKeysSet - > size ( ) ;
2013-04-03 01:36:50 +08:00
result . factorsRecalculated = nonlinearFactors_ . size ( ) ;
2012-03-17 04:55:21 +08:00
lastAffectedMarkedCount = markedKeys . size ( ) ;
lastAffectedVariableCount = affectedKeysSet - > size ( ) ;
2012-07-06 02:59:10 +08:00
lastAffectedFactorCount = linearized . size ( ) ;
2012-03-17 04:55:21 +08:00
2012-04-12 11:04:32 +08:00
// Reeliminated keys for detailed results
2012-05-02 02:54:44 +08:00
if ( params_ . enableDetailedResults ) {
BOOST_FOREACH ( Key key , theta_ . keys ( ) ) {
2012-05-25 04:11:45 +08:00
result . detail - > variableStatus [ key ] . isReeliminated = true ;
2012-05-02 02:54:44 +08:00
}
}
2012-04-12 11:04:32 +08:00
2012-10-03 04:18:41 +08:00
gttoc ( batch ) ;
2012-03-17 04:55:21 +08:00
} else {
2012-10-03 04:18:41 +08:00
gttic ( incremental ) ;
2012-03-17 04:55:21 +08:00
// 2. Add the new factors \Factors' into the resulting factor graph
FastList < Index > affectedAndNewKeys ;
affectedAndNewKeys . insert ( affectedAndNewKeys . end ( ) , affectedKeys . begin ( ) , affectedKeys . end ( ) ) ;
2012-04-12 11:04:32 +08:00
affectedAndNewKeys . insert ( affectedAndNewKeys . end ( ) , observedKeys . begin ( ) , observedKeys . end ( ) ) ;
2012-10-03 04:18:41 +08:00
gttic ( relinearizeAffected ) ;
2013-08-06 06:31:44 +08:00
GaussianFactorGraph factors ( * relinearizeAffectedFactors ( affectedAndNewKeys , relinKeys ) ) ;
2012-03-17 04:55:21 +08:00
if ( debug ) factors . print ( " Relinearized factors: " ) ;
2012-10-03 04:18:41 +08:00
gttoc ( relinearizeAffected ) ;
2012-03-17 04:55:21 +08:00
if ( debug ) { cout < < " Affected keys: " ; BOOST_FOREACH ( const Index key , affectedKeys ) { cout < < key < < " " ; } cout < < endl ; }
2012-04-12 11:04:32 +08:00
// Reeliminated keys for detailed results
2012-05-02 02:54:44 +08:00
if ( params_ . enableDetailedResults ) {
BOOST_FOREACH ( Index index , affectedAndNewKeys ) {
2013-01-09 07:31:06 +08:00
result . detail - > variableStatus [ ordering_ . key ( index ) ] . isReeliminated = true ;
2012-05-02 02:54:44 +08:00
}
}
2012-04-12 11:04:32 +08:00
2012-03-17 04:55:21 +08:00
result . variablesReeliminated = affectedAndNewKeys . size ( ) ;
2013-04-03 01:36:50 +08:00
result . factorsRecalculated = factors . size ( ) ;
2012-03-17 04:55:21 +08:00
lastAffectedMarkedCount = markedKeys . size ( ) ;
lastAffectedVariableCount = affectedKeys . size ( ) ;
lastAffectedFactorCount = factors . size ( ) ;
# ifdef PRINT_STATS
// output for generating figures
cout < < " linear: #markedKeys: " < < markedKeys . size ( ) < < " #affectedVariables: " < < affectedKeys . size ( )
< < " #affectedFactors: " < < factors . size ( ) < < " maxCliqueSize: " < < maxClique
< < " avgCliqueSize: " < < avgClique < < " #Cliques: " < < numCliques < < " nnzR: " < < nnzR < < endl ;
# endif
2012-10-03 04:18:41 +08:00
gttic ( cached ) ;
2012-03-17 04:55:21 +08:00
// add the cached intermediate results from the boundary of the orphans ...
2013-08-06 06:31:44 +08:00
GaussianFactorGraph cachedBoundary = getCachedBoundaryFactors ( orphans ) ;
2012-03-17 04:55:21 +08:00
if ( debug ) cachedBoundary . print ( " Boundary factors: " ) ;
2012-04-11 22:17:59 +08:00
factors . push_back ( cachedBoundary ) ;
2012-10-03 04:18:41 +08:00
gttoc ( cached ) ;
2012-03-17 04:55:21 +08:00
// END OF COPIED CODE
// 3. Re-order and eliminate the factor graph into a Bayes net (Algorithm [alg:eliminate]), and re-assemble into a new Bayes tree (Algorithm [alg:BayesTree])
2012-10-03 04:18:41 +08:00
gttic ( reorder_and_eliminate ) ;
2012-03-17 04:55:21 +08:00
2012-10-03 04:18:41 +08:00
gttic ( list_to_set ) ;
2012-03-17 04:55:21 +08:00
// create a partial reordering for the new and contaminated factors
// markedKeys are passed in: those variables will be forced to the end in the ordering
2012-04-12 11:04:32 +08:00
affectedKeysSet - > insert ( markedKeys . begin ( ) , markedKeys . end ( ) ) ;
2012-03-17 04:55:21 +08:00
affectedKeysSet - > insert ( affectedKeys . begin ( ) , affectedKeys . end ( ) ) ;
2012-10-03 04:18:41 +08:00
gttoc ( list_to_set ) ;
2012-03-17 04:55:21 +08:00
2012-10-03 04:18:41 +08:00
gttic ( PartialSolve ) ;
2012-03-18 07:57:42 +08:00
Impl : : ReorderingMode reorderingMode ;
2013-01-09 07:31:06 +08:00
reorderingMode . nFullSystemVars = ordering_ . size ( ) ;
2012-03-17 04:55:21 +08:00
reorderingMode . algorithm = Impl : : ReorderingMode : : COLAMD ;
reorderingMode . constrain = Impl : : ReorderingMode : : CONSTRAIN_LAST ;
2012-03-25 00:52:55 +08:00
if ( constrainKeys ) {
2012-03-17 04:55:21 +08:00
reorderingMode . constrainedKeys = * constrainKeys ;
2012-03-25 00:52:55 +08:00
} else {
reorderingMode . constrainedKeys = FastMap < Index , int > ( ) ;
2012-04-12 11:04:32 +08:00
BOOST_FOREACH ( Index var , observedKeys ) { reorderingMode . constrainedKeys - > insert ( make_pair ( var , 1 ) ) ; }
2012-03-25 00:52:55 +08:00
}
2012-10-02 22:40:07 +08:00
FastSet < Index > affectedUsedKeys = * affectedKeysSet ; // Remove unused keys from the set we pass to PartialSolve
BOOST_FOREACH ( Index unused , unusedIndices ) {
affectedUsedKeys . erase ( unused ) ;
}
2012-10-21 10:09:58 +08:00
// Remove unaffected keys from the constraints
FastMap < Index , int > : : iterator iter = reorderingMode . constrainedKeys - > begin ( ) ;
while ( iter ! = reorderingMode . constrainedKeys - > end ( ) ) {
if ( affectedUsedKeys . find ( iter - > first ) = = affectedUsedKeys . end ( ) ) {
reorderingMode . constrainedKeys - > erase ( iter + + ) ;
} else {
+ + iter ;
}
}
2012-03-18 07:57:42 +08:00
Impl : : PartialSolveResult partialSolveResult =
2012-07-07 02:33:01 +08:00
Impl : : PartialSolve ( factors , affectedUsedKeys , reorderingMode , ( params_ . factorization = = ISAM2Params : : QR ) ) ;
2012-10-03 04:18:41 +08:00
gttoc ( PartialSolve ) ;
2012-03-17 04:55:21 +08:00
// We now need to permute everything according this partial reordering: the
// delta vector, the global ordering, and the factors we're about to
// re-eliminate. The reordered variables are also mentioned in the
// orphans and the leftover cached factors.
2012-10-03 04:18:41 +08:00
gttic ( permute_global_variable_index ) ;
2012-12-18 22:21:28 +08:00
variableIndex_ . permuteInPlace ( partialSolveResult . reorderingSelector , partialSolveResult . reorderingPermutation ) ;
2012-10-03 04:18:41 +08:00
gttoc ( permute_global_variable_index ) ;
gttic ( permute_delta ) ;
2012-12-18 22:21:58 +08:00
delta_ . permuteInPlace ( partialSolveResult . reorderingSelector , partialSolveResult . reorderingPermutation ) ;
deltaNewton_ . permuteInPlace ( partialSolveResult . reorderingSelector , partialSolveResult . reorderingPermutation ) ;
RgProd_ . permuteInPlace ( partialSolveResult . reorderingSelector , partialSolveResult . reorderingPermutation ) ;
2012-10-03 04:18:41 +08:00
gttoc ( permute_delta ) ;
gttic ( permute_ordering ) ;
2013-01-09 07:31:06 +08:00
ordering_ . permuteInPlace ( partialSolveResult . reorderingSelector , partialSolveResult . reorderingPermutation ) ;
2012-10-03 04:18:41 +08:00
gttoc ( permute_ordering ) ;
2012-04-11 22:17:59 +08:00
if ( params_ . cacheLinearizedFactors ) {
2012-10-03 04:18:41 +08:00
gttic ( permute_cached_linear ) ;
2012-04-11 22:17:59 +08:00
//linearFactors_.permuteWithInverse(partialSolveResult.fullReorderingInverse);
FastList < size_t > permuteLinearIndices = getAffectedFactors ( affectedAndNewKeys ) ;
BOOST_FOREACH ( size_t idx , permuteLinearIndices ) {
2012-12-18 22:21:28 +08:00
linearFactors_ [ idx ] - > reduceWithInverse ( partialSolveResult . reorderingInverse ) ;
2012-04-11 22:17:59 +08:00
}
2012-10-03 04:18:41 +08:00
gttoc ( permute_cached_linear ) ;
2012-04-11 22:17:59 +08:00
}
2012-03-17 04:55:21 +08:00
2012-10-03 04:18:41 +08:00
gttoc ( reorder_and_eliminate ) ;
2012-03-17 04:55:21 +08:00
2012-10-03 04:18:41 +08:00
gttic ( reassemble ) ;
2012-03-17 04:55:21 +08:00
if ( partialSolveResult . bayesTree ) {
assert ( ! this - > root_ ) ;
this - > insert ( partialSolveResult . bayesTree ) ;
}
2012-10-03 04:18:41 +08:00
gttoc ( reassemble ) ;
2012-03-17 04:55:21 +08:00
// 4. Insert the orphans back into the new Bayes tree.
2012-10-03 04:18:41 +08:00
gttic ( orphans ) ;
gttic ( permute ) ;
2012-03-17 04:55:21 +08:00
BOOST_FOREACH ( sharedClique orphan , orphans ) {
2012-12-18 22:21:28 +08:00
( void ) orphan - > reduceSeparatorWithInverse ( partialSolveResult . reorderingInverse ) ;
2012-03-17 04:55:21 +08:00
}
2012-10-03 04:18:41 +08:00
gttoc ( permute ) ;
gttic ( insert ) ;
2012-03-17 04:55:21 +08:00
// add orphans to the bottom of the new tree
BOOST_FOREACH ( sharedClique orphan , orphans ) {
// Because the affectedKeysSelector is sorted, the orphan separator keys
// will be sorted correctly according to the new elimination order after
// applying the permutation, so findParentClique, which looks for the
// lowest-ordered parent, will still work.
Index parentRepresentative = Base : : findParentClique ( ( * orphan ) - > parents ( ) ) ;
sharedClique parent = ( * this ) [ parentRepresentative ] ;
parent - > children_ + = orphan ;
orphan - > parent_ = parent ; // set new parent!
}
2012-10-03 04:18:41 +08:00
gttoc ( insert ) ;
gttoc ( orphans ) ;
2012-03-17 04:55:21 +08:00
2012-10-03 04:18:41 +08:00
gttoc ( incremental ) ;
2012-03-17 04:55:21 +08:00
}
2012-04-12 11:04:32 +08:00
// Root clique variables for detailed results
2012-05-02 02:54:44 +08:00
if ( params_ . enableDetailedResults ) {
BOOST_FOREACH ( Index index , this - > root ( ) - > conditional ( ) - > frontals ( ) ) {
2013-01-09 07:31:06 +08:00
result . detail - > variableStatus [ ordering_ . key ( index ) ] . inRootClique = true ;
2012-05-02 02:54:44 +08:00
}
}
2012-04-12 11:04:32 +08:00
return affectedKeysSet ;
2012-03-17 04:55:21 +08:00
}
/* ************************************************************************* */
ISAM2Result ISAM2 : : update (
const NonlinearFactorGraph & newFactors , const Values & newTheta , const FastVector < size_t > & removeFactorIndices ,
2013-04-09 02:05:48 +08:00
const boost : : optional < FastMap < Key , int > > & constrainedKeys , const boost : : optional < FastList < Key > > & noRelinKeys ,
const boost : : optional < FastList < Key > > & extraReelimKeys , bool force_relinearize ) {
2012-03-17 04:55:21 +08:00
2012-03-25 00:52:55 +08:00
const bool debug = ISDEBUG ( " ISAM2 update " ) ;
const bool verbose = ISDEBUG ( " ISAM2 update verbose " ) ;
2012-03-17 04:55:21 +08:00
static int count = 0 ;
count + + ;
lastAffectedVariableCount = 0 ;
lastAffectedFactorCount = 0 ;
lastAffectedCliqueCount = 0 ;
lastAffectedMarkedCount = 0 ;
lastBacksubVariableCount = 0 ;
lastNnzTop = 0 ;
ISAM2Result result ;
2012-04-12 11:04:32 +08:00
if ( params_ . enableDetailedResults )
result . detail = ISAM2Result : : DetailedResults ( ) ;
2012-03-17 04:55:21 +08:00
const bool relinearizeThisStep = force_relinearize | | ( params_ . enableRelinearization & & count % params_ . relinearizeSkip = = 0 ) ;
if ( verbose ) {
cout < < " ISAM2::update \n " ;
this - > print ( " ISAM2: " ) ;
}
// Update delta if we need it to check relinearization later
if ( relinearizeThisStep ) {
2012-10-03 04:18:41 +08:00
gttic ( updateDelta ) ;
2012-03-17 04:55:21 +08:00
updateDelta ( disableReordering ) ;
2012-10-03 04:18:41 +08:00
gttoc ( updateDelta ) ;
2012-03-17 04:55:21 +08:00
}
2012-10-03 04:18:41 +08:00
gttic ( push_back_factors ) ;
2012-03-17 04:55:21 +08:00
// Add the new factor indices to the result struct
result . newFactorsIndices . resize ( newFactors . size ( ) ) ;
for ( size_t i = 0 ; i < newFactors . size ( ) ; + + i )
result . newFactorsIndices [ i ] = i + nonlinearFactors_ . size ( ) ;
// 1. Add any new factors \Factors:=\Factors\cup\Factors'.
if ( debug | | verbose ) newFactors . print ( " The new factors are: " ) ;
nonlinearFactors_ . push_back ( newFactors ) ;
// Remove the removed factors
NonlinearFactorGraph removeFactors ; removeFactors . reserve ( removeFactorIndices . size ( ) ) ;
BOOST_FOREACH ( size_t index , removeFactorIndices ) {
removeFactors . push_back ( nonlinearFactors_ [ index ] ) ;
nonlinearFactors_ . remove ( index ) ;
2012-10-02 22:40:07 +08:00
if ( params_ . cacheLinearizedFactors )
linearFactors_ . remove ( index ) ;
2012-03-17 04:55:21 +08:00
}
// Remove removed factors from the variable index so we do not attempt to relinearize them
variableIndex_ . remove ( removeFactorIndices , * removeFactors . symbolic ( ordering_ ) ) ;
2012-07-01 06:32:49 +08:00
2012-10-02 22:40:07 +08:00
// Compute unused keys and indices
FastSet < Key > unusedKeys ;
FastSet < Index > unusedIndices ;
{
// Get keys from removed factors and new factors, and compute unused keys,
// i.e., keys that are empty now and do not appear in the new factors.
FastSet < Key > removedAndEmpty ;
BOOST_FOREACH ( Key key , removeFactors . keys ( ) ) {
if ( variableIndex_ [ ordering_ [ key ] ] . empty ( ) )
removedAndEmpty . insert ( removedAndEmpty . end ( ) , key ) ;
}
FastSet < Key > newFactorSymbKeys = newFactors . keys ( ) ;
std : : set_difference ( removedAndEmpty . begin ( ) , removedAndEmpty . end ( ) ,
newFactorSymbKeys . begin ( ) , newFactorSymbKeys . end ( ) , std : : inserter ( unusedKeys , unusedKeys . end ( ) ) ) ;
// Get indices for unused keys
BOOST_FOREACH ( Key key , unusedKeys ) {
unusedIndices . insert ( unusedIndices . end ( ) , ordering_ [ key ] ) ;
}
}
2012-10-03 04:18:41 +08:00
gttoc ( push_back_factors ) ;
2012-03-17 04:55:21 +08:00
2012-10-03 04:18:41 +08:00
gttic ( add_new_variables ) ;
2012-03-17 04:55:21 +08:00
// 2. Initialize any new variables \Theta_{new} and add \Theta:=\Theta\cup\Theta_{new}.
2012-07-01 06:32:49 +08:00
Impl : : AddVariables ( newTheta , theta_ , delta_ , deltaNewton_ , RgProd_ , deltaReplacedMask_ , ordering_ ) ;
2012-04-12 11:04:32 +08:00
// New keys for detailed results
if ( params_ . enableDetailedResults ) {
BOOST_FOREACH ( Key key , newTheta . keys ( ) ) { result . detail - > variableStatus [ key ] . isNew = true ; } }
2012-10-03 04:18:41 +08:00
gttoc ( add_new_variables ) ;
2012-03-17 04:55:21 +08:00
2012-10-03 04:18:41 +08:00
gttic ( evaluate_error_before ) ;
2012-03-17 04:55:21 +08:00
if ( params_ . evaluateNonlinearError )
result . errorBefore . reset ( nonlinearFactors_ . error ( calculateEstimate ( ) ) ) ;
2012-10-03 04:18:41 +08:00
gttoc ( evaluate_error_before ) ;
2012-03-17 04:55:21 +08:00
2012-10-03 04:18:41 +08:00
gttic ( gather_involved_keys ) ;
2012-03-17 04:55:21 +08:00
// 3. Mark linear update
2012-07-07 02:33:01 +08:00
FastSet < Index > markedKeys = Impl : : IndicesFromFactors ( ordering_ , newFactors ) ; // Get keys from new factors
// Also mark keys involved in removed factors
{
FastSet < Index > markedRemoveKeys = Impl : : IndicesFromFactors ( ordering_ , removeFactors ) ; // Get keys involved in removed factors
markedKeys . insert ( markedRemoveKeys . begin ( ) , markedRemoveKeys . end ( ) ) ; // Add to the overall set of marked keys
}
2013-04-09 02:05:48 +08:00
// Also mark any provided extra re-eliminate keys
if ( extraReelimKeys ) {
BOOST_FOREACH ( Key key , * extraReelimKeys ) {
markedKeys . insert ( ordering_ . at ( key ) ) ;
}
}
2012-07-01 06:32:49 +08:00
2012-10-02 22:40:07 +08:00
// Observed keys for detailed results
2012-05-02 02:54:44 +08:00
if ( params_ . enableDetailedResults ) {
BOOST_FOREACH ( Index index , markedKeys ) {
2013-01-09 07:31:06 +08:00
result . detail - > variableStatus [ ordering_ . key ( index ) ] . isObserved = true ;
2012-05-02 02:54:44 +08:00
}
}
2012-03-17 04:55:21 +08:00
// NOTE: we use assign instead of the iterator constructor here because this
// is a vector of size_t, so the constructor unintentionally resolves to
// vector(size_t count, Index value) instead of the iterator constructor.
2012-07-07 02:33:01 +08:00
FastVector < Index > observedKeys ; observedKeys . reserve ( markedKeys . size ( ) ) ;
2012-10-02 22:40:07 +08:00
BOOST_FOREACH ( Index index , markedKeys ) {
if ( unusedIndices . find ( index ) = = unusedIndices . end ( ) ) // Only add if not unused
observedKeys . push_back ( index ) ; // Make a copy of these, as we'll soon add to them
}
2012-10-03 04:18:41 +08:00
gttoc ( gather_involved_keys ) ;
2012-03-17 04:55:21 +08:00
// Check relinearization if we're at the nth step, or we are using a looser loop relin threshold
2012-04-11 22:17:59 +08:00
FastSet < Index > relinKeys ;
2012-03-17 04:55:21 +08:00
if ( relinearizeThisStep ) {
2012-10-03 04:18:41 +08:00
gttic ( gather_relinearize_keys ) ;
2012-03-17 04:55:21 +08:00
// 4. Mark keys in \Delta above threshold \beta: J=\{\Delta_{j}\in\Delta|\Delta_{j}\geq\beta\}.
2012-06-29 04:46:53 +08:00
if ( params_ . enablePartialRelinearizationCheck )
relinKeys = Impl : : CheckRelinearizationPartial ( root_ , delta_ , ordering_ , params_ . relinearizeThreshold ) ;
else
relinKeys = Impl : : CheckRelinearizationFull ( delta_ , ordering_ , params_ . relinearizeThreshold ) ;
if ( disableReordering ) relinKeys = Impl : : CheckRelinearizationFull ( delta_ , ordering_ , 0.0 ) ; // This is used for debugging
2012-03-17 04:55:21 +08:00
2013-02-21 23:59:50 +08:00
// Remove from relinKeys any keys whose linearization points are fixed
2013-02-25 03:09:54 +08:00
BOOST_FOREACH ( Key key , fixedVariables_ ) {
relinKeys . erase ( ordering_ [ key ] ) ;
}
2013-02-21 23:59:50 +08:00
if ( noRelinKeys ) {
BOOST_FOREACH ( Key key , * noRelinKeys ) {
relinKeys . erase ( ordering_ [ key ] ) ;
}
}
2012-04-12 11:04:32 +08:00
// Above relin threshold keys for detailed results
if ( params_ . enableDetailedResults ) {
BOOST_FOREACH ( Index index , relinKeys ) {
2013-01-09 07:31:06 +08:00
result . detail - > variableStatus [ ordering_ . key ( index ) ] . isAboveRelinThreshold = true ;
result . detail - > variableStatus [ ordering_ . key ( index ) ] . isRelinearized = true ; } }
2012-04-12 11:04:32 +08:00
2012-03-17 04:55:21 +08:00
// Add the variables being relinearized to the marked keys
2013-02-21 23:59:50 +08:00
vector < bool > markedRelinMask ( ordering_ . size ( ) , false ) ;
2012-03-17 04:55:21 +08:00
BOOST_FOREACH ( const Index j , relinKeys ) { markedRelinMask [ j ] = true ; }
markedKeys . insert ( relinKeys . begin ( ) , relinKeys . end ( ) ) ;
2012-10-03 04:18:41 +08:00
gttoc ( gather_relinearize_keys ) ;
2012-03-17 04:55:21 +08:00
2012-10-03 04:18:41 +08:00
gttic ( fluid_find_all ) ;
2012-03-17 04:55:21 +08:00
// 5. Mark all cliques that involve marked variables \Theta_{J} and all their ancestors.
2012-04-12 11:04:32 +08:00
if ( ! relinKeys . empty ( ) & & this - > root ( ) ) {
// add other cliques that have the marked ones in the separator
Impl : : FindAll ( this - > root ( ) , markedKeys , markedRelinMask ) ;
// Relin involved keys for detailed results
if ( params_ . enableDetailedResults ) {
FastSet < Index > involvedRelinKeys ;
Impl : : FindAll ( this - > root ( ) , involvedRelinKeys , markedRelinMask ) ;
BOOST_FOREACH ( Index index , involvedRelinKeys ) {
2013-01-09 07:31:06 +08:00
if ( ! result . detail - > variableStatus [ ordering_ . key ( index ) ] . isAboveRelinThreshold ) {
result . detail - > variableStatus [ ordering_ . key ( index ) ] . isRelinearizeInvolved = true ;
result . detail - > variableStatus [ ordering_ . key ( index ) ] . isRelinearized = true ; } }
2012-04-12 11:04:32 +08:00
}
}
2012-10-03 04:18:41 +08:00
gttoc ( fluid_find_all ) ;
2012-03-17 04:55:21 +08:00
2012-10-03 04:18:41 +08:00
gttic ( expmap ) ;
2012-03-17 04:55:21 +08:00
// 6. Update linearization point for marked variables: \Theta_{J}:=\Theta_{J}+\Delta_{J}.
if ( ! relinKeys . empty ( ) )
Impl : : ExpmapMasked ( theta_ , delta_ , ordering_ , markedRelinMask , delta_ ) ;
2012-10-03 04:18:41 +08:00
gttoc ( expmap ) ;
2012-03-17 04:55:21 +08:00
result . variablesRelinearized = markedKeys . size ( ) ;
} else {
result . variablesRelinearized = 0 ;
}
2012-10-03 04:18:41 +08:00
gttic ( linearize_new ) ;
2012-03-17 04:55:21 +08:00
// 7. Linearize new factors
2012-04-11 22:17:59 +08:00
if ( params_ . cacheLinearizedFactors ) {
2012-10-03 04:18:41 +08:00
gttic ( linearize ) ;
2013-08-06 06:31:44 +08:00
FactorGraph < GaussianFactor > : : shared_ptr linearFactors = newFactors . linearize ( theta_ , ordering_ ) ;
2012-04-11 22:17:59 +08:00
linearFactors_ . push_back ( * linearFactors ) ;
assert ( nonlinearFactors_ . size ( ) = = linearFactors_ . size ( ) ) ;
2012-10-03 04:18:41 +08:00
gttoc ( linearize ) ;
2012-04-11 22:17:59 +08:00
2012-10-03 04:18:41 +08:00
gttic ( augment_VI ) ;
2012-04-11 22:17:59 +08:00
// Augment the variable index with the new factors
variableIndex_ . augment ( * linearFactors ) ;
2012-10-03 04:18:41 +08:00
gttoc ( augment_VI ) ;
2012-04-11 22:17:59 +08:00
} else {
variableIndex_ . augment ( * newFactors . symbolic ( ordering_ ) ) ;
}
2012-10-03 04:18:41 +08:00
gttoc ( linearize_new ) ;
2012-03-17 04:55:21 +08:00
2012-10-03 04:18:41 +08:00
gttic ( recalculate ) ;
2012-03-17 04:55:21 +08:00
// 8. Redo top of Bayes tree
// Convert constrained symbols to indices
2012-03-25 00:52:55 +08:00
boost : : optional < FastMap < Index , int > > constrainedIndices ;
2012-03-17 04:55:21 +08:00
if ( constrainedKeys ) {
2012-03-25 00:52:55 +08:00
constrainedIndices = FastMap < Index , int > ( ) ;
typedef pair < const Key , int > Key_Group ;
BOOST_FOREACH ( Key_Group key_group , * constrainedKeys ) {
constrainedIndices - > insert ( make_pair ( ordering_ [ key_group . first ] , key_group . second ) ) ;
2012-03-17 04:55:21 +08:00
}
}
boost : : shared_ptr < FastSet < Index > > replacedKeys ;
2012-04-12 11:04:32 +08:00
if ( ! markedKeys . empty ( ) | | ! observedKeys . empty ( ) )
2012-07-07 02:33:01 +08:00
replacedKeys = recalculate ( markedKeys , relinKeys , observedKeys , unusedIndices , constrainedIndices , result ) ;
2012-03-17 04:55:21 +08:00
// Update replaced keys mask (accumulates until back-substitution takes place)
if ( replacedKeys ) {
BOOST_FOREACH ( const Index var , * replacedKeys ) {
deltaReplacedMask_ [ var ] = true ; } }
2012-10-03 04:18:41 +08:00
gttoc ( recalculate ) ;
2012-03-17 04:55:21 +08:00
2012-10-02 22:40:07 +08:00
// After the top of the tree has been redone and may have index gaps from
// unused keys, condense the indices to remove gaps by rearranging indices
// in all data structures.
2012-08-02 05:31:19 +08:00
if ( ! unusedKeys . empty ( ) ) {
2012-10-03 04:18:41 +08:00
gttic ( remove_variables ) ;
2012-08-02 05:31:19 +08:00
Impl : : RemoveVariables ( unusedKeys , root_ , theta_ , variableIndex_ , delta_ , deltaNewton_ , RgProd_ ,
2013-02-25 03:09:54 +08:00
deltaReplacedMask_ , ordering_ , Base : : nodes_ , linearFactors_ , fixedVariables_ ) ;
2012-10-03 04:18:41 +08:00
gttoc ( remove_variables ) ;
2012-08-02 05:31:19 +08:00
}
2012-04-04 07:20:03 +08:00
result . cliques = this - > nodes ( ) . size ( ) ;
deltaDoglegUptodate_ = false ;
deltaUptodate_ = false ;
2012-10-03 04:18:41 +08:00
gttic ( evaluate_error_after ) ;
2012-03-17 04:55:21 +08:00
if ( params_ . evaluateNonlinearError )
result . errorAfter . reset ( nonlinearFactors_ . error ( calculateEstimate ( ) ) ) ;
2012-10-03 04:18:41 +08:00
gttoc ( evaluate_error_after ) ;
2012-03-17 04:55:21 +08:00
return result ;
}
2013-02-25 03:09:54 +08:00
/* ************************************************************************* */
2013-03-27 04:46:08 +08:00
void ISAM2 : : marginalizeLeaves ( const FastList < Key > & leafKeys )
2013-02-25 03:09:54 +08:00
{
// Convert set of keys into a set of indices
FastSet < Index > indices ;
BOOST_FOREACH ( Key key , leafKeys ) {
indices . insert ( ordering_ [ key ] ) ;
}
2013-03-19 03:28:02 +08:00
// Keep track of marginal factors - map from clique to the marginal factors
// that should be incorporated into it, passed up from it's children.
2013-08-06 06:31:44 +08:00
multimap < sharedClique , GaussianFactor : : shared_ptr > marginalFactors ;
2013-03-19 03:28:02 +08:00
// Remove each variable and its subtrees
2013-03-20 21:48:16 +08:00
BOOST_REVERSE_FOREACH ( Index j , indices ) {
2013-03-19 03:28:02 +08:00
if ( nodes_ [ j ] ) { // If the index was not already removed by removing another subtree
sharedClique clique = nodes_ [ j ] ;
// See if we should remove the whole clique
bool marginalizeEntireClique = true ;
BOOST_FOREACH ( Index frontal , clique - > conditional ( ) - > frontals ( ) ) {
if ( indices . find ( frontal ) = = indices . end ( ) ) {
marginalizeEntireClique = false ;
break ; } }
// Remove either the whole clique or part of it
if ( marginalizeEntireClique ) {
// Remove the whole clique and its subtree, and keep the marginal factor.
2013-08-06 06:31:44 +08:00
GaussianFactor : : shared_ptr marginalFactor = clique - > cachedFactor ( ) ;
2013-03-19 03:28:02 +08:00
// We do not need the marginal factors associated with this clique
// because their information is already incorporated in the new
// marginal factor. So, now associate this marginal factor with the
// parent of this clique.
marginalFactors . insert ( make_pair ( clique - > parent ( ) , marginalFactor ) ) ;
// Now remove this clique and its subtree - all of its marginal
// information has been stored in marginalFactors.
const Cliques removedCliques = this - > removeSubtree ( clique ) ; // Remove the subtree and throw away the cliques
BOOST_FOREACH ( const sharedClique & removedClique , removedCliques ) {
marginalFactors . erase ( removedClique ) ;
BOOST_FOREACH ( Index indexInClique , removedClique - > conditional ( ) - > frontals ( ) ) {
2013-03-20 21:48:16 +08:00
if ( indices . find ( indexInClique ) = = indices . end ( ) )
throw runtime_error ( " Requesting to marginalize variables that are not leaves, the ISAM2 object is now in an inconsistent state so should no longer be used. " ) ; }
2013-03-19 03:28:02 +08:00
}
}
else {
// Reeliminate the current clique and the marginals from its children,
// then keep only the marginal on the non-marginalized variables. We
// get the childrens' marginals from any existing children, plus
// the marginals from the marginalFactors multimap, which come from any
// subtrees already marginalized out.
// Add child marginals and remove marginalized subtrees
2013-08-06 06:31:44 +08:00
GaussianFactorGraph graph ;
2013-03-20 21:48:16 +08:00
FastSet < size_t > factorsInSubtreeRoot ;
2013-03-19 03:28:02 +08:00
Cliques subtreesToRemove ;
BOOST_FOREACH ( const sharedClique & child , clique - > children ( ) ) {
// Remove subtree if child depends on any marginalized keys
BOOST_FOREACH ( Index parentIndex , child - > conditional ( ) - > parents ( ) ) {
if ( indices . find ( parentIndex ) ! = indices . end ( ) ) {
subtreesToRemove . push_back ( child ) ;
2013-03-20 21:48:16 +08:00
graph . push_back ( child - > cachedFactor ( ) ) ; // Add child marginal
2013-03-19 03:28:02 +08:00
break ;
}
}
2013-02-25 03:09:54 +08:00
}
2013-03-20 21:48:16 +08:00
Cliques childrenRemoved ;
2013-03-19 03:28:02 +08:00
BOOST_FOREACH ( const sharedClique & childToRemove , subtreesToRemove ) {
const Cliques removedCliques = this - > removeSubtree ( childToRemove ) ; // Remove the subtree and throw away the cliques
2013-03-20 21:48:16 +08:00
childrenRemoved . insert ( childrenRemoved . end ( ) , removedCliques . begin ( ) , removedCliques . end ( ) ) ;
2013-03-19 03:28:02 +08:00
BOOST_FOREACH ( const sharedClique & removedClique , removedCliques ) {
2013-03-20 21:48:16 +08:00
marginalFactors . erase ( removedClique ) ;
BOOST_FOREACH ( Index indexInClique , removedClique - > conditional ( ) - > frontals ( ) ) {
if ( indices . find ( indexInClique ) = = indices . end ( ) )
throw runtime_error ( " Requesting to marginalize variables that are not leaves, the ISAM2 object is now in an inconsistent state so should no longer be used. " ) ; }
}
2013-03-05 13:47:27 +08:00
}
2013-03-19 03:28:02 +08:00
// Gather remaining children after we removed marginalized subtrees
vector < sharedClique > orphans ( clique - > children ( ) . begin ( ) , clique - > children ( ) . end ( ) ) ;
2013-03-20 21:48:16 +08:00
// Add the factors that are pulled into the current clique by the marginalized variables.
// These are the factors that involve *marginalized* frontal variables in this clique
// but do not involve frontal variables of any of its children.
FastSet < size_t > factorsFromMarginalizedInClique ;
BOOST_FOREACH ( Index indexInClique , clique - > conditional ( ) - > frontals ( ) ) {
if ( indices . find ( indexInClique ) ! = indices . end ( ) )
factorsFromMarginalizedInClique . insert ( variableIndex_ [ indexInClique ] . begin ( ) , variableIndex_ [ indexInClique ] . end ( ) ) ; }
BOOST_FOREACH ( const sharedClique & removedChild , childrenRemoved ) {
BOOST_FOREACH ( Index indexInClique , removedChild - > conditional ( ) - > frontals ( ) ) {
BOOST_FOREACH ( size_t factorInvolving , variableIndex_ [ indexInClique ] ) {
factorsFromMarginalizedInClique . erase ( factorInvolving ) ; } } }
BOOST_FOREACH ( size_t i , factorsFromMarginalizedInClique ) {
graph . push_back ( nonlinearFactors_ [ i ] - > linearize ( theta_ , ordering_ ) ) ; }
2013-03-19 03:28:02 +08:00
// Remove the current clique
sharedClique parent = clique - > parent ( ) ;
this - > removeClique ( clique ) ;
// Reeliminate the linear graph to get the marginal and discard the conditional
const FastSet < Index > cliqueFrontals ( clique - > conditional ( ) - > beginFrontals ( ) , clique - > conditional ( ) - > endFrontals ( ) ) ;
FastSet < Index > cliqueFrontalsToEliminate ;
std : : set_intersection ( cliqueFrontals . begin ( ) , cliqueFrontals . end ( ) , indices . begin ( ) , indices . end ( ) ,
std : : inserter ( cliqueFrontalsToEliminate , cliqueFrontalsToEliminate . end ( ) ) ) ;
vector < Index > cliqueFrontalsToEliminateV ( cliqueFrontalsToEliminate . begin ( ) , cliqueFrontalsToEliminate . end ( ) ) ;
2013-08-06 06:31:44 +08:00
pair < GaussianConditional : : shared_ptr , GaussianFactorGraph > eliminationResult1 =
2013-03-19 03:28:02 +08:00
graph . eliminate ( cliqueFrontalsToEliminateV ,
2013-08-06 06:31:44 +08:00
params_ . factorization = = ISAM2Params : : QR ? EliminateQR : EliminatePreferCholesky ) ;
2013-03-19 03:28:02 +08:00
// Add the resulting marginal
2013-08-06 06:31:44 +08:00
BOOST_FOREACH ( const GaussianFactor : : shared_ptr & marginal , eliminationResult1 . second ) {
2013-03-19 03:28:02 +08:00
if ( marginal )
marginalFactors . insert ( make_pair ( clique , marginal ) ) ; }
// Recover the conditional on the remaining subset of frontal variables
// of this clique being martially marginalized.
2013-03-20 21:48:16 +08:00
size_t nToEliminate = std : : find ( clique - > conditional ( ) - > beginFrontals ( ) , clique - > conditional ( ) - > endFrontals ( ) , j ) - clique - > conditional ( ) - > begin ( ) + 1 ;
2013-08-06 06:31:44 +08:00
GaussianFactorGraph graph2 ;
2013-03-20 21:48:16 +08:00
graph2 . push_back ( clique - > conditional ( ) - > toFactor ( ) ) ;
2013-08-06 06:31:44 +08:00
GaussianFactorGraph : : EliminationResult eliminationResult2 =
2013-03-20 21:48:16 +08:00
params_ . factorization = = ISAM2Params : : QR ?
2013-08-06 06:31:44 +08:00
EliminateQR ( graph2 , nToEliminate ) :
EliminatePreferCholesky ( graph2 , nToEliminate ) ;
GaussianFactorGraph graph3 ;
2013-03-20 21:48:16 +08:00
graph3 . push_back ( eliminationResult2 . second ) ;
2013-08-06 06:31:44 +08:00
GaussianFactorGraph : : EliminationResult eliminationResult3 =
2013-03-20 21:48:16 +08:00
params_ . factorization = = ISAM2Params : : QR ?
2013-08-06 06:31:44 +08:00
EliminateQR ( graph3 , clique - > conditional ( ) - > nrFrontals ( ) - nToEliminate ) :
EliminatePreferCholesky ( graph3 , clique - > conditional ( ) - > nrFrontals ( ) - nToEliminate ) ;
2013-03-20 21:48:16 +08:00
sharedClique newClique = boost : : make_shared < Clique > ( make_pair ( eliminationResult3 . first , clique - > cachedFactor ( ) ) ) ;
2013-03-19 03:28:02 +08:00
// Add the marginalized clique to the BayesTree
this - > addClique ( newClique , parent ) ;
// Add the orphans
BOOST_FOREACH ( const sharedClique & orphan , orphans ) {
this - > addClique ( orphan , newClique ) ; }
2013-02-25 03:09:54 +08:00
}
}
2013-03-19 03:28:02 +08:00
}
2013-02-25 03:09:54 +08:00
2013-03-19 03:28:02 +08:00
// At this point we have updated the BayesTree, now update the remaining iSAM2 data structures
// Gather factors to add - the new marginal factors
2013-08-06 06:31:44 +08:00
GaussianFactorGraph factorsToAdd ;
typedef pair < sharedClique , GaussianFactor : : shared_ptr > Clique_Factor ;
2013-03-19 03:28:02 +08:00
BOOST_FOREACH ( const Clique_Factor & clique_factor , marginalFactors ) {
if ( clique_factor . second )
factorsToAdd . push_back ( clique_factor . second ) ;
nonlinearFactors_ . push_back ( boost : : make_shared < LinearContainerFactor > (
clique_factor . second , ordering_ ) ) ;
if ( params_ . cacheLinearizedFactors )
linearFactors_ . push_back ( clique_factor . second ) ;
BOOST_FOREACH ( Index factorIndex , * clique_factor . second ) {
fixedVariables_ . insert ( ordering_ . key ( factorIndex ) ) ; }
2013-02-25 03:09:54 +08:00
}
2013-03-19 03:28:02 +08:00
variableIndex_ . augment ( factorsToAdd ) ; // Augment the variable index
2013-02-25 03:09:54 +08:00
2013-03-19 03:28:02 +08:00
// Remove the factors to remove that have been summarized in the newly-added marginal factors
2013-03-20 21:48:16 +08:00
FastSet < size_t > factorIndicesToRemove ;
BOOST_FOREACH ( Index j , indices ) {
factorIndicesToRemove . insert ( variableIndex_ [ j ] . begin ( ) , variableIndex_ [ j ] . end ( ) ) ; }
2013-02-25 03:09:54 +08:00
vector < size_t > removedFactorIndices ;
2013-08-06 06:31:44 +08:00
SymbolicFactorGraph removedFactors ;
2013-02-25 03:09:54 +08:00
BOOST_FOREACH ( size_t i , factorIndicesToRemove ) {
removedFactorIndices . push_back ( i ) ;
removedFactors . push_back ( nonlinearFactors_ [ i ] - > symbolic ( ordering_ ) ) ;
nonlinearFactors_ . remove ( i ) ;
if ( params_ . cacheLinearizedFactors )
linearFactors_ . remove ( i ) ;
}
2013-03-05 13:47:27 +08:00
variableIndex_ . remove ( removedFactorIndices , removedFactors ) ;
2013-02-25 03:09:54 +08:00
// Remove the marginalized variables
Impl : : RemoveVariables ( FastSet < Key > ( leafKeys . begin ( ) , leafKeys . end ( ) ) , root_ , theta_ , variableIndex_ , delta_ , deltaNewton_ , RgProd_ ,
deltaReplacedMask_ , ordering_ , nodes_ , linearFactors_ , fixedVariables_ ) ;
}
2012-03-17 04:55:21 +08:00
/* ************************************************************************* */
void ISAM2 : : updateDelta ( bool forceFullSolve ) const {
if ( params_ . optimizationParams . type ( ) = = typeid ( ISAM2GaussNewtonParams ) ) {
// If using Gauss-Newton, update with wildfireThreshold
const ISAM2GaussNewtonParams & gaussNewtonParams =
boost : : get < ISAM2GaussNewtonParams > ( params_ . optimizationParams ) ;
const double effectiveWildfireThreshold = forceFullSolve ? 0.0 : gaussNewtonParams . wildfireThreshold ;
2012-10-03 04:18:41 +08:00
gttic ( Wildfire_update ) ;
2012-03-17 04:55:21 +08:00
lastBacksubVariableCount = Impl : : UpdateDelta ( this - > root ( ) , deltaReplacedMask_ , delta_ , effectiveWildfireThreshold ) ;
2012-10-03 04:18:41 +08:00
gttoc ( Wildfire_update ) ;
2012-03-17 04:55:21 +08:00
} else if ( params_ . optimizationParams . type ( ) = = typeid ( ISAM2DoglegParams ) ) {
// If using Dogleg, do a Dogleg step
const ISAM2DoglegParams & doglegParams =
boost : : get < ISAM2DoglegParams > ( params_ . optimizationParams ) ;
// Do one Dogleg iteration
2012-10-03 04:18:41 +08:00
gttic ( Dogleg_Iterate ) ;
2012-03-22 14:18:38 +08:00
DoglegOptimizerImpl : : IterationResult doglegResult ( DoglegOptimizerImpl : : Iterate (
* doglegDelta_ , doglegParams . adaptationMode , * this , nonlinearFactors_ , theta_ , ordering_ , nonlinearFactors_ . error ( theta_ ) , doglegParams . verbose ) ) ;
2012-10-03 04:18:41 +08:00
gttoc ( Dogleg_Iterate ) ;
2012-03-17 04:55:21 +08:00
2012-10-03 04:18:41 +08:00
gttic ( Copy_dx_d ) ;
2012-03-17 04:55:21 +08:00
// Update Delta and linear step
doglegDelta_ = doglegResult . Delta ;
2012-06-30 09:45:21 +08:00
delta_ = doglegResult . dx_d ; // Copy the VectorValues containing with the linear solution
2012-10-03 04:18:41 +08:00
gttoc ( Copy_dx_d ) ;
2012-03-17 04:55:21 +08:00
}
deltaUptodate_ = true ;
}
/* ************************************************************************* */
Values ISAM2 : : calculateEstimate ( ) const {
// We use ExpmapMasked here instead of regular expmap because the former
// handles Permuted<VectorValues>
2012-10-03 04:18:41 +08:00
gttic ( Copy_Values ) ;
2012-05-25 04:11:45 +08:00
Values ret ( theta_ ) ;
2012-10-03 04:18:41 +08:00
gttoc ( Copy_Values ) ;
gttic ( getDelta ) ;
2013-08-06 06:31:44 +08:00
const VectorValues & delta ( getDelta ( ) ) ;
2012-10-03 04:18:41 +08:00
gttoc ( getDelta ) ;
gttic ( Expmap ) ;
2013-01-09 07:31:06 +08:00
vector < bool > mask ( ordering_ . size ( ) , true ) ;
2012-03-20 00:55:52 +08:00
Impl : : ExpmapMasked ( ret , delta , ordering_ , mask ) ;
2012-10-03 04:18:41 +08:00
gttoc ( Expmap ) ;
2012-03-17 04:55:21 +08:00
return ret ;
}
2013-06-29 10:19:03 +08:00
/* ************************************************************************* */
Matrix ISAM2 : : marginalCovariance ( Index key ) const {
return marginalFactor ( ordering_ [ key ] ,
2013-08-06 06:31:44 +08:00
params_ . factorization = = ISAM2Params : : QR ? EliminateQR : EliminatePreferCholesky )
2013-06-29 10:19:03 +08:00
- > information ( ) . inverse ( ) ;
}
2012-03-17 04:55:21 +08:00
/* ************************************************************************* */
Values ISAM2 : : calculateBestEstimate ( ) const {
2013-08-06 06:31:44 +08:00
VectorValues delta ( theta_ . dims ( ordering_ ) ) ;
2012-03-18 07:57:42 +08:00
internal : : optimizeInPlace < Base > ( this - > root ( ) , delta ) ;
2012-03-17 04:55:21 +08:00
return theta_ . retract ( delta , ordering_ ) ;
}
/* ************************************************************************* */
2013-08-06 06:31:44 +08:00
const VectorValues & ISAM2 : : getDelta ( ) const {
2012-03-17 04:55:21 +08:00
if ( ! deltaUptodate_ )
updateDelta ( ) ;
return delta_ ;
}
2012-03-18 07:57:42 +08:00
/* ************************************************************************* */
2013-08-06 06:31:44 +08:00
VectorValues optimize ( const ISAM2 & isam ) {
2012-10-03 04:18:41 +08:00
gttic ( allocateVectorValues ) ;
2013-08-06 06:31:44 +08:00
VectorValues delta = * allocateVectorValues ( isam ) ;
2012-10-03 04:18:41 +08:00
gttoc ( allocateVectorValues ) ;
2012-03-18 07:57:44 +08:00
optimizeInPlace ( isam , delta ) ;
2012-03-18 07:57:42 +08:00
return delta ;
}
2012-03-18 07:57:44 +08:00
/* ************************************************************************* */
2013-08-06 06:31:44 +08:00
void optimizeInPlace ( const ISAM2 & isam , VectorValues & delta ) {
2013-06-21 00:28:41 +08:00
// We may need to update the solution calculations
2012-03-19 22:32:37 +08:00
if ( ! isam . deltaDoglegUptodate_ ) {
2012-10-03 04:18:41 +08:00
gttic ( UpdateDoglegDeltas ) ;
2012-03-20 00:25:03 +08:00
double wildfireThreshold = 0.0 ;
if ( isam . params ( ) . optimizationParams . type ( ) = = typeid ( ISAM2GaussNewtonParams ) )
wildfireThreshold = boost : : get < ISAM2GaussNewtonParams > ( isam . params ( ) . optimizationParams ) . wildfireThreshold ;
else if ( isam . params ( ) . optimizationParams . type ( ) = = typeid ( ISAM2DoglegParams ) )
wildfireThreshold = boost : : get < ISAM2DoglegParams > ( isam . params ( ) . optimizationParams ) . wildfireThreshold ;
else
assert ( false ) ;
ISAM2 : : Impl : : UpdateDoglegDeltas ( isam , wildfireThreshold , isam . deltaReplacedMask_ , isam . deltaNewton_ , isam . RgProd_ ) ;
2012-03-19 22:32:37 +08:00
isam . deltaDoglegUptodate_ = true ;
2012-10-03 04:18:41 +08:00
gttoc ( UpdateDoglegDeltas ) ;
2012-03-19 22:32:37 +08:00
}
2012-10-03 04:18:41 +08:00
gttic ( copy_delta ) ;
2012-03-19 22:32:37 +08:00
delta = isam . deltaNewton_ ;
2012-10-03 04:18:41 +08:00
gttoc ( copy_delta ) ;
2012-03-18 07:57:44 +08:00
}
2012-03-17 04:55:21 +08:00
/* ************************************************************************* */
2013-08-06 06:31:44 +08:00
VectorValues optimizeGradientSearch ( const ISAM2 & isam ) {
2012-10-03 04:18:41 +08:00
gttic ( Allocate_VectorValues ) ;
2013-08-06 06:31:44 +08:00
VectorValues grad = * allocateVectorValues ( isam ) ;
2012-10-03 04:18:41 +08:00
gttoc ( Allocate_VectorValues ) ;
2012-03-17 04:55:21 +08:00
optimizeGradientSearchInPlace ( isam , grad ) ;
return grad ;
}
/* ************************************************************************* */
2013-08-06 06:31:44 +08:00
void optimizeGradientSearchInPlace ( const ISAM2 & isam , VectorValues & grad ) {
2012-03-19 22:32:37 +08:00
// We may need to update the solution calcaulations
if ( ! isam . deltaDoglegUptodate_ ) {
2012-10-03 04:18:41 +08:00
gttic ( UpdateDoglegDeltas ) ;
2012-03-20 00:25:03 +08:00
double wildfireThreshold = 0.0 ;
if ( isam . params ( ) . optimizationParams . type ( ) = = typeid ( ISAM2GaussNewtonParams ) )
wildfireThreshold = boost : : get < ISAM2GaussNewtonParams > ( isam . params ( ) . optimizationParams ) . wildfireThreshold ;
else if ( isam . params ( ) . optimizationParams . type ( ) = = typeid ( ISAM2DoglegParams ) )
wildfireThreshold = boost : : get < ISAM2DoglegParams > ( isam . params ( ) . optimizationParams ) . wildfireThreshold ;
else
assert ( false ) ;
ISAM2 : : Impl : : UpdateDoglegDeltas ( isam , wildfireThreshold , isam . deltaReplacedMask_ , isam . deltaNewton_ , isam . RgProd_ ) ;
2012-03-19 22:32:37 +08:00
isam . deltaDoglegUptodate_ = true ;
2012-10-03 04:18:41 +08:00
gttoc ( UpdateDoglegDeltas ) ;
2012-03-19 22:32:37 +08:00
}
2012-10-03 04:18:41 +08:00
gttic ( Compute_Gradient ) ;
2012-03-17 04:55:21 +08:00
// Compute gradient (call gradientAtZero function, which is defined for various linear systems)
2012-03-19 22:32:37 +08:00
gradientAtZero ( isam , grad ) ;
2012-03-17 04:55:21 +08:00
double gradientSqNorm = grad . dot ( grad ) ;
2012-10-03 04:18:41 +08:00
gttoc ( Compute_Gradient ) ;
2012-03-17 04:55:21 +08:00
2012-10-03 04:18:41 +08:00
gttic ( Compute_minimizing_step_size ) ;
2012-03-17 04:55:21 +08:00
// Compute minimizing step size
2012-11-24 07:22:53 +08:00
double RgNormSq = isam . RgProd_ . asVector ( ) . squaredNorm ( ) ;
2012-03-19 22:32:37 +08:00
double step = - gradientSqNorm / RgNormSq ;
2012-10-03 04:18:41 +08:00
gttoc ( Compute_minimizing_step_size ) ;
2012-03-17 04:55:21 +08:00
2012-10-03 04:18:41 +08:00
gttic ( Compute_point ) ;
2012-03-17 04:55:21 +08:00
// Compute steepest descent point
2012-12-18 22:21:02 +08:00
scal ( step , grad ) ;
2012-10-03 04:18:41 +08:00
gttoc ( Compute_point ) ;
2012-03-17 04:55:21 +08:00
}
/* ************************************************************************* */
2013-08-06 06:31:44 +08:00
VectorValues gradient ( const ISAM2 & bayesTree , const VectorValues & x0 ) {
return gradient ( FactorGraph < JacobianFactor > ( bayesTree ) , x0 ) ;
2012-03-17 04:55:21 +08:00
}
/* ************************************************************************* */
2013-08-06 06:31:44 +08:00
static void gradientAtZeroTreeAdder ( const boost : : shared_ptr < ISAM2Clique > & root , VectorValues & g ) {
2012-03-17 04:55:21 +08:00
// Loop through variables in each clique, adding contributions
int variablePosition = 0 ;
2013-08-06 06:31:44 +08:00
for ( GaussianConditional : : const_iterator jit = root - > conditional ( ) - > begin ( ) ; jit ! = root - > conditional ( ) - > end ( ) ; + + jit ) {
2012-03-17 04:55:21 +08:00
const int dim = root - > conditional ( ) - > dim ( jit ) ;
g [ * jit ] + = root - > gradientContribution ( ) . segment ( variablePosition , dim ) ;
variablePosition + = dim ;
}
// Recursively add contributions from children
typedef boost : : shared_ptr < ISAM2Clique > sharedClique ;
BOOST_FOREACH ( const sharedClique & child , root - > children ( ) ) {
gradientAtZeroTreeAdder ( child , g ) ;
}
}
/* ************************************************************************* */
2013-08-06 06:31:44 +08:00
void gradientAtZero ( const ISAM2 & bayesTree , VectorValues & g ) {
2012-03-17 04:55:21 +08:00
// Zero-out gradient
g . setZero ( ) ;
// Sum up contributions for each clique
2012-04-04 06:06:06 +08:00
if ( bayesTree . root ( ) )
gradientAtZeroTreeAdder ( bayesTree . root ( ) , g ) ;
2012-03-17 04:55:21 +08:00
}
}
/// namespace gtsam
2013-08-02 05:57:43 +08:00
# endif