Cleaned up cpplint errors - no functionality change

release/4.3a0
Frank Dellaert 2018-09-29 00:06:19 -04:00
parent 224299ccb9
commit e6c0d7334f
2 changed files with 401 additions and 243 deletions

View File

@ -247,7 +247,7 @@ ISAM2::relinearizeAffectedFactors(const FastList<Key>& affectedKeys, const KeySe
/* ************************************************************************* */ /* ************************************************************************* */
// find intermediate (linearized) factors from cache that are passed into the affected area // find intermediate (linearized) factors from cache that are passed into the affected area
GaussianFactorGraph ISAM2::getCachedBoundaryFactors(Cliques& orphans) { GaussianFactorGraph ISAM2::getCachedBoundaryFactors(const Cliques& orphans) {
GaussianFactorGraph cachedBoundary; GaussianFactorGraph cachedBoundary;
for(sharedClique orphan: orphans) { for(sharedClique orphan: orphans) {

View File

@ -11,7 +11,8 @@
/** /**
* @file ISAM2.h * @file ISAM2.h
* @brief Incremental update functionality (ISAM2) for BayesTree, with fluid relinearization. * @brief Incremental update functionality (ISAM2) for BayesTree, with fluid
* relinearization.
* @author Michael Kaess, Richard Roberts * @author Michael Kaess, Richard Roberts
*/ */
@ -19,9 +20,12 @@
#pragma once #pragma once
#include <gtsam/nonlinear/NonlinearFactorGraph.h> #include <string>
#include <gtsam/nonlinear/DoglegOptimizerImpl.h> #include <vector>
#include <gtsam/linear/GaussianBayesTree.h> #include <gtsam/linear/GaussianBayesTree.h>
#include <gtsam/nonlinear/DoglegOptimizerImpl.h>
#include <gtsam/nonlinear/NonlinearFactorGraph.h>
#include <boost/variant.hpp> #include <boost/variant.hpp>
@ -34,21 +38,29 @@ namespace gtsam {
* ISAM2Params, which should in turn be passed to ISAM2(const ISAM2Params&). * ISAM2Params, which should in turn be passed to ISAM2(const ISAM2Params&).
*/ */
struct GTSAM_EXPORT ISAM2GaussNewtonParams { struct GTSAM_EXPORT ISAM2GaussNewtonParams {
double wildfireThreshold; ///< Continue updating the linear delta only when changes are above this threshold (default: 0.001) double
wildfireThreshold; ///< Continue updating the linear delta only when
///< changes are above this threshold (default: 0.001)
/** Specify parameters as constructor arguments */ /** Specify parameters as constructor arguments */
ISAM2GaussNewtonParams( ISAM2GaussNewtonParams(
double _wildfireThreshold = 0.001 ///< see ISAM2GaussNewtonParams public variables, ISAM2GaussNewtonParams::wildfireThreshold double _wildfireThreshold =
) : wildfireThreshold(_wildfireThreshold) {} 0.001 ///< see ISAM2GaussNewtonParams public variables,
///< ISAM2GaussNewtonParams::wildfireThreshold
)
: wildfireThreshold(_wildfireThreshold) {}
void print(const std::string str = "") const { void print(const std::string str = "") const {
std::cout << str << "type: ISAM2GaussNewtonParams\n"; using std::cout;
std::cout << str << "wildfireThreshold: " << wildfireThreshold << "\n"; cout << str << "type: ISAM2GaussNewtonParams\n";
std::cout.flush(); cout << str << "wildfireThreshold: " << wildfireThreshold << "\n";
cout.flush();
} }
double getWildfireThreshold() const { return wildfireThreshold; } double getWildfireThreshold() const { return wildfireThreshold; }
void setWildfireThreshold(double wildfireThreshold) { this->wildfireThreshold = wildfireThreshold; } void setWildfireThreshold(double wildfireThreshold) {
this->wildfireThreshold = wildfireThreshold;
}
}; };
/** /**
@ -58,51 +70,81 @@ struct GTSAM_EXPORT ISAM2GaussNewtonParams {
* ISAM2Params, which should in turn be passed to ISAM2(const ISAM2Params&). * ISAM2Params, which should in turn be passed to ISAM2(const ISAM2Params&).
*/ */
struct GTSAM_EXPORT ISAM2DoglegParams { struct GTSAM_EXPORT ISAM2DoglegParams {
double initialDelta; ///< The initial trust region radius for Dogleg double initialDelta; ///< The initial trust region radius for Dogleg
double wildfireThreshold; ///< Continue updating the linear delta only when changes are above this threshold (default: 1e-5) double
DoglegOptimizerImpl::TrustRegionAdaptationMode adaptationMode; ///< See description in DoglegOptimizerImpl::TrustRegionAdaptationMode wildfireThreshold; ///< Continue updating the linear delta only when
bool verbose; ///< Whether Dogleg prints iteration and convergence information ///< changes are above this threshold (default: 1e-5)
DoglegOptimizerImpl::TrustRegionAdaptationMode
adaptationMode; ///< See description in
///< DoglegOptimizerImpl::TrustRegionAdaptationMode
bool
verbose; ///< Whether Dogleg prints iteration and convergence information
/** Specify parameters as constructor arguments */ /** Specify parameters as constructor arguments */
ISAM2DoglegParams( ISAM2DoglegParams(
double _initialDelta = 1.0, ///< see ISAM2DoglegParams::initialDelta double _initialDelta = 1.0, ///< see ISAM2DoglegParams::initialDelta
double _wildfireThreshold = 1e-5, ///< see ISAM2DoglegParams::wildfireThreshold double _wildfireThreshold =
DoglegOptimizerImpl::TrustRegionAdaptationMode _adaptationMode = DoglegOptimizerImpl::SEARCH_EACH_ITERATION, ///< see ISAM2DoglegParams::adaptationMode 1e-5, ///< see ISAM2DoglegParams::wildfireThreshold
bool _verbose = false ///< see ISAM2DoglegParams::verbose DoglegOptimizerImpl::TrustRegionAdaptationMode _adaptationMode =
) : initialDelta(_initialDelta), wildfireThreshold(_wildfireThreshold), DoglegOptimizerImpl::
adaptationMode(_adaptationMode), verbose(_verbose) {} SEARCH_EACH_ITERATION, ///< see ISAM2DoglegParams::adaptationMode
bool _verbose = false ///< see ISAM2DoglegParams::verbose
)
: initialDelta(_initialDelta),
wildfireThreshold(_wildfireThreshold),
adaptationMode(_adaptationMode),
verbose(_verbose) {}
void print(const std::string str = "") const { void print(const std::string str = "") const {
std::cout << str << "type: ISAM2DoglegParams\n"; using std::cout;
std::cout << str << "initialDelta: " << initialDelta << "\n"; cout << str << "type: ISAM2DoglegParams\n";
std::cout << str << "wildfireThreshold: " << wildfireThreshold << "\n"; cout << str << "initialDelta: " << initialDelta << "\n";
std::cout << str << "adaptationMode: " << adaptationModeTranslator(adaptationMode) << "\n"; cout << str << "wildfireThreshold: " << wildfireThreshold << "\n";
std::cout.flush(); cout << str
<< "adaptationMode: " << adaptationModeTranslator(adaptationMode)
<< "\n";
cout.flush();
} }
double getInitialDelta() const { return initialDelta; } double getInitialDelta() const { return initialDelta; }
double getWildfireThreshold() const { return wildfireThreshold; } double getWildfireThreshold() const { return wildfireThreshold; }
std::string getAdaptationMode() const { return adaptationModeTranslator(adaptationMode); }; std::string getAdaptationMode() const {
bool isVerbose() const { return verbose; }; return adaptationModeTranslator(adaptationMode);
}
bool isVerbose() const { return verbose; }
void setInitialDelta(double initialDelta) {
this->initialDelta = initialDelta;
}
void setWildfireThreshold(double wildfireThreshold) {
this->wildfireThreshold = wildfireThreshold;
}
void setAdaptationMode(const std::string& adaptationMode) {
this->adaptationMode = adaptationModeTranslator(adaptationMode);
}
void setVerbose(bool verbose) { this->verbose = verbose; }
void setInitialDelta(double initialDelta) { this->initialDelta = initialDelta; } std::string adaptationModeTranslator(
void setWildfireThreshold(double wildfireThreshold) { this->wildfireThreshold = wildfireThreshold; } const DoglegOptimizerImpl::TrustRegionAdaptationMode& adaptationMode)
void setAdaptationMode(const std::string& adaptationMode) { this->adaptationMode = adaptationModeTranslator(adaptationMode); } const;
void setVerbose(bool verbose) { this->verbose = verbose; }; DoglegOptimizerImpl::TrustRegionAdaptationMode adaptationModeTranslator(
const std::string& adaptationMode) const;
std::string adaptationModeTranslator(const DoglegOptimizerImpl::TrustRegionAdaptationMode& adaptationMode) const;
DoglegOptimizerImpl::TrustRegionAdaptationMode adaptationModeTranslator(const std::string& adaptationMode) const;
}; };
/** /**
* @addtogroup ISAM2 * @addtogroup ISAM2
* Parameters for the ISAM2 algorithm. Default parameter values are listed below. * Parameters for the ISAM2 algorithm. Default parameter values are listed
* below.
*/ */
typedef FastMap<char,Vector> ISAM2ThresholdMap; typedef FastMap<char, Vector> ISAM2ThresholdMap;
typedef ISAM2ThresholdMap::value_type ISAM2ThresholdMapValue; typedef ISAM2ThresholdMap::value_type ISAM2ThresholdMapValue;
struct GTSAM_EXPORT ISAM2Params { struct GTSAM_EXPORT ISAM2Params {
typedef boost::variant<ISAM2GaussNewtonParams, ISAM2DoglegParams> OptimizationParams; ///< Either ISAM2GaussNewtonParams or ISAM2DoglegParams typedef boost::variant<ISAM2GaussNewtonParams, ISAM2DoglegParams>
typedef boost::variant<double, FastMap<char,Vector> > RelinearizationThreshold; ///< Either a constant relinearization threshold or a per-variable-type set of thresholds OptimizationParams; ///< Either ISAM2GaussNewtonParams or
///< ISAM2DoglegParams
typedef boost::variant<double, FastMap<char, Vector> >
RelinearizationThreshold; ///< Either a constant relinearization
///< threshold or a per-variable-type set of
///< thresholds
/** Optimization parameters, this both selects the nonlinear optimization /** Optimization parameters, this both selects the nonlinear optimization
* method and specifies its parameters, either ISAM2GaussNewtonParams or * method and specifies its parameters, either ISAM2GaussNewtonParams or
@ -122,27 +164,36 @@ struct GTSAM_EXPORT ISAM2Params {
* entries would be added with: * entries would be added with:
* \code * \code
FastMap<char,Vector> thresholds; FastMap<char,Vector> thresholds;
thresholds['x'] = (Vector(6) << 0.1, 0.1, 0.1, 0.5, 0.5, 0.5).finished(); // 0.1 rad rotation threshold, 0.5 m translation threshold thresholds['x'] = (Vector(6) << 0.1, 0.1, 0.1, 0.5, 0.5, 0.5).finished();
thresholds['l'] = Vector3(1.0, 1.0, 1.0); // 1.0 m landmark position threshold // 0.1 rad rotation threshold, 0.5 m translation threshold thresholds['l'] =
Vector3(1.0, 1.0, 1.0); // 1.0 m landmark position threshold
params.relinearizeThreshold = thresholds; params.relinearizeThreshold = thresholds;
\endcode \endcode
*/ */
RelinearizationThreshold relinearizeThreshold; RelinearizationThreshold relinearizeThreshold;
int relinearizeSkip; ///< Only relinearize any variables every relinearizeSkip calls to ISAM2::update (default: 10) int relinearizeSkip; ///< Only relinearize any variables every
///< relinearizeSkip calls to ISAM2::update (default:
///< 10)
bool enableRelinearization; ///< Controls whether ISAM2 will ever relinearize any variables (default: true) bool enableRelinearization; ///< Controls whether ISAM2 will ever relinearize
///< any variables (default: true)
bool evaluateNonlinearError; ///< Whether to evaluate the nonlinear error before and after the update, to return in ISAM2Result from update() bool evaluateNonlinearError; ///< Whether to evaluate the nonlinear error
///< before and after the update, to return in
///< ISAM2Result from update()
enum Factorization { CHOLESKY, QR }; enum Factorization { CHOLESKY, QR };
/** Specifies whether to use QR or CHOESKY numerical factorization (default: CHOLESKY). /** Specifies whether to use QR or CHOESKY numerical factorization (default:
* Cholesky is faster but potentially numerically unstable for poorly-conditioned problems, which can occur when * CHOLESKY). Cholesky is faster but potentially numerically unstable for
* uncertainty is very low in some variables (or dimensions of variables) and very high in others. QR is * poorly-conditioned problems, which can occur when uncertainty is very low
* slower but more numerically stable in poorly-conditioned problems. We suggest using the default of Cholesky * in some variables (or dimensions of variables) and very high in others. QR
* unless gtsam sometimes throws IndefiniteLinearSystemException when your problem's Hessian is actually positive * is slower but more numerically stable in poorly-conditioned problems. We
* definite. For positive definite problems, numerical error accumulation can cause the problem to become * suggest using the default of Cholesky unless gtsam sometimes throws
* numerically negative or indefinite as solving proceeds, especially when using Cholesky. * IndefiniteLinearSystemException when your problem's Hessian is actually
* positive definite. For positive definite problems, numerical error
* accumulation can cause the problem to become numerically negative or
* indefinite as solving proceeds, especially when using Cholesky.
*/ */
Factorization factorization; Factorization factorization;
@ -153,97 +204,156 @@ struct GTSAM_EXPORT ISAM2Params {
*/ */
bool cacheLinearizedFactors; bool cacheLinearizedFactors;
KeyFormatter keyFormatter; ///< A KeyFormatter for when keys are printed during debugging (default: DefaultKeyFormatter) KeyFormatter
keyFormatter; ///< A KeyFormatter for when keys are printed during
///< debugging (default: DefaultKeyFormatter)
bool enableDetailedResults; ///< Whether to compute and return ISAM2Result::detailedResults, this can increase running time (default: false) bool enableDetailedResults; ///< Whether to compute and return
///< ISAM2Result::detailedResults, this can
///< increase running time (default: false)
/** Check variables for relinearization in tree-order, stopping the check once a variable does not need to be relinearized (default: false). /** Check variables for relinearization in tree-order, stopping the check once
* This can improve speed by only checking a small part of the top of the tree. However, variables below the check cut-off can accumulate * a variable does not need to be relinearized (default: false). This can
* significant deltas without triggering relinearization. This is particularly useful in exploration scenarios where real-time performance * improve speed by only checking a small part of the top of the tree.
* is desired over correctness. Use with caution. * However, variables below the check cut-off can accumulate significant
* deltas without triggering relinearization. This is particularly useful in
* exploration scenarios where real-time performance is desired over
* correctness. Use with caution.
*/ */
bool enablePartialRelinearizationCheck; bool enablePartialRelinearizationCheck;
/// When you will be removing many factors, e.g. when using ISAM2 as a fixed-lag smoother, enable this option to /// When you will be removing many factors, e.g. when using ISAM2 as a
/// add factors in the first available factor slots, to avoid accumulating NULL factor slots, at the cost of /// fixed-lag smoother, enable this option to add factors in the first
/// having to search for slots every time a factor is added. /// available factor slots, to avoid accumulating NULL factor slots, at the
/// cost of having to search for slots every time a factor is added.
bool findUnusedFactorSlots; bool findUnusedFactorSlots;
/** Specify parameters as constructor arguments */ /**
ISAM2Params( * Specify parameters as constructor arguments
OptimizationParams _optimizationParams = ISAM2GaussNewtonParams(), ///< see ISAM2Params::optimizationParams * See the documentation of member variables above.
RelinearizationThreshold _relinearizeThreshold = 0.1, ///< see ISAM2Params::relinearizeThreshold */
int _relinearizeSkip = 10, ///< see ISAM2Params::relinearizeSkip ISAM2Params(OptimizationParams _optimizationParams = ISAM2GaussNewtonParams(),
bool _enableRelinearization = true, ///< see ISAM2Params::enableRelinearization RelinearizationThreshold _relinearizeThreshold = 0.1,
bool _evaluateNonlinearError = false, ///< see ISAM2Params::evaluateNonlinearError int _relinearizeSkip = 10, bool _enableRelinearization = true,
Factorization _factorization = ISAM2Params::CHOLESKY, ///< see ISAM2Params::factorization bool _evaluateNonlinearError = false,
bool _cacheLinearizedFactors = true, ///< see ISAM2Params::cacheLinearizedFactors Factorization _factorization = ISAM2Params::CHOLESKY,
const KeyFormatter& _keyFormatter = DefaultKeyFormatter ///< see ISAM2::Params::keyFormatter bool _cacheLinearizedFactors = true,
) : optimizationParams(_optimizationParams), relinearizeThreshold(_relinearizeThreshold), const KeyFormatter& _keyFormatter =
relinearizeSkip(_relinearizeSkip), enableRelinearization(_enableRelinearization), DefaultKeyFormatter ///< see ISAM2::Params::keyFormatter
evaluateNonlinearError(_evaluateNonlinearError), factorization(_factorization), )
cacheLinearizedFactors(_cacheLinearizedFactors), keyFormatter(_keyFormatter), : optimizationParams(_optimizationParams),
enableDetailedResults(false), enablePartialRelinearizationCheck(false), relinearizeThreshold(_relinearizeThreshold),
findUnusedFactorSlots(false) {} relinearizeSkip(_relinearizeSkip),
enableRelinearization(_enableRelinearization),
evaluateNonlinearError(_evaluateNonlinearError),
factorization(_factorization),
cacheLinearizedFactors(_cacheLinearizedFactors),
keyFormatter(_keyFormatter),
enableDetailedResults(false),
enablePartialRelinearizationCheck(false),
findUnusedFactorSlots(false) {}
/// print iSAM2 parameters /// print iSAM2 parameters
void print(const std::string& str = "") const { void print(const std::string& str = "") const {
std::cout << str << "\n"; using std::cout;
if(optimizationParams.type() == typeid(ISAM2GaussNewtonParams)) cout << str << "\n";
boost::get<ISAM2GaussNewtonParams>(optimizationParams).print("optimizationParams: ");
else if(optimizationParams.type() == typeid(ISAM2DoglegParams)) static const std::string kStr("optimizationParams: ");
boost::get<ISAM2DoglegParams>(optimizationParams).print("optimizationParams: "); if (optimizationParams.type() == typeid(ISAM2GaussNewtonParams))
boost::get<ISAM2GaussNewtonParams>(optimizationParams).print();
else if (optimizationParams.type() == typeid(ISAM2DoglegParams))
boost::get<ISAM2DoglegParams>(optimizationParams).print(kStr);
else else
std::cout << "optimizationParams: " << "{unknown type}" << "\n"; cout << kStr << "{unknown type}\n";
if(relinearizeThreshold.type() == typeid(double))
std::cout << "relinearizeThreshold: " << boost::get<double>(relinearizeThreshold) << "\n"; cout << "relinearizeThreshold: ";
else if (relinearizeThreshold.type() == typeid(double)) {
{ cout << boost::get<double>(relinearizeThreshold) << "\n";
std::cout << "relinearizeThreshold: " << "{mapped}" << "\n"; } else {
for(const ISAM2ThresholdMapValue& value: boost::get<ISAM2ThresholdMap>(relinearizeThreshold)) { cout << "{mapped}\n";
std::cout << " '" << value.first << "' -> [" << value.second.transpose() << " ]\n"; for (const ISAM2ThresholdMapValue& value :
boost::get<ISAM2ThresholdMap>(relinearizeThreshold)) {
cout << " '" << value.first
<< "' -> [" << value.second.transpose() << " ]\n";
} }
} }
std::cout << "relinearizeSkip: " << relinearizeSkip << "\n";
std::cout << "enableRelinearization: " << enableRelinearization << "\n"; cout << "relinearizeSkip: " << relinearizeSkip << "\n";
std::cout << "evaluateNonlinearError: " << evaluateNonlinearError << "\n"; cout << "enableRelinearization: " << enableRelinearization
std::cout << "factorization: " << factorizationTranslator(factorization) << "\n"; << "\n";
std::cout << "cacheLinearizedFactors: " << cacheLinearizedFactors << "\n"; cout << "evaluateNonlinearError: " << evaluateNonlinearError
std::cout << "enableDetailedResults: " << enableDetailedResults << "\n"; << "\n";
std::cout << "enablePartialRelinearizationCheck: " << enablePartialRelinearizationCheck << "\n"; cout << "factorization: "
std::cout << "findUnusedFactorSlots: " << findUnusedFactorSlots << "\n"; << factorizationTranslator(factorization) << "\n";
std::cout.flush(); cout << "cacheLinearizedFactors: " << cacheLinearizedFactors
<< "\n";
cout << "enableDetailedResults: " << enableDetailedResults
<< "\n";
cout << "enablePartialRelinearizationCheck: "
<< enablePartialRelinearizationCheck << "\n";
cout << "findUnusedFactorSlots: " << findUnusedFactorSlots
<< "\n";
cout.flush();
} }
/// @name Getters and Setters for all properties /// @name Getters and Setters for all properties
/// @{ /// @{
OptimizationParams getOptimizationParams() const { return this->optimizationParams; } OptimizationParams getOptimizationParams() const {
RelinearizationThreshold getRelinearizeThreshold() const { return relinearizeThreshold; } return this->optimizationParams;
}
RelinearizationThreshold getRelinearizeThreshold() const {
return relinearizeThreshold;
}
int getRelinearizeSkip() const { return relinearizeSkip; } int getRelinearizeSkip() const { return relinearizeSkip; }
bool isEnableRelinearization() const { return enableRelinearization; } bool isEnableRelinearization() const { return enableRelinearization; }
bool isEvaluateNonlinearError() const { return evaluateNonlinearError; } bool isEvaluateNonlinearError() const { return evaluateNonlinearError; }
std::string getFactorization() const { return factorizationTranslator(factorization); } std::string getFactorization() const {
return factorizationTranslator(factorization);
}
bool isCacheLinearizedFactors() const { return cacheLinearizedFactors; } bool isCacheLinearizedFactors() const { return cacheLinearizedFactors; }
KeyFormatter getKeyFormatter() const { return keyFormatter; } KeyFormatter getKeyFormatter() const { return keyFormatter; }
bool isEnableDetailedResults() const { return enableDetailedResults; } bool isEnableDetailedResults() const { return enableDetailedResults; }
bool isEnablePartialRelinearizationCheck() const { return enablePartialRelinearizationCheck; } bool isEnablePartialRelinearizationCheck() const {
return enablePartialRelinearizationCheck;
}
void setOptimizationParams(OptimizationParams optimizationParams) { this->optimizationParams = optimizationParams; } void setOptimizationParams(OptimizationParams optimizationParams) {
void setRelinearizeThreshold(RelinearizationThreshold relinearizeThreshold) { this->relinearizeThreshold = relinearizeThreshold; } this->optimizationParams = optimizationParams;
void setRelinearizeSkip(int relinearizeSkip) { this->relinearizeSkip = relinearizeSkip; } }
void setEnableRelinearization(bool enableRelinearization) { this->enableRelinearization = enableRelinearization; } void setRelinearizeThreshold(RelinearizationThreshold relinearizeThreshold) {
void setEvaluateNonlinearError(bool evaluateNonlinearError) { this->evaluateNonlinearError = evaluateNonlinearError; } this->relinearizeThreshold = relinearizeThreshold;
void setFactorization(const std::string& factorization) { this->factorization = factorizationTranslator(factorization); } }
void setCacheLinearizedFactors(bool cacheLinearizedFactors) { this->cacheLinearizedFactors = cacheLinearizedFactors; } void setRelinearizeSkip(int relinearizeSkip) {
void setKeyFormatter(KeyFormatter keyFormatter) { this->keyFormatter = keyFormatter; } this->relinearizeSkip = relinearizeSkip;
void setEnableDetailedResults(bool enableDetailedResults) { this->enableDetailedResults = enableDetailedResults; } }
void setEnablePartialRelinearizationCheck(bool enablePartialRelinearizationCheck) { this->enablePartialRelinearizationCheck = enablePartialRelinearizationCheck; } void setEnableRelinearization(bool enableRelinearization) {
this->enableRelinearization = enableRelinearization;
}
void setEvaluateNonlinearError(bool evaluateNonlinearError) {
this->evaluateNonlinearError = evaluateNonlinearError;
}
void setFactorization(const std::string& factorization) {
this->factorization = factorizationTranslator(factorization);
}
void setCacheLinearizedFactors(bool cacheLinearizedFactors) {
this->cacheLinearizedFactors = cacheLinearizedFactors;
}
void setKeyFormatter(KeyFormatter keyFormatter) {
this->keyFormatter = keyFormatter;
}
void setEnableDetailedResults(bool enableDetailedResults) {
this->enableDetailedResults = enableDetailedResults;
}
void setEnablePartialRelinearizationCheck(
bool enablePartialRelinearizationCheck) {
this->enablePartialRelinearizationCheck = enablePartialRelinearizationCheck;
}
GaussianFactorGraph::Eliminate getEliminationFunction() const { GaussianFactorGraph::Eliminate getEliminationFunction() const {
return factorization == CHOLESKY return factorization == CHOLESKY
? (GaussianFactorGraph::Eliminate)EliminatePreferCholesky ? (GaussianFactorGraph::Eliminate)EliminatePreferCholesky
: (GaussianFactorGraph::Eliminate)EliminateQR; : (GaussianFactorGraph::Eliminate)EliminateQR;
} }
/// @} /// @}
@ -275,8 +385,9 @@ struct GTSAM_EXPORT ISAM2Result {
* delta, as computed by ISAM2::calculateEstimate(). * delta, as computed by ISAM2::calculateEstimate().
* \li New variables will be evaluated at their initialization points passed * \li New variables will be evaluated at their initialization points passed
* into the current call to update. * into the current call to update.
* \par Note: This will only be computed if ISAM2Params::evaluateNonlinearError * \par Note: This will only be computed if
* is set to \c true, because there is some cost to this computation. * ISAM2Params::evaluateNonlinearError is set to \c true, because there is
* some cost to this computation.
*/ */
boost::optional<double> errorBefore; boost::optional<double> errorBefore;
@ -286,8 +397,9 @@ struct GTSAM_EXPORT ISAM2Result {
* variables have undergone one linear update. Variable values are * variables have undergone one linear update. Variable values are
* again computed by combining their linearization points with their * again computed by combining their linearization points with their
* partial linear deltas, by ISAM2::calculateEstimate(). * partial linear deltas, by ISAM2::calculateEstimate().
* \par Note: This will only be computed if ISAM2Params::evaluateNonlinearError * \par Note: This will only be computed if
* is set to \c true, because there is some cost to this computation. * ISAM2Params::evaluateNonlinearError is set to \c true, because there is
* some cost to this computation.
*/ */
boost::optional<double> errorAfter; boost::optional<double> errorAfter;
@ -309,7 +421,8 @@ struct GTSAM_EXPORT ISAM2Result {
*/ */
size_t variablesReeliminated; size_t variablesReeliminated;
/** The number of factors that were included in reelimination of the Bayes' tree. */ /** The number of factors that were included in reelimination of the Bayes'
* tree. */
size_t factorsRecalculated; size_t factorsRecalculated;
/** The number of cliques in the Bayes' Tree */ /** The number of cliques in the Bayes' Tree */
@ -332,14 +445,29 @@ struct GTSAM_EXPORT ISAM2Result {
* observed, new, or on the path up to the root clique from another * observed, new, or on the path up to the root clique from another
* reeliminated variable. */ * reeliminated variable. */
bool isReeliminated; bool isReeliminated;
bool isAboveRelinThreshold; ///< Whether the variable was just relinearized due to being above the relinearization threshold bool isAboveRelinThreshold; ///< Whether the variable was just
bool isRelinearizeInvolved; ///< Whether the variable was below the relinearization threshold but was relinearized by being involved in a factor with a variable above the relinearization threshold ///< relinearized due to being above the
bool isRelinearized; /// Whether the variable was relinearized, either by being above the relinearization threshold or by involvement. ///< relinearization threshold
bool isObserved; ///< Whether the variable was just involved in new factors bool isRelinearizeInvolved; ///< Whether the variable was below the
bool isNew; ///< Whether the variable itself was just added ///< relinearization threshold but was
bool inRootClique; ///< Whether the variable is in the root clique ///< relinearized by being involved in a
VariableStatus(): isReeliminated(false), isAboveRelinThreshold(false), isRelinearizeInvolved(false), ///< factor with a variable above the
isRelinearized(false), isObserved(false), isNew(false), inRootClique(false) {} ///< relinearization threshold
bool isRelinearized; /// Whether the variable was relinearized, either by
/// being above the relinearization threshold or by
/// involvement.
bool isObserved; ///< Whether the variable was just involved in new
///< factors
bool isNew; ///< Whether the variable itself was just added
bool inRootClique; ///< Whether the variable is in the root clique
VariableStatus()
: isReeliminated(false),
isAboveRelinThreshold(false),
isRelinearizeInvolved(false),
isRelinearized(false),
isObserved(false),
isNew(false),
inRootClique(false) {}
}; };
/** The status of each variable during this update, see VariableStatus. /** The status of each variable during this update, see VariableStatus.
@ -351,24 +479,27 @@ struct GTSAM_EXPORT ISAM2Result {
* Detail for information about the results data stored here. */ * Detail for information about the results data stored here. */
boost::optional<DetailedResults> detail; boost::optional<DetailedResults> detail;
void print(const std::string str = "") const { void print(const std::string str = "") const {
std::cout << str << " Reelimintated: " << variablesReeliminated << " Relinearized: " << variablesRelinearized << " Cliques: " << cliques << std::endl; using std::cout;
cout << str << " Reelimintated: " << variablesReeliminated
<< " Relinearized: " << variablesRelinearized
<< " Cliques: " << cliques << std::endl;
} }
/** Getters and Setters */ /** Getters and Setters */
size_t getVariablesRelinearized() const { return variablesRelinearized; }; size_t getVariablesRelinearized() const { return variablesRelinearized; }
size_t getVariablesReeliminated() const { return variablesReeliminated; }; size_t getVariablesReeliminated() const { return variablesReeliminated; }
size_t getCliques() const { return cliques; }; size_t getCliques() const { return cliques; }
}; };
/** /**
* Specialized Clique structure for ISAM2, incorporating caching and gradient contribution * Specialized Clique structure for ISAM2, incorporating caching and gradient
* contribution
* TODO: more documentation * TODO: more documentation
*/ */
class GTSAM_EXPORT ISAM2Clique : public BayesTreeCliqueBase<ISAM2Clique, GaussianFactorGraph> class GTSAM_EXPORT ISAM2Clique
{ : public BayesTreeCliqueBase<ISAM2Clique, GaussianFactorGraph> {
public: public:
typedef ISAM2Clique This; typedef ISAM2Clique This;
typedef BayesTreeCliqueBase<This, GaussianFactorGraph> Base; typedef BayesTreeCliqueBase<This, GaussianFactorGraph> Base;
typedef boost::shared_ptr<This> shared_ptr; typedef boost::shared_ptr<This> shared_ptr;
@ -383,13 +514,16 @@ public:
/// Default constructor /// Default constructor
ISAM2Clique() : Base() {} ISAM2Clique() : Base() {}
/// Copy constructor, does *not* copy solution pointers as these are invalid in different trees. /// Copy constructor, does *not* copy solution pointers as these are invalid
ISAM2Clique(const ISAM2Clique& other) : /// in different trees.
Base(other), cachedFactor_(other.cachedFactor_), gradientContribution_(other.gradientContribution_) {} ISAM2Clique(const ISAM2Clique& other)
: Base(other),
cachedFactor_(other.cachedFactor_),
gradientContribution_(other.gradientContribution_) {}
/// Assignment operator, does *not* copy solution pointers as these are invalid in different trees. /// Assignment operator, does *not* copy solution pointers as these are
ISAM2Clique& operator=(const ISAM2Clique& other) /// invalid in different trees.
{ ISAM2Clique& operator=(const ISAM2Clique& other) {
Base::operator=(other); Base::operator=(other);
cachedFactor_ = other.cachedFactor_; cachedFactor_ = other.cachedFactor_;
gradientContribution_ = other.gradientContribution_; gradientContribution_ = other.gradientContribution_;
@ -397,7 +531,8 @@ public:
} }
/// Overridden to also store the remaining factor and gradient contribution /// Overridden to also store the remaining factor and gradient contribution
void setEliminationResult(const FactorGraphType::EliminationResult& eliminationResult); void setEliminationResult(
const FactorGraphType::EliminationResult& eliminationResult);
/** Access the cached factor */ /** Access the cached factor */
Base::FactorType::shared_ptr& cachedFactor() { return cachedFactor_; } Base::FactorType::shared_ptr& cachedFactor() { return cachedFactor_; }
@ -405,44 +540,45 @@ public:
/** Access the gradient contribution */ /** Access the gradient contribution */
const Vector& gradientContribution() const { return gradientContribution_; } const Vector& gradientContribution() const { return gradientContribution_; }
bool equals(const This& other, double tol=1e-9) const; bool equals(const This& other, double tol = 1e-9) const;
/** print this node */ /** print this node */
void print(const std::string& s = "", const KeyFormatter& formatter = DefaultKeyFormatter) const; void print(const std::string& s = "",
const KeyFormatter& formatter = DefaultKeyFormatter) const;
private:
private:
/** Serialization function */ /** Serialization function */
friend class boost::serialization::access; friend class boost::serialization::access;
template<class ARCHIVE> template <class ARCHIVE>
void serialize(ARCHIVE & ar, const unsigned int /*version*/) { void serialize(ARCHIVE& ar, const unsigned int /*version*/) {
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base); ar& BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base);
ar & BOOST_SERIALIZATION_NVP(cachedFactor_); ar& BOOST_SERIALIZATION_NVP(cachedFactor_);
ar & BOOST_SERIALIZATION_NVP(gradientContribution_); ar& BOOST_SERIALIZATION_NVP(gradientContribution_);
} }
}; // \struct ISAM2Clique }; // \struct ISAM2Clique
/** /**
* @addtogroup ISAM2 * @addtogroup ISAM2
* Implementation of the full ISAM2 algorithm for incremental nonlinear optimization. * Implementation of the full ISAM2 algorithm for incremental nonlinear
* optimization.
* *
* The typical cycle of using this class to create an instance by providing ISAM2Params * The typical cycle of using this class to create an instance by providing
* to the constructor, then add measurements and variables as they arrive using the update() * ISAM2Params to the constructor, then add measurements and variables as they
* method. At any time, calculateEstimate() may be called to obtain the current * arrive using the update() method. At any time, calculateEstimate() may be
* estimate of all variables. * called to obtain the current estimate of all variables.
* *
*/ */
class GTSAM_EXPORT ISAM2: public BayesTree<ISAM2Clique> { class GTSAM_EXPORT ISAM2 : public BayesTree<ISAM2Clique> {
protected:
protected:
/** The current linearization point */ /** The current linearization point */
Values theta_; Values theta_;
/** VariableIndex lets us look up factors by involved variable and keeps track of dimensions */ /** VariableIndex lets us look up factors by involved variable and keeps track
* of dimensions */
VariableIndex variableIndex_; VariableIndex variableIndex_;
/** The linear delta from the last linear solution, an update to the estimate in theta /** The linear delta from the last linear solution, an update to the estimate
* in theta
* *
* This is \c mutable because it is a "cached" variable - it is not updated * This is \c mutable because it is a "cached" variable - it is not updated
* until either requested with getDelta() or calculateEstimate(), or needed * until either requested with getDelta() or calculateEstimate(), or needed
@ -450,8 +586,10 @@ protected:
*/ */
mutable VectorValues delta_; mutable VectorValues delta_;
mutable VectorValues deltaNewton_; // Only used when using Dogleg - stores the Gauss-Newton update mutable VectorValues deltaNewton_; // Only used when using Dogleg - stores
mutable VectorValues RgProd_; // Only used when using Dogleg - stores R*g and is updated incrementally // the Gauss-Newton update
mutable VectorValues RgProd_; // Only used when using Dogleg - stores R*g and
// is updated incrementally
/** A cumulative mask for the variables that were replaced and have not yet /** A cumulative mask for the variables that were replaced and have not yet
* been updated in the linear solution delta_, this is only used internally, * been updated in the linear solution delta_, this is only used internally,
@ -461,9 +599,11 @@ protected:
* This is \c mutable because it is used internally to not update delta_ * This is \c mutable because it is used internally to not update delta_
* until it is needed. * until it is needed.
*/ */
mutable KeySet deltaReplacedMask_; // TODO: Make sure accessed in the right way mutable KeySet
deltaReplacedMask_; // TODO: Make sure accessed in the right way
/** All original nonlinear factors are stored here to use during relinearization */ /** All original nonlinear factors are stored here to use during
* relinearization */
NonlinearFactorGraph nonlinearFactors_; NonlinearFactorGraph nonlinearFactors_;
/** The current linear factors, which are only updated as needed */ /** The current linear factors, which are only updated as needed */
@ -479,20 +619,21 @@ protected:
* variables and thus cannot have their linearization points changed. */ * variables and thus cannot have their linearization points changed. */
KeySet fixedVariables_; KeySet fixedVariables_;
int update_count_; ///< Counter incremented every update(), used to determine periodic relinearization int update_count_; ///< Counter incremented every update(), used to determine
///< periodic relinearization
public: public:
typedef ISAM2 This; ///< This class
typedef ISAM2 This; ///< This class typedef BayesTree<ISAM2Clique> Base; ///< The BayesTree base class
typedef BayesTree<ISAM2Clique> Base; ///< The BayesTree base class typedef Base::Clique Clique; ///< A clique
typedef Base::Clique Clique; ///< A clique typedef Base::sharedClique sharedClique; ///< Shared pointer to a clique
typedef Base::sharedClique sharedClique; ///< Shared pointer to a clique typedef Base::Cliques Cliques; ///< List of Clique typedef from base class
typedef Base::Cliques Cliques; ///< List of Clique typedef from base class
/** Create an empty ISAM2 instance */ /** Create an empty ISAM2 instance */
ISAM2(const ISAM2Params& params); explicit ISAM2(const ISAM2Params& params);
/** Create an empty ISAM2 instance using the default set of parameters (see ISAM2Params) */ /** Create an empty ISAM2 instance using the default set of parameters (see
* ISAM2Params) */
ISAM2(); ISAM2();
/** default virtual destructor */ /** default virtual destructor */
@ -513,26 +654,31 @@ public:
* thresholds. * thresholds.
* *
* @param newFactors The new factors to be added to the system * @param newFactors The new factors to be added to the system
* @param newTheta Initialization points for new variables to be added to the system. * @param newTheta Initialization points for new variables to be added to the
* You must include here all new variables occuring in newFactors (which were not already * system. You must include here all new variables occuring in newFactors
* in the system). There must not be any variables here that do not occur in newFactors, * (which were not already in the system). There must not be any variables
* and additionally, variables that were already in the system must not be included here. * here that do not occur in newFactors, and additionally, variables that were
* already in the system must not be included here.
* @param removeFactorIndices Indices of factors to remove from system * @param removeFactorIndices Indices of factors to remove from system
* @param force_relinearize Relinearize any variables whose delta magnitude is sufficiently * @param force_relinearize Relinearize any variables whose delta magnitude is
* large (Params::relinearizeThreshold), regardless of the relinearization interval * sufficiently large (Params::relinearizeThreshold), regardless of the
* (Params::relinearizeSkip). * relinearization interval (Params::relinearizeSkip).
* @param constrainedKeys is an optional map of keys to group labels, such that a variable can * @param constrainedKeys is an optional map of keys to group labels, such
* be constrained to a particular grouping in the BayesTree * that a variable can be constrained to a particular grouping in the
* @param noRelinKeys is an optional set of nonlinear keys that iSAM2 will hold at a constant linearization * BayesTree
* point, regardless of the size of the linear delta * @param noRelinKeys is an optional set of nonlinear keys that iSAM2 will
* @param extraReelimKeys is an optional set of nonlinear keys that iSAM2 will re-eliminate, regardless * hold at a constant linearization point, regardless of the size of the
* of the size of the linear delta. This allows the provided keys to be reordered. * linear delta
* @param extraReelimKeys is an optional set of nonlinear keys that iSAM2 will
* re-eliminate, regardless of the size of the linear delta. This allows the
* provided keys to be reordered.
* @return An ISAM2Result struct containing information about the update * @return An ISAM2Result struct containing information about the update
*/ */
virtual ISAM2Result update(const NonlinearFactorGraph& newFactors = NonlinearFactorGraph(), virtual ISAM2Result update(
const NonlinearFactorGraph& newFactors = NonlinearFactorGraph(),
const Values& newTheta = Values(), const Values& newTheta = Values(),
const FactorIndices& removeFactorIndices = FactorIndices(), const FactorIndices& removeFactorIndices = FactorIndices(),
const boost::optional<FastMap<Key,int> >& constrainedKeys = boost::none, const boost::optional<FastMap<Key, int> >& constrainedKeys = boost::none,
const boost::optional<FastList<Key> >& noRelinKeys = boost::none, const boost::optional<FastList<Key> >& noRelinKeys = boost::none,
const boost::optional<FastList<Key> >& extraReelimKeys = boost::none, const boost::optional<FastList<Key> >& extraReelimKeys = boost::none,
bool force_relinearize = false); bool force_relinearize = false);
@ -542,48 +688,50 @@ public:
* requested to be marginalized. Marginalization leaves a linear * requested to be marginalized. Marginalization leaves a linear
* approximation of the marginal in the system, and the linearization points * approximation of the marginal in the system, and the linearization points
* of any variables involved in this linear marginal become fixed. The set * of any variables involved in this linear marginal become fixed. The set
* fixed variables will include any key involved with the marginalized variables * fixed variables will include any key involved with the marginalized
* in the original factors, and possibly additional ones due to fill-in. * variables in the original factors, and possibly additional ones due to
* fill-in.
* *
* If provided, 'marginalFactorsIndices' will be augmented with the factor graph * If provided, 'marginalFactorsIndices' will be augmented with the factor
* indices of the marginal factors added during the 'marginalizeLeaves' call * graph indices of the marginal factors added during the 'marginalizeLeaves'
* call
* *
* If provided, 'deletedFactorsIndices' will be augmented with the factor graph * If provided, 'deletedFactorsIndices' will be augmented with the factor
* indices of any factor that was removed during the 'marginalizeLeaves' call * graph indices of any factor that was removed during the 'marginalizeLeaves'
* call
*/ */
void marginalizeLeaves(const FastList<Key>& leafKeys, void marginalizeLeaves(
boost::optional<FactorIndices&> marginalFactorsIndices = boost::none, const FastList<Key>& leafKeys,
boost::optional<FactorIndices&> deletedFactorsIndices = boost::none); boost::optional<FactorIndices&> marginalFactorsIndices = boost::none,
boost::optional<FactorIndices&> deletedFactorsIndices = boost::none);
/// Access the current linearization point /// Access the current linearization point
const Values& getLinearizationPoint() const { const Values& getLinearizationPoint() const { return theta_; }
return theta_;
}
/// Check whether variable with given key exists in linearization point /// Check whether variable with given key exists in linearization point
bool valueExists(Key key) const { bool valueExists(Key key) const { return theta_.exists(key); }
return theta_.exists(key);
}
/** Compute an estimate from the incomplete linear delta computed during the last update. /** Compute an estimate from the incomplete linear delta computed during the
* This delta is incomplete because it was not updated below wildfire_threshold. If only * last update. This delta is incomplete because it was not updated below
* a single variable is needed, it is faster to call calculateEstimate(const KEY&). * wildfire_threshold. If only a single variable is needed, it is faster to
* call calculateEstimate(const KEY&).
*/ */
Values calculateEstimate() const; Values calculateEstimate() const;
/** Compute an estimate for a single variable using its incomplete linear delta computed /** Compute an estimate for a single variable using its incomplete linear
* during the last update. This is faster than calling the no-argument version of * delta computed during the last update. This is faster than calling the
* calculateEstimate, which operates on all variables. * no-argument version of calculateEstimate, which operates on all variables.
* @param key * @param key
* @return * @return
*/ */
template<class VALUE> template <class VALUE>
VALUE calculateEstimate(Key key) const; VALUE calculateEstimate(Key key) const;
/** Compute an estimate for a single variable using its incomplete linear delta computed /** Compute an estimate for a single variable using its incomplete linear
* during the last update. This is faster than calling the no-argument version of * delta computed during the last update. This is faster than calling the
* calculateEstimate, which operates on all variables. This is a non-templated version * no-argument version of calculateEstimate, which operates on all variables.
* that returns a Value base class for use with the MATLAB wrapper. * This is a non-templated version that returns a Value base class for use
* with the MATLAB wrapper.
* @param key * @param key
* @return * @return
*/ */
@ -598,7 +746,8 @@ public:
/** Internal implementation functions */ /** Internal implementation functions */
struct Impl; struct Impl;
/** Compute an estimate using a complete delta computed by a full back-substitution. /** Compute an estimate using a complete delta computed by a full
* back-substitution.
*/ */
Values calculateBestEstimate() const; Values calculateBestEstimate() const;
@ -609,7 +758,9 @@ public:
double error(const VectorValues& x) const; double error(const VectorValues& x) const;
/** Access the set of nonlinear factors */ /** Access the set of nonlinear factors */
const NonlinearFactorGraph& getFactorsUnsafe() const { return nonlinearFactors_; } const NonlinearFactorGraph& getFactorsUnsafe() const {
return nonlinearFactors_;
}
/** Access the nonlinear variable index */ /** Access the nonlinear variable index */
const VariableIndex& getVariableIndex() const { return variableIndex_; } const VariableIndex& getVariableIndex() const { return variableIndex_; }
@ -628,31 +779,36 @@ public:
/** prints out clique statistics */ /** prints out clique statistics */
void printStats() const { getCliqueData().getStats().print(); } void printStats() const { getCliqueData().getStats().print(); }
/** Compute the gradient of the energy function, \f$ \nabla_{x=0} \left\Vert \Sigma^{-1} R x - d /** Compute the gradient of the energy function, \f$ \nabla_{x=0} \left\Vert
* \right\Vert^2 \f$, centered around zero. The gradient about zero is \f$ -R^T d \f$. See also * \Sigma^{-1} R x - d \right\Vert^2 \f$, centered around zero. The gradient
* gradient(const GaussianBayesNet&, const VectorValues&). * about zero is \f$ -R^T d \f$. See also gradient(const GaussianBayesNet&,
* const VectorValues&).
* *
* @return A VectorValues storing the gradient. * @return A VectorValues storing the gradient.
*/ */
VectorValues gradientAtZero() const; VectorValues gradientAtZero() const;
/// @} /// @}
protected: protected:
FastSet<Key> getAffectedFactors(const FastList<Key>& keys) const; FastSet<Key> getAffectedFactors(const FastList<Key>& keys) const;
GaussianFactorGraph::shared_ptr relinearizeAffectedFactors(const FastList<Key>& affectedKeys, const KeySet& relinKeys) const; GaussianFactorGraph::shared_ptr relinearizeAffectedFactors(
GaussianFactorGraph getCachedBoundaryFactors(Cliques& orphans); const FastList<Key>& affectedKeys, const KeySet& relinKeys) const;
GaussianFactorGraph getCachedBoundaryFactors(const Cliques& orphans);
virtual boost::shared_ptr<KeySet > recalculate(const KeySet& markedKeys, const KeySet& relinKeys, virtual boost::shared_ptr<KeySet> recalculate(
const std::vector<Key>& observedKeys, const KeySet& unusedIndices, const boost::optional<FastMap<Key,int> >& constrainKeys, ISAM2Result& result); const KeySet& markedKeys, const KeySet& relinKeys,
const std::vector<Key>& observedKeys, const KeySet& unusedIndices,
const boost::optional<FastMap<Key, int> >& constrainKeys,
ISAM2Result& result);
void updateDelta(bool forceFullSolve = false) const; void updateDelta(bool forceFullSolve = false) const;
}; // ISAM2 }; // ISAM2
/// traits /// traits
template<> struct traits<ISAM2> : public Testable<ISAM2> {}; template <>
struct traits<ISAM2> : public Testable<ISAM2> {};
/// Optimize the BayesTree, starting from the root. /// Optimize the BayesTree, starting from the root.
/// @param replaced Needs to contain /// @param replaced Needs to contain
@ -665,19 +821,21 @@ template<> struct traits<ISAM2> : public Testable<ISAM2> {};
/// and recursive backsubstitution might eventually stop if none of the changed /// and recursive backsubstitution might eventually stop if none of the changed
/// variables are contained in the subtree. /// variables are contained in the subtree.
/// @return The number of variables that were solved for /// @return The number of variables that were solved for
template<class CLIQUE> template <class CLIQUE>
size_t optimizeWildfire(const boost::shared_ptr<CLIQUE>& root, size_t optimizeWildfire(const boost::shared_ptr<CLIQUE>& root, double threshold,
double threshold, const KeySet& replaced, VectorValues& delta); const KeySet& replaced, VectorValues& delta);
template<class CLIQUE> template <class CLIQUE>
size_t optimizeWildfireNonRecursive(const boost::shared_ptr<CLIQUE>& root, size_t optimizeWildfireNonRecursive(const boost::shared_ptr<CLIQUE>& root,
double threshold, const KeySet& replaced, VectorValues& delta); double threshold, const KeySet& replaced,
VectorValues& delta);
/// calculate the number of non-zero entries for the tree starting at clique (use root for complete matrix) /// calculate the number of non-zero entries for the tree starting at clique
template<class CLIQUE> /// (use root for complete matrix)
template <class CLIQUE>
int calculate_nnz(const boost::shared_ptr<CLIQUE>& clique); int calculate_nnz(const boost::shared_ptr<CLIQUE>& clique);
} /// namespace gtsam } // namespace gtsam
#include <gtsam/nonlinear/ISAM2-inl.h>
#include <gtsam/nonlinear/ISAM2-impl.h> #include <gtsam/nonlinear/ISAM2-impl.h>
#include <gtsam/nonlinear/ISAM2-inl.h>