| 
									
										
										
										
											2013-08-11 01:15:31 +08:00
										 |  |  | /* ----------------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-11 22:39:48 +08:00
										 |  |  |  * GTSAM Copyright 2010, Georgia Tech Research Corporation, | 
					
						
							| 
									
										
										
										
											2013-08-11 01:15:31 +08:00
										 |  |  |  * 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_); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2013-10-04 03:51:56 +08:00
										 |  |  | ConcurrentIncrementalSmoother::Result ConcurrentIncrementalSmoother::update(const NonlinearFactorGraph& newFactors, const Values& newTheta, | 
					
						
							| 
									
										
										
										
											2016-02-26 15:51:01 +08:00
										 |  |  |     const boost::optional<FactorIndices>& removeFactorIndices) { | 
					
						
							| 
									
										
										
										
											2013-08-11 01:15:31 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   gttic(update); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Create the return result meta-data
 | 
					
						
							|  |  |  |   Result result; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-26 14:07:04 +08:00
										 |  |  |   FastVector<size_t> removedFactors; | 
					
						
							| 
									
										
										
										
											2013-10-04 03:51:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   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());
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-11 01:15:31 +08:00
										 |  |  |   // 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; | 
					
						
							| 
									
										
										
										
											2023-01-23 04:18:09 +08:00
										 |  |  |   for (const auto key : separatorValues_.keys()) { | 
					
						
							|  |  |  |     constrainedKeys[key] = 1; | 
					
						
							|  |  |  |     noRelinKeys.push_back(key); | 
					
						
							| 
									
										
										
										
											2013-08-11 01:15:31 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Use iSAM2 to perform an update
 | 
					
						
							| 
									
										
										
										
											2016-02-26 14:07:04 +08:00
										 |  |  |   ISAM2Result isam2Result; | 
					
						
							| 
									
										
										
										
											2013-08-11 01:15:31 +08:00
										 |  |  |   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
 | 
					
						
							| 
									
										
										
										
											2023-01-23 04:18:09 +08:00
										 |  |  |       for(const auto key: smootherValues_.keys()) { | 
					
						
							|  |  |  |         if(!isam2_.getLinearizationPoint().exists(key)) { | 
					
						
							|  |  |  |           values.insert(key, smootherValues_.at(key)); | 
					
						
							| 
									
										
										
										
											2013-08-11 01:15:31 +08:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2023-01-23 04:18:09 +08:00
										 |  |  |       for(const auto key: separatorValues_.keys()) { | 
					
						
							|  |  |  |         if(!isam2_.getLinearizationPoint().exists(key)) { | 
					
						
							|  |  |  |           values.insert(key, separatorValues_.at(key)); | 
					
						
							| 
									
										
										
										
											2013-08-11 01:15:31 +08:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // 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
 | 
					
						
							| 
									
										
										
										
											2016-02-26 15:51:01 +08:00
										 |  |  |       isam2Result = isam2_.update(newFactors, newTheta, FactorIndices(), constrainedKeys, noRelinKeys); | 
					
						
							| 
									
										
										
										
											2013-08-11 01:15:31 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // 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; | 
					
						
							| 
									
										
										
										
											2016-05-21 23:52:14 +08:00
										 |  |  |   for(Key key: separatorValues_.keys()) { | 
					
						
							| 
									
										
										
										
											2013-08-16 06:12:07 +08:00
										 |  |  |     ISAM2Clique::shared_ptr clique = isam2_[key]; | 
					
						
							| 
									
										
										
										
											2013-08-11 01:15:31 +08:00
										 |  |  |     separatorCliques.insert( clique ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-16 06:12:07 +08:00
										 |  |  |   // Create the set of clique keys LC:
 | 
					
						
							| 
									
										
										
										
											2018-11-08 13:58:50 +08:00
										 |  |  |   KeyVector cliqueKeys; | 
					
						
							| 
									
										
										
										
											2016-05-21 23:52:14 +08:00
										 |  |  |   for(const ISAM2Clique::shared_ptr& clique: separatorCliques) { | 
					
						
							|  |  |  |     for(Key key: clique->conditional()->frontals()) { | 
					
						
							| 
									
										
										
										
											2013-08-16 06:12:07 +08:00
										 |  |  |       cliqueKeys.push_back(key); | 
					
						
							| 
									
										
										
										
											2013-08-11 01:15:31 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   std::sort(cliqueKeys.begin(), cliqueKeys.end()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Gather all factors that involve only clique keys
 | 
					
						
							|  |  |  |   std::set<size_t> cliqueFactorSlots; | 
					
						
							| 
									
										
										
										
											2016-05-21 23:52:14 +08:00
										 |  |  |   for(Key key: cliqueKeys) { | 
					
						
							|  |  |  |     for(size_t slot: isam2_.getVariableIndex()[key]) { | 
					
						
							| 
									
										
										
										
											2013-08-11 01:15:31 +08:00
										 |  |  |       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
 | 
					
						
							| 
									
										
										
										
											2016-05-21 23:52:14 +08:00
										 |  |  |   for(size_t slot: filterSummarizationSlots_) { | 
					
						
							| 
									
										
										
										
											2013-08-11 01:15:31 +08:00
										 |  |  |     cliqueFactorSlots.erase(slot); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Create a factor graph from the identified factors
 | 
					
						
							|  |  |  |   NonlinearFactorGraph graph; | 
					
						
							| 
									
										
										
										
											2016-05-21 23:52:14 +08:00
										 |  |  |   for(size_t slot: cliqueFactorSlots) { | 
					
						
							| 
									
										
										
										
											2013-08-11 01:15:31 +08:00
										 |  |  |     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
 | 
					
						
							| 
									
										
										
										
											2016-05-21 23:52:14 +08:00
										 |  |  |   for(const ISAM2Clique::shared_ptr& clique: separatorCliques) { | 
					
						
							| 
									
										
										
										
											2013-08-16 06:12:07 +08:00
										 |  |  |     childCliques.insert(clique->children.begin(), clique->children.end()); | 
					
						
							| 
									
										
										
										
											2013-08-11 01:15:31 +08:00
										 |  |  |   } | 
					
						
							|  |  |  |   // Remove any separator cliques that were added because they were children of other separator cliques
 | 
					
						
							| 
									
										
										
										
											2016-05-21 23:52:14 +08:00
										 |  |  |   for(const ISAM2Clique::shared_ptr& clique: separatorCliques) { | 
					
						
							| 
									
										
										
										
											2013-08-11 01:15:31 +08:00
										 |  |  |     childCliques.erase(clique); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Augment the factor graph with cached factors from the children
 | 
					
						
							| 
									
										
										
										
											2016-05-21 23:52:14 +08:00
										 |  |  |   for(const ISAM2Clique::shared_ptr& clique: childCliques) { | 
					
						
							| 
									
										
										
										
											2013-08-16 06:12:07 +08:00
										 |  |  |     LinearContainerFactor::shared_ptr factor(new LinearContainerFactor(clique->cachedFactor(), isam2_.getLinearizationPoint())); | 
					
						
							| 
									
										
										
										
											2013-08-11 01:15:31 +08:00
										 |  |  |     graph.push_back( factor ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Get the set of separator keys
 | 
					
						
							| 
									
										
										
										
											2023-01-23 04:18:09 +08:00
										 |  |  |   const KeySet separatorKeys = separatorValues_.keySet(); | 
					
						
							| 
									
										
										
										
											2013-08-11 01:15:31 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Calculate the marginal factors on the separator
 | 
					
						
							|  |  |  |   smootherSummarization_ = internal::calculateMarginalFactors(graph, isam2_.getLinearizationPoint(), separatorKeys, | 
					
						
							| 
									
										
										
										
											2013-08-17 05:16:06 +08:00
										 |  |  |       isam2_.params().getEliminationFunction()); | 
					
						
							| 
									
										
										
										
											2013-08-11 01:15:31 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }/// namespace gtsam
 |