258 lines
9.8 KiB
C++
258 lines
9.8 KiB
C++
/* ----------------------------------------------------------------------------
|
|
|
|
* 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 ConcurrentIncrementalSmoother.cpp
|
|
* @brief An iSAM2-based Smoother that implements the
|
|
* Concurrent Filtering and Smoothing interface.
|
|
* @author Stephen Williams
|
|
*/
|
|
|
|
#include <gtsam_unstable/nonlinear/ConcurrentIncrementalSmoother.h>
|
|
#include <gtsam/nonlinear/LinearContainerFactor.h>
|
|
#include <gtsam/base/timing.h>
|
|
#include <gtsam/base/debug.h>
|
|
|
|
namespace gtsam {
|
|
|
|
/* ************************************************************************* */
|
|
void ConcurrentIncrementalSmoother::print(const std::string& s, const KeyFormatter& keyFormatter) const {
|
|
std::cout << s;
|
|
isam2_.print("");
|
|
}
|
|
|
|
/* ************************************************************************* */
|
|
bool ConcurrentIncrementalSmoother::equals(const ConcurrentSmoother& rhs, double tol) const {
|
|
const ConcurrentIncrementalSmoother* smoother = dynamic_cast<const ConcurrentIncrementalSmoother*>(&rhs);
|
|
return smoother
|
|
&& isam2_.equals(smoother->isam2_)
|
|
&& smootherFactors_.equals(smoother->smootherFactors_)
|
|
&& smootherValues_.equals(smoother->smootherValues_)
|
|
&& filterSummarizationFactors_.equals(smoother->filterSummarizationFactors_)
|
|
&& separatorValues_.equals(smoother->separatorValues_)
|
|
&& (filterSummarizationSlots_.size() == smoother->filterSummarizationSlots_.size())
|
|
&& std::equal(filterSummarizationSlots_.begin(), filterSummarizationSlots_.end(), smoother->filterSummarizationSlots_.begin())
|
|
&& smootherSummarization_.equals(smoother->smootherSummarization_);
|
|
}
|
|
|
|
/* ************************************************************************* */
|
|
ConcurrentIncrementalSmoother::Result ConcurrentIncrementalSmoother::update(const NonlinearFactorGraph& newFactors, const Values& newTheta,
|
|
const std::optional<FactorIndices>& removeFactorIndices) {
|
|
|
|
gttic(update);
|
|
|
|
// Create the return result meta-data
|
|
Result result;
|
|
|
|
FastVector<size_t> removedFactors;
|
|
|
|
if(removeFactorIndices){
|
|
// Be very careful to this line
|
|
std::cout << "ConcurrentIncrementalSmoother::update removeFactorIndices - not implemented yet" << std::endl;
|
|
filterSummarizationSlots_.insert(filterSummarizationSlots_.end(), removeFactorIndices->begin(), removeFactorIndices->end());
|
|
// before it was:
|
|
// removedFactors.insert(removedFactors.end(), removeFactorIndices->begin(), removeFactorIndices->end());
|
|
}
|
|
|
|
// Constrain the separator keys to remain in the root
|
|
// Also, mark the separator keys as fixed linearization points
|
|
FastMap<Key,int> constrainedKeys;
|
|
FastList<Key> noRelinKeys;
|
|
for (const auto key : separatorValues_.keys()) {
|
|
constrainedKeys[key] = 1;
|
|
noRelinKeys.push_back(key);
|
|
}
|
|
|
|
// Use iSAM2 to perform an update
|
|
ISAM2Result isam2Result;
|
|
if(isam2_.getFactorsUnsafe().size() + newFactors.size() + smootherFactors_.size() + filterSummarizationFactors_.size() > 0) {
|
|
if(synchronizationUpdatesAvailable_) {
|
|
// Augment any new factors/values with the cached data from the last synchronization
|
|
NonlinearFactorGraph graph(newFactors);
|
|
graph.push_back(smootherFactors_);
|
|
graph.push_back(filterSummarizationFactors_);
|
|
Values values(newTheta);
|
|
// Unfortunately, we must be careful here, as some of the smoother values
|
|
// and/or separator values may have been added previously
|
|
for(const auto key: smootherValues_.keys()) {
|
|
if(!isam2_.getLinearizationPoint().exists(key)) {
|
|
values.insert(key, smootherValues_.at(key));
|
|
}
|
|
}
|
|
for(const auto key: separatorValues_.keys()) {
|
|
if(!isam2_.getLinearizationPoint().exists(key)) {
|
|
values.insert(key, separatorValues_.at(key));
|
|
}
|
|
}
|
|
|
|
// Update the system using iSAM2
|
|
isam2Result = isam2_.update(graph, values, filterSummarizationSlots_, constrainedKeys, noRelinKeys);
|
|
|
|
// Clear out the cache and update the filter summarization slots
|
|
smootherFactors_.resize(0);
|
|
smootherValues_.clear();
|
|
filterSummarizationSlots_.clear();
|
|
filterSummarizationSlots_.insert(filterSummarizationSlots_.end(),
|
|
isam2Result.newFactorsIndices.end()-filterSummarizationFactors_.size(), isam2Result.newFactorsIndices.end());
|
|
filterSummarizationFactors_.resize(0);
|
|
synchronizationUpdatesAvailable_ = false;
|
|
} else {
|
|
// Update the system using iSAM2
|
|
isam2Result = isam2_.update(newFactors, newTheta, FactorIndices(), constrainedKeys, noRelinKeys);
|
|
}
|
|
}
|
|
|
|
// Extract the ConcurrentIncrementalSmoother::Result information
|
|
result.iterations = 1;
|
|
result.linearVariables = separatorValues_.size();
|
|
result.nonlinearVariables = isam2_.getLinearizationPoint().size() - separatorValues_.size();
|
|
result.error = isam2_.getFactorsUnsafe().error(isam2_.calculateEstimate());
|
|
|
|
// Calculate the marginal on the separator from the smoother factors
|
|
if(separatorValues_.size() > 0) {
|
|
gttic(presync);
|
|
updateSmootherSummarization();
|
|
gttoc(presync);
|
|
}
|
|
|
|
gttoc(update);
|
|
|
|
return result;
|
|
}
|
|
|
|
/* ************************************************************************* */
|
|
void ConcurrentIncrementalSmoother::presync() {
|
|
|
|
gttic(presync);
|
|
|
|
gttoc(presync);
|
|
}
|
|
|
|
/* ************************************************************************* */
|
|
void ConcurrentIncrementalSmoother::getSummarizedFactors(NonlinearFactorGraph& summarizedFactors, Values& separatorValues) {
|
|
|
|
gttic(get_summarized_factors);
|
|
|
|
// Copy the previous calculated smoother summarization factors into the output
|
|
summarizedFactors.push_back(smootherSummarization_);
|
|
|
|
// Copy the separator values into the output
|
|
separatorValues.insert(separatorValues_);
|
|
|
|
gttoc(get_summarized_factors);
|
|
}
|
|
|
|
/* ************************************************************************* */
|
|
void ConcurrentIncrementalSmoother::synchronize(const NonlinearFactorGraph& smootherFactors, const Values& smootherValues,
|
|
const NonlinearFactorGraph& summarizedFactors, const Values& separatorValues) {
|
|
|
|
gttic(synchronize);
|
|
|
|
// Store the new smoother factors and values for addition during the next update call
|
|
smootherFactors_ = smootherFactors;
|
|
smootherValues_ = smootherValues;
|
|
|
|
// Store the new filter summarization and separator, to be replaced during the next update call
|
|
filterSummarizationFactors_ = summarizedFactors;
|
|
separatorValues_ = separatorValues;
|
|
|
|
// Flag the next smoother update to include the synchronization data
|
|
synchronizationUpdatesAvailable_ = true;
|
|
|
|
gttoc(synchronize);
|
|
}
|
|
|
|
/* ************************************************************************* */
|
|
void ConcurrentIncrementalSmoother::postsync() {
|
|
|
|
gttic(postsync);
|
|
|
|
gttoc(postsync);
|
|
}
|
|
|
|
/* ************************************************************************* */
|
|
void ConcurrentIncrementalSmoother::updateSmootherSummarization() {
|
|
|
|
// The smoother summarization factors are the resulting marginal factors on the separator
|
|
// variables that result from marginalizing out all of the other variables
|
|
// These marginal factors will be cached for later transmission to the filter using
|
|
// linear container factors
|
|
|
|
// Find all cliques that contain any separator variables
|
|
std::set<ISAM2Clique::shared_ptr> separatorCliques;
|
|
for(Key key: separatorValues_.keys()) {
|
|
ISAM2Clique::shared_ptr clique = isam2_[key];
|
|
separatorCliques.insert( clique );
|
|
}
|
|
|
|
// Create the set of clique keys LC:
|
|
KeyVector cliqueKeys;
|
|
for(const ISAM2Clique::shared_ptr& clique: separatorCliques) {
|
|
for(Key key: clique->conditional()->frontals()) {
|
|
cliqueKeys.push_back(key);
|
|
}
|
|
}
|
|
std::sort(cliqueKeys.begin(), cliqueKeys.end());
|
|
|
|
// Gather all factors that involve only clique keys
|
|
std::set<size_t> cliqueFactorSlots;
|
|
for(Key key: cliqueKeys) {
|
|
for(size_t slot: isam2_.getVariableIndex()[key]) {
|
|
const NonlinearFactor::shared_ptr& factor = isam2_.getFactorsUnsafe().at(slot);
|
|
if(factor) {
|
|
std::set<Key> factorKeys(factor->begin(), factor->end());
|
|
if(std::includes(cliqueKeys.begin(), cliqueKeys.end(), factorKeys.begin(), factorKeys.end())) {
|
|
cliqueFactorSlots.insert(slot);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Remove any factor included in the filter summarization
|
|
for(size_t slot: filterSummarizationSlots_) {
|
|
cliqueFactorSlots.erase(slot);
|
|
}
|
|
|
|
// Create a factor graph from the identified factors
|
|
NonlinearFactorGraph graph;
|
|
for(size_t slot: cliqueFactorSlots) {
|
|
graph.push_back(isam2_.getFactorsUnsafe().at(slot));
|
|
}
|
|
|
|
// Find the set of children of the separator cliques
|
|
std::set<ISAM2Clique::shared_ptr> childCliques;
|
|
// Add all of the children
|
|
for(const ISAM2Clique::shared_ptr& clique: separatorCliques) {
|
|
childCliques.insert(clique->children.begin(), clique->children.end());
|
|
}
|
|
// Remove any separator cliques that were added because they were children of other separator cliques
|
|
for(const ISAM2Clique::shared_ptr& clique: separatorCliques) {
|
|
childCliques.erase(clique);
|
|
}
|
|
|
|
// Augment the factor graph with cached factors from the children
|
|
for(const ISAM2Clique::shared_ptr& clique: childCliques) {
|
|
LinearContainerFactor::shared_ptr factor(new LinearContainerFactor(clique->cachedFactor(), isam2_.getLinearizationPoint()));
|
|
graph.push_back( factor );
|
|
}
|
|
|
|
// Get the set of separator keys
|
|
const KeySet separatorKeys = separatorValues_.keySet();
|
|
|
|
// Calculate the marginal factors on the separator
|
|
smootherSummarization_ = internal::calculateMarginalFactors(graph, isam2_.getLinearizationPoint(), separatorKeys,
|
|
isam2_.params().getEliminationFunction());
|
|
}
|
|
|
|
/* ************************************************************************* */
|
|
|
|
}/// namespace gtsam
|