commit
cd69c51e86
|
|
@ -159,6 +159,10 @@ TEST(DiscreteBayesTree, ThinTree) {
|
||||||
clique->separatorMarginal(EliminateDiscrete);
|
clique->separatorMarginal(EliminateDiscrete);
|
||||||
DOUBLES_EQUAL(joint_8_12, separatorMarginal0(all1), 1e-9);
|
DOUBLES_EQUAL(joint_8_12, separatorMarginal0(all1), 1e-9);
|
||||||
|
|
||||||
|
DOUBLES_EQUAL(joint_12_14, 0.1875, 1e-9);
|
||||||
|
DOUBLES_EQUAL(joint_8_12_14, 0.0375, 1e-9);
|
||||||
|
DOUBLES_EQUAL(joint_9_12_14, 0.15, 1e-9);
|
||||||
|
|
||||||
// check separator marginal P(S9), should be P(14)
|
// check separator marginal P(S9), should be P(14)
|
||||||
clique = (*self.bayesTree)[9];
|
clique = (*self.bayesTree)[9];
|
||||||
DiscreteFactorGraph separatorMarginal9 =
|
DiscreteFactorGraph separatorMarginal9 =
|
||||||
|
|
|
||||||
|
|
@ -128,17 +128,40 @@ void GaussianMixture::print(const std::string &s,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *******************************************************************************/
|
/* ************************************************************************* */
|
||||||
void GaussianMixture::prune(const DecisionTreeFactor &decisionTree) {
|
/// Return the DiscreteKey vector as a set.
|
||||||
// Functional which loops over all assignments and create a set of
|
std::set<DiscreteKey> DiscreteKeysAsSet(const DiscreteKeys &dkeys) {
|
||||||
// GaussianConditionals
|
std::set<DiscreteKey> s;
|
||||||
auto pruner = [&decisionTree](
|
s.insert(dkeys.begin(), dkeys.end());
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ************************************************************************* */
|
||||||
|
/**
|
||||||
|
* @brief Helper function to get the pruner functional.
|
||||||
|
*
|
||||||
|
* @param decisionTree The probability decision tree of only discrete keys.
|
||||||
|
* @return std::function<GaussianConditional::shared_ptr(
|
||||||
|
* const Assignment<Key> &, const GaussianConditional::shared_ptr &)>
|
||||||
|
*/
|
||||||
|
std::function<GaussianConditional::shared_ptr(
|
||||||
|
const Assignment<Key> &, const GaussianConditional::shared_ptr &)>
|
||||||
|
GaussianMixture::prunerFunc(const DecisionTreeFactor &decisionTree) {
|
||||||
|
// Get the discrete keys as sets for the decision tree
|
||||||
|
// and the gaussian mixture.
|
||||||
|
auto decisionTreeKeySet = DiscreteKeysAsSet(decisionTree.discreteKeys());
|
||||||
|
auto gaussianMixtureKeySet = DiscreteKeysAsSet(this->discreteKeys());
|
||||||
|
|
||||||
|
auto pruner = [decisionTree, decisionTreeKeySet, gaussianMixtureKeySet](
|
||||||
const Assignment<Key> &choices,
|
const Assignment<Key> &choices,
|
||||||
const GaussianConditional::shared_ptr &conditional)
|
const GaussianConditional::shared_ptr &conditional)
|
||||||
-> GaussianConditional::shared_ptr {
|
-> GaussianConditional::shared_ptr {
|
||||||
// typecast so we can use this to get probability value
|
// typecast so we can use this to get probability value
|
||||||
DiscreteValues values(choices);
|
DiscreteValues values(choices);
|
||||||
|
|
||||||
|
// Case where the gaussian mixture has the same
|
||||||
|
// discrete keys as the decision tree.
|
||||||
|
if (gaussianMixtureKeySet == decisionTreeKeySet) {
|
||||||
if (decisionTree(values) == 0.0) {
|
if (decisionTree(values) == 0.0) {
|
||||||
// empty aka null pointer
|
// empty aka null pointer
|
||||||
boost::shared_ptr<GaussianConditional> null;
|
boost::shared_ptr<GaussianConditional> null;
|
||||||
|
|
@ -146,7 +169,40 @@ void GaussianMixture::prune(const DecisionTreeFactor &decisionTree) {
|
||||||
} else {
|
} else {
|
||||||
return conditional;
|
return conditional;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
std::vector<DiscreteKey> set_diff;
|
||||||
|
std::set_difference(decisionTreeKeySet.begin(), decisionTreeKeySet.end(),
|
||||||
|
gaussianMixtureKeySet.begin(),
|
||||||
|
gaussianMixtureKeySet.end(),
|
||||||
|
std::back_inserter(set_diff));
|
||||||
|
|
||||||
|
const std::vector<DiscreteValues> assignments =
|
||||||
|
DiscreteValues::CartesianProduct(set_diff);
|
||||||
|
for (const DiscreteValues &assignment : assignments) {
|
||||||
|
DiscreteValues augmented_values(values);
|
||||||
|
augmented_values.insert(assignment.begin(), assignment.end());
|
||||||
|
|
||||||
|
// If any one of the sub-branches are non-zero,
|
||||||
|
// we need this conditional.
|
||||||
|
if (decisionTree(augmented_values) > 0.0) {
|
||||||
|
return conditional;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we are here, it means that all the sub-branches are 0,
|
||||||
|
// so we prune.
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
return pruner;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* *******************************************************************************/
|
||||||
|
void GaussianMixture::prune(const DecisionTreeFactor &decisionTree) {
|
||||||
|
auto decisionTreeKeySet = DiscreteKeysAsSet(decisionTree.discreteKeys());
|
||||||
|
auto gmKeySet = DiscreteKeysAsSet(this->discreteKeys());
|
||||||
|
// Functional which loops over all assignments and create a set of
|
||||||
|
// GaussianConditionals
|
||||||
|
auto pruner = prunerFunc(decisionTree);
|
||||||
|
|
||||||
auto pruned_conditionals = conditionals_.apply(pruner);
|
auto pruned_conditionals = conditionals_.apply(pruner);
|
||||||
conditionals_.root_ = pruned_conditionals.root_;
|
conditionals_.root_ = pruned_conditionals.root_;
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,17 @@ class GTSAM_EXPORT GaussianMixture
|
||||||
*/
|
*/
|
||||||
Sum asGaussianFactorGraphTree() const;
|
Sum asGaussianFactorGraphTree() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Helper function to get the pruner functor.
|
||||||
|
*
|
||||||
|
* @param decisionTree The pruned discrete probability decision tree.
|
||||||
|
* @return std::function<GaussianConditional::shared_ptr(
|
||||||
|
* const Assignment<Key> &, const GaussianConditional::shared_ptr &)>
|
||||||
|
*/
|
||||||
|
std::function<GaussianConditional::shared_ptr(
|
||||||
|
const Assignment<Key> &, const GaussianConditional::shared_ptr &)>
|
||||||
|
prunerFunc(const DecisionTreeFactor &decisionTree);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// @name Constructors
|
/// @name Constructors
|
||||||
/// @{
|
/// @{
|
||||||
|
|
|
||||||
|
|
@ -57,11 +57,12 @@ void GaussianMixtureFactor::print(const std::string &s,
|
||||||
[&](const GaussianFactor::shared_ptr &gf) -> std::string {
|
[&](const GaussianFactor::shared_ptr &gf) -> std::string {
|
||||||
RedirectCout rd;
|
RedirectCout rd;
|
||||||
std::cout << ":\n";
|
std::cout << ":\n";
|
||||||
if (gf)
|
if (gf && !gf->empty()) {
|
||||||
gf->print("", formatter);
|
gf->print("", formatter);
|
||||||
else
|
|
||||||
return {"nullptr"};
|
|
||||||
return rd.str();
|
return rd.str();
|
||||||
|
} else {
|
||||||
|
return "nullptr";
|
||||||
|
}
|
||||||
});
|
});
|
||||||
std::cout << "}" << std::endl;
|
std::cout << "}" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,14 +22,6 @@
|
||||||
|
|
||||||
namespace gtsam {
|
namespace gtsam {
|
||||||
|
|
||||||
/* ************************************************************************* */
|
|
||||||
/// Return the DiscreteKey vector as a set.
|
|
||||||
static std::set<DiscreteKey> DiscreteKeysAsSet(const DiscreteKeys &dkeys) {
|
|
||||||
std::set<DiscreteKey> s;
|
|
||||||
s.insert(dkeys.begin(), dkeys.end());
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
DecisionTreeFactor::shared_ptr HybridBayesNet::discreteConditionals() const {
|
DecisionTreeFactor::shared_ptr HybridBayesNet::discreteConditionals() const {
|
||||||
AlgebraicDecisionTree<Key> decisionTree;
|
AlgebraicDecisionTree<Key> decisionTree;
|
||||||
|
|
@ -66,61 +58,18 @@ HybridBayesNet HybridBayesNet::prune(size_t maxNrLeaves) const {
|
||||||
|
|
||||||
HybridBayesNet prunedBayesNetFragment;
|
HybridBayesNet prunedBayesNetFragment;
|
||||||
|
|
||||||
// Functional which loops over all assignments and create a set of
|
|
||||||
// GaussianConditionals
|
|
||||||
auto pruner = [&](const Assignment<Key> &choices,
|
|
||||||
const GaussianConditional::shared_ptr &conditional)
|
|
||||||
-> GaussianConditional::shared_ptr {
|
|
||||||
// typecast so we can use this to get probability value
|
|
||||||
DiscreteValues values(choices);
|
|
||||||
|
|
||||||
if ((*discreteFactor)(values) == 0.0) {
|
|
||||||
// empty aka null pointer
|
|
||||||
boost::shared_ptr<GaussianConditional> null;
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return conditional;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Go through all the conditionals in the
|
// Go through all the conditionals in the
|
||||||
// Bayes Net and prune them as per discreteFactor.
|
// Bayes Net and prune them as per discreteFactor.
|
||||||
for (size_t i = 0; i < this->size(); i++) {
|
for (size_t i = 0; i < this->size(); i++) {
|
||||||
HybridConditional::shared_ptr conditional = this->at(i);
|
HybridConditional::shared_ptr conditional = this->at(i);
|
||||||
|
|
||||||
GaussianMixture::shared_ptr gaussianMixture =
|
if (conditional->isHybrid()) {
|
||||||
boost::dynamic_pointer_cast<GaussianMixture>(conditional->inner());
|
GaussianMixture::shared_ptr gaussianMixture = conditional->asMixture();
|
||||||
|
|
||||||
if (gaussianMixture) {
|
// Make a copy of the gaussian mixture and prune it!
|
||||||
// We may have mixtures with less discrete keys than discreteFactor so we
|
auto prunedGaussianMixture =
|
||||||
// skip those since the label assignment does not exist.
|
boost::make_shared<GaussianMixture>(*gaussianMixture);
|
||||||
auto gmKeySet = DiscreteKeysAsSet(gaussianMixture->discreteKeys());
|
prunedGaussianMixture->prune(*discreteFactor);
|
||||||
auto dfKeySet = DiscreteKeysAsSet(discreteFactor->discreteKeys());
|
|
||||||
if (gmKeySet != dfKeySet) {
|
|
||||||
// Add the gaussianMixture which doesn't have to be pruned.
|
|
||||||
prunedBayesNetFragment.push_back(
|
|
||||||
boost::make_shared<HybridConditional>(gaussianMixture));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run the pruning to get a new, pruned tree
|
|
||||||
GaussianMixture::Conditionals prunedTree =
|
|
||||||
gaussianMixture->conditionals().apply(pruner);
|
|
||||||
|
|
||||||
DiscreteKeys discreteKeys = gaussianMixture->discreteKeys();
|
|
||||||
// reverse keys to get a natural ordering
|
|
||||||
std::reverse(discreteKeys.begin(), discreteKeys.end());
|
|
||||||
|
|
||||||
// Convert from boost::iterator_range to KeyVector
|
|
||||||
// so we can pass it to constructor.
|
|
||||||
KeyVector frontals(gaussianMixture->frontals().begin(),
|
|
||||||
gaussianMixture->frontals().end()),
|
|
||||||
parents(gaussianMixture->parents().begin(),
|
|
||||||
gaussianMixture->parents().end());
|
|
||||||
|
|
||||||
// Create the new gaussian mixture and add it to the bayes net.
|
|
||||||
auto prunedGaussianMixture = boost::make_shared<GaussianMixture>(
|
|
||||||
frontals, parents, discreteKeys, prunedTree);
|
|
||||||
|
|
||||||
// Type-erase and add to the pruned Bayes Net fragment.
|
// Type-erase and add to the pruned Bayes Net fragment.
|
||||||
prunedBayesNetFragment.push_back(
|
prunedBayesNetFragment.push_back(
|
||||||
|
|
@ -173,7 +122,7 @@ GaussianBayesNet HybridBayesNet::choose(
|
||||||
return gbn;
|
return gbn;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *******************************************************************************/
|
/* ************************************************************************* */
|
||||||
HybridValues HybridBayesNet::optimize() const {
|
HybridValues HybridBayesNet::optimize() const {
|
||||||
// Solve for the MPE
|
// Solve for the MPE
|
||||||
DiscreteBayesNet discrete_bn;
|
DiscreteBayesNet discrete_bn;
|
||||||
|
|
@ -190,7 +139,7 @@ HybridValues HybridBayesNet::optimize() const {
|
||||||
return HybridValues(mpe, gbn.optimize());
|
return HybridValues(mpe, gbn.optimize());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *******************************************************************************/
|
/* ************************************************************************* */
|
||||||
VectorValues HybridBayesNet::optimize(const DiscreteValues &assignment) const {
|
VectorValues HybridBayesNet::optimize(const DiscreteValues &assignment) const {
|
||||||
GaussianBayesNet gbn = this->choose(assignment);
|
GaussianBayesNet gbn = this->choose(assignment);
|
||||||
return gbn.optimize();
|
return gbn.optimize();
|
||||||
|
|
|
||||||
|
|
@ -149,16 +149,16 @@ void HybridBayesTree::prune(const size_t maxNrLeaves) {
|
||||||
auto decisionTree = boost::dynamic_pointer_cast<DecisionTreeFactor>(
|
auto decisionTree = boost::dynamic_pointer_cast<DecisionTreeFactor>(
|
||||||
this->roots_.at(0)->conditional()->inner());
|
this->roots_.at(0)->conditional()->inner());
|
||||||
|
|
||||||
DecisionTreeFactor prunedDiscreteFactor = decisionTree->prune(maxNrLeaves);
|
DecisionTreeFactor prunedDecisionTree = decisionTree->prune(maxNrLeaves);
|
||||||
decisionTree->root_ = prunedDiscreteFactor.root_;
|
decisionTree->root_ = prunedDecisionTree.root_;
|
||||||
|
|
||||||
/// Helper struct for pruning the hybrid bayes tree.
|
/// Helper struct for pruning the hybrid bayes tree.
|
||||||
struct HybridPrunerData {
|
struct HybridPrunerData {
|
||||||
/// The discrete decision tree after pruning.
|
/// The discrete decision tree after pruning.
|
||||||
DecisionTreeFactor prunedDiscreteFactor;
|
DecisionTreeFactor prunedDecisionTree;
|
||||||
HybridPrunerData(const DecisionTreeFactor& prunedDiscreteFactor,
|
HybridPrunerData(const DecisionTreeFactor& prunedDecisionTree,
|
||||||
const HybridBayesTree::sharedNode& parentClique)
|
const HybridBayesTree::sharedNode& parentClique)
|
||||||
: prunedDiscreteFactor(prunedDiscreteFactor) {}
|
: prunedDecisionTree(prunedDecisionTree) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A function used during tree traversal that operates on each node
|
* @brief A function used during tree traversal that operates on each node
|
||||||
|
|
@ -178,19 +178,13 @@ void HybridBayesTree::prune(const size_t maxNrLeaves) {
|
||||||
if (conditional->isHybrid()) {
|
if (conditional->isHybrid()) {
|
||||||
auto gaussianMixture = conditional->asMixture();
|
auto gaussianMixture = conditional->asMixture();
|
||||||
|
|
||||||
// Check if the number of discrete keys match,
|
gaussianMixture->prune(parentData.prunedDecisionTree);
|
||||||
// else we get an assignment error.
|
|
||||||
// TODO(Varun) Update prune method to handle assignment subset?
|
|
||||||
if (gaussianMixture->discreteKeys() ==
|
|
||||||
parentData.prunedDiscreteFactor.discreteKeys()) {
|
|
||||||
gaussianMixture->prune(parentData.prunedDiscreteFactor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return parentData;
|
return parentData;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
HybridPrunerData rootData(prunedDiscreteFactor, 0);
|
HybridPrunerData rootData(prunedDecisionTree, 0);
|
||||||
{
|
{
|
||||||
treeTraversal::no_op visitorPost;
|
treeTraversal::no_op visitorPost;
|
||||||
// Limits OpenMP threads since we're mixing TBB and OpenMP
|
// Limits OpenMP threads since we're mixing TBB and OpenMP
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,7 @@ DiscreteKeys CollectDiscreteKeys(const DiscreteKeys &key1,
|
||||||
|
|
||||||
/* ************************************************************************ */
|
/* ************************************************************************ */
|
||||||
HybridFactor::HybridFactor(const KeyVector &keys)
|
HybridFactor::HybridFactor(const KeyVector &keys)
|
||||||
: Base(keys),
|
: Base(keys), isContinuous_(true), continuousKeys_(keys) {}
|
||||||
isContinuous_(true),
|
|
||||||
continuousKeys_(keys) {}
|
|
||||||
|
|
||||||
/* ************************************************************************ */
|
/* ************************************************************************ */
|
||||||
HybridFactor::HybridFactor(const KeyVector &continuousKeys,
|
HybridFactor::HybridFactor(const KeyVector &continuousKeys,
|
||||||
|
|
@ -101,7 +99,6 @@ void HybridFactor::print(const std::string &s,
|
||||||
if (d < discreteKeys_.size() - 1) {
|
if (d < discreteKeys_.size() - 1) {
|
||||||
std::cout << " ";
|
std::cout << " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
std::cout << "]";
|
std::cout << "]";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -219,10 +219,10 @@ hybridElimination(const HybridGaussianFactorGraph &factors,
|
||||||
result = EliminatePreferCholesky(graph, frontalKeys);
|
result = EliminatePreferCholesky(graph, frontalKeys);
|
||||||
|
|
||||||
if (keysOfEliminated.empty()) {
|
if (keysOfEliminated.empty()) {
|
||||||
keysOfEliminated =
|
// Initialize the keysOfEliminated to be the keys of the
|
||||||
result.first->keys(); // Initialize the keysOfEliminated to be the
|
// eliminated GaussianConditional
|
||||||
|
keysOfEliminated = result.first->keys();
|
||||||
}
|
}
|
||||||
// keysOfEliminated of the GaussianConditional
|
|
||||||
if (keysOfSeparator.empty()) {
|
if (keysOfSeparator.empty()) {
|
||||||
keysOfSeparator = result.second->keys();
|
keysOfSeparator = result.second->keys();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,8 +59,9 @@ void HybridGaussianISAM::updateInternal(
|
||||||
factors += newFactors;
|
factors += newFactors;
|
||||||
|
|
||||||
// Add the orphaned subtrees
|
// Add the orphaned subtrees
|
||||||
for (const sharedClique& orphan : *orphans)
|
for (const sharedClique& orphan : *orphans) {
|
||||||
factors += boost::make_shared<BayesTreeOrphanWrapper<Node>>(orphan);
|
factors += boost::make_shared<BayesTreeOrphanWrapper<Node>>(orphan);
|
||||||
|
}
|
||||||
|
|
||||||
// Get all the discrete keys from the factors
|
// Get all the discrete keys from the factors
|
||||||
KeySet allDiscrete = factors.discreteKeys();
|
KeySet allDiscrete = factors.discreteKeys();
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ void HybridNonlinearISAM::print(const string& s,
|
||||||
const KeyFormatter& keyFormatter) const {
|
const KeyFormatter& keyFormatter) const {
|
||||||
cout << s << "ReorderInterval: " << reorderInterval_
|
cout << s << "ReorderInterval: " << reorderInterval_
|
||||||
<< " Current Count: " << reorderCounter_ << endl;
|
<< " Current Count: " << reorderCounter_ << endl;
|
||||||
isam_.print("HybridGaussianISAM:\n");
|
isam_.print("HybridGaussianISAM:\n", keyFormatter);
|
||||||
linPoint_.print("Linearization Point:\n", keyFormatter);
|
linPoint_.print("Linearization Point:\n", keyFormatter);
|
||||||
factors_.print("Nonlinear Graph:\n", keyFormatter);
|
factors_.print("Nonlinear Graph:\n", keyFormatter);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -337,7 +337,7 @@ TEST(HybridGaussianElimination, Incremental_approximate) {
|
||||||
EXPECT_LONGS_EQUAL(
|
EXPECT_LONGS_EQUAL(
|
||||||
2, incrementalHybrid[X(1)]->conditional()->asMixture()->nrComponents());
|
2, incrementalHybrid[X(1)]->conditional()->asMixture()->nrComponents());
|
||||||
EXPECT_LONGS_EQUAL(
|
EXPECT_LONGS_EQUAL(
|
||||||
4, incrementalHybrid[X(2)]->conditional()->asMixture()->nrComponents());
|
3, incrementalHybrid[X(2)]->conditional()->asMixture()->nrComponents());
|
||||||
EXPECT_LONGS_EQUAL(
|
EXPECT_LONGS_EQUAL(
|
||||||
5, incrementalHybrid[X(3)]->conditional()->asMixture()->nrComponents());
|
5, incrementalHybrid[X(3)]->conditional()->asMixture()->nrComponents());
|
||||||
EXPECT_LONGS_EQUAL(
|
EXPECT_LONGS_EQUAL(
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
/**
|
/**
|
||||||
* @file testHybridNonlinearISAM.cpp
|
* @file testHybridNonlinearISAM.cpp
|
||||||
* @brief Unit tests for nonlinear incremental inference
|
* @brief Unit tests for nonlinear incremental inference
|
||||||
* @author Fan Jiang, Varun Agrawal, Frank Dellaert
|
* @author Varun Agrawal, Fan Jiang, Frank Dellaert
|
||||||
* @date Jan 2021
|
* @date Jan 2021
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -363,7 +363,7 @@ TEST(HybridNonlinearISAM, Incremental_approximate) {
|
||||||
EXPECT_LONGS_EQUAL(
|
EXPECT_LONGS_EQUAL(
|
||||||
2, bayesTree[X(1)]->conditional()->asMixture()->nrComponents());
|
2, bayesTree[X(1)]->conditional()->asMixture()->nrComponents());
|
||||||
EXPECT_LONGS_EQUAL(
|
EXPECT_LONGS_EQUAL(
|
||||||
4, bayesTree[X(2)]->conditional()->asMixture()->nrComponents());
|
3, bayesTree[X(2)]->conditional()->asMixture()->nrComponents());
|
||||||
EXPECT_LONGS_EQUAL(
|
EXPECT_LONGS_EQUAL(
|
||||||
5, bayesTree[X(3)]->conditional()->asMixture()->nrComponents());
|
5, bayesTree[X(3)]->conditional()->asMixture()->nrComponents());
|
||||||
EXPECT_LONGS_EQUAL(
|
EXPECT_LONGS_EQUAL(
|
||||||
|
|
@ -432,9 +432,9 @@ TEST(HybridNonlinearISAM, NonTrivial) {
|
||||||
|
|
||||||
// Don't run update now since we don't have discrete variables involved.
|
// Don't run update now since we don't have discrete variables involved.
|
||||||
|
|
||||||
/*************** Run Round 2 ***************/
|
|
||||||
using PlanarMotionModel = BetweenFactor<Pose2>;
|
using PlanarMotionModel = BetweenFactor<Pose2>;
|
||||||
|
|
||||||
|
/*************** Run Round 2 ***************/
|
||||||
// Add odometry factor with discrete modes.
|
// Add odometry factor with discrete modes.
|
||||||
Pose2 odometry(1.0, 0.0, 0.0);
|
Pose2 odometry(1.0, 0.0, 0.0);
|
||||||
KeyVector contKeys = {W(0), W(1)};
|
KeyVector contKeys = {W(0), W(1)};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue