Merge branch 'hybrid-error-scalars' into hybrid-enum
commit
340fae9f11
|
|
@ -55,24 +55,6 @@ HybridGaussianConditional::conditionals() const {
|
||||||
return conditionals_;
|
return conditionals_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *******************************************************************************/
|
|
||||||
HybridGaussianConditional::HybridGaussianConditional(
|
|
||||||
KeyVector &&continuousFrontals, KeyVector &&continuousParents,
|
|
||||||
DiscreteKeys &&discreteParents,
|
|
||||||
std::vector<GaussianConditional::shared_ptr> &&conditionals)
|
|
||||||
: HybridGaussianConditional(continuousFrontals, continuousParents,
|
|
||||||
discreteParents,
|
|
||||||
Conditionals(discreteParents, conditionals)) {}
|
|
||||||
|
|
||||||
/* *******************************************************************************/
|
|
||||||
HybridGaussianConditional::HybridGaussianConditional(
|
|
||||||
const KeyVector &continuousFrontals, const KeyVector &continuousParents,
|
|
||||||
const DiscreteKeys &discreteParents,
|
|
||||||
const std::vector<GaussianConditional::shared_ptr> &conditionals)
|
|
||||||
: HybridGaussianConditional(continuousFrontals, continuousParents,
|
|
||||||
discreteParents,
|
|
||||||
Conditionals(discreteParents, conditionals)) {}
|
|
||||||
|
|
||||||
/* *******************************************************************************/
|
/* *******************************************************************************/
|
||||||
// TODO(dellaert): This is copy/paste: HybridGaussianConditional should be
|
// TODO(dellaert): This is copy/paste: HybridGaussianConditional should be
|
||||||
// derived from HybridGaussianFactor, no?
|
// derived from HybridGaussianFactor, no?
|
||||||
|
|
|
||||||
|
|
@ -106,32 +106,6 @@ class GTSAM_EXPORT HybridGaussianConditional
|
||||||
const DiscreteKeys &discreteParents,
|
const DiscreteKeys &discreteParents,
|
||||||
const Conditionals &conditionals);
|
const Conditionals &conditionals);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Make a Gaussian Mixture from a list of Gaussian conditionals
|
|
||||||
*
|
|
||||||
* @param continuousFrontals The continuous frontal variables
|
|
||||||
* @param continuousParents The continuous parent variables
|
|
||||||
* @param discreteParents Discrete parents variables
|
|
||||||
* @param conditionals List of conditionals
|
|
||||||
*/
|
|
||||||
HybridGaussianConditional(
|
|
||||||
KeyVector &&continuousFrontals, KeyVector &&continuousParents,
|
|
||||||
DiscreteKeys &&discreteParents,
|
|
||||||
std::vector<GaussianConditional::shared_ptr> &&conditionals);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Make a Gaussian Mixture from a list of Gaussian conditionals
|
|
||||||
*
|
|
||||||
* @param continuousFrontals The continuous frontal variables
|
|
||||||
* @param continuousParents The continuous parent variables
|
|
||||||
* @param discreteParents Discrete parents variables
|
|
||||||
* @param conditionals List of conditionals
|
|
||||||
*/
|
|
||||||
HybridGaussianConditional(
|
|
||||||
const KeyVector &continuousFrontals, const KeyVector &continuousParents,
|
|
||||||
const DiscreteKeys &discreteParents,
|
|
||||||
const std::vector<GaussianConditional::shared_ptr> &conditionals);
|
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
/// @name Testable
|
/// @name Testable
|
||||||
/// @{
|
/// @{
|
||||||
|
|
@ -273,7 +247,7 @@ class GTSAM_EXPORT HybridGaussianConditional
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Return the DiscreteKey vector as a set.
|
/// Return the DiscreteKeys vector as a set.
|
||||||
std::set<DiscreteKey> DiscreteKeysAsSet(const DiscreteKeys &discreteKeys);
|
std::set<DiscreteKey> DiscreteKeysAsSet(const DiscreteKeys &discreteKeys);
|
||||||
|
|
||||||
// traits
|
// traits
|
||||||
|
|
|
||||||
|
|
@ -42,9 +42,11 @@ HybridGaussianFactor::Factors augment(
|
||||||
const HybridGaussianFactor::FactorValuePairs &factors) {
|
const HybridGaussianFactor::FactorValuePairs &factors) {
|
||||||
// Find the minimum value so we can "proselytize" to positive values.
|
// Find the minimum value so we can "proselytize" to positive values.
|
||||||
// Done because we can't have sqrt of negative numbers.
|
// Done because we can't have sqrt of negative numbers.
|
||||||
auto unzipped_pair = unzip(factors);
|
HybridGaussianFactor::Factors gaussianFactors;
|
||||||
const HybridGaussianFactor::Factors gaussianFactors = unzipped_pair.first;
|
AlgebraicDecisionTree<Key> valueTree;
|
||||||
const AlgebraicDecisionTree<Key> valueTree = unzipped_pair.second;
|
std::tie(gaussianFactors, valueTree) = unzip(factors);
|
||||||
|
|
||||||
|
// Normalize
|
||||||
double min_value = valueTree.min();
|
double min_value = valueTree.min();
|
||||||
AlgebraicDecisionTree<Key> values =
|
AlgebraicDecisionTree<Key> values =
|
||||||
valueTree.apply([&min_value](double n) { return n - min_value; });
|
valueTree.apply([&min_value](double n) { return n - min_value; });
|
||||||
|
|
|
||||||
|
|
@ -96,15 +96,15 @@ class GTSAM_EXPORT HybridGaussianFactor : public HybridFactor {
|
||||||
* GaussianFactor shared pointers.
|
* GaussianFactor shared pointers.
|
||||||
*
|
*
|
||||||
* @param continuousKeys Vector of keys for continuous factors.
|
* @param continuousKeys Vector of keys for continuous factors.
|
||||||
* @param discreteKeys Vector of discrete keys.
|
* @param discreteKey The discrete key to index each component.
|
||||||
* @param factors Vector of gaussian factor shared pointers
|
* @param factors Vector of gaussian factor shared pointers
|
||||||
* and arbitrary scalars.
|
* and arbitrary scalars. Same size as the cardinality of discreteKey.
|
||||||
*/
|
*/
|
||||||
HybridGaussianFactor(const KeyVector &continuousKeys,
|
HybridGaussianFactor(const KeyVector &continuousKeys,
|
||||||
const DiscreteKeys &discreteKeys,
|
const DiscreteKey &discreteKey,
|
||||||
const std::vector<GaussianFactorValuePair> &factors)
|
const std::vector<GaussianFactorValuePair> &factors)
|
||||||
: HybridGaussianFactor(continuousKeys, discreteKeys,
|
: HybridGaussianFactor(continuousKeys, {discreteKey},
|
||||||
FactorValuePairs(discreteKeys, factors)) {}
|
FactorValuePairs({discreteKey}, factors)) {}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
/// @name Testable
|
/// @name Testable
|
||||||
|
|
|
||||||
|
|
@ -92,17 +92,18 @@ class HybridNonlinearFactor : public HybridFactor {
|
||||||
* @tparam FACTOR The type of the factor shared pointers being passed in.
|
* @tparam FACTOR The type of the factor shared pointers being passed in.
|
||||||
* Will be typecast to NonlinearFactor shared pointers.
|
* Will be typecast to NonlinearFactor shared pointers.
|
||||||
* @param keys Vector of keys for continuous factors.
|
* @param keys Vector of keys for continuous factors.
|
||||||
* @param discreteKeys Vector of discrete keys.
|
* @param discreteKey The discrete key indexing each component factor.
|
||||||
* @param factors Vector of nonlinear factor and scalar pairs.
|
* @param factors Vector of nonlinear factor and scalar pairs.
|
||||||
|
* Same size as the cardinality of discreteKey.
|
||||||
* @param normalized Flag indicating if the factor error is already
|
* @param normalized Flag indicating if the factor error is already
|
||||||
* normalized.
|
* normalized.
|
||||||
*/
|
*/
|
||||||
template <typename FACTOR>
|
template <typename FACTOR>
|
||||||
HybridNonlinearFactor(
|
HybridNonlinearFactor(
|
||||||
const KeyVector& keys, const DiscreteKeys& discreteKeys,
|
const KeyVector& keys, const DiscreteKey& discreteKey,
|
||||||
const std::vector<std::pair<std::shared_ptr<FACTOR>, double>>& factors,
|
const std::vector<std::pair<std::shared_ptr<FACTOR>, double>>& factors,
|
||||||
bool normalized = false)
|
bool normalized = false)
|
||||||
: Base(keys, discreteKeys), normalized_(normalized) {
|
: Base(keys, {discreteKey}), normalized_(normalized) {
|
||||||
std::vector<NonlinearFactorValuePair> nonlinear_factors;
|
std::vector<NonlinearFactorValuePair> nonlinear_factors;
|
||||||
KeySet continuous_keys_set(keys.begin(), keys.end());
|
KeySet continuous_keys_set(keys.begin(), keys.end());
|
||||||
KeySet factor_keys_set;
|
KeySet factor_keys_set;
|
||||||
|
|
@ -118,7 +119,7 @@ class HybridNonlinearFactor : public HybridFactor {
|
||||||
"Factors passed into HybridNonlinearFactor need to be nonlinear!");
|
"Factors passed into HybridNonlinearFactor need to be nonlinear!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
factors_ = Factors(discreteKeys, nonlinear_factors);
|
factors_ = Factors({discreteKey}, nonlinear_factors);
|
||||||
|
|
||||||
if (continuous_keys_set != factor_keys_set) {
|
if (continuous_keys_set != factor_keys_set) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
|
|
@ -140,7 +141,7 @@ class HybridNonlinearFactor : public HybridFactor {
|
||||||
auto errorFunc =
|
auto errorFunc =
|
||||||
[continuousValues](const std::pair<sharedFactor, double>& f) {
|
[continuousValues](const std::pair<sharedFactor, double>& f) {
|
||||||
auto [factor, val] = f;
|
auto [factor, val] = f;
|
||||||
return factor->error(continuousValues) + (0.5 * val * val);
|
return factor->error(continuousValues) + (0.5 * val);
|
||||||
};
|
};
|
||||||
DecisionTree<Key, double> result(factors_, errorFunc);
|
DecisionTree<Key, double> result(factors_, errorFunc);
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -159,7 +160,7 @@ class HybridNonlinearFactor : public HybridFactor {
|
||||||
auto [factor, val] = factors_(discreteValues);
|
auto [factor, val] = factors_(discreteValues);
|
||||||
// Compute the error for the selected factor
|
// Compute the error for the selected factor
|
||||||
const double factorError = factor->error(continuousValues);
|
const double factorError = factor->error(continuousValues);
|
||||||
return factorError + (0.5 * val * val);
|
return factorError + (0.5 * val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -57,15 +57,16 @@ inline HybridGaussianFactorGraph::shared_ptr makeSwitchingChain(
|
||||||
|
|
||||||
// keyFunc(1) to keyFunc(n+1)
|
// keyFunc(1) to keyFunc(n+1)
|
||||||
for (size_t t = 1; t < n; t++) {
|
for (size_t t = 1; t < n; t++) {
|
||||||
std::vector<GaussianFactorValuePair> components = {
|
DiscreteKeys dKeys{{dKeyFunc(t), 2}};
|
||||||
{std::make_shared<JacobianFactor>(keyFunc(t), I_3x3, keyFunc(t + 1),
|
HybridGaussianFactor::FactorValuePairs components(
|
||||||
I_3x3, Z_3x1),
|
dKeys, {{std::make_shared<JacobianFactor>(keyFunc(t), I_3x3,
|
||||||
|
keyFunc(t + 1), I_3x3, Z_3x1),
|
||||||
0.0},
|
0.0},
|
||||||
{std::make_shared<JacobianFactor>(keyFunc(t), I_3x3, keyFunc(t + 1),
|
{std::make_shared<JacobianFactor>(
|
||||||
I_3x3, Vector3::Ones()),
|
keyFunc(t), I_3x3, keyFunc(t + 1), I_3x3, Vector3::Ones()),
|
||||||
0.0}};
|
0.0}});
|
||||||
hfg.add(HybridGaussianFactor({keyFunc(t), keyFunc(t + 1)},
|
hfg.add(
|
||||||
{{dKeyFunc(t), 2}}, components));
|
HybridGaussianFactor({keyFunc(t), keyFunc(t + 1)}, dKeys, components));
|
||||||
|
|
||||||
if (t > 1) {
|
if (t > 1) {
|
||||||
hfg.add(DecisionTreeFactor({{dKeyFunc(t - 1), 2}, {dKeyFunc(t), 2}},
|
hfg.add(DecisionTreeFactor({{dKeyFunc(t - 1), 2}, {dKeyFunc(t), 2}},
|
||||||
|
|
@ -167,8 +168,8 @@ struct Switching {
|
||||||
components.push_back(
|
components.push_back(
|
||||||
{std::dynamic_pointer_cast<NonlinearFactor>(f), 0.0});
|
{std::dynamic_pointer_cast<NonlinearFactor>(f), 0.0});
|
||||||
}
|
}
|
||||||
nonlinearFactorGraph.emplace_shared<HybridNonlinearFactor>(
|
nonlinearFactorGraph.emplace_shared<HybridNonlinearFactor>(keys, modes[k],
|
||||||
keys, DiscreteKeys{modes[k]}, components);
|
components);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add measurement factors
|
// Add measurement factors
|
||||||
|
|
|
||||||
|
|
@ -43,12 +43,13 @@ inline HybridBayesNet createHybridBayesNet(size_t num_measurements = 1,
|
||||||
// Create Gaussian mixture z_i = x0 + noise for each measurement.
|
// Create Gaussian mixture z_i = x0 + noise for each measurement.
|
||||||
for (size_t i = 0; i < num_measurements; i++) {
|
for (size_t i = 0; i < num_measurements; i++) {
|
||||||
const auto mode_i = manyModes ? DiscreteKey{M(i), 2} : mode;
|
const auto mode_i = manyModes ? DiscreteKey{M(i), 2} : mode;
|
||||||
|
DiscreteKeys modes{mode_i};
|
||||||
|
std::vector<GaussianConditional::shared_ptr> conditionals{
|
||||||
|
GaussianConditional::sharedMeanAndStddev(Z(i), I_1x1, X(0), Z_1x1, 0.5),
|
||||||
|
GaussianConditional::sharedMeanAndStddev(Z(i), I_1x1, X(0), Z_1x1, 3)};
|
||||||
bayesNet.emplace_shared<HybridGaussianConditional>(
|
bayesNet.emplace_shared<HybridGaussianConditional>(
|
||||||
KeyVector{Z(i)}, KeyVector{X(0)}, DiscreteKeys{mode_i},
|
KeyVector{Z(i)}, KeyVector{X(0)}, DiscreteKeys{mode_i},
|
||||||
std::vector{GaussianConditional::sharedMeanAndStddev(Z(i), I_1x1, X(0),
|
HybridGaussianConditional::Conditionals(modes, conditionals));
|
||||||
Z_1x1, 0.5),
|
|
||||||
GaussianConditional::sharedMeanAndStddev(Z(i), I_1x1, X(0),
|
|
||||||
Z_1x1, 3)});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create prior on X(0).
|
// Create prior on X(0).
|
||||||
|
|
|
||||||
|
|
@ -107,9 +107,11 @@ TEST(HybridBayesNet, evaluateHybrid) {
|
||||||
// Create hybrid Bayes net.
|
// Create hybrid Bayes net.
|
||||||
HybridBayesNet bayesNet;
|
HybridBayesNet bayesNet;
|
||||||
bayesNet.push_back(continuousConditional);
|
bayesNet.push_back(continuousConditional);
|
||||||
|
DiscreteKeys discreteParents{Asia};
|
||||||
bayesNet.emplace_shared<HybridGaussianConditional>(
|
bayesNet.emplace_shared<HybridGaussianConditional>(
|
||||||
KeyVector{X(1)}, KeyVector{}, DiscreteKeys{Asia},
|
KeyVector{X(1)}, KeyVector{}, discreteParents,
|
||||||
std::vector{conditional0, conditional1});
|
HybridGaussianConditional::Conditionals(
|
||||||
|
discreteParents, std::vector{conditional0, conditional1}));
|
||||||
bayesNet.emplace_shared<DiscreteConditional>(Asia, "99/1");
|
bayesNet.emplace_shared<DiscreteConditional>(Asia, "99/1");
|
||||||
|
|
||||||
// Create values at which to evaluate.
|
// Create values at which to evaluate.
|
||||||
|
|
@ -168,9 +170,11 @@ TEST(HybridBayesNet, Error) {
|
||||||
conditional1 = std::make_shared<GaussianConditional>(
|
conditional1 = std::make_shared<GaussianConditional>(
|
||||||
X(1), Vector1::Constant(2), I_1x1, model1);
|
X(1), Vector1::Constant(2), I_1x1, model1);
|
||||||
|
|
||||||
|
DiscreteKeys discreteParents{Asia};
|
||||||
auto gm = std::make_shared<HybridGaussianConditional>(
|
auto gm = std::make_shared<HybridGaussianConditional>(
|
||||||
KeyVector{X(1)}, KeyVector{}, DiscreteKeys{Asia},
|
KeyVector{X(1)}, KeyVector{}, discreteParents,
|
||||||
std::vector{conditional0, conditional1});
|
HybridGaussianConditional::Conditionals(
|
||||||
|
discreteParents, std::vector{conditional0, conditional1}));
|
||||||
// Create hybrid Bayes net.
|
// Create hybrid Bayes net.
|
||||||
HybridBayesNet bayesNet;
|
HybridBayesNet bayesNet;
|
||||||
bayesNet.push_back(continuousConditional);
|
bayesNet.push_back(continuousConditional);
|
||||||
|
|
@ -383,15 +387,15 @@ TEST(HybridBayesNet, Sampling) {
|
||||||
HybridNonlinearFactorGraph nfg;
|
HybridNonlinearFactorGraph nfg;
|
||||||
|
|
||||||
auto noise_model = noiseModel::Diagonal::Sigmas(Vector1(1.0));
|
auto noise_model = noiseModel::Diagonal::Sigmas(Vector1(1.0));
|
||||||
|
nfg.emplace_shared<PriorFactor<double>>(X(0), 0.0, noise_model);
|
||||||
|
|
||||||
auto zero_motion =
|
auto zero_motion =
|
||||||
std::make_shared<BetweenFactor<double>>(X(0), X(1), 0, noise_model);
|
std::make_shared<BetweenFactor<double>>(X(0), X(1), 0, noise_model);
|
||||||
auto one_motion =
|
auto one_motion =
|
||||||
std::make_shared<BetweenFactor<double>>(X(0), X(1), 1, noise_model);
|
std::make_shared<BetweenFactor<double>>(X(0), X(1), 1, noise_model);
|
||||||
|
|
||||||
DiscreteKeys discreteKeys{DiscreteKey(M(0), 2)};
|
DiscreteKeys discreteKeys{DiscreteKey(M(0), 2)};
|
||||||
HybridNonlinearFactor::Factors factors(
|
HybridNonlinearFactor::Factors factors(
|
||||||
discreteKeys, {{zero_motion, 0.0}, {one_motion, 0.0}});
|
discreteKeys, {{zero_motion, 0.0}, {one_motion, 0.0}});
|
||||||
nfg.emplace_shared<PriorFactor<double>>(X(0), 0.0, noise_model);
|
|
||||||
nfg.emplace_shared<HybridNonlinearFactor>(KeyVector{X(0), X(1)}, discreteKeys,
|
nfg.emplace_shared<HybridNonlinearFactor>(KeyVector{X(0), X(1)}, discreteKeys,
|
||||||
factors);
|
factors);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -437,8 +437,8 @@ static HybridNonlinearFactorGraph createHybridNonlinearFactorGraph() {
|
||||||
std::make_shared<BetweenFactor<double>>(X(0), X(1), 1, noise_model);
|
std::make_shared<BetweenFactor<double>>(X(0), X(1), 1, noise_model);
|
||||||
std::vector<NonlinearFactorValuePair> components = {{zero_motion, 0.0},
|
std::vector<NonlinearFactorValuePair> components = {{zero_motion, 0.0},
|
||||||
{one_motion, 0.0}};
|
{one_motion, 0.0}};
|
||||||
nfg.emplace_shared<HybridNonlinearFactor>(KeyVector{X(0), X(1)},
|
nfg.emplace_shared<HybridNonlinearFactor>(KeyVector{X(0), X(1)}, m,
|
||||||
DiscreteKeys{m}, components);
|
components);
|
||||||
|
|
||||||
return nfg;
|
return nfg;
|
||||||
}
|
}
|
||||||
|
|
@ -583,9 +583,6 @@ TEST(HybridEstimation, ModeSelection) {
|
||||||
graph.emplace_shared<PriorFactor<double>>(X(0), 0.0, measurement_model);
|
graph.emplace_shared<PriorFactor<double>>(X(0), 0.0, measurement_model);
|
||||||
graph.emplace_shared<PriorFactor<double>>(X(1), 0.0, measurement_model);
|
graph.emplace_shared<PriorFactor<double>>(X(1), 0.0, measurement_model);
|
||||||
|
|
||||||
DiscreteKeys modes;
|
|
||||||
modes.emplace_back(M(0), 2);
|
|
||||||
|
|
||||||
// The size of the noise model
|
// The size of the noise model
|
||||||
size_t d = 1;
|
size_t d = 1;
|
||||||
double noise_tight = 0.5, noise_loose = 5.0;
|
double noise_tight = 0.5, noise_loose = 5.0;
|
||||||
|
|
@ -594,11 +591,11 @@ TEST(HybridEstimation, ModeSelection) {
|
||||||
X(0), X(1), 0.0, noiseModel::Isotropic::Sigma(d, noise_loose)),
|
X(0), X(1), 0.0, noiseModel::Isotropic::Sigma(d, noise_loose)),
|
||||||
model1 = std::make_shared<MotionModel>(
|
model1 = std::make_shared<MotionModel>(
|
||||||
X(0), X(1), 0.0, noiseModel::Isotropic::Sigma(d, noise_tight));
|
X(0), X(1), 0.0, noiseModel::Isotropic::Sigma(d, noise_tight));
|
||||||
|
|
||||||
std::vector<NonlinearFactorValuePair> components = {{model0, 0.0},
|
std::vector<NonlinearFactorValuePair> components = {{model0, 0.0},
|
||||||
{model1, 0.0}};
|
{model1, 0.0}};
|
||||||
|
|
||||||
KeyVector keys = {X(0), X(1)};
|
KeyVector keys = {X(0), X(1)};
|
||||||
|
DiscreteKey modes(M(0), 2);
|
||||||
HybridNonlinearFactor mf(keys, modes, components);
|
HybridNonlinearFactor mf(keys, modes, components);
|
||||||
|
|
||||||
initial.insert(X(0), 0.0);
|
initial.insert(X(0), 0.0);
|
||||||
|
|
@ -617,18 +614,22 @@ TEST(HybridEstimation, ModeSelection) {
|
||||||
|
|
||||||
/**************************************************************/
|
/**************************************************************/
|
||||||
HybridBayesNet bn;
|
HybridBayesNet bn;
|
||||||
const DiscreteKey mode{M(0), 2};
|
const DiscreteKey mode(M(0), 2);
|
||||||
|
|
||||||
bn.push_back(
|
bn.push_back(
|
||||||
GaussianConditional::sharedMeanAndStddev(Z(0), -I_1x1, X(0), Z_1x1, 0.1));
|
GaussianConditional::sharedMeanAndStddev(Z(0), -I_1x1, X(0), Z_1x1, 0.1));
|
||||||
bn.push_back(
|
bn.push_back(
|
||||||
GaussianConditional::sharedMeanAndStddev(Z(0), -I_1x1, X(1), Z_1x1, 0.1));
|
GaussianConditional::sharedMeanAndStddev(Z(0), -I_1x1, X(1), Z_1x1, 0.1));
|
||||||
|
|
||||||
|
std::vector<GaussianConditional::shared_ptr> conditionals{
|
||||||
|
GaussianConditional::sharedMeanAndStddev(Z(0), I_1x1, X(0), -I_1x1, X(1),
|
||||||
|
Z_1x1, noise_loose),
|
||||||
|
GaussianConditional::sharedMeanAndStddev(Z(0), I_1x1, X(0), -I_1x1, X(1),
|
||||||
|
Z_1x1, noise_tight)};
|
||||||
bn.emplace_shared<HybridGaussianConditional>(
|
bn.emplace_shared<HybridGaussianConditional>(
|
||||||
KeyVector{Z(0)}, KeyVector{X(0), X(1)}, DiscreteKeys{mode},
|
KeyVector{Z(0)}, KeyVector{X(0), X(1)}, DiscreteKeys{mode},
|
||||||
std::vector{GaussianConditional::sharedMeanAndStddev(
|
HybridGaussianConditional::Conditionals(DiscreteKeys{mode},
|
||||||
Z(0), I_1x1, X(0), -I_1x1, X(1), Z_1x1, noise_loose),
|
conditionals));
|
||||||
GaussianConditional::sharedMeanAndStddev(
|
|
||||||
Z(0), I_1x1, X(0), -I_1x1, X(1), Z_1x1, noise_tight)});
|
|
||||||
|
|
||||||
VectorValues vv;
|
VectorValues vv;
|
||||||
vv.insert(Z(0), Z_1x1);
|
vv.insert(Z(0), Z_1x1);
|
||||||
|
|
@ -648,18 +649,22 @@ TEST(HybridEstimation, ModeSelection2) {
|
||||||
double noise_tight = 0.5, noise_loose = 5.0;
|
double noise_tight = 0.5, noise_loose = 5.0;
|
||||||
|
|
||||||
HybridBayesNet bn;
|
HybridBayesNet bn;
|
||||||
const DiscreteKey mode{M(0), 2};
|
const DiscreteKey mode(M(0), 2);
|
||||||
|
|
||||||
bn.push_back(
|
bn.push_back(
|
||||||
GaussianConditional::sharedMeanAndStddev(Z(0), -I_3x3, X(0), Z_3x1, 0.1));
|
GaussianConditional::sharedMeanAndStddev(Z(0), -I_3x3, X(0), Z_3x1, 0.1));
|
||||||
bn.push_back(
|
bn.push_back(
|
||||||
GaussianConditional::sharedMeanAndStddev(Z(0), -I_3x3, X(1), Z_3x1, 0.1));
|
GaussianConditional::sharedMeanAndStddev(Z(0), -I_3x3, X(1), Z_3x1, 0.1));
|
||||||
|
|
||||||
|
std::vector<GaussianConditional::shared_ptr> conditionals{
|
||||||
|
GaussianConditional::sharedMeanAndStddev(Z(0), I_3x3, X(0), -I_3x3, X(1),
|
||||||
|
Z_3x1, noise_loose),
|
||||||
|
GaussianConditional::sharedMeanAndStddev(Z(0), I_3x3, X(0), -I_3x3, X(1),
|
||||||
|
Z_3x1, noise_tight)};
|
||||||
bn.emplace_shared<HybridGaussianConditional>(
|
bn.emplace_shared<HybridGaussianConditional>(
|
||||||
KeyVector{Z(0)}, KeyVector{X(0), X(1)}, DiscreteKeys{mode},
|
KeyVector{Z(0)}, KeyVector{X(0), X(1)}, DiscreteKeys{mode},
|
||||||
std::vector{GaussianConditional::sharedMeanAndStddev(
|
HybridGaussianConditional::Conditionals(DiscreteKeys{mode},
|
||||||
Z(0), I_3x3, X(0), -I_3x3, X(1), Z_3x1, noise_loose),
|
conditionals));
|
||||||
GaussianConditional::sharedMeanAndStddev(
|
|
||||||
Z(0), I_3x3, X(0), -I_3x3, X(1), Z_3x1, noise_tight)});
|
|
||||||
|
|
||||||
VectorValues vv;
|
VectorValues vv;
|
||||||
vv.insert(Z(0), Z_3x1);
|
vv.insert(Z(0), Z_3x1);
|
||||||
|
|
@ -679,18 +684,15 @@ TEST(HybridEstimation, ModeSelection2) {
|
||||||
graph.emplace_shared<PriorFactor<Vector3>>(X(0), Z_3x1, measurement_model);
|
graph.emplace_shared<PriorFactor<Vector3>>(X(0), Z_3x1, measurement_model);
|
||||||
graph.emplace_shared<PriorFactor<Vector3>>(X(1), Z_3x1, measurement_model);
|
graph.emplace_shared<PriorFactor<Vector3>>(X(1), Z_3x1, measurement_model);
|
||||||
|
|
||||||
DiscreteKeys modes;
|
|
||||||
modes.emplace_back(M(0), 2);
|
|
||||||
|
|
||||||
auto model0 = std::make_shared<BetweenFactor<Vector3>>(
|
auto model0 = std::make_shared<BetweenFactor<Vector3>>(
|
||||||
X(0), X(1), Z_3x1, noiseModel::Isotropic::Sigma(d, noise_loose)),
|
X(0), X(1), Z_3x1, noiseModel::Isotropic::Sigma(d, noise_loose)),
|
||||||
model1 = std::make_shared<BetweenFactor<Vector3>>(
|
model1 = std::make_shared<BetweenFactor<Vector3>>(
|
||||||
X(0), X(1), Z_3x1, noiseModel::Isotropic::Sigma(d, noise_tight));
|
X(0), X(1), Z_3x1, noiseModel::Isotropic::Sigma(d, noise_tight));
|
||||||
|
|
||||||
std::vector<NonlinearFactorValuePair> components = {{model0, 0.0},
|
std::vector<NonlinearFactorValuePair> components = {{model0, 0.0},
|
||||||
{model1, 0.0}};
|
{model1, 0.0}};
|
||||||
|
|
||||||
KeyVector keys = {X(0), X(1)};
|
KeyVector keys = {X(0), X(1)};
|
||||||
|
DiscreteKey modes(M(0), 2);
|
||||||
HybridNonlinearFactor mf(keys, modes, components);
|
HybridNonlinearFactor mf(keys, modes, components);
|
||||||
|
|
||||||
initial.insert<Vector3>(X(0), Z_3x1);
|
initial.insert<Vector3>(X(0), Z_3x1);
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,9 @@ const std::vector<GaussianConditional::shared_ptr> conditionals{
|
||||||
commonSigma),
|
commonSigma),
|
||||||
GaussianConditional::sharedMeanAndStddev(Z(0), I_1x1, X(0), Vector1(0.0),
|
GaussianConditional::sharedMeanAndStddev(Z(0), I_1x1, X(0), Vector1(0.0),
|
||||||
commonSigma)};
|
commonSigma)};
|
||||||
const HybridGaussianConditional mixture({Z(0)}, {X(0)}, {mode}, conditionals);
|
const HybridGaussianConditional mixture(
|
||||||
|
{Z(0)}, {X(0)}, {mode},
|
||||||
|
HybridGaussianConditional::Conditionals({mode}, conditionals));
|
||||||
} // namespace equal_constants
|
} // namespace equal_constants
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
|
|
@ -153,7 +155,9 @@ const std::vector<GaussianConditional::shared_ptr> conditionals{
|
||||||
0.5),
|
0.5),
|
||||||
GaussianConditional::sharedMeanAndStddev(Z(0), I_1x1, X(0), Vector1(0.0),
|
GaussianConditional::sharedMeanAndStddev(Z(0), I_1x1, X(0), Vector1(0.0),
|
||||||
3.0)};
|
3.0)};
|
||||||
const HybridGaussianConditional mixture({Z(0)}, {X(0)}, {mode}, conditionals);
|
const HybridGaussianConditional mixture(
|
||||||
|
{Z(0)}, {X(0)}, {mode},
|
||||||
|
HybridGaussianConditional::Conditionals({mode}, conditionals));
|
||||||
} // namespace mode_dependent_constants
|
} // namespace mode_dependent_constants
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
|
|
|
||||||
|
|
@ -233,8 +233,11 @@ static HybridBayesNet GetGaussianMixtureModel(double mu0, double mu1,
|
||||||
c1 = make_shared<GaussianConditional>(z, Vector1(mu1), I_1x1, model1);
|
c1 = make_shared<GaussianConditional>(z, Vector1(mu1), I_1x1, model1);
|
||||||
|
|
||||||
HybridBayesNet hbn;
|
HybridBayesNet hbn;
|
||||||
|
DiscreteKeys discreteParents{m};
|
||||||
hbn.emplace_shared<HybridGaussianConditional>(
|
hbn.emplace_shared<HybridGaussianConditional>(
|
||||||
KeyVector{z}, KeyVector{}, DiscreteKeys{m}, std::vector{c0, c1});
|
KeyVector{z}, KeyVector{}, discreteParents,
|
||||||
|
HybridGaussianConditional::Conditionals(discreteParents,
|
||||||
|
std::vector{c0, c1}));
|
||||||
|
|
||||||
auto mixing = make_shared<DiscreteConditional>(m, "50/50");
|
auto mixing = make_shared<DiscreteConditional>(m, "50/50");
|
||||||
hbn.push_back(mixing);
|
hbn.push_back(mixing);
|
||||||
|
|
@ -408,8 +411,11 @@ static HybridGaussianConditional::shared_ptr CreateHybridMotionModel(
|
||||||
-I_1x1, model0),
|
-I_1x1, model0),
|
||||||
c1 = make_shared<GaussianConditional>(X(1), Vector1(mu1), I_1x1, X(0),
|
c1 = make_shared<GaussianConditional>(X(1), Vector1(mu1), I_1x1, X(0),
|
||||||
-I_1x1, model1);
|
-I_1x1, model1);
|
||||||
|
DiscreteKeys discreteParents{m1};
|
||||||
return std::make_shared<HybridGaussianConditional>(
|
return std::make_shared<HybridGaussianConditional>(
|
||||||
KeyVector{X(1)}, KeyVector{X(0)}, DiscreteKeys{m1}, std::vector{c0, c1});
|
KeyVector{X(1)}, KeyVector{X(0)}, discreteParents,
|
||||||
|
HybridGaussianConditional::Conditionals(discreteParents,
|
||||||
|
std::vector{c0, c1}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create two state Bayes network with 1 or two measurement models
|
/// Create two state Bayes network with 1 or two measurement models
|
||||||
|
|
|
||||||
|
|
@ -181,7 +181,7 @@ TEST(HybridGaussianFactorGraph, eliminateFullMultifrontalSimple) {
|
||||||
std::vector<GaussianFactorValuePair> factors = {
|
std::vector<GaussianFactorValuePair> factors = {
|
||||||
{std::make_shared<JacobianFactor>(X(1), I_3x3, Z_3x1), 0.0},
|
{std::make_shared<JacobianFactor>(X(1), I_3x3, Z_3x1), 0.0},
|
||||||
{std::make_shared<JacobianFactor>(X(1), I_3x3, Vector3::Ones()), 0.0}};
|
{std::make_shared<JacobianFactor>(X(1), I_3x3, Vector3::Ones()), 0.0}};
|
||||||
hfg.add(HybridGaussianFactor({X(1)}, {{M(1), 2}}, factors));
|
hfg.add(HybridGaussianFactor({X(1)}, {M(1), 2}, factors));
|
||||||
|
|
||||||
hfg.add(DecisionTreeFactor(m1, {2, 8}));
|
hfg.add(DecisionTreeFactor(m1, {2, 8}));
|
||||||
// TODO(Varun) Adding extra discrete variable not connected to continuous
|
// TODO(Varun) Adding extra discrete variable not connected to continuous
|
||||||
|
|
@ -241,7 +241,7 @@ TEST(HybridGaussianFactorGraph, eliminateFullMultifrontalTwoClique) {
|
||||||
std::vector<GaussianFactorValuePair> factors = {
|
std::vector<GaussianFactorValuePair> factors = {
|
||||||
{std::make_shared<JacobianFactor>(X(0), I_3x3, Z_3x1), 0.0},
|
{std::make_shared<JacobianFactor>(X(0), I_3x3, Z_3x1), 0.0},
|
||||||
{std::make_shared<JacobianFactor>(X(0), I_3x3, Vector3::Ones()), 0.0}};
|
{std::make_shared<JacobianFactor>(X(0), I_3x3, Vector3::Ones()), 0.0}};
|
||||||
hfg.add(HybridGaussianFactor({X(0)}, {{M(0), 2}}, factors));
|
hfg.add(HybridGaussianFactor({X(0)}, {M(0), 2}, factors));
|
||||||
|
|
||||||
DecisionTree<Key, GaussianFactorValuePair> dt1(
|
DecisionTree<Key, GaussianFactorValuePair> dt1(
|
||||||
M(1), {std::make_shared<JacobianFactor>(X(2), I_3x3, Z_3x1), 0.0},
|
M(1), {std::make_shared<JacobianFactor>(X(2), I_3x3, Z_3x1), 0.0},
|
||||||
|
|
@ -682,8 +682,11 @@ TEST(HybridGaussianFactorGraph, ErrorTreeWithConditional) {
|
||||||
x0, -I_1x1, model0),
|
x0, -I_1x1, model0),
|
||||||
c1 = make_shared<GaussianConditional>(f01, Vector1(mu), I_1x1, x1, I_1x1,
|
c1 = make_shared<GaussianConditional>(f01, Vector1(mu), I_1x1, x1, I_1x1,
|
||||||
x0, -I_1x1, model1);
|
x0, -I_1x1, model1);
|
||||||
|
DiscreteKeys discreteParents{m1};
|
||||||
hbn.emplace_shared<HybridGaussianConditional>(
|
hbn.emplace_shared<HybridGaussianConditional>(
|
||||||
KeyVector{f01}, KeyVector{x0, x1}, DiscreteKeys{m1}, std::vector{c0, c1});
|
KeyVector{f01}, KeyVector{x0, x1}, discreteParents,
|
||||||
|
HybridGaussianConditional::Conditionals(discreteParents,
|
||||||
|
std::vector{c0, c1}));
|
||||||
|
|
||||||
// Discrete uniform prior.
|
// Discrete uniform prior.
|
||||||
hbn.emplace_shared<DiscreteConditional>(m1, "0.5/0.5");
|
hbn.emplace_shared<DiscreteConditional>(m1, "0.5/0.5");
|
||||||
|
|
@ -806,9 +809,11 @@ TEST(HybridGaussianFactorGraph, EliminateTiny1) {
|
||||||
X(0), Vector1(14.1421), I_1x1 * 2.82843),
|
X(0), Vector1(14.1421), I_1x1 * 2.82843),
|
||||||
conditional1 = std::make_shared<GaussianConditional>(
|
conditional1 = std::make_shared<GaussianConditional>(
|
||||||
X(0), Vector1(10.1379), I_1x1 * 2.02759);
|
X(0), Vector1(10.1379), I_1x1 * 2.02759);
|
||||||
|
DiscreteKeys discreteParents{mode};
|
||||||
expectedBayesNet.emplace_shared<HybridGaussianConditional>(
|
expectedBayesNet.emplace_shared<HybridGaussianConditional>(
|
||||||
KeyVector{X(0)}, KeyVector{}, DiscreteKeys{mode},
|
KeyVector{X(0)}, KeyVector{}, discreteParents,
|
||||||
std::vector{conditional0, conditional1});
|
HybridGaussianConditional::Conditionals(
|
||||||
|
discreteParents, std::vector{conditional0, conditional1}));
|
||||||
|
|
||||||
// Add prior on mode.
|
// Add prior on mode.
|
||||||
expectedBayesNet.emplace_shared<DiscreteConditional>(mode, "74/26");
|
expectedBayesNet.emplace_shared<DiscreteConditional>(mode, "74/26");
|
||||||
|
|
@ -831,12 +836,13 @@ TEST(HybridGaussianFactorGraph, EliminateTiny1Swapped) {
|
||||||
HybridBayesNet bn;
|
HybridBayesNet bn;
|
||||||
|
|
||||||
// Create Gaussian mixture z_0 = x0 + noise for each measurement.
|
// Create Gaussian mixture z_0 = x0 + noise for each measurement.
|
||||||
|
std::vector<GaussianConditional::shared_ptr> conditionals{
|
||||||
|
GaussianConditional::sharedMeanAndStddev(Z(0), I_1x1, X(0), Z_1x1, 3),
|
||||||
|
GaussianConditional::sharedMeanAndStddev(Z(0), I_1x1, X(0), Z_1x1, 0.5)};
|
||||||
auto gm = std::make_shared<HybridGaussianConditional>(
|
auto gm = std::make_shared<HybridGaussianConditional>(
|
||||||
KeyVector{Z(0)}, KeyVector{X(0)}, DiscreteKeys{mode},
|
KeyVector{Z(0)}, KeyVector{X(0)}, DiscreteKeys{mode},
|
||||||
std::vector{
|
HybridGaussianConditional::Conditionals(DiscreteKeys{mode},
|
||||||
GaussianConditional::sharedMeanAndStddev(Z(0), I_1x1, X(0), Z_1x1, 3),
|
conditionals));
|
||||||
GaussianConditional::sharedMeanAndStddev(Z(0), I_1x1, X(0), Z_1x1,
|
|
||||||
0.5)});
|
|
||||||
bn.push_back(gm);
|
bn.push_back(gm);
|
||||||
|
|
||||||
// Create prior on X(0).
|
// Create prior on X(0).
|
||||||
|
|
@ -865,7 +871,8 @@ TEST(HybridGaussianFactorGraph, EliminateTiny1Swapped) {
|
||||||
X(0), Vector1(14.1421), I_1x1 * 2.82843);
|
X(0), Vector1(14.1421), I_1x1 * 2.82843);
|
||||||
expectedBayesNet.emplace_shared<HybridGaussianConditional>(
|
expectedBayesNet.emplace_shared<HybridGaussianConditional>(
|
||||||
KeyVector{X(0)}, KeyVector{}, DiscreteKeys{mode},
|
KeyVector{X(0)}, KeyVector{}, DiscreteKeys{mode},
|
||||||
std::vector{conditional0, conditional1});
|
HybridGaussianConditional::Conditionals(
|
||||||
|
DiscreteKeys{mode}, std::vector{conditional0, conditional1}));
|
||||||
|
|
||||||
// Add prior on mode.
|
// Add prior on mode.
|
||||||
expectedBayesNet.emplace_shared<DiscreteConditional>(mode, "1/1");
|
expectedBayesNet.emplace_shared<DiscreteConditional>(mode, "1/1");
|
||||||
|
|
@ -902,7 +909,8 @@ TEST(HybridGaussianFactorGraph, EliminateTiny2) {
|
||||||
X(0), Vector1(10.274), I_1x1 * 2.0548);
|
X(0), Vector1(10.274), I_1x1 * 2.0548);
|
||||||
expectedBayesNet.emplace_shared<HybridGaussianConditional>(
|
expectedBayesNet.emplace_shared<HybridGaussianConditional>(
|
||||||
KeyVector{X(0)}, KeyVector{}, DiscreteKeys{mode},
|
KeyVector{X(0)}, KeyVector{}, DiscreteKeys{mode},
|
||||||
std::vector{conditional0, conditional1});
|
HybridGaussianConditional::Conditionals(
|
||||||
|
DiscreteKeys{mode}, std::vector{conditional0, conditional1}));
|
||||||
|
|
||||||
// Add prior on mode.
|
// Add prior on mode.
|
||||||
expectedBayesNet.emplace_shared<DiscreteConditional>(mode, "23/77");
|
expectedBayesNet.emplace_shared<DiscreteConditional>(mode, "23/77");
|
||||||
|
|
@ -947,12 +955,14 @@ TEST(HybridGaussianFactorGraph, EliminateSwitchingNetwork) {
|
||||||
for (size_t t : {0, 1, 2}) {
|
for (size_t t : {0, 1, 2}) {
|
||||||
// Create Gaussian mixture on Z(t) conditioned on X(t) and mode N(t):
|
// Create Gaussian mixture on Z(t) conditioned on X(t) and mode N(t):
|
||||||
const auto noise_mode_t = DiscreteKey{N(t), 2};
|
const auto noise_mode_t = DiscreteKey{N(t), 2};
|
||||||
|
std::vector<GaussianConditional::shared_ptr> conditionals{
|
||||||
|
GaussianConditional::sharedMeanAndStddev(Z(t), I_1x1, X(t), Z_1x1, 0.5),
|
||||||
|
GaussianConditional::sharedMeanAndStddev(Z(t), I_1x1, X(t), Z_1x1,
|
||||||
|
3.0)};
|
||||||
bn.emplace_shared<HybridGaussianConditional>(
|
bn.emplace_shared<HybridGaussianConditional>(
|
||||||
KeyVector{Z(t)}, KeyVector{X(t)}, DiscreteKeys{noise_mode_t},
|
KeyVector{Z(t)}, KeyVector{X(t)}, DiscreteKeys{noise_mode_t},
|
||||||
std::vector{GaussianConditional::sharedMeanAndStddev(Z(t), I_1x1, X(t),
|
HybridGaussianConditional::Conditionals(DiscreteKeys{noise_mode_t},
|
||||||
Z_1x1, 0.5),
|
conditionals));
|
||||||
GaussianConditional::sharedMeanAndStddev(Z(t), I_1x1, X(t),
|
|
||||||
Z_1x1, 3.0)});
|
|
||||||
|
|
||||||
// Create prior on discrete mode N(t):
|
// Create prior on discrete mode N(t):
|
||||||
bn.emplace_shared<DiscreteConditional>(noise_mode_t, "20/80");
|
bn.emplace_shared<DiscreteConditional>(noise_mode_t, "20/80");
|
||||||
|
|
@ -962,12 +972,15 @@ TEST(HybridGaussianFactorGraph, EliminateSwitchingNetwork) {
|
||||||
for (size_t t : {2, 1}) {
|
for (size_t t : {2, 1}) {
|
||||||
// Create Gaussian mixture on X(t) conditioned on X(t-1) and mode M(t-1):
|
// Create Gaussian mixture on X(t) conditioned on X(t-1) and mode M(t-1):
|
||||||
const auto motion_model_t = DiscreteKey{M(t), 2};
|
const auto motion_model_t = DiscreteKey{M(t), 2};
|
||||||
|
std::vector<GaussianConditional::shared_ptr> conditionals{
|
||||||
|
GaussianConditional::sharedMeanAndStddev(X(t), I_1x1, X(t - 1), Z_1x1,
|
||||||
|
0.2),
|
||||||
|
GaussianConditional::sharedMeanAndStddev(X(t), I_1x1, X(t - 1), I_1x1,
|
||||||
|
0.2)};
|
||||||
auto gm = std::make_shared<HybridGaussianConditional>(
|
auto gm = std::make_shared<HybridGaussianConditional>(
|
||||||
KeyVector{X(t)}, KeyVector{X(t - 1)}, DiscreteKeys{motion_model_t},
|
KeyVector{X(t)}, KeyVector{X(t - 1)}, DiscreteKeys{motion_model_t},
|
||||||
std::vector{GaussianConditional::sharedMeanAndStddev(
|
HybridGaussianConditional::Conditionals(DiscreteKeys{motion_model_t},
|
||||||
X(t), I_1x1, X(t - 1), Z_1x1, 0.2),
|
conditionals));
|
||||||
GaussianConditional::sharedMeanAndStddev(
|
|
||||||
X(t), I_1x1, X(t - 1), I_1x1, 0.2)});
|
|
||||||
bn.push_back(gm);
|
bn.push_back(gm);
|
||||||
|
|
||||||
// Create prior on motion model M(t):
|
// Create prior on motion model M(t):
|
||||||
|
|
|
||||||
|
|
@ -423,7 +423,7 @@ TEST(HybridGaussianISAM, NonTrivial) {
|
||||||
std::vector<std::pair<PlanarMotionModel::shared_ptr, double>> components = {
|
std::vector<std::pair<PlanarMotionModel::shared_ptr, double>> components = {
|
||||||
{moving, 0.0}, {still, 0.0}};
|
{moving, 0.0}, {still, 0.0}};
|
||||||
auto mixtureFactor = std::make_shared<HybridNonlinearFactor>(
|
auto mixtureFactor = std::make_shared<HybridNonlinearFactor>(
|
||||||
contKeys, DiscreteKeys{gtsam::DiscreteKey(M(1), 2)}, components);
|
contKeys, gtsam::DiscreteKey(M(1), 2), components);
|
||||||
fg.push_back(mixtureFactor);
|
fg.push_back(mixtureFactor);
|
||||||
|
|
||||||
// Add equivalent of ImuFactor
|
// Add equivalent of ImuFactor
|
||||||
|
|
@ -463,7 +463,7 @@ TEST(HybridGaussianISAM, NonTrivial) {
|
||||||
std::make_shared<PlanarMotionModel>(W(1), W(2), odometry, noise_model);
|
std::make_shared<PlanarMotionModel>(W(1), W(2), odometry, noise_model);
|
||||||
components = {{moving, 0.0}, {still, 0.0}};
|
components = {{moving, 0.0}, {still, 0.0}};
|
||||||
mixtureFactor = std::make_shared<HybridNonlinearFactor>(
|
mixtureFactor = std::make_shared<HybridNonlinearFactor>(
|
||||||
contKeys, DiscreteKeys{gtsam::DiscreteKey(M(2), 2)}, components);
|
contKeys, gtsam::DiscreteKey(M(2), 2), components);
|
||||||
fg.push_back(mixtureFactor);
|
fg.push_back(mixtureFactor);
|
||||||
|
|
||||||
// Add equivalent of ImuFactor
|
// Add equivalent of ImuFactor
|
||||||
|
|
@ -506,7 +506,7 @@ TEST(HybridGaussianISAM, NonTrivial) {
|
||||||
std::make_shared<PlanarMotionModel>(W(2), W(3), odometry, noise_model);
|
std::make_shared<PlanarMotionModel>(W(2), W(3), odometry, noise_model);
|
||||||
components = {{moving, 0.0}, {still, 0.0}};
|
components = {{moving, 0.0}, {still, 0.0}};
|
||||||
mixtureFactor = std::make_shared<HybridNonlinearFactor>(
|
mixtureFactor = std::make_shared<HybridNonlinearFactor>(
|
||||||
contKeys, DiscreteKeys{gtsam::DiscreteKey(M(3), 2)}, components);
|
contKeys, gtsam::DiscreteKey(M(3), 2), components);
|
||||||
fg.push_back(mixtureFactor);
|
fg.push_back(mixtureFactor);
|
||||||
|
|
||||||
// Add equivalent of ImuFactor
|
// Add equivalent of ImuFactor
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ TEST(HybridGaussianFactorGraph, Resize) {
|
||||||
std::vector<std::pair<MotionModel::shared_ptr, double>> components = {
|
std::vector<std::pair<MotionModel::shared_ptr, double>> components = {
|
||||||
{still, 0.0}, {moving, 0.0}};
|
{still, 0.0}, {moving, 0.0}};
|
||||||
auto dcFactor = std::make_shared<HybridNonlinearFactor>(
|
auto dcFactor = std::make_shared<HybridNonlinearFactor>(
|
||||||
contKeys, DiscreteKeys{gtsam::DiscreteKey(M(1), 2)}, components);
|
contKeys, gtsam::DiscreteKey(M(1), 2), components);
|
||||||
nhfg.push_back(dcFactor);
|
nhfg.push_back(dcFactor);
|
||||||
|
|
||||||
Values linearizationPoint;
|
Values linearizationPoint;
|
||||||
|
|
@ -170,12 +170,12 @@ TEST(HybridGaussianFactorGraph, HybridNonlinearFactor) {
|
||||||
// Check for exception when number of continuous keys are under-specified.
|
// Check for exception when number of continuous keys are under-specified.
|
||||||
KeyVector contKeys = {X(0)};
|
KeyVector contKeys = {X(0)};
|
||||||
THROWS_EXCEPTION(std::make_shared<HybridNonlinearFactor>(
|
THROWS_EXCEPTION(std::make_shared<HybridNonlinearFactor>(
|
||||||
contKeys, DiscreteKeys{gtsam::DiscreteKey(M(1), 2)}, components));
|
contKeys, gtsam::DiscreteKey(M(1), 2), components));
|
||||||
|
|
||||||
// Check for exception when number of continuous keys are too many.
|
// Check for exception when number of continuous keys are too many.
|
||||||
contKeys = {X(0), X(1), X(2)};
|
contKeys = {X(0), X(1), X(2)};
|
||||||
THROWS_EXCEPTION(std::make_shared<HybridNonlinearFactor>(
|
THROWS_EXCEPTION(std::make_shared<HybridNonlinearFactor>(
|
||||||
contKeys, DiscreteKeys{gtsam::DiscreteKey(M(1), 2)}, components));
|
contKeys, gtsam::DiscreteKey(M(1), 2), components));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
@ -807,7 +807,7 @@ TEST(HybridFactorGraph, DefaultDecisionTree) {
|
||||||
std::vector<std::pair<PlanarMotionModel::shared_ptr, double>> motion_models =
|
std::vector<std::pair<PlanarMotionModel::shared_ptr, double>> motion_models =
|
||||||
{{still, 0.0}, {moving, 0.0}};
|
{{still, 0.0}, {moving, 0.0}};
|
||||||
fg.emplace_shared<HybridNonlinearFactor>(
|
fg.emplace_shared<HybridNonlinearFactor>(
|
||||||
contKeys, DiscreteKeys{gtsam::DiscreteKey(M(1), 2)}, motion_models);
|
contKeys, gtsam::DiscreteKey(M(1), 2), motion_models);
|
||||||
|
|
||||||
// Add Range-Bearing measurements to from X0 to L0 and X1 to L1.
|
// Add Range-Bearing measurements to from X0 to L0 and X1 to L1.
|
||||||
// create a noise model for the landmark measurements
|
// create a noise model for the landmark measurements
|
||||||
|
|
|
||||||
|
|
@ -442,7 +442,7 @@ TEST(HybridNonlinearISAM, NonTrivial) {
|
||||||
std::vector<std::pair<PlanarMotionModel::shared_ptr, double>> components = {
|
std::vector<std::pair<PlanarMotionModel::shared_ptr, double>> components = {
|
||||||
{moving, 0.0}, {still, 0.0}};
|
{moving, 0.0}, {still, 0.0}};
|
||||||
auto mixtureFactor = std::make_shared<HybridNonlinearFactor>(
|
auto mixtureFactor = std::make_shared<HybridNonlinearFactor>(
|
||||||
contKeys, DiscreteKeys{gtsam::DiscreteKey(M(1), 2)}, components);
|
contKeys, gtsam::DiscreteKey(M(1), 2), components);
|
||||||
fg.push_back(mixtureFactor);
|
fg.push_back(mixtureFactor);
|
||||||
|
|
||||||
// Add equivalent of ImuFactor
|
// Add equivalent of ImuFactor
|
||||||
|
|
@ -482,7 +482,7 @@ TEST(HybridNonlinearISAM, NonTrivial) {
|
||||||
std::make_shared<PlanarMotionModel>(W(1), W(2), odometry, noise_model);
|
std::make_shared<PlanarMotionModel>(W(1), W(2), odometry, noise_model);
|
||||||
components = {{moving, 0.0}, {still, 0.0}};
|
components = {{moving, 0.0}, {still, 0.0}};
|
||||||
mixtureFactor = std::make_shared<HybridNonlinearFactor>(
|
mixtureFactor = std::make_shared<HybridNonlinearFactor>(
|
||||||
contKeys, DiscreteKeys{gtsam::DiscreteKey(M(2), 2)}, components);
|
contKeys, gtsam::DiscreteKey(M(2), 2), components);
|
||||||
fg.push_back(mixtureFactor);
|
fg.push_back(mixtureFactor);
|
||||||
|
|
||||||
// Add equivalent of ImuFactor
|
// Add equivalent of ImuFactor
|
||||||
|
|
@ -525,7 +525,7 @@ TEST(HybridNonlinearISAM, NonTrivial) {
|
||||||
std::make_shared<PlanarMotionModel>(W(2), W(3), odometry, noise_model);
|
std::make_shared<PlanarMotionModel>(W(2), W(3), odometry, noise_model);
|
||||||
components = {{moving, 0.0}, {still, 0.0}};
|
components = {{moving, 0.0}, {still, 0.0}};
|
||||||
mixtureFactor = std::make_shared<HybridNonlinearFactor>(
|
mixtureFactor = std::make_shared<HybridNonlinearFactor>(
|
||||||
contKeys, DiscreteKeys{gtsam::DiscreteKey(M(3), 2)}, components);
|
contKeys, gtsam::DiscreteKey(M(3), 2), components);
|
||||||
fg.push_back(mixtureFactor);
|
fg.push_back(mixtureFactor);
|
||||||
|
|
||||||
// Add equivalent of ImuFactor
|
// Add equivalent of ImuFactor
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ BOOST_CLASS_EXPORT_GUID(HybridBayesNet, "gtsam_HybridBayesNet");
|
||||||
// Test HybridGaussianFactor serialization.
|
// Test HybridGaussianFactor serialization.
|
||||||
TEST(HybridSerialization, HybridGaussianFactor) {
|
TEST(HybridSerialization, HybridGaussianFactor) {
|
||||||
KeyVector continuousKeys{X(0)};
|
KeyVector continuousKeys{X(0)};
|
||||||
DiscreteKeys discreteKeys{{M(0), 2}};
|
DiscreteKey discreteKey{M(0), 2};
|
||||||
|
|
||||||
auto A = Matrix::Zero(2, 1);
|
auto A = Matrix::Zero(2, 1);
|
||||||
auto b0 = Matrix::Zero(2, 1);
|
auto b0 = Matrix::Zero(2, 1);
|
||||||
|
|
@ -85,7 +85,7 @@ TEST(HybridSerialization, HybridGaussianFactor) {
|
||||||
auto f1 = std::make_shared<JacobianFactor>(X(0), A, b1);
|
auto f1 = std::make_shared<JacobianFactor>(X(0), A, b1);
|
||||||
std::vector<GaussianFactorValuePair> factors{{f0, 0.0}, {f1, 0.0}};
|
std::vector<GaussianFactorValuePair> factors{{f0, 0.0}, {f1, 0.0}};
|
||||||
|
|
||||||
const HybridGaussianFactor factor(continuousKeys, discreteKeys, factors);
|
const HybridGaussianFactor factor(continuousKeys, discreteKey, factors);
|
||||||
|
|
||||||
EXPECT(equalsObj<HybridGaussianFactor>(factor));
|
EXPECT(equalsObj<HybridGaussianFactor>(factor));
|
||||||
EXPECT(equalsXML<HybridGaussianFactor>(factor));
|
EXPECT(equalsXML<HybridGaussianFactor>(factor));
|
||||||
|
|
@ -116,7 +116,8 @@ TEST(HybridSerialization, HybridGaussianConditional) {
|
||||||
const auto conditional1 = std::make_shared<GaussianConditional>(
|
const auto conditional1 = std::make_shared<GaussianConditional>(
|
||||||
GaussianConditional::FromMeanAndStddev(Z(0), I, X(0), Vector1(0), 3));
|
GaussianConditional::FromMeanAndStddev(Z(0), I, X(0), Vector1(0), 3));
|
||||||
const HybridGaussianConditional gm({Z(0)}, {X(0)}, {mode},
|
const HybridGaussianConditional gm({Z(0)}, {X(0)}, {mode},
|
||||||
{conditional0, conditional1});
|
HybridGaussianConditional::Conditionals(
|
||||||
|
{mode}, {conditional0, conditional1}));
|
||||||
|
|
||||||
EXPECT(equalsObj<HybridGaussianConditional>(gm));
|
EXPECT(equalsObj<HybridGaussianConditional>(gm));
|
||||||
EXPECT(equalsXML<HybridGaussianConditional>(gm));
|
EXPECT(equalsXML<HybridGaussianConditional>(gm));
|
||||||
|
|
|
||||||
|
|
@ -714,6 +714,9 @@ double ComputeLogNormalizer(
|
||||||
const noiseModel::Gaussian::shared_ptr& noise_model) {
|
const noiseModel::Gaussian::shared_ptr& noise_model) {
|
||||||
// Since noise models are Gaussian, we can get the logDeterminant using
|
// Since noise models are Gaussian, we can get the logDeterminant using
|
||||||
// the same trick as in GaussianConditional
|
// the same trick as in GaussianConditional
|
||||||
|
// Sigma = (R'R)^{-1}, det(Sigma) = det((R'R)^{-1}) = det(R'R)^{-1}
|
||||||
|
// log det(Sigma) = -log(det(R'R)) = -2*log(det(R))
|
||||||
|
// Hence, log det(Sigma)) = -2.0 * logDetR()
|
||||||
double logDetR = noise_model->R()
|
double logDetR = noise_model->R()
|
||||||
.diagonal()
|
.diagonal()
|
||||||
.unaryExpr([](double x) { return log(x); })
|
.unaryExpr([](double x) { return log(x); })
|
||||||
|
|
|
||||||
|
|
@ -752,7 +752,7 @@ namespace gtsam {
|
||||||
template<> struct traits<noiseModel::Unit> : public Testable<noiseModel::Unit> {};
|
template<> struct traits<noiseModel::Unit> : public Testable<noiseModel::Unit> {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Helper function to compute the sqrt(|2πΣ|) normalizer values
|
* @brief Helper function to compute the log(|2πΣ|) normalizer values
|
||||||
* for a Gaussian noise model.
|
* for a Gaussian noise model.
|
||||||
* We compute this in the log-space for numerical accuracy.
|
* We compute this in the log-space for numerical accuracy.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -807,6 +807,26 @@ TEST(NoiseModel, NonDiagonalGaussian)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(NoiseModel, ComputeLogNormalizer) {
|
||||||
|
// Very simple 1D noise model, which we can compute by hand.
|
||||||
|
double sigma = 0.1;
|
||||||
|
auto noise_model = Isotropic::Sigma(1, sigma);
|
||||||
|
double actual_value = ComputeLogNormalizer(noise_model);
|
||||||
|
// Compute log(|2πΣ|) by hand.
|
||||||
|
// = log(2π) + log(Σ) (since it is 1D)
|
||||||
|
constexpr double log2pi = 1.8378770664093454835606594728112;
|
||||||
|
double expected_value = log2pi + log(sigma * sigma);
|
||||||
|
EXPECT_DOUBLES_EQUAL(expected_value, actual_value, 1e-9);
|
||||||
|
|
||||||
|
// Similar situation in the 3D case
|
||||||
|
size_t n = 3;
|
||||||
|
auto noise_model2 = Isotropic::Sigma(n, sigma);
|
||||||
|
double actual_value2 = ComputeLogNormalizer(noise_model2);
|
||||||
|
// We multiply by 3 due to the determinant
|
||||||
|
double expected_value2 = n * (log2pi + log(sigma * sigma));
|
||||||
|
EXPECT_DOUBLES_EQUAL(expected_value2, actual_value2, 1e-9);
|
||||||
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
int main() { TestResult tr; return TestRegistry::runAllTests(tr); }
|
int main() { TestResult tr; return TestRegistry::runAllTests(tr); }
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue