Fix HybridNonlinearFactor

release/4.3a0
Frank Dellaert 2024-09-26 14:50:50 -07:00
parent e18dd3e905
commit 2c12e685ea
3 changed files with 70 additions and 48 deletions

View File

@ -196,16 +196,15 @@ class GTSAM_EXPORT HybridGaussianFactor : public HybridFactor {
double potentiallyPrunedComponentError( double potentiallyPrunedComponentError(
const sharedFactor &gf, const VectorValues &continuousValues) const; const sharedFactor &gf, const VectorValues &continuousValues) const;
/// Helper struct to assist in constructing the HybridGaussianFactor /// Helper struct to assist private constructor below.
struct ConstructorHelper { struct ConstructorHelper {
KeyVector continuousKeys; // Continuous keys extracted from factors KeyVector continuousKeys; // Continuous keys extracted from factors
DiscreteKeys discreteKeys; // Discrete keys provided to the constructors DiscreteKeys discreteKeys; // Discrete keys provided to the constructors
FactorValuePairs pairs; // Used only if factorsTree is empty FactorValuePairs pairs; // Used only if factorsTree is empty
Factors factorsTree; Factors factorsTree;
ConstructorHelper( ConstructorHelper(const DiscreteKey &discreteKey,
const DiscreteKey &discreteKey, const std::vector<GaussianFactor::shared_ptr> &factors);
const std::vector<GaussianFactor::shared_ptr> &factorsVec);
ConstructorHelper(const DiscreteKey &discreteKey, ConstructorHelper(const DiscreteKey &discreteKey,
const std::vector<GaussianFactorValuePair> &factorPairs); const std::vector<GaussianFactorValuePair> &factorPairs);
@ -214,7 +213,7 @@ class GTSAM_EXPORT HybridGaussianFactor : public HybridFactor {
const FactorValuePairs &factorPairs); const FactorValuePairs &factorPairs);
}; };
// Private constructor using ConstructorHelper // Private constructor using ConstructorHelper above.
HybridGaussianFactor(const ConstructorHelper &helper) HybridGaussianFactor(const ConstructorHelper &helper)
: Base(helper.continuousKeys, helper.discreteKeys), : Base(helper.continuousKeys, helper.discreteKeys),
factors_(helper.factorsTree.empty() ? augment(helper.pairs) factors_(helper.factorsTree.empty() ? augment(helper.pairs)

View File

@ -18,55 +18,59 @@
#include <gtsam/hybrid/HybridNonlinearFactor.h> #include <gtsam/hybrid/HybridNonlinearFactor.h>
#include <memory>
#include "gtsam/nonlinear/NonlinearFactor.h"
namespace gtsam { namespace gtsam {
/* *******************************************************************************/ /* *******************************************************************************/
static void checkKeys(const KeyVector& continuousKeys, static void CopyOrCheckContinuousKeys(const NonlinearFactor::shared_ptr& factor,
const std::vector<NonlinearFactorValuePair>& pairs) { KeyVector* continuousKeys) {
KeySet factor_keys_set; if (!factor) return;
for (const auto& pair : pairs) { if (continuousKeys->empty()) {
auto f = pair.first; *continuousKeys = factor->keys();
// Insert all factor continuous keys in the continuous keys set. } else if (factor->keys() != *continuousKeys) {
std::copy(f->keys().begin(), f->keys().end(),
std::inserter(factor_keys_set, factor_keys_set.end()));
}
KeySet continuous_keys_set(continuousKeys.begin(), continuousKeys.end());
if (continuous_keys_set != factor_keys_set) {
throw std::runtime_error( throw std::runtime_error(
"HybridNonlinearFactor: The specified continuous keys and the keys in " "HybridNonlinearFactor: all factors should have the same keys!");
"the factors do not match!");
} }
} }
/* *******************************************************************************/ /* *******************************************************************************/
HybridNonlinearFactor::HybridNonlinearFactor( HybridNonlinearFactor::ConstructorHelper::ConstructorHelper(
const KeyVector& continuousKeys, const DiscreteKey& discreteKey, const DiscreteKey& discreteKey,
const std::vector<NonlinearFactor::shared_ptr>& factors) const std::vector<NonlinearFactor::shared_ptr>& factors)
: Base(continuousKeys, {discreteKey}) { : discreteKeys({discreteKey}) {
std::vector<NonlinearFactorValuePair> pairs; std::vector<NonlinearFactorValuePair> pairs;
for (auto&& f : factors) { // Extract continuous keys from the first non-null factor
pairs.emplace_back(f, 0.0); for (const auto& factor : factors) {
pairs.emplace_back(factor, 0.0);
CopyOrCheckContinuousKeys(factor, &continuousKeys);
} }
checkKeys(continuousKeys, pairs); factorTree = FactorValuePairs({discreteKey}, pairs);
factors_ = FactorValuePairs({discreteKey}, pairs);
} }
/* *******************************************************************************/ /* *******************************************************************************/
HybridNonlinearFactor::HybridNonlinearFactor( HybridNonlinearFactor::ConstructorHelper::ConstructorHelper(
const KeyVector& continuousKeys, const DiscreteKey& discreteKey, const DiscreteKey& discreteKey,
const std::vector<NonlinearFactorValuePair>& pairs) const std::vector<NonlinearFactorValuePair>& pairs)
: Base(continuousKeys, {discreteKey}) { : discreteKeys({discreteKey}) {
KeySet continuous_keys_set(continuousKeys.begin(), continuousKeys.end()); // Extract continuous keys from the first non-null factor
checkKeys(continuousKeys, pairs); for (const auto& pair : pairs) {
factors_ = FactorValuePairs({discreteKey}, pairs); CopyOrCheckContinuousKeys(pair.first, &continuousKeys);
}
factorTree = FactorValuePairs({discreteKey}, pairs);
} }
/* *******************************************************************************/ /* *******************************************************************************/
HybridNonlinearFactor::HybridNonlinearFactor(const KeyVector& continuousKeys, HybridNonlinearFactor::ConstructorHelper::ConstructorHelper(
const DiscreteKeys& discreteKeys, const DiscreteKeys& discreteKeys, const FactorValuePairs& factorPairs)
const FactorValuePairs& factors) : discreteKeys(discreteKeys), factorTree(factorPairs) {
: Base(continuousKeys, discreteKeys), factors_(factors) {} // Extract continuous keys from the first non-null factor
factorPairs.visit([&](const NonlinearFactorValuePair& pair) {
CopyOrCheckContinuousKeys(pair.first, &continuousKeys);
});
}
/* *******************************************************************************/ /* *******************************************************************************/
AlgebraicDecisionTree<Key> HybridNonlinearFactor::errorTree( AlgebraicDecisionTree<Key> HybridNonlinearFactor::errorTree(

View File

@ -90,13 +90,12 @@ class GTSAM_EXPORT HybridNonlinearFactor : public HybridFactor {
* providing the factors for each mode m as a vector of factors ϕ_m(x). * providing the factors for each mode m as a vector of factors ϕ_m(x).
* The value ϕ(x,m) for the factor is simply ϕ_m(x). * The value ϕ(x,m) for the factor is simply ϕ_m(x).
* *
* @param continuousKeys Vector of keys for continuous factors.
* @param discreteKey The discrete key for the "mode", indexing components. * @param discreteKey The discrete key for the "mode", indexing components.
* @param factors Vector of gaussian factors, one for each mode. * @param factors Vector of gaussian factors, one for each mode.
*/ */
HybridNonlinearFactor( HybridNonlinearFactor(const DiscreteKey& discreteKey,
const KeyVector& continuousKeys, const DiscreteKey& discreteKey, const std::vector<NonlinearFactor::shared_ptr>& factors)
const std::vector<NonlinearFactor::shared_ptr>& factors); : HybridNonlinearFactor(ConstructorHelper(discreteKey, factors)) {}
/** /**
* @brief Construct a new HybridNonlinearFactor on a single discrete key, * @brief Construct a new HybridNonlinearFactor on a single discrete key,
@ -104,13 +103,12 @@ class GTSAM_EXPORT HybridNonlinearFactor : public HybridFactor {
* provided as a vector of pairs (ϕ_m(x), E_m). * provided as a vector of pairs (ϕ_m(x), E_m).
* The value ϕ(x,m) for the factor is now ϕ_m(x) + E_m. * The value ϕ(x,m) for the factor is now ϕ_m(x) + E_m.
* *
* @param continuousKeys Vector of keys for continuous factors.
* @param discreteKey The discrete key for the "mode", indexing components. * @param discreteKey The discrete key for the "mode", indexing components.
* @param pairs Vector of gaussian factor-scalar pairs, one per mode. * @param pairs Vector of gaussian factor-scalar pairs, one per mode.
*/ */
HybridNonlinearFactor(const KeyVector& continuousKeys, HybridNonlinearFactor(const DiscreteKey& discreteKey,
const DiscreteKey& discreteKey, const std::vector<NonlinearFactorValuePair>& pairs)
const std::vector<NonlinearFactorValuePair>& pairs); : HybridNonlinearFactor(ConstructorHelper(discreteKey, pairs)) {}
/** /**
* @brief Construct a new HybridNonlinearFactor on a several discrete keys M, * @brief Construct a new HybridNonlinearFactor on a several discrete keys M,
@ -118,13 +116,12 @@ class GTSAM_EXPORT HybridNonlinearFactor : public HybridFactor {
* scalars are provided as a DecisionTree<Key> of pairs (ϕ_M(x), E_M). * scalars are provided as a DecisionTree<Key> of pairs (ϕ_M(x), E_M).
* The value ϕ(x,M) for the factor is again ϕ_m(x) + E_m. * The value ϕ(x,M) for the factor is again ϕ_m(x) + E_m.
* *
* @param continuousKeys A vector of keys representing continuous variables.
* @param discreteKeys Discrete variables and their cardinalities. * @param discreteKeys Discrete variables and their cardinalities.
* @param factors The decision tree of nonlinear factor/scalar pairs. * @param factors The decision tree of nonlinear factor/scalar pairs.
*/ */
HybridNonlinearFactor(const KeyVector& continuousKeys, HybridNonlinearFactor(const DiscreteKeys& discreteKeys,
const DiscreteKeys& discreteKeys, const FactorValuePairs& factors)
const FactorValuePairs& factors); : HybridNonlinearFactor(ConstructorHelper(discreteKeys, factors)) {}
/** /**
* @brief Compute error of the HybridNonlinearFactor as a tree. * @brief Compute error of the HybridNonlinearFactor as a tree.
* *
@ -181,6 +178,28 @@ class GTSAM_EXPORT HybridNonlinearFactor : public HybridFactor {
/// Linearize all the continuous factors to get a HybridGaussianFactor. /// Linearize all the continuous factors to get a HybridGaussianFactor.
std::shared_ptr<HybridGaussianFactor> linearize( std::shared_ptr<HybridGaussianFactor> linearize(
const Values& continuousValues) const; const Values& continuousValues) const;
private:
/// Helper struct to assist private constructor below.
struct ConstructorHelper {
KeyVector continuousKeys; // Continuous keys extracted from factors
DiscreteKeys discreteKeys; // Discrete keys provided to the constructors
FactorValuePairs factorTree;
ConstructorHelper(const DiscreteKey& discreteKey,
const std::vector<NonlinearFactor::shared_ptr>& factors);
ConstructorHelper(const DiscreteKey& discreteKey,
const std::vector<NonlinearFactorValuePair>& factorPairs);
ConstructorHelper(const DiscreteKeys& discreteKeys,
const FactorValuePairs& factorPairs);
};
// Private constructor using ConstructorHelper above.
HybridNonlinearFactor(const ConstructorHelper& helper)
: Base(helper.continuousKeys, helper.discreteKeys),
factors_(helper.factorTree) {}
}; };
// traits // traits