Detailed results optionally returned by ISAM2::update, with the status of each variable
parent
fbef6ce63f
commit
792c8ee55a
|
@ -206,7 +206,7 @@ GaussianFactorGraph ISAM2::getCachedBoundaryFactors(Cliques& orphans) {
|
|||
}
|
||||
|
||||
boost::shared_ptr<FastSet<Index> > ISAM2::recalculate(
|
||||
const FastSet<Index>& markedKeys, const FastSet<Index>& relinKeys, const FastVector<Index>& newKeys,
|
||||
const FastSet<Index>& markedKeys, const FastSet<Index>& relinKeys, const FastVector<Index>& observedKeys,
|
||||
const boost::optional<FastMap<Index,int> >& constrainKeys, ISAM2Result& result) {
|
||||
|
||||
// TODO: new factors are linearized twice, the newFactors passed in are not used.
|
||||
|
@ -237,8 +237,8 @@ boost::shared_ptr<FastSet<Index> > ISAM2::recalculate(
|
|||
cout << "markedKeys: ";
|
||||
BOOST_FOREACH(const Index key, markedKeys) { cout << key << " "; }
|
||||
cout << endl;
|
||||
cout << "newKeys: ";
|
||||
BOOST_FOREACH(const Index key, newKeys) { cout << key << " "; }
|
||||
cout << "observedKeys: ";
|
||||
BOOST_FOREACH(const Index key, observedKeys) { cout << key << " "; }
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
|
@ -270,12 +270,13 @@ boost::shared_ptr<FastSet<Index> > ISAM2::recalculate(
|
|||
FastList<Index> affectedKeys = affectedBayesNet.ordering();
|
||||
toc(2,"affectedKeys");
|
||||
|
||||
boost::shared_ptr<FastSet<Index> > affectedKeysSet(new FastSet<Index>()); // Will return this result
|
||||
|
||||
if(affectedKeys.size() >= theta_.size() * batchThreshold) {
|
||||
|
||||
tic(3,"batch");
|
||||
|
||||
tic(0,"add keys");
|
||||
boost::shared_ptr<FastSet<Index> > affectedKeysSet(new FastSet<Index>());
|
||||
BOOST_FOREACH(const Ordering::value_type& key_index, ordering_) { affectedKeysSet->insert(key_index.second); }
|
||||
toc(0,"add keys");
|
||||
|
||||
|
@ -296,8 +297,8 @@ boost::shared_ptr<FastSet<Index> > ISAM2::recalculate(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if(theta_.size() > newKeys.size()) { // Only if some variables are unconstrained
|
||||
BOOST_FOREACH(Index var, newKeys) { cmember[var] = 1; }
|
||||
if(theta_.size() > observedKeys.size()) { // Only if some variables are unconstrained
|
||||
BOOST_FOREACH(Index var, observedKeys) { cmember[var] = 1; }
|
||||
}
|
||||
}
|
||||
Permutation::shared_ptr colamd(inference::PermutationCOLAMD_(variableIndex_, cmember));
|
||||
|
@ -338,15 +339,17 @@ boost::shared_ptr<FastSet<Index> > ISAM2::recalculate(
|
|||
this->insert(newRoot);
|
||||
toc(6,"insert");
|
||||
|
||||
toc(3,"batch");
|
||||
|
||||
result.variablesReeliminated = affectedKeysSet->size();
|
||||
|
||||
lastAffectedMarkedCount = markedKeys.size();
|
||||
lastAffectedVariableCount = affectedKeysSet->size();
|
||||
lastAffectedFactorCount = linearFactors_.size();
|
||||
|
||||
return affectedKeysSet;
|
||||
// Reeliminated keys for detailed results
|
||||
if(params_.enableDetailedResults)
|
||||
BOOST_FOREACH(Key key, theta_.keys()) { result.detail->variableStatus[key].isReeliminated = true; }
|
||||
|
||||
toc(3,"batch");
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -355,7 +358,7 @@ boost::shared_ptr<FastSet<Index> > ISAM2::recalculate(
|
|||
// 2. Add the new factors \Factors' into the resulting factor graph
|
||||
FastList<Index> affectedAndNewKeys;
|
||||
affectedAndNewKeys.insert(affectedAndNewKeys.end(), affectedKeys.begin(), affectedKeys.end());
|
||||
affectedAndNewKeys.insert(affectedAndNewKeys.end(), newKeys.begin(), newKeys.end());
|
||||
affectedAndNewKeys.insert(affectedAndNewKeys.end(), observedKeys.begin(), observedKeys.end());
|
||||
tic(1,"relinearizeAffected");
|
||||
GaussianFactorGraph factors(*relinearizeAffectedFactors(affectedAndNewKeys, relinKeys));
|
||||
if(debug) factors.print("Relinearized factors: ");
|
||||
|
@ -363,6 +366,10 @@ boost::shared_ptr<FastSet<Index> > ISAM2::recalculate(
|
|||
|
||||
if(debug) { cout << "Affected keys: "; BOOST_FOREACH(const Index key, affectedKeys) { cout << key << " "; } cout << endl; }
|
||||
|
||||
// Reeliminated keys for detailed results
|
||||
if(params_.enableDetailedResults)
|
||||
BOOST_FOREACH(Index index, affectedAndNewKeys) { result.detail->variableStatus[inverseOrdering_->at(index)].isReeliminated = true; }
|
||||
|
||||
result.variablesReeliminated = affectedAndNewKeys.size();
|
||||
lastAffectedMarkedCount = markedKeys.size();
|
||||
lastAffectedVariableCount = affectedKeys.size();
|
||||
|
@ -391,7 +398,7 @@ boost::shared_ptr<FastSet<Index> > ISAM2::recalculate(
|
|||
tic(1,"list to set");
|
||||
// create a partial reordering for the new and contaminated factors
|
||||
// markedKeys are passed in: those variables will be forced to the end in the ordering
|
||||
boost::shared_ptr<FastSet<Index> > affectedKeysSet(new FastSet<Index>(markedKeys));
|
||||
affectedKeysSet->insert(markedKeys.begin(), markedKeys.end());
|
||||
affectedKeysSet->insert(affectedKeys.begin(), affectedKeys.end());
|
||||
toc(1,"list to set");
|
||||
|
||||
|
@ -404,7 +411,7 @@ boost::shared_ptr<FastSet<Index> > ISAM2::recalculate(
|
|||
reorderingMode.constrainedKeys = *constrainKeys;
|
||||
} else {
|
||||
reorderingMode.constrainedKeys = FastMap<Index,int>();
|
||||
BOOST_FOREACH(Index var, newKeys) { reorderingMode.constrainedKeys->insert(make_pair(var, 1)); }
|
||||
BOOST_FOREACH(Index var, observedKeys) { reorderingMode.constrainedKeys->insert(make_pair(var, 1)); }
|
||||
}
|
||||
Impl::PartialSolveResult partialSolveResult =
|
||||
Impl::PartialSolve(factors, *affectedKeysSet, reorderingMode, (params_.factorization == ISAM2Params::QR));
|
||||
|
@ -467,9 +474,13 @@ boost::shared_ptr<FastSet<Index> > ISAM2::recalculate(
|
|||
toc(7,"orphans");
|
||||
|
||||
toc(4,"incremental");
|
||||
|
||||
return affectedKeysSet;
|
||||
}
|
||||
|
||||
// Root clique variables for detailed results
|
||||
if(params_.enableDetailedResults)
|
||||
BOOST_FOREACH(Index index, this->root()->conditional()->frontals()) { result.detail->variableStatus[inverseOrdering_->at(index)].inRootClique = true; }
|
||||
|
||||
return affectedKeysSet;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
@ -490,6 +501,8 @@ ISAM2Result ISAM2::update(
|
|||
lastBacksubVariableCount = 0;
|
||||
lastNnzTop = 0;
|
||||
ISAM2Result result;
|
||||
if(params_.enableDetailedResults)
|
||||
result.detail = ISAM2Result::DetailedResults();
|
||||
const bool relinearizeThisStep = force_relinearize || (params_.enableRelinearization && count % params_.relinearizeSkip == 0);
|
||||
|
||||
if(verbose) {
|
||||
|
@ -528,6 +541,10 @@ ISAM2Result ISAM2::update(
|
|||
tic(2,"add new variables");
|
||||
// 2. Initialize any new variables \Theta_{new} and add \Theta:=\Theta\cup\Theta_{new}.
|
||||
Impl::AddVariables(newTheta, theta_, delta_, deltaNewton_, RgProd_, deltaReplacedMask_, ordering_, Base::nodes_);
|
||||
// New keys for detailed results
|
||||
if(params_.enableDetailedResults) {
|
||||
inverseOrdering_ = ordering_.invert();
|
||||
BOOST_FOREACH(Key key, newTheta.keys()) { result.detail->variableStatus[key].isNew = true; } }
|
||||
toc(2,"add new variables");
|
||||
|
||||
tic(3,"evaluate error before");
|
||||
|
@ -543,10 +560,13 @@ ISAM2Result ISAM2::update(
|
|||
FastSet<Index> markedRemoveKeys = Impl::IndicesFromFactors(ordering_, removeFactors); // Get keys involved in removed factors
|
||||
markedKeys.insert(markedRemoveKeys.begin(), markedRemoveKeys.end()); // Add to the overall set of marked keys
|
||||
}
|
||||
// Observed keys for detailed results
|
||||
if(params_.enableDetailedResults)
|
||||
BOOST_FOREACH(Index index, markedKeys) { result.detail->variableStatus[inverseOrdering_->at(index)].isObserved = true; }
|
||||
// NOTE: we use assign instead of the iterator constructor here because this
|
||||
// is a vector of size_t, so the constructor unintentionally resolves to
|
||||
// vector(size_t count, Index value) instead of the iterator constructor.
|
||||
FastVector<Index> newKeys; newKeys.assign(markedKeys.begin(), markedKeys.end()); // Make a copy of these, as we'll soon add to them
|
||||
FastVector<Index> observedKeys; observedKeys.assign(markedKeys.begin(), markedKeys.end()); // Make a copy of these, as we'll soon add to them
|
||||
toc(4,"gather involved keys");
|
||||
|
||||
// Check relinearization if we're at the nth step, or we are using a looser loop relin threshold
|
||||
|
@ -558,6 +578,12 @@ ISAM2Result ISAM2::update(
|
|||
relinKeys = Impl::CheckRelinearization(delta_, ordering_, params_.relinearizeThreshold);
|
||||
if(disableReordering) relinKeys = Impl::CheckRelinearization(delta_, ordering_, 0.0); // This is used for debugging
|
||||
|
||||
// Above relin threshold keys for detailed results
|
||||
if(params_.enableDetailedResults) {
|
||||
BOOST_FOREACH(Index index, relinKeys) {
|
||||
result.detail->variableStatus[inverseOrdering_->at(index)].isAboveRelinThreshold = true;
|
||||
result.detail->variableStatus[inverseOrdering_->at(index)].isRelinearized = true; } }
|
||||
|
||||
// Add the variables being relinearized to the marked keys
|
||||
BOOST_FOREACH(const Index j, relinKeys) { markedRelinMask[j] = true; }
|
||||
markedKeys.insert(relinKeys.begin(), relinKeys.end());
|
||||
|
@ -565,8 +591,20 @@ ISAM2Result ISAM2::update(
|
|||
|
||||
tic(6,"fluid find_all");
|
||||
// 5. Mark all cliques that involve marked variables \Theta_{J} and all their ancestors.
|
||||
if (!relinKeys.empty() && this->root())
|
||||
Impl::FindAll(this->root(), markedKeys, markedRelinMask); // add other cliques that have the marked ones in the separator
|
||||
if (!relinKeys.empty() && this->root()) {
|
||||
// add other cliques that have the marked ones in the separator
|
||||
Impl::FindAll(this->root(), markedKeys, markedRelinMask);
|
||||
|
||||
// Relin involved keys for detailed results
|
||||
if(params_.enableDetailedResults) {
|
||||
FastSet<Index> involvedRelinKeys;
|
||||
Impl::FindAll(this->root(), involvedRelinKeys, markedRelinMask);
|
||||
BOOST_FOREACH(Index index, involvedRelinKeys) {
|
||||
if(!result.detail->variableStatus[inverseOrdering_->at(index)].isAboveRelinThreshold) {
|
||||
result.detail->variableStatus[inverseOrdering_->at(index)].isRelinearizeInvolved = true;
|
||||
result.detail->variableStatus[inverseOrdering_->at(index)].isRelinearized = true; } }
|
||||
}
|
||||
}
|
||||
toc(6,"fluid find_all");
|
||||
|
||||
tic(7,"expmap");
|
||||
|
@ -617,8 +655,8 @@ ISAM2Result ISAM2::update(
|
|||
}
|
||||
}
|
||||
boost::shared_ptr<FastSet<Index> > replacedKeys;
|
||||
if(!markedKeys.empty() || !newKeys.empty())
|
||||
replacedKeys = recalculate(markedKeys, relinKeys, newKeys, constrainedIndices, result);
|
||||
if(!markedKeys.empty() || !observedKeys.empty())
|
||||
replacedKeys = recalculate(markedKeys, relinKeys, observedKeys, constrainedIndices, result);
|
||||
|
||||
// Update replaced keys mask (accumulates until back-substitution takes place)
|
||||
if(replacedKeys) {
|
||||
|
|
|
@ -127,6 +127,8 @@ struct ISAM2Params {
|
|||
|
||||
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)
|
||||
|
||||
/** Specify parameters as constructor arguments */
|
||||
ISAM2Params(
|
||||
OptimizationParams _optimizationParams = ISAM2GaussNewtonParams(), ///< see ISAM2Params::optimizationParams
|
||||
|
@ -140,7 +142,8 @@ struct ISAM2Params {
|
|||
) : optimizationParams(_optimizationParams), relinearizeThreshold(_relinearizeThreshold),
|
||||
relinearizeSkip(_relinearizeSkip), enableRelinearization(_enableRelinearization),
|
||||
evaluateNonlinearError(_evaluateNonlinearError), factorization(_factorization),
|
||||
cacheLinearizedFactors(_cacheLinearizedFactors), keyFormatter(_keyFormatter) {}
|
||||
cacheLinearizedFactors(_cacheLinearizedFactors), keyFormatter(_keyFormatter),
|
||||
enableDetailedResults(false) {}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -201,6 +204,35 @@ struct ISAM2Result {
|
|||
* used later to refer to the factors in order to remove them.
|
||||
*/
|
||||
FastVector<size_t> newFactorsIndices;
|
||||
|
||||
/** A struct holding detailed results, which must be enabled with
|
||||
* ISAM2Params::enableDetailedResults.
|
||||
*/
|
||||
struct DetailedResults {
|
||||
/** The status of a single variable, this struct is stored in
|
||||
* DetailedResults::variableStatus */
|
||||
struct VariableStatus {
|
||||
/** Whether the variable was just reeliminated, due to being relinearized,
|
||||
* observed, new, or on the path up to the root clique from another
|
||||
* reeliminated variable. */
|
||||
bool isReeliminated;
|
||||
bool isAboveRelinThreshold; ///< Whether the variable was just relinearized due to being above the relinearization threshold
|
||||
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
|
||||
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), isRelinearized(false), isObserved(false), isNew(false), inRootClique(false) {}
|
||||
};
|
||||
|
||||
/** The status of each variable during this update, see VariableStatus.
|
||||
*/
|
||||
FastMap<Key, VariableStatus> variableStatus;
|
||||
};
|
||||
|
||||
/** Detailed results, if enabled by ISAM2Params::enableDetailedResults. See
|
||||
* Detail for information about the results data stored here. */
|
||||
boost::optional<DetailedResults> detail;
|
||||
};
|
||||
|
||||
struct ISAM2Clique : public BayesTreeCliqueBase<ISAM2Clique, GaussianConditional> {
|
||||
|
@ -364,6 +396,9 @@ protected:
|
|||
/** The current Dogleg Delta (trust region radius) */
|
||||
mutable boost::optional<double> doglegDelta_;
|
||||
|
||||
/** The inverse ordering, only used for creating ISAM2Result::DetailedResults */
|
||||
boost::optional<Ordering::InvertedMap> inverseOrdering_;
|
||||
|
||||
private:
|
||||
#ifndef NDEBUG
|
||||
std::vector<bool> lastRelinVariables_;
|
||||
|
@ -468,7 +503,7 @@ private:
|
|||
GaussianFactorGraph getCachedBoundaryFactors(Cliques& orphans);
|
||||
|
||||
boost::shared_ptr<FastSet<Index> > recalculate(const FastSet<Index>& markedKeys, const FastSet<Index>& relinKeys,
|
||||
const FastVector<Index>& newKeys,
|
||||
const FastVector<Index>& observedKeys,
|
||||
const boost::optional<FastMap<Index,int> >& constrainKeys, ISAM2Result& result);
|
||||
// void linear_update(const GaussianFactorGraph& newFactors);
|
||||
void updateDelta(bool forceFullSolve = false) const;
|
||||
|
|
Loading…
Reference in New Issue