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
*/
# 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>
2013-08-13 22:21:12 +08:00
# include <boost/range/algorithm/copy.hpp>
2012-07-20 03:50:00 +08:00
# include <boost/algorithm/string.hpp>
2013-08-07 10:56:39 +08:00
namespace br { using namespace boost : : range ; using namespace boost : : adaptors ; }
2012-03-17 04:55:21 +08:00
# include <gtsam/base/timing.h>
# include <gtsam/base/debug.h>
2013-08-09 05:41:29 +08:00
# include <gtsam/inference/BayesTree-inst.h>
2013-08-10 05:35:47 +08:00
# include <gtsam/inference/BayesTreeCliqueBase-inst.h>
2013-08-09 05:41:29 +08:00
# include <gtsam/inference/JunctionTree-inst.h> // We need the inst file because we'll make a special JT templated on ISAM2
2013-08-10 05:35:47 +08:00
# include <gtsam/linear/linearAlgorithms-inst.h>
2013-08-06 06:31:33 +08:00
# include <gtsam/linear/HessianFactor.h>
# include <gtsam/linear/GaussianFactorGraph.h>
2013-08-09 05:41:29 +08:00
# include <gtsam/linear/GaussianEliminationTree.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
2013-08-10 05:35:47 +08:00
using namespace std ;
2012-03-17 04:55:21 +08:00
namespace gtsam {
2013-08-10 05:35:47 +08:00
// Instantiate base classes
template class BayesTreeCliqueBase < ISAM2Clique , GaussianFactorGraph > ;
template class BayesTree < ISAM2Clique > ;
2012-03-17 04:55:21 +08:00
static const bool disableReordering = false ;
static const double batchThreshold = 0.65 ;
2013-08-09 05:41:29 +08:00
/* ************************************************************************* */
// Special BayesTree class that uses ISAM2 cliques - this is the result of reeliminating ISAM2
// subtrees.
class ISAM2BayesTree : public ISAM2 : : Base
{
public :
typedef ISAM2 : : Base Base ;
typedef ISAM2BayesTree This ;
typedef boost : : shared_ptr < This > shared_ptr ;
ISAM2BayesTree ( ) { }
} ;
/* ************************************************************************* */
// Special JunctionTree class that produces ISAM2 BayesTree cliques, used for reeliminating ISAM2
// subtrees.
class ISAM2JunctionTree : public JunctionTree < ISAM2BayesTree , GaussianFactorGraph >
{
public :
typedef JunctionTree < ISAM2BayesTree , GaussianFactorGraph > Base ;
typedef ISAM2JunctionTree This ;
typedef boost : : shared_ptr < This > shared_ptr ;
ISAM2JunctionTree ( const GaussianEliminationTree & eliminationTree ) :
2013-08-27 23:53:30 +08:00
Base ( eliminationTree ) { }
2013-08-09 05:41:29 +08:00
} ;
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 ;
}
2013-08-07 10:56:39 +08:00
/* ************************************************************************* */
2013-08-10 05:35:47 +08:00
void ISAM2Clique : : setEliminationResult ( const FactorGraphType : : EliminationResult & eliminationResult )
2013-08-07 10:56:39 +08:00
{
conditional_ = eliminationResult . first ;
cachedFactor_ = eliminationResult . second ;
// Compute gradient contribution
gradientContribution_ . resize ( conditional_ - > cols ( ) - 1 ) ;
// Rewrite -(R * P')'*d as -(d' * R * P')' for computational speed reasons
2013-08-10 05:35:47 +08:00
gradientContribution_ < < - conditional_ - > get_R ( ) . transpose ( ) * conditional_ - > get_d ( ) ,
2013-08-07 10:56:39 +08:00
- conditional_ - > get_S ( ) . transpose ( ) * conditional_ - > get_d ( ) ;
}
/* ************************************************************************* */
bool ISAM2Clique : : equals ( const This & other , double tol ) const {
return Base : : equals ( other ) & &
( ( ! cachedFactor_ & & ! other . cachedFactor_ )
| | ( cachedFactor_ & & other . cachedFactor_
& & cachedFactor_ - > equals ( * other . cachedFactor_ , tol ) ) ) ;
}
/* ************************************************************************* */
void ISAM2Clique : : print ( const std : : string & s , const KeyFormatter & formatter ) const
{
Base : : print ( s , formatter ) ;
if ( cachedFactor_ )
cachedFactor_ - > print ( s + " Cached: " , formatter ) ;
else
std : : cout < < s < < " Cached empty " < < std : : endl ;
if ( gradientContribution_ . rows ( ) ! = 0 )
gtsam : : print ( gradientContribution_ , " Gradient contribution: " ) ;
}
2012-03-17 04:55:21 +08:00
/* ************************************************************************* */
2014-03-28 04:15:29 +08:00
ISAM2 : : ISAM2 ( const ISAM2Params & params ) : params_ ( params ) , update_count_ ( 0 ) {
2012-03-17 04:55:21 +08:00
if ( params_ . optimizationParams . type ( ) = = typeid ( ISAM2DoglegParams ) )
doglegDelta_ = boost : : get < ISAM2DoglegParams > ( params_ . optimizationParams ) . initialDelta ;
}
/* ************************************************************************* */
2014-03-28 04:15:29 +08:00
ISAM2 : : ISAM2 ( ) : update_count_ ( 0 ) {
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
/* ************************************************************************* */
2013-08-10 05:35:47 +08:00
bool ISAM2 : : equals ( const ISAM2 & other , double tol ) const {
return Base : : equals ( other , tol )
& & theta_ . equals ( other . theta_ , tol ) & & variableIndex_ . equals ( other . variableIndex_ , tol )
& & nonlinearFactors_ . equals ( other . nonlinearFactors_ , tol )
& & fixedVariables_ = = other . fixedVariables_ ;
2012-04-07 02:56:07 +08:00
}
2012-03-17 04:55:21 +08:00
/* ************************************************************************* */
2013-08-15 03:28:45 +08:00
FastSet < size_t > ISAM2 : : getAffectedFactors ( const FastList < Key > & keys ) const {
2012-03-17 04:55:21 +08:00
static const bool debug = false ;
if ( debug ) cout < < " Getting affected factors for " ;
2013-08-07 10:56:39 +08:00
if ( debug ) { BOOST_FOREACH ( const Key key , keys ) { cout < < key < < " " ; } }
2012-03-17 04:55:21 +08:00
if ( debug ) cout < < endl ;
2013-08-07 10:56:39 +08:00
NonlinearFactorGraph allAffected ;
2013-08-15 03:28:45 +08:00
FastSet < size_t > indices ;
2013-08-07 10:56:39 +08:00
BOOST_FOREACH ( const Key key , keys ) {
2013-08-06 06:31:44 +08:00
const VariableIndex : : Factors & factors ( variableIndex_ [ key ] ) ;
2013-08-15 03:28:45 +08:00
indices . insert ( factors . begin ( ) , factors . end ( ) ) ;
2012-03-17 04:55:21 +08:00
}
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
2013-08-07 10:56:39 +08:00
GaussianFactorGraph : : shared_ptr
ISAM2 : : relinearizeAffectedFactors ( const FastList < Key > & affectedKeys , const FastSet < Key > & relinKeys ) const
{
2012-10-03 04:18:41 +08:00
gttic ( getAffectedFactors ) ;
2013-08-15 03:28:45 +08:00
FastSet < 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
2013-08-07 10:56:39 +08:00
FastSet < Key > affectedKeysSet ;
2012-03-17 04:55:21 +08:00
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-07 10:56:39 +08:00
GaussianFactorGraph : : shared_ptr linearized = boost : : make_shared < GaussianFactorGraph > ( ) ;
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 ( ) ) {
2013-08-07 10:56:39 +08:00
if ( affectedKeysSet . find ( key ) = = affectedKeysSet . end ( ) ) {
2012-03-17 04:55:21 +08:00
inside = false ;
break ;
}
2013-08-07 10:56:39 +08:00
if ( useCachedLinear & & relinKeys . find ( key ) ! = relinKeys . end ( ) )
2012-04-11 22:17:59 +08:00
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 ] ) ;
2013-08-07 10:56:39 +08:00
assert ( linearFactors_ [ idx ] - > keys ( ) = = nonlinearFactors_ [ idx ] - > 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-07 10:56:39 +08:00
GaussianFactor : : shared_ptr linearFactor = nonlinearFactors_ [ idx ] - > linearize ( theta_ ) ;
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 ) {
GaussianFactorGraph cachedBoundary ;
2012-03-17 04:55:21 +08:00
BOOST_FOREACH ( sharedClique orphan , orphans ) {
// 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
}
return cachedBoundary ;
}
2013-08-07 10:56:39 +08:00
/* ************************************************************************* */
boost : : shared_ptr < FastSet < Key > > ISAM2 : : recalculate ( const FastSet < Key > & markedKeys , const FastSet < Key > & relinKeys ,
2013-08-13 02:21:23 +08:00
const vector < Key > & observedKeys ,
2013-08-07 10:56:39 +08:00
const FastSet < Key > & unusedIndices ,
const boost : : optional < FastMap < Key , 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: " ;
2013-08-07 10:56:39 +08:00
BOOST_FOREACH ( const Key key , markedKeys ) { cout < < key < < " " ; }
2012-03-17 04:55:21 +08:00
cout < < endl ;
2012-04-12 11:04:32 +08:00
cout < < " observedKeys: " ;
2013-08-07 10:56:39 +08:00
BOOST_FOREACH ( const Key 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-07 10:56:39 +08:00
GaussianBayesNet affectedBayesNet ;
2013-08-16 01:21:20 +08:00
this - > removeTop ( FastVector < Key > ( markedKeys . begin ( ) , markedKeys . end ( ) ) , affectedBayesNet , orphans ) ;
2012-10-03 04:18:41 +08:00
gttoc ( removetop ) ;
2012-03-17 04:55:21 +08:00
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 ) ;
2013-08-07 10:56:39 +08:00
FastList < Key > affectedKeys ;
BOOST_FOREACH ( const ConditionalType : : shared_ptr & conditional , affectedBayesNet )
affectedKeys . insert ( affectedKeys . end ( ) , conditional - > beginFrontals ( ) , conditional - > endFrontals ( ) ) ;
2012-10-03 04:18:41 +08:00
gttoc ( affectedKeys ) ;
2012-03-17 04:55:21 +08:00
2013-11-09 00:35:28 +08:00
boost : : shared_ptr < FastSet < Key > > affectedKeysSet ( new FastSet < Key > ( ) ) ; // Will return this result
2012-03-17 04:55:21 +08:00
2013-08-07 10:56:39 +08:00
if ( affectedKeys . size ( ) > = theta_ . size ( ) * batchThreshold )
{
2013-08-09 05:41:29 +08:00
// Do a batch step - reorder and relinearize all variables
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-07 10:56:39 +08:00
br : : copy ( variableIndex_ | br : : map_keys , std : : inserter ( * affectedKeysSet , affectedKeysSet - > end ( ) ) ) ;
2012-10-03 04:18:41 +08:00
gttoc ( add_keys ) ;
2012-03-17 04:55:21 +08:00
2013-08-09 05:41:29 +08:00
gttic ( ordering ) ;
Ordering order ;
if ( constrainKeys )
{
2014-11-18 05:16:52 +08:00
order = Ordering : : colamdConstrained ( variableIndex_ , * constrainKeys ) ;
2013-08-09 05:41:29 +08:00
}
else
{
if ( theta_ . size ( ) > observedKeys . size ( ) )
{
// Only if some variables are unconstrained
FastMap < Key , int > constraintGroups ;
BOOST_FOREACH ( Key var , observedKeys )
constraintGroups [ var ] = 1 ;
2014-11-18 05:16:52 +08:00
order = Ordering : : colamdConstrained ( variableIndex_ , constraintGroups ) ;
2012-03-25 00:52:55 +08:00
}
2013-08-09 05:41:29 +08:00
else
{
2014-11-18 05:16:52 +08:00
order = Ordering : : colamd ( variableIndex_ ) ;
2012-04-03 04:04:43 +08:00
}
2012-03-17 04:55:21 +08:00
}
2013-08-15 01:39:36 +08:00
gttoc ( ordering ) ;
2012-03-17 04:55:21 +08:00
2012-10-03 04:18:41 +08:00
gttic ( linearize ) ;
2013-08-09 05:41:29 +08:00
GaussianFactorGraph linearized = * nonlinearFactors_ . linearize ( theta_ ) ;
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-10 05:35:47 +08:00
ISAM2BayesTree : : shared_ptr bayesTree = ISAM2JunctionTree ( GaussianEliminationTree ( linearized , variableIndex_ , order ) )
2013-08-09 05:41:29 +08:00
. eliminate ( params_ . getEliminationFunction ( ) ) . first ;
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 ( ) ;
2013-08-10 05:35:47 +08:00
this - > roots_ . insert ( this - > roots_ . end ( ) , bayesTree - > roots ( ) . begin ( ) , bayesTree - > roots ( ) . end ( ) ) ;
this - > nodes_ . insert ( bayesTree - > nodes ( ) . begin ( ) , bayesTree - > nodes ( ) . end ( ) ) ;
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
2013-08-09 05:41:29 +08:00
FastList < Key > affectedAndNewKeys ;
2012-03-17 04:55:21 +08:00
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
2013-11-09 00:35:28 +08:00
if ( debug ) { cout < < " Affected keys: " ; BOOST_FOREACH ( const Key key , affectedKeys ) { cout < < key < < " " ; } cout < < endl ; }
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 ) {
2013-11-09 00:35:28 +08:00
BOOST_FOREACH ( Key key , affectedAndNewKeys ) {
2013-08-09 05:41:29 +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-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
2013-08-10 05:35:47 +08:00
gttic ( orphans ) ;
// Add the orphaned subtrees
BOOST_FOREACH ( const sharedClique & orphan , orphans )
factors + = boost : : make_shared < BayesTreeOrphanWrapper < Clique > > ( orphan ) ;
gttoc ( orphans ) ;
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
2013-08-10 05:35:47 +08:00
VariableIndex affectedFactorsVarIndex ( factors ) ;
gttic ( ordering_constraints ) ;
// Create ordering constraints
FastMap < Key , int > constraintGroups ;
2012-03-25 00:52:55 +08:00
if ( constrainKeys ) {
2013-08-10 05:35:47 +08:00
constraintGroups = * constrainKeys ;
2012-03-25 00:52:55 +08:00
} else {
2013-08-10 05:35:47 +08:00
constraintGroups = FastMap < Key , int > ( ) ;
const int group = observedKeys . size ( ) < affectedFactorsVarIndex . size ( )
? 1 : 0 ;
2013-08-09 05:41:29 +08:00
BOOST_FOREACH ( Key var , observedKeys )
2013-08-10 05:35:47 +08:00
constraintGroups . insert ( make_pair ( var , group ) ) ;
2012-03-25 00:52:55 +08:00
}
2013-08-10 05:35:47 +08:00
2012-10-21 10:09:58 +08:00
// Remove unaffected keys from the constraints
2013-08-20 06:07:31 +08:00
for ( FastMap < Key , int > : : iterator iter = constraintGroups . begin ( ) ; iter ! = constraintGroups . end ( ) ; /*Incremented in loop ++iter*/ ) {
2013-08-10 05:35:47 +08:00
if ( unusedIndices . exists ( iter - > first ) | | ! affectedKeysSet - > exists ( iter - > first ) )
2013-08-20 06:07:31 +08:00
constraintGroups . erase ( iter + + ) ;
else
+ + iter ;
2013-08-10 05:35:47 +08:00
}
gttoc ( ordering_constraints ) ;
// Generate ordering
gttic ( Ordering ) ;
2014-11-18 05:16:52 +08:00
Ordering ordering = Ordering : : colamdConstrained ( affectedFactorsVarIndex , constraintGroups ) ;
2013-08-15 03:25:02 +08:00
gttoc ( Ordering ) ;
2013-08-10 05:35:47 +08:00
ISAM2BayesTree : : shared_ptr bayesTree = ISAM2JunctionTree ( GaussianEliminationTree (
factors , affectedFactorsVarIndex , ordering ) ) . eliminate ( params_ . getEliminationFunction ( ) ) . first ;
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 ) ;
2013-08-10 05:35:47 +08:00
this - > roots_ . insert ( this - > roots_ . end ( ) , bayesTree - > roots ( ) . begin ( ) , bayesTree - > roots ( ) . end ( ) ) ;
this - > nodes_ . insert ( bayesTree - > nodes ( ) . begin ( ) , bayesTree - > nodes ( ) . end ( ) ) ;
2012-10-03 04:18:41 +08:00
gttoc ( reassemble ) ;
2012-03-17 04:55:21 +08:00
2013-08-09 05:41:29 +08:00
// 4. The orphans have already been inserted during elimination
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
2013-08-13 22:17:05 +08:00
if ( params_ . enableDetailedResults ) {
2013-08-09 05:41:29 +08:00
BOOST_FOREACH ( const sharedNode & root , this - > roots ( ) )
2013-08-10 05:35:47 +08:00
BOOST_FOREACH ( Key var , * root - > conditional ( ) )
2013-08-09 05:41:29 +08:00
result . detail - > variableStatus [ var ] . inRootClique = true ;
2013-08-13 22:17:05 +08:00
}
2012-04-12 11:04:32 +08:00
return affectedKeysSet ;
2012-03-17 04:55:21 +08:00
}
/* ************************************************************************* */
ISAM2Result ISAM2 : : update (
2013-08-13 02:21:23 +08:00
const NonlinearFactorGraph & newFactors , const Values & newTheta , const vector < size_t > & removeFactorIndices ,
2013-04-09 02:05:48 +08:00
const boost : : optional < FastMap < Key , int > > & constrainedKeys , const boost : : optional < FastList < Key > > & noRelinKeys ,
2013-08-15 01:39:36 +08:00
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
2013-08-15 01:39:36 +08:00
gttic ( ISAM2_update ) ;
2014-03-28 04:15:29 +08:00
this - > update_count_ + + ;
2012-03-17 04:55:21 +08:00
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 ( ) ;
2014-03-28 04:15:29 +08:00
const bool relinearizeThisStep = force_relinearize
| | ( params_ . enableRelinearization & & update_count_ % params_ . relinearizeSkip = = 0 ) ;
2012-03-17 04:55:21 +08:00
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
// 1. Add any new factors \Factors:=\Factors\cup\Factors'.
2013-11-19 03:23:09 +08:00
// Add the new factor indices to the result struct
2012-03-17 04:55:21 +08:00
if ( debug | | verbose ) newFactors . print ( " The new factors are: " ) ;
2013-11-19 03:23:09 +08:00
Impl : : AddFactorsStep1 ( newFactors , params_ . findUnusedFactorSlots , nonlinearFactors_ , result . newFactorsIndices ) ;
2012-03-17 04:55:21 +08:00
// 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
2013-08-10 05:35:47 +08:00
variableIndex_ . remove ( removeFactorIndices . begin ( ) , removeFactorIndices . end ( ) , removeFactors ) ;
2012-07-01 06:32:49 +08:00
2012-10-02 22:40:07 +08:00
// Compute unused keys and indices
FastSet < Key > unusedKeys ;
2013-11-09 00:35:28 +08:00
FastSet < Key > unusedIndices ;
2012-10-02 22:40:07 +08:00
{
// 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 ( ) ) {
2013-08-09 05:41:29 +08:00
if ( variableIndex_ [ key ] . empty ( ) )
2012-10-02 22:40:07 +08:00
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 ) {
2013-08-09 05:41:29 +08:00
unusedIndices . insert ( unusedIndices . end ( ) , key ) ;
2012-10-02 22:40:07 +08:00
}
}
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}.
2013-08-10 05:35:47 +08:00
Impl : : AddVariables ( newTheta , theta_ , delta_ , deltaNewton_ , RgProd_ ) ;
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
2013-08-09 05:41:29 +08:00
FastSet < Key > markedKeys = newFactors . keys ( ) ; // Get keys from new factors
2012-07-07 02:33:01 +08:00
// Also mark keys involved in removed factors
{
2013-11-09 00:35:28 +08:00
FastSet < Key > markedRemoveKeys = removeFactors . keys ( ) ; // Get keys involved in removed factors
2012-07-07 02:33:01 +08:00
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 ) {
2013-08-09 05:41:29 +08:00
markedKeys . insert ( key ) ;
2013-04-09 02:05:48 +08:00
}
}
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 ) {
2013-08-09 05:41:29 +08:00
BOOST_FOREACH ( Key key , markedKeys ) {
result . detail - > variableStatus [ key ] . 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
2013-11-09 00:35:28 +08:00
// vector(size_t count, Key value) instead of the iterator constructor.
FastVector < Key > observedKeys ; observedKeys . reserve ( markedKeys . size ( ) ) ;
BOOST_FOREACH ( Key index , markedKeys ) {
2012-10-02 22:40:07 +08:00
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
2013-11-09 00:35:28 +08:00
FastSet < Key > 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 )
2013-08-09 05:41:29 +08:00
relinKeys = Impl : : CheckRelinearizationPartial ( roots_ , delta_ , params_ . relinearizeThreshold ) ;
2012-06-29 04:46:53 +08:00
else
2013-08-09 05:41:29 +08:00
relinKeys = Impl : : CheckRelinearizationFull ( delta_ , params_ . relinearizeThreshold ) ;
if ( disableReordering ) relinKeys = Impl : : CheckRelinearizationFull ( delta_ , 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_ ) {
2013-08-09 05:41:29 +08:00
relinKeys . erase ( key ) ;
2013-02-25 03:09:54 +08:00
}
2013-02-21 23:59:50 +08:00
if ( noRelinKeys ) {
BOOST_FOREACH ( Key key , * noRelinKeys ) {
2013-08-09 05:41:29 +08:00
relinKeys . erase ( key ) ;
2013-02-21 23:59:50 +08:00
}
}
2012-04-12 11:04:32 +08:00
// Above relin threshold keys for detailed results
if ( params_ . enableDetailedResults ) {
2013-08-09 05:41:29 +08:00
BOOST_FOREACH ( Key key , relinKeys ) {
result . detail - > variableStatus [ key ] . isAboveRelinThreshold = true ;
result . detail - > variableStatus [ key ] . 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-08-09 05:41:29 +08:00
FastSet < Key > markedRelinMask ;
BOOST_FOREACH ( const Key key , relinKeys )
markedRelinMask . insert ( key ) ;
2012-03-17 04:55:21 +08:00
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.
2013-08-09 05:41:29 +08:00
if ( ! relinKeys . empty ( ) ) {
BOOST_FOREACH ( const sharedClique & root , roots_ )
// add other cliques that have the marked ones in the separator
Impl : : FindAll ( root , markedKeys , markedRelinMask ) ;
2012-04-12 11:04:32 +08:00
// Relin involved keys for detailed results
if ( params_ . enableDetailedResults ) {
2013-11-09 00:35:28 +08:00
FastSet < Key > involvedRelinKeys ;
2013-08-09 05:41:29 +08:00
BOOST_FOREACH ( const sharedClique & root , roots_ )
Impl : : FindAll ( root , involvedRelinKeys , markedRelinMask ) ;
BOOST_FOREACH ( Key key , involvedRelinKeys ) {
if ( ! result . detail - > variableStatus [ key ] . isAboveRelinThreshold ) {
result . detail - > variableStatus [ key ] . isRelinearizeInvolved = true ;
result . detail - > variableStatus [ key ] . 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 ( ) )
2013-08-09 05:41:29 +08:00
Impl : : ExpmapMasked ( theta_ , delta_ , 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-09 05:41:29 +08:00
GaussianFactorGraph : : shared_ptr linearFactors = newFactors . linearize ( theta_ ) ;
2013-11-19 03:23:09 +08:00
if ( params_ . findUnusedFactorSlots )
{
linearFactors_ . resize ( nonlinearFactors_ . size ( ) ) ;
for ( size_t newFactorI = 0 ; newFactorI < newFactors . size ( ) ; + + newFactorI )
linearFactors_ [ result . newFactorsIndices [ newFactorI ] ] = ( * linearFactors ) [ newFactorI ] ;
}
else
{
linearFactors_ . push_back ( * linearFactors ) ;
}
2012-04-11 22:17:59 +08:00
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
gttoc ( linearize_new ) ;
2012-03-17 04:55:21 +08:00
2013-11-13 01:02:46 +08:00
gttic ( augment_VI ) ;
// Augment the variable index with the new factors
2013-11-19 03:23:09 +08:00
if ( params_ . findUnusedFactorSlots )
variableIndex_ . augment ( newFactors , result . newFactorsIndices ) ;
else
variableIndex_ . augment ( newFactors ) ;
2013-11-13 01:02:46 +08:00
gttoc ( augment_VI ) ;
2012-10-03 04:18:41 +08:00
gttic ( recalculate ) ;
2012-03-17 04:55:21 +08:00
// 8. Redo top of Bayes tree
2013-08-09 05:41:29 +08:00
boost : : shared_ptr < FastSet < Key > > replacedKeys ;
2012-04-12 11:04:32 +08:00
if ( ! markedKeys . empty ( ) | | ! observedKeys . empty ( ) )
2013-08-09 05:41:29 +08:00
replacedKeys = recalculate ( markedKeys , relinKeys , observedKeys , unusedIndices , constrainedKeys , result ) ;
2012-03-17 04:55:21 +08:00
// Update replaced keys mask (accumulates until back-substitution takes place)
2013-08-10 05:35:47 +08:00
if ( replacedKeys )
deltaReplacedMask_ . insert ( replacedKeys - > begin ( ) , replacedKeys - > end ( ) ) ;
2012-10-03 04:18:41 +08:00
gttoc ( recalculate ) ;
2012-03-17 04:55:21 +08:00
2013-11-19 03:23:09 +08:00
// Update data structures to remove unused keys
2012-08-02 05:31:19 +08:00
if ( ! unusedKeys . empty ( ) ) {
2012-10-03 04:18:41 +08:00
gttic ( remove_variables ) ;
2013-08-10 05:35:47 +08:00
Impl : : RemoveVariables ( unusedKeys , roots_ , theta_ , variableIndex_ , delta_ , deltaNewton_ , RgProd_ ,
deltaReplacedMask_ , Base : : nodes_ , 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 ( ) ;
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-08-14 23:21:10 +08:00
void ISAM2 : : marginalizeLeaves ( const FastList < Key > & leafKeysList ,
boost : : optional < std : : vector < size_t > & > marginalFactorsIndices ,
boost : : optional < std : : vector < size_t > & > deletedFactorsIndices )
2013-02-25 03:09:54 +08:00
{
2013-08-09 05:41:29 +08:00
// Convert to ordered set
FastSet < Key > leafKeys ( leafKeysList . begin ( ) , leafKeysList . end ( ) ) ;
2013-02-25 03:09:54 +08:00
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-21 01:33:10 +08:00
// multimap<sharedClique, GaussianFactor::shared_ptr> marginalFactors;
2013-11-09 00:35:28 +08:00
map < Key , vector < GaussianFactor : : shared_ptr > > marginalFactors ;
2013-03-19 03:28:02 +08:00
2013-11-06 00:06:06 +08:00
// Keep track of factors that get summarized by removing cliques
FastSet < size_t > factorIndicesToRemove ;
// Keep track of variables removed in subtrees
FastSet < Key > leafKeysRemoved ;
2013-03-19 03:28:02 +08:00
// Remove each variable and its subtrees
2013-11-06 00:06:06 +08:00
BOOST_FOREACH ( Key j , leafKeys ) {
if ( ! leafKeysRemoved . exists ( j ) ) { // If the index was not already removed by removing another subtree
// Traverse up the tree to find the root of the marginalized subtree
2013-03-19 03:28:02 +08:00
sharedClique clique = nodes_ [ j ] ;
2013-11-06 00:06:06 +08:00
while ( ! clique - > parent_ . _empty ( ) )
{
// Check if parent contains a marginalized leaf variable. Only need to check the first
// variable because it is the closest to the leaves.
sharedClique parent = clique - > parent ( ) ;
if ( leafKeys . exists ( parent - > conditional ( ) - > front ( ) ) )
clique = parent ;
else
break ;
}
2013-03-19 03:28:02 +08:00
// See if we should remove the whole clique
bool marginalizeEntireClique = true ;
2013-08-09 05:41:29 +08:00
BOOST_FOREACH ( Key frontal , clique - > conditional ( ) - > frontals ( ) ) {
if ( ! leafKeys . exists ( frontal ) ) {
2013-03-19 03:28:02 +08:00
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.
2013-08-21 01:33:10 +08:00
marginalFactors [ clique - > parent ( ) - > conditional ( ) - > front ( ) ] . push_back ( marginalFactor ) ;
2013-03-19 03:28:02 +08:00
// 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 ) {
2013-08-21 01:33:10 +08:00
marginalFactors . erase ( removedClique - > conditional ( ) - > front ( ) ) ;
2013-11-06 00:06:06 +08:00
leafKeysRemoved . insert ( removedClique - > conditional ( ) - > beginFrontals ( ) , removedClique - > conditional ( ) - > endFrontals ( ) ) ;
BOOST_FOREACH ( Key frontal , removedClique - > conditional ( ) - > frontals ( ) )
{
// Add to factors to remove
const VariableIndex : : Factors & involvedFactors = variableIndex_ [ frontal ] ;
factorIndicesToRemove . insert ( involvedFactors . begin ( ) , involvedFactors . end ( ) ) ;
// Check for non-leaf keys
2013-08-09 05:41:29 +08:00
if ( ! leafKeys . exists ( frontal ) )
2013-11-06 00:06:06 +08:00
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 ;
2013-08-09 05:41:29 +08:00
BOOST_FOREACH ( const sharedClique & child , clique - > children ) {
2013-03-19 03:28:02 +08:00
// Remove subtree if child depends on any marginalized keys
2013-08-09 05:41:29 +08:00
BOOST_FOREACH ( Key parent , child - > conditional ( ) - > parents ( ) ) {
if ( leafKeys . exists ( parent ) ) {
2013-03-19 03:28:02 +08:00
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-08-21 01:33:10 +08:00
marginalFactors . erase ( removedClique - > conditional ( ) - > front ( ) ) ;
2013-11-06 00:06:06 +08:00
leafKeysRemoved . insert ( removedClique - > conditional ( ) - > beginFrontals ( ) , removedClique - > conditional ( ) - > endFrontals ( ) ) ;
BOOST_FOREACH ( Key frontal , removedClique - > conditional ( ) - > frontals ( ) )
{
// Add to factors to remove
const VariableIndex : : Factors & involvedFactors = variableIndex_ [ frontal ] ;
factorIndicesToRemove . insert ( involvedFactors . begin ( ) , involvedFactors . end ( ) ) ;
// Check for non-leaf keys
2013-08-09 05:41:29 +08:00
if ( ! leafKeys . exists ( frontal ) )
2013-11-06 00:06:06 +08:00
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-20 21:48:16 +08:00
}
2013-03-05 13:47:27 +08:00
}
2013-03-19 03:28:02 +08:00
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.
2013-11-06 00:06:06 +08:00
// TODO: reuse cached linear factors
FastSet < size_t > factorsFromMarginalizedInClique_step1 ;
2013-08-09 05:41:29 +08:00
BOOST_FOREACH ( Key frontal , clique - > conditional ( ) - > frontals ( ) ) {
if ( leafKeys . exists ( frontal ) )
2013-11-06 00:06:06 +08:00
factorsFromMarginalizedInClique_step1 . insert ( variableIndex_ [ frontal ] . begin ( ) , variableIndex_ [ frontal ] . end ( ) ) ; }
// Remove any factors in subtrees that we're removing at this step
2013-03-20 21:48:16 +08:00
BOOST_FOREACH ( const sharedClique & removedChild , childrenRemoved ) {
2013-11-09 00:35:28 +08:00
BOOST_FOREACH ( Key indexInClique , removedChild - > conditional ( ) - > frontals ( ) ) {
2013-03-20 21:48:16 +08:00
BOOST_FOREACH ( size_t factorInvolving , variableIndex_ [ indexInClique ] ) {
2013-11-06 00:06:06 +08:00
factorsFromMarginalizedInClique_step1 . erase ( factorInvolving ) ; } } }
// Create factor graph from factor indices
BOOST_FOREACH ( size_t i , factorsFromMarginalizedInClique_step1 ) {
2013-08-09 05:41:29 +08:00
graph . push_back ( nonlinearFactors_ [ i ] - > linearize ( theta_ ) ) ; }
2013-03-19 03:28:02 +08:00
// Reeliminate the linear graph to get the marginal and discard the conditional
2013-11-09 00:35:28 +08:00
const FastSet < Key > cliqueFrontals ( clique - > conditional ( ) - > beginFrontals ( ) , clique - > conditional ( ) - > endFrontals ( ) ) ;
FastVector < Key > cliqueFrontalsToEliminate ;
2013-08-09 05:41:29 +08:00
std : : set_intersection ( cliqueFrontals . begin ( ) , cliqueFrontals . end ( ) , leafKeys . begin ( ) , leafKeys . end ( ) ,
2013-11-06 00:06:06 +08:00
std : : back_inserter ( cliqueFrontalsToEliminate ) ) ;
2013-08-09 05:41:29 +08:00
pair < GaussianConditional : : shared_ptr , GaussianFactor : : shared_ptr > eliminationResult1 =
2013-11-06 00:06:06 +08:00
params_ . getEliminationFunction ( ) ( graph , Ordering ( cliqueFrontalsToEliminate ) ) ;
2013-03-19 03:28:02 +08:00
// Add the resulting marginal
2013-08-09 05:41:29 +08:00
if ( eliminationResult1 . second )
2013-08-21 01:33:10 +08:00
marginalFactors [ clique - > conditional ( ) - > front ( ) ] . push_back ( eliminationResult1 . second ) ;
2013-03-19 03:28:02 +08:00
2013-11-06 00:06:06 +08:00
// Split the current clique
// Find the position of the last leaf key in this clique
DenseIndex nToRemove = 0 ;
while ( leafKeys . exists ( clique - > conditional ( ) - > keys ( ) [ nToRemove ] ) )
+ + nToRemove ;
// Make the clique's matrix appear as a subset
const DenseIndex dimToRemove = clique - > conditional ( ) - > matrixObject ( ) . offset ( nToRemove ) ;
clique - > conditional ( ) - > matrixObject ( ) . firstBlock ( ) = nToRemove ;
clique - > conditional ( ) - > matrixObject ( ) . rowStart ( ) = dimToRemove ;
// Change the keys in the clique
FastVector < Key > originalKeys ; originalKeys . swap ( clique - > conditional ( ) - > keys ( ) ) ;
clique - > conditional ( ) - > keys ( ) . assign ( originalKeys . begin ( ) + nToRemove , originalKeys . end ( ) ) ;
clique - > conditional ( ) - > nrFrontals ( ) - = nToRemove ;
// Add to factors to remove factors involved in frontals of current clique
BOOST_FOREACH ( Key frontal , cliqueFrontalsToEliminate )
{
const VariableIndex : : Factors & involvedFactors = variableIndex_ [ frontal ] ;
factorIndicesToRemove . insert ( involvedFactors . begin ( ) , involvedFactors . end ( ) ) ;
}
// Add removed keys
leafKeysRemoved . insert ( cliqueFrontalsToEliminate . begin ( ) , cliqueFrontalsToEliminate . end ( ) ) ;
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 ;
2013-08-21 01:33:10 +08:00
typedef pair < Key , vector < GaussianFactor : : shared_ptr > > Key_Factors ;
BOOST_FOREACH ( const Key_Factors & key_factors , marginalFactors ) {
BOOST_FOREACH ( const GaussianFactor : : shared_ptr & factor , key_factors . second ) {
if ( factor ) {
factorsToAdd . push_back ( factor ) ;
if ( marginalFactorsIndices )
marginalFactorsIndices - > push_back ( nonlinearFactors_ . size ( ) ) ;
nonlinearFactors_ . push_back ( boost : : make_shared < LinearContainerFactor > (
factor ) ) ;
if ( params_ . cacheLinearizedFactors )
linearFactors_ . push_back ( factor ) ;
BOOST_FOREACH ( Key factorKey , * factor ) {
fixedVariables_ . insert ( factorKey ) ; }
}
}
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-08-10 05:35:47 +08:00
NonlinearFactorGraph removedFactors ;
2013-02-25 03:09:54 +08:00
BOOST_FOREACH ( size_t i , factorIndicesToRemove ) {
2013-08-10 05:35:47 +08:00
removedFactors . push_back ( nonlinearFactors_ [ i ] ) ;
2013-02-25 03:09:54 +08:00
nonlinearFactors_ . remove ( i ) ;
if ( params_ . cacheLinearizedFactors )
linearFactors_ . remove ( i ) ;
}
2013-08-14 23:21:10 +08:00
variableIndex_ . remove ( factorIndicesToRemove . begin ( ) , factorIndicesToRemove . end ( ) , removedFactors ) ;
if ( deletedFactorsIndices )
deletedFactorsIndices - > assign ( factorIndicesToRemove . begin ( ) , factorIndicesToRemove . end ( ) ) ;
2013-02-25 03:09:54 +08:00
// Remove the marginalized variables
2013-08-10 05:35:47 +08:00
Impl : : RemoveVariables ( FastSet < Key > ( leafKeys . begin ( ) , leafKeys . end ( ) ) , roots_ , theta_ , variableIndex_ , delta_ , deltaNewton_ , RgProd_ ,
deltaReplacedMask_ , nodes_ , fixedVariables_ ) ;
2013-02-25 03:09:54 +08:00
}
2012-03-17 04:55:21 +08:00
/* ************************************************************************* */
2013-08-15 01:39:36 +08:00
void ISAM2 : : updateDelta ( bool forceFullSolve ) const
{
gttic ( updateDelta ) ;
2012-03-17 04:55:21 +08:00
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 ) ;
2014-02-23 05:46:38 +08:00
lastBacksubVariableCount = Impl : : UpdateGaussNewtonDelta (
roots_ , deltaReplacedMask_ , delta_ , effectiveWildfireThreshold ) ;
deltaReplacedMask_ . clear ( ) ;
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 ) ;
2014-02-23 05:46:38 +08:00
const double effectiveWildfireThreshold = forceFullSolve ? 0.0 : doglegParams . wildfireThreshold ;
2012-03-17 04:55:21 +08:00
// Do one Dogleg iteration
2012-10-03 04:18:41 +08:00
gttic ( Dogleg_Iterate ) ;
2014-02-23 05:46:38 +08:00
// Compute Newton's method step
gttic ( Wildfire_update ) ;
lastBacksubVariableCount = Impl : : UpdateGaussNewtonDelta ( roots_ , deltaReplacedMask_ , deltaNewton_ , effectiveWildfireThreshold ) ;
gttoc ( Wildfire_update ) ;
// Compute steepest descent step
const VectorValues gradAtZero = this - > gradientAtZero ( ) ; // Compute gradient
Impl : : UpdateRgProd ( roots_ , deltaReplacedMask_ , gradAtZero , RgProd_ ) ; // Update RgProd
const VectorValues dx_u = Impl : : ComputeGradientSearch ( gradAtZero , RgProd_ ) ; // Compute gradient search point
// Clear replaced keys mask because now we've updated deltaNewton_ and RgProd_
deltaReplacedMask_ . clear ( ) ;
// Compute dogleg point
2012-03-22 14:18:38 +08:00
DoglegOptimizerImpl : : IterationResult doglegResult ( DoglegOptimizerImpl : : Iterate (
2014-02-23 05:46:38 +08:00
* doglegDelta_ , doglegParams . adaptationMode , dx_u , deltaNewton_ , * this , nonlinearFactors_ ,
2013-08-10 05:35:47 +08:00
theta_ , 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
}
}
/* ************************************************************************* */
Values ISAM2 : : calculateEstimate ( ) const {
2013-08-15 01:39:36 +08:00
gttic ( ISAM2_calculateEstimate ) ;
2013-08-06 06:31:44 +08:00
const VectorValues & delta ( getDelta ( ) ) ;
2012-10-03 04:18:41 +08:00
gttic ( Expmap ) ;
2014-02-23 05:46:38 +08:00
return theta_ . retract ( delta ) ;
2012-10-03 04:18:41 +08:00
gttoc ( Expmap ) ;
2012-03-17 04:55:21 +08:00
}
2013-06-29 10:19:03 +08:00
/* ************************************************************************* */
2013-08-03 00:04:17 +08:00
const Value & ISAM2 : : calculateEstimate ( Key key ) const {
2013-08-10 05:35:47 +08:00
const Vector & delta = getDelta ( ) [ key ] ;
2013-08-03 00:04:17 +08:00
return * theta_ . at ( key ) . retract_ ( delta ) ;
2013-06-29 10:19:03 +08:00
}
2012-03-17 04:55:21 +08:00
/* ************************************************************************* */
Values ISAM2 : : calculateBestEstimate ( ) const {
2014-02-23 05:46:38 +08:00
updateDelta ( true ) ; // Force full solve when updating delta_
return theta_ . retract ( delta_ ) ;
2012-03-17 04:55:21 +08:00
}
2013-08-03 00:04:17 +08:00
/* ************************************************************************* */
2013-08-10 05:35:47 +08:00
Matrix ISAM2 : : marginalCovariance ( Key key ) const {
return marginalFactor ( key , params_ . getEliminationFunction ( ) ) - > information ( ) . inverse ( ) ;
2013-08-03 00:04:17 +08:00
}
2012-03-17 04:55:21 +08:00
/* ************************************************************************* */
2013-08-06 06:31:44 +08:00
const VectorValues & ISAM2 : : getDelta ( ) const {
2014-02-23 05:46:38 +08:00
if ( ! deltaReplacedMask_ . empty ( ) )
2012-03-17 04:55:21 +08:00
updateDelta ( ) ;
return delta_ ;
}
2012-03-18 07:57:42 +08:00
/* ************************************************************************* */
2013-08-10 05:35:47 +08:00
double ISAM2 : : error ( const VectorValues & x ) const
{
return GaussianFactorGraph ( * this ) . error ( x ) ;
}
2013-08-06 06:31:44 +08:00
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
2013-08-10 05:35:47 +08:00
DenseIndex variablePosition = 0 ;
2013-08-06 06:31:44 +08:00
for ( GaussianConditional : : const_iterator jit = root - > conditional ( ) - > begin ( ) ; jit ! = root - > conditional ( ) - > end ( ) ; + + jit ) {
2013-08-10 05:35:47 +08:00
const DenseIndex dim = root - > conditional ( ) - > getDim ( jit ) ;
pair < VectorValues : : iterator , bool > pos_ins =
g . tryInsert ( * jit , root - > gradientContribution ( ) . segment ( variablePosition , dim ) ) ;
if ( ! pos_ins . second )
pos_ins . first - > second + = root - > gradientContribution ( ) . segment ( variablePosition , dim ) ;
2012-03-17 04:55:21 +08:00
variablePosition + = dim ;
}
// Recursively add contributions from children
typedef boost : : shared_ptr < ISAM2Clique > sharedClique ;
2013-08-10 05:35:47 +08:00
BOOST_FOREACH ( const sharedClique & child , root - > children ) {
2012-03-17 04:55:21 +08:00
gradientAtZeroTreeAdder ( child , g ) ;
}
}
/* ************************************************************************* */
2014-02-23 05:46:38 +08:00
VectorValues ISAM2 : : gradientAtZero ( ) const
{
// Create result
VectorValues g ;
2012-03-17 04:55:21 +08:00
// Sum up contributions for each clique
2014-02-23 05:46:38 +08:00
BOOST_FOREACH ( const ISAM2 : : sharedClique & root , this - > roots ( ) )
gradientAtZeroTreeAdder ( root , g ) ;
return g ;
2012-03-17 04:55:21 +08:00
}
}
/// namespace gtsam