Created Concurrent Incremental Filter and Smoother
							parent
							
								
									663c598591
								
							
						
					
					
						commit
						f656e93202
					
				|  | @ -0,0 +1,410 @@ | |||
| /* ----------------------------------------------------------------------------
 | ||||
| 
 | ||||
|  * 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    ConcurrentIncrementalFilter.cpp | ||||
|  * @brief   An iSAM2-based Filter that implements the | ||||
|  *          Concurrent Filtering and Smoothing interface. | ||||
|  * @author  Stephen Williams | ||||
|  */ | ||||
| #include <gtsam_unstable/nonlinear/ConcurrentIncrementalFilter.h> | ||||
| #include <gtsam/nonlinear/LinearContainerFactor.h> | ||||
| #include <gtsam/base/timing.h> | ||||
| #include <gtsam/base/debug.h> | ||||
| 
 | ||||
| namespace gtsam { | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| void ConcurrentIncrementalFilter::print(const std::string& s, const KeyFormatter& keyFormatter) const { | ||||
|   std::cout << s; | ||||
|   isam2_.print(""); | ||||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| bool ConcurrentIncrementalFilter::equals(const ConcurrentFilter& rhs, double tol) const { | ||||
|   const ConcurrentIncrementalFilter* filter = dynamic_cast<const ConcurrentIncrementalFilter*>(&rhs); | ||||
|   return filter | ||||
|       && isam2_.equals(filter->isam2_) | ||||
|       && (currentSmootherSummarizationSlots_.size() == filter->currentSmootherSummarizationSlots_.size()) | ||||
|       && std::equal(currentSmootherSummarizationSlots_.begin(), currentSmootherSummarizationSlots_.end(), filter->currentSmootherSummarizationSlots_.begin()) | ||||
|       && previousSmootherSummarization_.equals(filter->previousSmootherSummarization_) | ||||
|       && smootherShortcut_.equals(filter->smootherShortcut_) | ||||
|       && smootherFactors_.equals(filter->smootherFactors_) | ||||
|       && smootherValues_.equals(filter->smootherValues_); | ||||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| ConcurrentIncrementalFilter::Result ConcurrentIncrementalFilter::update(const NonlinearFactorGraph& newFactors, const Values& newTheta, const boost::optional<FastList<Key> >& keysToMove) { | ||||
| 
 | ||||
|   gttic(update); | ||||
| 
 | ||||
| //  const bool debug = ISDEBUG("ConcurrentIncrementalFilter update");
 | ||||
|   const bool debug = false; | ||||
| 
 | ||||
|   if(debug) std::cout << "ConcurrentIncrementalFilter::update  Begin" << std::endl; | ||||
| 
 | ||||
|   // Create the return result meta-data
 | ||||
|   Result result; | ||||
| 
 | ||||
|   // We do not need to remove any factors at this time
 | ||||
|   gtsam::FastVector<size_t> removedFactors; | ||||
| 
 | ||||
|   // Generate ordering constraints that force the 'keys to move' to the end
 | ||||
|   boost::optional<gtsam::FastMap<gtsam::Key,int> > orderingConstraints = boost::none; | ||||
|   if(keysToMove && keysToMove->size() > 0) { | ||||
|     orderingConstraints = gtsam::FastMap<gtsam::Key,int>(); | ||||
|     int group = 1; | ||||
|     // Set all existing variables to Group1
 | ||||
|     if(isam2_.getLinearizationPoint().size() > 0) { | ||||
|       BOOST_FOREACH(const gtsam::Values::ConstKeyValuePair& key_value, isam2_.getLinearizationPoint()) { | ||||
|         orderingConstraints->operator[](key_value.key) = group; | ||||
|       } | ||||
|       ++group; | ||||
|     } | ||||
|     // Assign new variables to the root
 | ||||
|     BOOST_FOREACH(const gtsam::Values::ConstKeyValuePair& key_value, newTheta) { | ||||
|       orderingConstraints->operator[](key_value.key) = group; | ||||
|     } | ||||
|     // Set marginalizable variables to Group0
 | ||||
|     BOOST_FOREACH(gtsam::Key key, *keysToMove){ | ||||
|       orderingConstraints->operator[](key) = 0; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // Create the set of linear keys that iSAM2 should hold constant
 | ||||
|   // iSAM2 takes care of this for us; no need to specify additional noRelin keys
 | ||||
|   boost::optional<gtsam::FastList<gtsam::Key> > noRelinKeys = boost::none; | ||||
| 
 | ||||
|   // Mark additional keys between the 'keys to move' and the leaves
 | ||||
|   boost::optional<FastList<Key> > additionalKeys = boost::none; | ||||
|   if(keysToMove && keysToMove->size() > 0) { | ||||
|     std::set<Key> markedKeys; | ||||
|     BOOST_FOREACH(gtsam::Key key, *keysToMove) { | ||||
|       if(isam2_.getLinearizationPoint().exists(key)) { | ||||
|         Index index = isam2_.getOrdering().at(key); | ||||
|         ISAM2Clique::shared_ptr clique = isam2_[index]; | ||||
|         GaussianConditional::const_iterator index_iter = clique->conditional()->begin(); | ||||
|         while(*index_iter != index) { | ||||
|           markedKeys.insert(isam2_.getOrdering().key(*index_iter)); | ||||
|           ++index_iter; | ||||
|         } | ||||
|         BOOST_FOREACH(const gtsam::ISAM2Clique::shared_ptr& child, clique->children()) { | ||||
|           RecursiveMarkAffectedKeys(index, child, isam2_.getOrdering(), markedKeys); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     additionalKeys = FastList<Key>(markedKeys.begin(), markedKeys.end()); | ||||
|   } | ||||
| 
 | ||||
|   // Update the system using iSAM2
 | ||||
|   gttic(isam2); | ||||
|   gtsam::ISAM2Result isam2Result = isam2_.update(newFactors, newTheta, removedFactors, orderingConstraints, noRelinKeys, additionalKeys); | ||||
|   gttoc(isam2); | ||||
| 
 | ||||
|   if(keysToMove && keysToMove->size() > 0) { | ||||
| 
 | ||||
|     gttic(cache_smoother_factors); | ||||
|     // Find the set of factors that will be removed
 | ||||
|     std::vector<size_t> removedFactorSlots = FindAdjacentFactors(isam2_, *keysToMove, currentSmootherSummarizationSlots_); | ||||
|     // Cache these factors for later transmission to the smoother
 | ||||
|     NonlinearFactorGraph removedFactors; | ||||
|     BOOST_FOREACH(size_t slot, removedFactorSlots) { | ||||
|       const NonlinearFactor::shared_ptr& factor = isam2_.getFactorsUnsafe().at(slot); | ||||
|       if(factor) { | ||||
|         smootherFactors_.push_back(factor); | ||||
|         removedFactors.push_back(factor); | ||||
|       } | ||||
|     } | ||||
|     // Cache removed values for later transmission to the smoother
 | ||||
|     BOOST_FOREACH(Key key, *keysToMove) { | ||||
|       smootherValues_.insert(key, isam2_.getLinearizationPoint().at(key)); | ||||
|     } | ||||
|     gttoc(cache_smoother_factors); | ||||
| 
 | ||||
|     gttic(marginalize); | ||||
|     std::vector<size_t> marginalFactorsIndices; | ||||
|     std::vector<size_t> deletedFactorsIndices; | ||||
|     isam2_.marginalizeLeaves(*keysToMove, marginalFactorsIndices, deletedFactorsIndices); | ||||
|     currentSmootherSummarizationSlots_.insert(currentSmootherSummarizationSlots_.end(), marginalFactorsIndices.begin(), marginalFactorsIndices.end()); | ||||
|     BOOST_FOREACH(size_t index, deletedFactorsIndices) { | ||||
|       currentSmootherSummarizationSlots_.erase(std::remove(currentSmootherSummarizationSlots_.begin(), currentSmootherSummarizationSlots_.end(), index), currentSmootherSummarizationSlots_.end()); | ||||
|     } | ||||
|     gttoc(marginalize); | ||||
| 
 | ||||
|     // Calculate a new shortcut
 | ||||
|     updateShortcut(removedFactors); | ||||
|   } | ||||
| 
 | ||||
|   // Extract the ConcurrentIncrementalFilter::Result information
 | ||||
|   result.iterations = 1; | ||||
|   result.linearVariables = isam2_.getFixedVariables().size(); | ||||
|   result.nonlinearVariables = isam2_.getLinearizationPoint().size() - result.linearVariables; | ||||
|   result.error = isam2_.getFactorsUnsafe().error(isam2_.calculateEstimate()); | ||||
| 
 | ||||
|   if(debug) std::cout << "ConcurrentIncrementalFilter::update  End" << std::endl; | ||||
| 
 | ||||
|   gttoc(update); | ||||
| 
 | ||||
|   return result; | ||||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| void ConcurrentIncrementalFilter::presync() { | ||||
| 
 | ||||
|   gttic(presync); | ||||
| 
 | ||||
|   gttoc(presync); | ||||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| void ConcurrentIncrementalFilter::synchronize(const NonlinearFactorGraph& smootherSummarization, const Values& smootherSummarizationValues) { | ||||
| 
 | ||||
|   gttic(synchronize); | ||||
| //  const bool debug = ISDEBUG("ConcurrentIncrementalFilter synchronize");
 | ||||
|   const bool debug = false; | ||||
| 
 | ||||
|   if(debug) std::cout << "ConcurrentIncrementalFilter::synchronize  Begin" << std::endl; | ||||
| 
 | ||||
|   // Update the smoother summarization on the old separator
 | ||||
|   previousSmootherSummarization_ = smootherSummarization; | ||||
| 
 | ||||
|   // Find the set of new separator keys
 | ||||
|   const FastSet<Key>& newSeparatorKeys = isam2_.getFixedVariables(); | ||||
| 
 | ||||
|   // Use the shortcut to calculate an updated marginal on the current separator
 | ||||
|   // Combine just the shortcut and the previousSmootherSummarization
 | ||||
|   NonlinearFactorGraph graph; | ||||
|   graph.push_back(previousSmootherSummarization_); | ||||
|   graph.push_back(smootherShortcut_); | ||||
|   Values values; | ||||
|   values.insert(smootherSummarizationValues); | ||||
|   BOOST_FOREACH(Key key, newSeparatorKeys) { | ||||
|     if(!values.exists(key)) { | ||||
|       values.insert(key, isam2_.getLinearizationPoint().at(key)); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // Force iSAM2 not to relinearize anything during this iteration
 | ||||
|   FastList<Key> noRelinKeys; | ||||
|   BOOST_FOREACH(const Values::ConstKeyValuePair& key_value, isam2_.getLinearizationPoint()) { | ||||
|     noRelinKeys.push_back(key_value.key); | ||||
|   } | ||||
| 
 | ||||
|   // Calculate the summarized factor on just the new separator keys
 | ||||
|   NonlinearFactorGraph currentSmootherSummarization = internal::calculateMarginalFactors(graph, values, newSeparatorKeys, | ||||
|       isam2_.params().factorization == ISAM2Params::CHOLESKY ? EliminateCholesky : EliminateQR); | ||||
| 
 | ||||
|   // Remove the old factors on the separator and insert the new ones
 | ||||
|   FastVector<size_t> removeFactors(currentSmootherSummarizationSlots_.begin(), currentSmootherSummarizationSlots_.end()); | ||||
|   ISAM2Result result = isam2_.update(currentSmootherSummarization, Values(), removeFactors, boost::none, noRelinKeys, boost::none, false); | ||||
|   currentSmootherSummarizationSlots_ = result.newFactorsIndices; | ||||
| 
 | ||||
|   // Set the previous smoother summarization to the current smoother summarization and clear the smoother shortcut
 | ||||
|   previousSmootherSummarization_ = currentSmootherSummarization; | ||||
|   smootherShortcut_.resize(0); | ||||
| 
 | ||||
|   if(debug) std::cout << "ConcurrentIncrementalFilter::synchronize  End" << std::endl; | ||||
| 
 | ||||
|   gttoc(synchronize); | ||||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| void ConcurrentIncrementalFilter::getSummarizedFactors(NonlinearFactorGraph& filterSummarization, Values& filterSummarizationValues) { | ||||
| 
 | ||||
|   gttic(get_summarized_factors); | ||||
| 
 | ||||
|   // Calculate the current filter summarization
 | ||||
|   filterSummarization = calculateFilterSummarization(); | ||||
| 
 | ||||
|   // Copy the current separator values into the output
 | ||||
|   BOOST_FOREACH(Key key, isam2_.getFixedVariables()) { | ||||
|     filterSummarizationValues.insert(key, isam2_.getLinearizationPoint().at(key)); | ||||
|   } | ||||
| 
 | ||||
|   gttoc(get_summarized_factors); | ||||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| void ConcurrentIncrementalFilter::getSmootherFactors(NonlinearFactorGraph& smootherFactors, Values& smootherValues) { | ||||
| 
 | ||||
|   gttic(get_smoother_factors); | ||||
| 
 | ||||
|   // Copy the previous calculated smoother summarization factors into the output
 | ||||
|   smootherFactors.push_back(smootherFactors_); | ||||
|   smootherValues.insert(smootherValues_); | ||||
| 
 | ||||
|   gttoc(get_smoother_factors); | ||||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| void ConcurrentIncrementalFilter::postsync() { | ||||
| 
 | ||||
|   gttic(postsync); | ||||
| 
 | ||||
|   // Clear out the factors and values that were just sent to the smoother
 | ||||
|   smootherFactors_.resize(0); | ||||
|   smootherValues_.clear(); | ||||
| 
 | ||||
|   gttoc(postsync); | ||||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| void ConcurrentIncrementalFilter::RecursiveMarkAffectedKeys(Index index, const ISAM2Clique::shared_ptr& clique, const Ordering& ordering, std::set<Key>& additionalKeys) { | ||||
| 
 | ||||
|   // Check if the separator keys of the current clique contain the specified key
 | ||||
|   if(std::find(clique->conditional()->beginParents(), clique->conditional()->endParents(), index) != clique->conditional()->endParents()) { | ||||
| 
 | ||||
|     // Mark the frontal keys of the current clique
 | ||||
|     BOOST_FOREACH(Index idx, clique->conditional()->frontals()) { | ||||
|       additionalKeys.insert(ordering.key(idx)); | ||||
|     } | ||||
| 
 | ||||
|     // Recursively mark all of the children
 | ||||
|     BOOST_FOREACH(const ISAM2Clique::shared_ptr& child, clique->children()) { | ||||
|       RecursiveMarkAffectedKeys(index, child, ordering, additionalKeys); | ||||
|     } | ||||
|   } | ||||
|   // If the key was not found in the separator/parents, then none of its children can have it either
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| std::vector<size_t> ConcurrentIncrementalFilter::FindAdjacentFactors(const ISAM2& isam2, const FastList<Key>& keys, const std::vector<size_t>& factorsToIgnore) { | ||||
| 
 | ||||
|   // Identify any new factors to be sent to the smoother (i.e. any factor involving keysToMove)
 | ||||
|   std::vector<size_t> removedFactorSlots; | ||||
|   const VariableIndex& variableIndex = isam2.getVariableIndex(); | ||||
|   BOOST_FOREACH(Key key, keys) { | ||||
|     const FastList<size_t>& slots = variableIndex[isam2.getOrdering().at(key)]; | ||||
|     removedFactorSlots.insert(removedFactorSlots.end(), slots.begin(), slots.end()); | ||||
|   } | ||||
| 
 | ||||
|   // Sort and remove duplicates
 | ||||
|   std::sort(removedFactorSlots.begin(), removedFactorSlots.end()); | ||||
|   removedFactorSlots.erase(std::unique(removedFactorSlots.begin(), removedFactorSlots.end()), removedFactorSlots.end()); | ||||
| 
 | ||||
|   // Remove any linear/marginal factor that made it into the set
 | ||||
|   BOOST_FOREACH(size_t index, factorsToIgnore) { | ||||
|     removedFactorSlots.erase(std::remove(removedFactorSlots.begin(), removedFactorSlots.end(), index), removedFactorSlots.end()); | ||||
|   } | ||||
| 
 | ||||
|   return removedFactorSlots; | ||||
| } | ||||
| 
 | ||||
| ///* ************************************************************************* */
 | ||||
| // TODO: Make this a static function
 | ||||
| void ConcurrentIncrementalFilter::updateShortcut(const NonlinearFactorGraph& removedFactors) { | ||||
| 
 | ||||
|   // Calculate the set of shortcut keys: NewSeparatorKeys + OldSeparatorKeys
 | ||||
|   FastSet<Key> shortcutKeys; | ||||
|   BOOST_FOREACH(size_t slot, currentSmootherSummarizationSlots_) { | ||||
|     const NonlinearFactor::shared_ptr& factor = isam2_.getFactorsUnsafe().at(slot); | ||||
|     if(factor) { | ||||
|       shortcutKeys.insert(factor->begin(), factor->end()); | ||||
|     } | ||||
|   } | ||||
|   BOOST_FOREACH(Key key, previousSmootherSummarization_.keys()) { | ||||
|     shortcutKeys.insert(key); | ||||
|   } | ||||
| 
 | ||||
|   // Combine the previous shortcut factor with all of the new factors being sent to the smoother
 | ||||
|   NonlinearFactorGraph graph; | ||||
|   graph.push_back(removedFactors); | ||||
|   graph.push_back(smootherShortcut_); | ||||
|   Values values; | ||||
|   values.insert(smootherValues_); | ||||
|   values.insert(isam2_.getLinearizationPoint()); | ||||
|   // Calculate the summarized factor on the shortcut keys
 | ||||
|   smootherShortcut_ = internal::calculateMarginalFactors(graph, values, shortcutKeys, | ||||
|       isam2_.params().factorization == ISAM2Params::CHOLESKY ? EliminateCholesky : EliminateQR); | ||||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| // TODO: Make this a static function
 | ||||
| NonlinearFactorGraph ConcurrentIncrementalFilter::calculateFilterSummarization() const { | ||||
| 
 | ||||
|   // The filter summarization factors are the resulting marginal factors on the separator
 | ||||
|   // variables that result from marginalizing out all of the other variables
 | ||||
| 
 | ||||
|   // Find the set of current separator keys
 | ||||
|   const FastSet<Key>& separatorKeys = isam2_.getFixedVariables(); | ||||
| 
 | ||||
|   // Find all cliques that contain any separator variables
 | ||||
|   std::set<ISAM2Clique::shared_ptr> separatorCliques; | ||||
|   BOOST_FOREACH(Key key, separatorKeys) { | ||||
|     Index index = isam2_.getOrdering().at(key); | ||||
|     ISAM2Clique::shared_ptr clique = isam2_[index]; | ||||
|     separatorCliques.insert( clique ); | ||||
|   } | ||||
| 
 | ||||
|   // Create the set of clique keys
 | ||||
|   std::vector<Index> cliqueIndices; | ||||
|   std::vector<Key> cliqueKeys; | ||||
|   BOOST_FOREACH(const ISAM2Clique::shared_ptr& clique, separatorCliques) { | ||||
|     BOOST_FOREACH(Index index, clique->conditional()->frontals()) { | ||||
|       cliqueIndices.push_back(index); | ||||
|       cliqueKeys.push_back(isam2_.getOrdering().key(index)); | ||||
|     } | ||||
|   } | ||||
|   std::sort(cliqueIndices.begin(), cliqueIndices.end()); | ||||
|   std::sort(cliqueKeys.begin(), cliqueKeys.end()); | ||||
| 
 | ||||
|   // Gather all factors that involve only clique keys
 | ||||
|   std::set<size_t> cliqueFactorSlots; | ||||
|   BOOST_FOREACH(Index index, cliqueIndices) { | ||||
|     BOOST_FOREACH(size_t slot, isam2_.getVariableIndex()[index]) { | ||||
|       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 current smoother summarization
 | ||||
|   BOOST_FOREACH(size_t slot, currentSmootherSummarizationSlots_) { | ||||
|     cliqueFactorSlots.erase(slot); | ||||
|   } | ||||
| 
 | ||||
|   // Create a factor graph from the identified factors
 | ||||
|   NonlinearFactorGraph graph; | ||||
|   BOOST_FOREACH(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
 | ||||
|   BOOST_FOREACH(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
 | ||||
|   BOOST_FOREACH(const ISAM2Clique::shared_ptr& clique, separatorCliques) { | ||||
|     childCliques.erase(clique); | ||||
|   } | ||||
| 
 | ||||
|   // Augment the factor graph with cached factors from the children
 | ||||
|   BOOST_FOREACH(const ISAM2Clique::shared_ptr& clique, childCliques) { | ||||
|     LinearContainerFactor::shared_ptr factor(new LinearContainerFactor(clique->cachedFactor(), isam2_.getOrdering(), isam2_.getLinearizationPoint())); | ||||
|     graph.push_back( factor ); | ||||
|   } | ||||
| 
 | ||||
|   // Calculate the marginal factors on the separator
 | ||||
|   NonlinearFactorGraph filterSummarization = internal::calculateMarginalFactors(graph, isam2_.getLinearizationPoint(), separatorKeys, | ||||
|       isam2_.params().factorization == ISAM2Params::CHOLESKY ? EliminateCholesky : EliminateQR); | ||||
| 
 | ||||
|   return filterSummarization; | ||||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| }/// namespace gtsam
 | ||||
|  | @ -0,0 +1,189 @@ | |||
| /* ----------------------------------------------------------------------------
 | ||||
| 
 | ||||
|  * 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    ConcurrentBatchFilter.h | ||||
|  * @brief   An iSAM2-based Filter that implements the | ||||
|  *          Concurrent Filtering and Smoothing interface. | ||||
|  * @author  Stephen Williams | ||||
|  */ | ||||
| 
 | ||||
| // \callgraph
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <gtsam_unstable/nonlinear/ConcurrentFilteringAndSmoothing.h> | ||||
| #include <gtsam/nonlinear/ISAM2.h> | ||||
| 
 | ||||
| namespace gtsam { | ||||
| 
 | ||||
| /**
 | ||||
|  * An iSAM2-based Batch Filter that implements the Concurrent Filtering and Smoother interface. | ||||
|  */ | ||||
| class GTSAM_UNSTABLE_EXPORT ConcurrentIncrementalFilter : public virtual ConcurrentFilter { | ||||
| 
 | ||||
| public: | ||||
|   typedef boost::shared_ptr<ConcurrentIncrementalFilter> shared_ptr; | ||||
|   typedef ConcurrentFilter Base; ///< typedef for base class
 | ||||
| 
 | ||||
|   /** Meta information returned about the update */ | ||||
|   struct Result { | ||||
|     size_t iterations; ///< The number of optimizer iterations performed
 | ||||
|     size_t nonlinearVariables; ///< The number of variables that can be relinearized
 | ||||
|     size_t linearVariables; ///< The number of variables that must keep a constant linearization point
 | ||||
|     double error; ///< The final factor graph error
 | ||||
| 
 | ||||
|     /// Constructor
 | ||||
|     Result() : iterations(0), nonlinearVariables(0), linearVariables(0), error(0) {}; | ||||
| 
 | ||||
|     /// Getter methods
 | ||||
|     size_t getIterations() const { return iterations; } | ||||
|     size_t getNonlinearVariables() const { return nonlinearVariables; } | ||||
|     size_t getLinearVariables() const { return linearVariables; } | ||||
|     double getError() const { return error; } | ||||
|   }; | ||||
| 
 | ||||
|   /** Default constructor */ | ||||
|   ConcurrentIncrementalFilter(const ISAM2Params& parameters = ISAM2Params()) : isam2_(parameters) {}; | ||||
| 
 | ||||
|   /** Default destructor */ | ||||
|   virtual ~ConcurrentIncrementalFilter() {}; | ||||
| 
 | ||||
|   /** Implement a GTSAM standard 'print' function */ | ||||
|   virtual void print(const std::string& s = "Concurrent Incremental Filter:\n", const KeyFormatter& keyFormatter = DefaultKeyFormatter) const; | ||||
| 
 | ||||
|   /** Check if two Concurrent Filters are equal */ | ||||
|   virtual bool equals(const ConcurrentFilter& rhs, double tol = 1e-9) const; | ||||
| 
 | ||||
|   /** Access the current set of factors */ | ||||
|   const NonlinearFactorGraph& getFactors() const { | ||||
|     return isam2_.getFactorsUnsafe(); | ||||
|   } | ||||
| 
 | ||||
|   /** Access the current linearization point */ | ||||
|   const Values& getLinearizationPoint() const { | ||||
|     return isam2_.getLinearizationPoint(); | ||||
|   } | ||||
| 
 | ||||
|   /** Access the current ordering */ | ||||
|   const Ordering& getOrdering() const { | ||||
|     return isam2_.getOrdering(); | ||||
|   } | ||||
| 
 | ||||
|   /** Access the current set of deltas to the linearization point */ | ||||
|   const VectorValues& getDelta() const { | ||||
|     return isam2_.getDelta(); | ||||
|   } | ||||
| 
 | ||||
|   /** Compute the current best estimate of all variables and return a full Values structure.
 | ||||
|    * If only a single variable is needed, it may be faster to call calculateEstimate(const KEY&). | ||||
|    */ | ||||
|   Values calculateEstimate() const { | ||||
|     return isam2_.calculateEstimate(); | ||||
|   } | ||||
| 
 | ||||
|   /** Compute the current best estimate of a single variable. This is generally faster than
 | ||||
|    * calling the no-argument version of calculateEstimate if only specific variables are needed. | ||||
|    * @param key | ||||
|    * @return | ||||
|    */ | ||||
|   template<class VALUE> | ||||
|   VALUE calculateEstimate(Key key) const { | ||||
|     return isam2_.calculateEstimate<VALUE>(key); | ||||
|   } | ||||
| 
 | ||||
|   /**
 | ||||
|    * Add new factors and variables to the filter. | ||||
|    * | ||||
|    * Add new measurements, and optionally new variables, to the filter. | ||||
|    * This runs a full update step of the derived filter algorithm | ||||
|    * | ||||
|    * @param newFactors The new factors to be added to the smoother | ||||
|    * @param newTheta Initialization points for new variables to be added to the filter | ||||
|    * You must include here all new variables occurring in newFactors that were not already | ||||
|    * in the filter. | ||||
|    * @param keysToMove An optional set of keys to move from the filter to the smoother | ||||
|    */ | ||||
|   Result update(const NonlinearFactorGraph& newFactors = NonlinearFactorGraph(), const Values& newTheta = Values(), | ||||
|       const boost::optional<FastList<Key> >& keysToMove = boost::none); | ||||
| 
 | ||||
|   /**
 | ||||
|    * Perform any required operations before the synchronization process starts. | ||||
|    * Called by 'synchronize' | ||||
|    */ | ||||
|   virtual void presync(); | ||||
| 
 | ||||
|   /**
 | ||||
|    * Populate the provided containers with factors that constitute the filter branch summarization | ||||
|    * needed by the smoother. Also, linearization points for the new root clique must be provided. | ||||
|    * | ||||
|    * @param summarizedFactors The summarized factors for the filter branch | ||||
|    * @param rootValues The linearization points of the root clique variables | ||||
|    */ | ||||
|   virtual void getSummarizedFactors(NonlinearFactorGraph& filterSummarization, Values& filterSummarizationValues); | ||||
| 
 | ||||
|   /**
 | ||||
|    * Populate the provided containers with factors being sent to the smoother from the filter. These | ||||
|    * may be original nonlinear factors, or factors encoding a summarization of the filter information. | ||||
|    * The specifics will be implementation-specific for a given filter. | ||||
|    * | ||||
|    * @param smootherFactors The new factors to be added to the smoother | ||||
|    * @param smootherValues The linearization points of any new variables | ||||
|    */ | ||||
|   virtual void getSmootherFactors(NonlinearFactorGraph& smootherFactors, Values& smootherValues); | ||||
| 
 | ||||
|   /**
 | ||||
|    * Apply the updated version of the smoother branch summarized factors. | ||||
|    * | ||||
|    * @param summarizedFactors An updated version of the smoother branch summarized factors | ||||
|    */ | ||||
|   virtual void synchronize(const NonlinearFactorGraph& smootherSummarization, const Values& smootherSummarizationValues); | ||||
| 
 | ||||
|   /**
 | ||||
|    * Perform any required operations after the synchronization process finishes. | ||||
|    * Called by 'synchronize' | ||||
|    */ | ||||
|   virtual void postsync(); | ||||
| 
 | ||||
| protected: | ||||
| 
 | ||||
|   ISAM2 isam2_; ///< The iSAM2 inference engine
 | ||||
| 
 | ||||
|   // ???
 | ||||
|   NonlinearFactorGraph previousSmootherSummarization_; ///< The smoother summarization on the old separator sent by the smoother during the last synchronization
 | ||||
|   std::vector<size_t> currentSmootherSummarizationSlots_;  ///< The slots in factor graph that correspond to the current smoother summarization on the current separator
 | ||||
|   NonlinearFactorGraph smootherShortcut_; ///< A set of conditional factors from the old separator to the current separator (recursively calculated during each filter update)
 | ||||
| 
 | ||||
|   // Storage for information to be sent to the smoother
 | ||||
|   NonlinearFactorGraph smootherFactors_;  ///< A temporary holding place for the set of full nonlinear factors being sent to the smoother
 | ||||
|   Values smootherValues_; ///< A temporary holding place for the linearization points of all keys being sent to the smoother
 | ||||
| 
 | ||||
| private: | ||||
| 
 | ||||
|   /** Traverse the iSAM2 Bayes Tree, inserting all descendants of the provided index/key into 'additionalKeys' */ | ||||
|   static void RecursiveMarkAffectedKeys(Index index, const ISAM2Clique::shared_ptr& clique, const Ordering& ordering, std::set<Key>& additionalKeys); | ||||
| 
 | ||||
|   /** Find the set of iSAM2 factors adjacent to 'keys' */ | ||||
|   static std::vector<size_t> FindAdjacentFactors(const ISAM2& isam2, const FastList<Key>& keys, const std::vector<size_t>& factorsToIgnore); | ||||
| 
 | ||||
|   /** Update the shortcut marginal between the current separator keys and the previous separator keys */ | ||||
|   // TODO: Make this a static function
 | ||||
|   void updateShortcut(const NonlinearFactorGraph& removedFactors); | ||||
| 
 | ||||
|   /** Calculate marginal factors on the current separator variables using just the information in the filter */ | ||||
|   // TODO: Make this a static function
 | ||||
|   NonlinearFactorGraph calculateFilterSummarization() const; | ||||
| 
 | ||||
| }; // ConcurrentBatchFilter
 | ||||
| 
 | ||||
| /// Typedef for Matlab wrapping
 | ||||
| typedef ConcurrentIncrementalFilter::Result ConcurrentIncrementalFilterResult; | ||||
| 
 | ||||
| }/// namespace gtsam
 | ||||
|  | @ -0,0 +1,253 @@ | |||
| /* ----------------------------------------------------------------------------
 | ||||
| 
 | ||||
|  * 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) { | ||||
| 
 | ||||
|   gttic(update); | ||||
| 
 | ||||
|   // Create the return result meta-data
 | ||||
|   Result result; | ||||
| 
 | ||||
|   // 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; | ||||
|   BOOST_FOREACH(const Values::ConstKeyValuePair& key_value, separatorValues_) { | ||||
|     constrainedKeys[key_value.key] = 1; | ||||
|     noRelinKeys.push_back(key_value.key); | ||||
|   } | ||||
| 
 | ||||
|   // Use iSAM2 to perform an update
 | ||||
|   gtsam::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
 | ||||
|       BOOST_FOREACH(const Values::ConstKeyValuePair& key_value, smootherValues_) { | ||||
|         if(!isam2_.getLinearizationPoint().exists(key_value.key)) { | ||||
|           values.insert(key_value.key, smootherValues_.at(key_value.key)); | ||||
|         } | ||||
|       } | ||||
|       BOOST_FOREACH(const Values::ConstKeyValuePair& key_value, separatorValues_) { | ||||
|         if(!isam2_.getLinearizationPoint().exists(key_value.key)) { | ||||
|           values.insert(key_value.key, separatorValues_.at(key_value.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, FastVector<size_t>(), 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; | ||||
|   BOOST_FOREACH(const Values::ConstKeyValuePair& key_value, separatorValues_) { | ||||
|     Index index = isam2_.getOrdering().at(key_value.key); | ||||
|     ISAM2Clique::shared_ptr clique = isam2_[index]; | ||||
|     separatorCliques.insert( clique ); | ||||
|   } | ||||
| 
 | ||||
|   // Create the set of clique keys
 | ||||
|   std::vector<Index> cliqueIndices; | ||||
|   std::vector<Key> cliqueKeys; | ||||
|   BOOST_FOREACH(const ISAM2Clique::shared_ptr& clique, separatorCliques) { | ||||
|     BOOST_FOREACH(Index index, clique->conditional()->frontals()) { | ||||
|       cliqueIndices.push_back(index); | ||||
|       cliqueKeys.push_back(isam2_.getOrdering().key(index)); | ||||
|     } | ||||
|   } | ||||
|   std::sort(cliqueIndices.begin(), cliqueIndices.end()); | ||||
|   std::sort(cliqueKeys.begin(), cliqueKeys.end()); | ||||
| 
 | ||||
|   // Gather all factors that involve only clique keys
 | ||||
|   std::set<size_t> cliqueFactorSlots; | ||||
|   BOOST_FOREACH(Index index, cliqueIndices) { | ||||
|     BOOST_FOREACH(size_t slot, isam2_.getVariableIndex()[index]) { | ||||
|       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
 | ||||
|   BOOST_FOREACH(size_t slot, filterSummarizationSlots_) { | ||||
|     cliqueFactorSlots.erase(slot); | ||||
|   } | ||||
| 
 | ||||
|   // Create a factor graph from the identified factors
 | ||||
|   NonlinearFactorGraph graph; | ||||
|   BOOST_FOREACH(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
 | ||||
|   BOOST_FOREACH(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
 | ||||
|   BOOST_FOREACH(const ISAM2Clique::shared_ptr& clique, separatorCliques) { | ||||
|     childCliques.erase(clique); | ||||
|   } | ||||
| 
 | ||||
|   // Augment the factor graph with cached factors from the children
 | ||||
|   BOOST_FOREACH(const ISAM2Clique::shared_ptr& clique, childCliques) { | ||||
|     LinearContainerFactor::shared_ptr factor(new LinearContainerFactor(clique->cachedFactor(), isam2_.getOrdering(), isam2_.getLinearizationPoint())); | ||||
|     graph.push_back( factor ); | ||||
|   } | ||||
| 
 | ||||
|   // Get the set of separator keys
 | ||||
|   gtsam::FastSet<Key> separatorKeys; | ||||
|   BOOST_FOREACH(const Values::ConstKeyValuePair& key_value, separatorValues_) { | ||||
|     separatorKeys.insert(key_value.key); | ||||
|   } | ||||
| 
 | ||||
|   // Calculate the marginal factors on the separator
 | ||||
|   smootherSummarization_ = internal::calculateMarginalFactors(graph, isam2_.getLinearizationPoint(), separatorKeys, | ||||
|       isam2_.params().factorization == ISAM2Params::CHOLESKY ? EliminateCholesky : EliminateQR); | ||||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| 
 | ||||
| }/// namespace gtsam
 | ||||
|  | @ -0,0 +1,175 @@ | |||
| /* ----------------------------------------------------------------------------
 | ||||
| 
 | ||||
|  * 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.h | ||||
|  * @brief   An iSAM2-based Smoother that implements the | ||||
|  *          Concurrent Filtering and Smoothing interface. | ||||
|  * @author  Stephen Williams | ||||
|  */ | ||||
| 
 | ||||
| // \callgraph
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <gtsam_unstable/nonlinear/ConcurrentFilteringAndSmoothing.h> | ||||
| #include <gtsam/nonlinear/ISAM2.h> | ||||
| 
 | ||||
| namespace gtsam { | ||||
| 
 | ||||
| /**
 | ||||
|  * A Levenberg-Marquardt Batch Smoother that implements the Concurrent Filtering and Smoother interface. | ||||
|  */ | ||||
| class GTSAM_UNSTABLE_EXPORT ConcurrentIncrementalSmoother : public virtual ConcurrentSmoother { | ||||
| 
 | ||||
| public: | ||||
|   typedef boost::shared_ptr<ConcurrentIncrementalSmoother> shared_ptr; | ||||
|   typedef ConcurrentSmoother Base; ///< typedef for base class
 | ||||
| 
 | ||||
|   /** Meta information returned about the update */ | ||||
|   struct Result { | ||||
|     size_t iterations; ///< The number of optimizer iterations performed
 | ||||
|     size_t nonlinearVariables; ///< The number of variables that can be relinearized
 | ||||
|     size_t linearVariables; ///< The number of variables that must keep a constant linearization point
 | ||||
|     double error; ///< The final factor graph error
 | ||||
| 
 | ||||
|     /// Constructor
 | ||||
|     Result() : iterations(0), nonlinearVariables(0), linearVariables(0), error(0) {}; | ||||
| 
 | ||||
|     /// Getter methods
 | ||||
|     size_t getIterations() const { return iterations; } | ||||
|     size_t getNonlinearVariables() const { return nonlinearVariables; } | ||||
|     size_t getLinearVariables() const { return linearVariables; } | ||||
|     double getError() const { return error; } | ||||
|   }; | ||||
| 
 | ||||
|   /** Default constructor */ | ||||
|   ConcurrentIncrementalSmoother(const ISAM2Params& parameters = ISAM2Params()) : isam2_(parameters) {}; | ||||
| 
 | ||||
|   /** Default destructor */ | ||||
|   virtual ~ConcurrentIncrementalSmoother() {}; | ||||
| 
 | ||||
|   /** Implement a GTSAM standard 'print' function */ | ||||
|   virtual void print(const std::string& s = "Concurrent Incremental Smoother:\n", const KeyFormatter& keyFormatter = DefaultKeyFormatter) const; | ||||
| 
 | ||||
|   /** Check if two Concurrent Smoothers are equal */ | ||||
|   virtual bool equals(const ConcurrentSmoother& rhs, double tol = 1e-9) const; | ||||
| 
 | ||||
|   /** Access the current set of factors */ | ||||
|   const NonlinearFactorGraph& getFactors() const { | ||||
|     return isam2_.getFactorsUnsafe(); | ||||
|   } | ||||
| 
 | ||||
|   /** Access the current linearization point */ | ||||
|   const Values& getLinearizationPoint() const { | ||||
|     return isam2_.getLinearizationPoint(); | ||||
|   } | ||||
| 
 | ||||
|   /** Access the current ordering */ | ||||
|   const Ordering& getOrdering() const { | ||||
|     return isam2_.getOrdering(); | ||||
|   } | ||||
| 
 | ||||
|   /** Access the current set of deltas to the linearization point */ | ||||
|   const VectorValues& getDelta() const { | ||||
|     return isam2_.getDelta(); | ||||
|   } | ||||
| 
 | ||||
|   /** Compute the current best estimate of all variables and return a full Values structure.
 | ||||
|    * If only a single variable is needed, it may be faster to call calculateEstimate(const KEY&). | ||||
|    */ | ||||
|   Values calculateEstimate() const { | ||||
|     return isam2_.calculateEstimate(); | ||||
|   } | ||||
| 
 | ||||
|   /** Compute the current best estimate of a single variable. This is generally faster than
 | ||||
|    * calling the no-argument version of calculateEstimate if only specific variables are needed. | ||||
|    * @param key | ||||
|    * @return | ||||
|    */ | ||||
|   template<class VALUE> | ||||
|   VALUE calculateEstimate(Key key) const { | ||||
|     return isam2_.calculateEstimate<VALUE>(key); | ||||
|   } | ||||
| 
 | ||||
|   /**
 | ||||
|    * Add new factors and variables to the smoother. | ||||
|    * | ||||
|    * Add new measurements, and optionally new variables, to the smoother. | ||||
|    * This runs a full step of the ISAM2 algorithm, relinearizing and updating | ||||
|    * the solution as needed, according to the wildfire and relinearize | ||||
|    * thresholds. | ||||
|    * | ||||
|    * @param newFactors The new factors to be added to the smoother | ||||
|    * @param newTheta Initialization points for new variables to be added to the smoother | ||||
|    * You must include here all new variables occuring in newFactors (which were not already | ||||
|    * in the smoother).  There must not be any variables here that do not occur in newFactors, | ||||
|    * and additionally, variables that were already in the system must not be included here. | ||||
|    */ | ||||
|   Result update(const NonlinearFactorGraph& newFactors = NonlinearFactorGraph(), const Values& newTheta = Values()); | ||||
| 
 | ||||
|   /**
 | ||||
|    * Perform any required operations before the synchronization process starts. | ||||
|    * Called by 'synchronize' | ||||
|    */ | ||||
|   virtual void presync(); | ||||
| 
 | ||||
|   /**
 | ||||
|    * Populate the provided containers with factors that constitute the smoother branch summarization | ||||
|    * needed by the filter. | ||||
|    * | ||||
|    * @param summarizedFactors The summarized factors for the filter branch | ||||
|    */ | ||||
|   virtual void getSummarizedFactors(NonlinearFactorGraph& summarizedFactors, Values& separatorValues); | ||||
| 
 | ||||
|   /**
 | ||||
|    * Apply the new smoother factors sent by the filter, and the updated version of the filter | ||||
|    * branch summarized factors. | ||||
|    * | ||||
|    * @param smootherFactors A set of new factors added to the smoother from the filter | ||||
|    * @param smootherValues Linearization points for any new variables | ||||
|    * @param summarizedFactors An updated version of the filter branch summarized factors | ||||
|    * @param rootValues The linearization point of the root variables | ||||
|    */ | ||||
|   virtual void synchronize(const NonlinearFactorGraph& smootherFactors, const Values& smootherValues, | ||||
|       const NonlinearFactorGraph& summarizedFactors, const Values& separatorValues); | ||||
| 
 | ||||
|   /**
 | ||||
|    * Perform any required operations after the synchronization process finishes. | ||||
|    * Called by 'synchronize' | ||||
|    */ | ||||
|   virtual void postsync(); | ||||
| 
 | ||||
| protected: | ||||
| 
 | ||||
|   ISAM2 isam2_; ///< iSAM2 inference engine
 | ||||
| 
 | ||||
|   // Storage for information received from the filter during the last synchronization
 | ||||
|   NonlinearFactorGraph smootherFactors_; ///< New factors to be added to the smoother during the next update
 | ||||
|   Values smootherValues_; ///< New variables to be added to the smoother during the next update
 | ||||
|   NonlinearFactorGraph filterSummarizationFactors_; ///< New filter summarization factors to replace the existing filter summarization during the next update
 | ||||
|   Values separatorValues_; ///< The linearization points of the separator variables. These should not be changed during optimization.
 | ||||
|   FastVector<size_t> filterSummarizationSlots_;  ///< The slots in factor graph that correspond to the current filter summarization factors
 | ||||
|   bool synchronizationUpdatesAvailable_; ///< Flag indicating the currently stored synchronization updates have not been applied yet
 | ||||
| 
 | ||||
|   // Storage for information to be sent to the filter
 | ||||
|   NonlinearFactorGraph smootherSummarization_; ///< A temporary holding place for calculated smoother summarization
 | ||||
| 
 | ||||
| private: | ||||
| 
 | ||||
|   /** Calculate the smoother marginal factors on the separator variables */ | ||||
|   void updateSmootherSummarization(); | ||||
| 
 | ||||
| }; // ConcurrentBatchSmoother
 | ||||
| 
 | ||||
| /// Typedef for Matlab wrapping
 | ||||
| typedef ConcurrentIncrementalSmoother::Result ConcurrentIncrementalSmootherResult; | ||||
| 
 | ||||
| }/// namespace gtsam
 | ||||
		Loading…
	
		Reference in New Issue