HybridGaussianFactor tests passing
parent
4343b3aadc
commit
0bbf16bf4b
|
@ -220,22 +220,19 @@ std::shared_ptr<HybridGaussianFactor> HybridGaussianConditional::likelihood(
|
||||||
const DiscreteKeys discreteParentKeys = discreteKeys();
|
const DiscreteKeys discreteParentKeys = discreteKeys();
|
||||||
const KeyVector continuousParentKeys = continuousParents();
|
const KeyVector continuousParentKeys = continuousParents();
|
||||||
const HybridGaussianFactor::Factors likelihoods(
|
const HybridGaussianFactor::Factors likelihoods(
|
||||||
conditionals_, [&](const GaussianConditional::shared_ptr &conditional) {
|
conditionals_,
|
||||||
const auto likelihood_m = conditional->likelihood(given);
|
[&](const GaussianConditional::shared_ptr &conditional)
|
||||||
|
-> std::pair<GaussianFactor::shared_ptr, double> {
|
||||||
|
auto likelihood_m = conditional->likelihood(given);
|
||||||
const double Cgm_Kgcm =
|
const double Cgm_Kgcm =
|
||||||
logConstant_ - conditional->logNormalizationConstant();
|
logConstant_ - conditional->logNormalizationConstant();
|
||||||
if (Cgm_Kgcm == 0.0) {
|
if (Cgm_Kgcm == 0.0) {
|
||||||
return likelihood_m;
|
return {likelihood_m, 0.0};
|
||||||
} else {
|
} else {
|
||||||
// Add a constant factor to the likelihood in case the noise models
|
// Add a constant factor to the likelihood in case the noise models
|
||||||
// are not all equal.
|
// are not all equal.
|
||||||
GaussianFactorGraph gfg;
|
double c = std::sqrt(2.0 * Cgm_Kgcm);
|
||||||
gfg.push_back(likelihood_m);
|
return {likelihood_m, c};
|
||||||
Vector c(1);
|
|
||||||
c << std::sqrt(2.0 * Cgm_Kgcm);
|
|
||||||
auto constantFactor = std::make_shared<JacobianFactor>(c);
|
|
||||||
gfg.push_back(constantFactor);
|
|
||||||
return std::make_shared<JacobianFactor>(gfg);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return std::make_shared<HybridGaussianFactor>(
|
return std::make_shared<HybridGaussianFactor>(
|
||||||
|
|
|
@ -46,8 +46,10 @@ bool HybridGaussianFactor::equals(const HybridFactor &lf, double tol) const {
|
||||||
// Check the base and the factors:
|
// Check the base and the factors:
|
||||||
return Base::equals(*e, tol) &&
|
return Base::equals(*e, tol) &&
|
||||||
factors_.equals(e->factors_,
|
factors_.equals(e->factors_,
|
||||||
[tol](const sharedFactor &f1, const sharedFactor &f2) {
|
[tol](const std::pair<sharedFactor, double> &f1,
|
||||||
return f1->equals(*f2, tol);
|
const std::pair<sharedFactor, double> &f2) {
|
||||||
|
return f1.first->equals(*f2.first, tol) &&
|
||||||
|
(f1.second == f2.second);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,11 +65,13 @@ void HybridGaussianFactor::print(const std::string &s,
|
||||||
} else {
|
} else {
|
||||||
factors_.print(
|
factors_.print(
|
||||||
"", [&](Key k) { return formatter(k); },
|
"", [&](Key k) { return formatter(k); },
|
||||||
[&](const sharedFactor &gf) -> std::string {
|
[&](const std::pair<sharedFactor, double> &gfv) -> std::string {
|
||||||
|
auto [gf, val] = gfv;
|
||||||
RedirectCout rd;
|
RedirectCout rd;
|
||||||
std::cout << ":\n";
|
std::cout << ":\n";
|
||||||
if (gf) {
|
if (gf) {
|
||||||
gf->print("", formatter);
|
gf->print("", formatter);
|
||||||
|
std::cout << "value: " << val << std::endl;
|
||||||
return rd.str();
|
return rd.str();
|
||||||
} else {
|
} else {
|
||||||
return "nullptr";
|
return "nullptr";
|
||||||
|
@ -78,8 +82,8 @@ void HybridGaussianFactor::print(const std::string &s,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *******************************************************************************/
|
/* *******************************************************************************/
|
||||||
HybridGaussianFactor::sharedFactor HybridGaussianFactor::operator()(
|
std::pair<HybridGaussianFactor::sharedFactor, double>
|
||||||
const DiscreteValues &assignment) const {
|
HybridGaussianFactor::operator()(const DiscreteValues &assignment) const {
|
||||||
return factors_(assignment);
|
return factors_(assignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +103,9 @@ GaussianFactorGraphTree HybridGaussianFactor::add(
|
||||||
/* *******************************************************************************/
|
/* *******************************************************************************/
|
||||||
GaussianFactorGraphTree HybridGaussianFactor::asGaussianFactorGraphTree()
|
GaussianFactorGraphTree HybridGaussianFactor::asGaussianFactorGraphTree()
|
||||||
const {
|
const {
|
||||||
auto wrap = [](const sharedFactor &gf) { return GaussianFactorGraph{gf}; };
|
auto wrap = [](const std::pair<sharedFactor, double> &gfv) {
|
||||||
|
return GaussianFactorGraph{gfv.first};
|
||||||
|
};
|
||||||
return {factors_, wrap};
|
return {factors_, wrap};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,17 +113,19 @@ GaussianFactorGraphTree HybridGaussianFactor::asGaussianFactorGraphTree()
|
||||||
AlgebraicDecisionTree<Key> HybridGaussianFactor::errorTree(
|
AlgebraicDecisionTree<Key> HybridGaussianFactor::errorTree(
|
||||||
const VectorValues &continuousValues) const {
|
const VectorValues &continuousValues) const {
|
||||||
// functor to convert from sharedFactor to double error value.
|
// functor to convert from sharedFactor to double error value.
|
||||||
auto errorFunc = [&continuousValues](const sharedFactor &gf) {
|
auto errorFunc =
|
||||||
return gf->error(continuousValues);
|
[&continuousValues](const std::pair<sharedFactor, double> &gfv) {
|
||||||
};
|
auto [gf, val] = gfv;
|
||||||
|
return gf->error(continuousValues) + val;
|
||||||
|
};
|
||||||
DecisionTree<Key, double> error_tree(factors_, errorFunc);
|
DecisionTree<Key, double> error_tree(factors_, errorFunc);
|
||||||
return error_tree;
|
return error_tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *******************************************************************************/
|
/* *******************************************************************************/
|
||||||
double HybridGaussianFactor::error(const HybridValues &values) const {
|
double HybridGaussianFactor::error(const HybridValues &values) const {
|
||||||
const sharedFactor gf = factors_(values.discrete());
|
auto &&[gf, val] = factors_(values.discrete());
|
||||||
return gf->error(values.continuous());
|
return gf->error(values.continuous()) + val;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace gtsam
|
} // namespace gtsam
|
||||||
|
|
|
@ -53,7 +53,7 @@ class GTSAM_EXPORT HybridGaussianFactor : public HybridFactor {
|
||||||
using sharedFactor = std::shared_ptr<GaussianFactor>;
|
using sharedFactor = std::shared_ptr<GaussianFactor>;
|
||||||
|
|
||||||
/// typedef for Decision Tree of Gaussian factors and log-constant.
|
/// typedef for Decision Tree of Gaussian factors and log-constant.
|
||||||
using Factors = DecisionTree<Key, sharedFactor>;
|
using Factors = DecisionTree<Key, std::pair<sharedFactor, double>>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Decision tree of Gaussian factors indexed by discrete keys.
|
/// Decision tree of Gaussian factors indexed by discrete keys.
|
||||||
|
@ -80,8 +80,7 @@ class GTSAM_EXPORT HybridGaussianFactor : public HybridFactor {
|
||||||
* @param continuousKeys A vector of keys representing continuous variables.
|
* @param continuousKeys A vector of keys representing continuous variables.
|
||||||
* @param discreteKeys A vector of keys representing discrete variables and
|
* @param discreteKeys A vector of keys representing discrete variables and
|
||||||
* their cardinalities.
|
* their cardinalities.
|
||||||
* @param factors The decision tree of Gaussian factors stored
|
* @param factors The decision tree of Gaussian factors and arbitrary scalars.
|
||||||
* as the mixture density.
|
|
||||||
*/
|
*/
|
||||||
HybridGaussianFactor(const KeyVector &continuousKeys,
|
HybridGaussianFactor(const KeyVector &continuousKeys,
|
||||||
const DiscreteKeys &discreteKeys,
|
const DiscreteKeys &discreteKeys,
|
||||||
|
@ -93,11 +92,12 @@ class GTSAM_EXPORT HybridGaussianFactor : public HybridFactor {
|
||||||
*
|
*
|
||||||
* @param continuousKeys Vector of keys for continuous factors.
|
* @param continuousKeys Vector of keys for continuous factors.
|
||||||
* @param discreteKeys Vector of discrete keys.
|
* @param discreteKeys Vector of discrete keys.
|
||||||
* @param factors Vector of gaussian factor shared pointers.
|
* @param factors Vector of gaussian factor shared pointers
|
||||||
|
* and arbitrary scalars.
|
||||||
*/
|
*/
|
||||||
HybridGaussianFactor(const KeyVector &continuousKeys,
|
HybridGaussianFactor(
|
||||||
const DiscreteKeys &discreteKeys,
|
const KeyVector &continuousKeys, const DiscreteKeys &discreteKeys,
|
||||||
const std::vector<sharedFactor> &factors)
|
const std::vector<std::pair<sharedFactor, double>> &factors)
|
||||||
: HybridGaussianFactor(continuousKeys, discreteKeys,
|
: HybridGaussianFactor(continuousKeys, discreteKeys,
|
||||||
Factors(discreteKeys, factors)) {}
|
Factors(discreteKeys, factors)) {}
|
||||||
|
|
||||||
|
@ -114,8 +114,9 @@ class GTSAM_EXPORT HybridGaussianFactor : public HybridFactor {
|
||||||
/// @name Standard API
|
/// @name Standard API
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
/// Get factor at a given discrete assignment.
|
/// Get the factor and scalar at a given discrete assignment.
|
||||||
sharedFactor operator()(const DiscreteValues &assignment) const;
|
std::pair<sharedFactor, double> operator()(
|
||||||
|
const DiscreteValues &assignment) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Combine the Gaussian Factor Graphs in `sum` and `this` while
|
* @brief Combine the Gaussian Factor Graphs in `sum` and `this` while
|
||||||
|
|
|
@ -92,13 +92,15 @@ void HybridGaussianFactorGraph::printErrors(
|
||||||
// Clear the stringstream
|
// Clear the stringstream
|
||||||
ss.str(std::string());
|
ss.str(std::string());
|
||||||
|
|
||||||
if (auto gmf = std::dynamic_pointer_cast<HybridGaussianFactor>(factor)) {
|
if (auto hgf = std::dynamic_pointer_cast<HybridGaussianFactor>(factor)) {
|
||||||
if (factor == nullptr) {
|
if (factor == nullptr) {
|
||||||
std::cout << "nullptr"
|
std::cout << "nullptr"
|
||||||
<< "\n";
|
<< "\n";
|
||||||
} else {
|
} else {
|
||||||
gmf->operator()(values.discrete())->print(ss.str(), keyFormatter);
|
auto [factor, val] = hgf->operator()(values.discrete());
|
||||||
std::cout << "error = " << gmf->error(values) << std::endl;
|
factor->print(ss.str(), keyFormatter);
|
||||||
|
std::cout << "value: " << val << std::endl;
|
||||||
|
std::cout << "error = " << factor->error(values) << std::endl;
|
||||||
}
|
}
|
||||||
} else if (auto hc = std::dynamic_pointer_cast<HybridConditional>(factor)) {
|
} else if (auto hc = std::dynamic_pointer_cast<HybridConditional>(factor)) {
|
||||||
if (factor == nullptr) {
|
if (factor == nullptr) {
|
||||||
|
@ -262,9 +264,12 @@ discreteElimination(const HybridGaussianFactorGraph &factors,
|
||||||
// Case where we have a HybridGaussianFactor with no continuous keys.
|
// Case where we have a HybridGaussianFactor with no continuous keys.
|
||||||
// In this case, compute discrete probabilities.
|
// In this case, compute discrete probabilities.
|
||||||
auto logProbability =
|
auto logProbability =
|
||||||
[&](const GaussianFactor::shared_ptr &factor) -> double {
|
[&](const std::pair<GaussianFactor::shared_ptr, double> &fv)
|
||||||
if (!factor) return 0.0;
|
-> double {
|
||||||
return -factor->error(VectorValues());
|
auto [factor, val] = fv;
|
||||||
|
double v = 0.5 * val * val;
|
||||||
|
if (!factor) return -v;
|
||||||
|
return -(factor->error(VectorValues()) + v);
|
||||||
};
|
};
|
||||||
AlgebraicDecisionTree<Key> logProbabilities =
|
AlgebraicDecisionTree<Key> logProbabilities =
|
||||||
DecisionTree<Key, double>(gmf->factors(), logProbability);
|
DecisionTree<Key, double>(gmf->factors(), logProbability);
|
||||||
|
@ -348,7 +353,8 @@ static std::shared_ptr<Factor> createHybridGaussianFactor(
|
||||||
const KeyVector &continuousSeparator,
|
const KeyVector &continuousSeparator,
|
||||||
const DiscreteKeys &discreteSeparator) {
|
const DiscreteKeys &discreteSeparator) {
|
||||||
// Correct for the normalization constant used up by the conditional
|
// Correct for the normalization constant used up by the conditional
|
||||||
auto correct = [&](const Result &pair) -> GaussianFactor::shared_ptr {
|
auto correct =
|
||||||
|
[&](const Result &pair) -> std::pair<GaussianFactor::shared_ptr, double> {
|
||||||
const auto &[conditional, factor] = pair;
|
const auto &[conditional, factor] = pair;
|
||||||
if (factor) {
|
if (factor) {
|
||||||
auto hf = std::dynamic_pointer_cast<HessianFactor>(factor);
|
auto hf = std::dynamic_pointer_cast<HessianFactor>(factor);
|
||||||
|
@ -357,10 +363,10 @@ static std::shared_ptr<Factor> createHybridGaussianFactor(
|
||||||
// as per the Hessian definition
|
// as per the Hessian definition
|
||||||
hf->constantTerm() += 2.0 * conditional->logNormalizationConstant();
|
hf->constantTerm() += 2.0 * conditional->logNormalizationConstant();
|
||||||
}
|
}
|
||||||
return factor;
|
return {factor, 0.0};
|
||||||
};
|
};
|
||||||
DecisionTree<Key, GaussianFactor::shared_ptr> newFactors(eliminationResults,
|
DecisionTree<Key, std::pair<GaussianFactor::shared_ptr, double>> newFactors(
|
||||||
correct);
|
eliminationResults, correct);
|
||||||
|
|
||||||
return std::make_shared<HybridGaussianFactor>(continuousSeparator,
|
return std::make_shared<HybridGaussianFactor>(continuousSeparator,
|
||||||
discreteSeparator, newFactors);
|
discreteSeparator, newFactors);
|
||||||
|
@ -597,10 +603,10 @@ GaussianFactorGraph HybridGaussianFactorGraph::operator()(
|
||||||
gfg.push_back(gf);
|
gfg.push_back(gf);
|
||||||
} else if (auto gc = std::dynamic_pointer_cast<GaussianConditional>(f)) {
|
} else if (auto gc = std::dynamic_pointer_cast<GaussianConditional>(f)) {
|
||||||
gfg.push_back(gf);
|
gfg.push_back(gf);
|
||||||
} else if (auto gmf = std::dynamic_pointer_cast<HybridGaussianFactor>(f)) {
|
} else if (auto hgf = std::dynamic_pointer_cast<HybridGaussianFactor>(f)) {
|
||||||
gfg.push_back((*gmf)(assignment));
|
gfg.push_back((*hgf)(assignment).first);
|
||||||
} else if (auto gm = dynamic_pointer_cast<HybridGaussianConditional>(f)) {
|
} else if (auto hgc = dynamic_pointer_cast<HybridGaussianConditional>(f)) {
|
||||||
gfg.push_back((*gm)(assignment));
|
gfg.push_back((*hgc)(assignment));
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -245,10 +245,11 @@ class HybridNonlinearFactor : public HybridFactor {
|
||||||
const Values& continuousValues) const {
|
const Values& continuousValues) const {
|
||||||
// functional to linearize each factor in the decision tree
|
// functional to linearize each factor in the decision tree
|
||||||
auto linearizeDT =
|
auto linearizeDT =
|
||||||
[continuousValues](const std::pair<sharedFactor, double>& f) {
|
[continuousValues](const std::pair<sharedFactor, double>& f)
|
||||||
auto [factor, val] = f;
|
-> std::pair<GaussianFactor::shared_ptr, double> {
|
||||||
return {factor->linearize(continuousValues), val};
|
auto [factor, val] = f;
|
||||||
};
|
return {factor->linearize(continuousValues), val};
|
||||||
|
};
|
||||||
|
|
||||||
DecisionTree<Key, std::pair<GaussianFactor::shared_ptr, double>>
|
DecisionTree<Key, std::pair<GaussianFactor::shared_ptr, double>>
|
||||||
linearized_factors(factors_, linearizeDT);
|
linearized_factors(factors_, linearizeDT);
|
||||||
|
|
|
@ -71,8 +71,10 @@ TEST(HybridGaussianFactor, Sum) {
|
||||||
auto f20 = std::make_shared<JacobianFactor>(X(1), A1, X(3), A3, b);
|
auto f20 = std::make_shared<JacobianFactor>(X(1), A1, X(3), A3, b);
|
||||||
auto f21 = std::make_shared<JacobianFactor>(X(1), A1, X(3), A3, b);
|
auto f21 = std::make_shared<JacobianFactor>(X(1), A1, X(3), A3, b);
|
||||||
auto f22 = std::make_shared<JacobianFactor>(X(1), A1, X(3), A3, b);
|
auto f22 = std::make_shared<JacobianFactor>(X(1), A1, X(3), A3, b);
|
||||||
std::vector<GaussianFactor::shared_ptr> factorsA{f10, f11};
|
std::vector<std::pair<GaussianFactor::shared_ptr, double>> factorsA{
|
||||||
std::vector<GaussianFactor::shared_ptr> factorsB{f20, f21, f22};
|
{f10, 0.0}, {f11, 0.0}};
|
||||||
|
std::vector<std::pair<GaussianFactor::shared_ptr, double>> factorsB{
|
||||||
|
{f20, 0.0}, {f21, 0.0}, {f22, 0.0}};
|
||||||
|
|
||||||
// TODO(Frank): why specify keys at all? And: keys in factor should be *all*
|
// TODO(Frank): why specify keys at all? And: keys in factor should be *all*
|
||||||
// keys, deviating from Kevin's scheme. Should we index DT on DiscreteKey?
|
// keys, deviating from Kevin's scheme. Should we index DT on DiscreteKey?
|
||||||
|
@ -109,7 +111,8 @@ TEST(HybridGaussianFactor, Printing) {
|
||||||
auto b = Matrix::Zero(2, 1);
|
auto b = Matrix::Zero(2, 1);
|
||||||
auto f10 = std::make_shared<JacobianFactor>(X(1), A1, X(2), A2, b);
|
auto f10 = std::make_shared<JacobianFactor>(X(1), A1, X(2), A2, b);
|
||||||
auto f11 = std::make_shared<JacobianFactor>(X(1), A1, X(2), A2, b);
|
auto f11 = std::make_shared<JacobianFactor>(X(1), A1, X(2), A2, b);
|
||||||
std::vector<GaussianFactor::shared_ptr> factors{f10, f11};
|
std::vector<std::pair<GaussianFactor::shared_ptr, double>> factors{
|
||||||
|
{f10, 0.0}, {f11, 0.0}};
|
||||||
|
|
||||||
HybridGaussianFactor mixtureFactor({X(1), X(2)}, {m1}, factors);
|
HybridGaussianFactor mixtureFactor({X(1), X(2)}, {m1}, factors);
|
||||||
|
|
||||||
|
@ -128,6 +131,7 @@ Hybrid [x1 x2; 1]{
|
||||||
]
|
]
|
||||||
b = [ 0 0 ]
|
b = [ 0 0 ]
|
||||||
No noise model
|
No noise model
|
||||||
|
value: 0
|
||||||
|
|
||||||
1 Leaf :
|
1 Leaf :
|
||||||
A[x1] = [
|
A[x1] = [
|
||||||
|
@ -140,6 +144,7 @@ Hybrid [x1 x2; 1]{
|
||||||
]
|
]
|
||||||
b = [ 0 0 ]
|
b = [ 0 0 ]
|
||||||
No noise model
|
No noise model
|
||||||
|
value: 0
|
||||||
|
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
@ -178,7 +183,8 @@ TEST(HybridGaussianFactor, Error) {
|
||||||
|
|
||||||
auto f0 = std::make_shared<JacobianFactor>(X(1), A01, X(2), A02, b);
|
auto f0 = std::make_shared<JacobianFactor>(X(1), A01, X(2), A02, b);
|
||||||
auto f1 = std::make_shared<JacobianFactor>(X(1), A11, X(2), A12, b);
|
auto f1 = std::make_shared<JacobianFactor>(X(1), A11, X(2), A12, b);
|
||||||
std::vector<GaussianFactor::shared_ptr> factors{f0, f1};
|
std::vector<std::pair<GaussianFactor::shared_ptr, double>> factors{{f0, 0.0},
|
||||||
|
{f1, 0.0}};
|
||||||
|
|
||||||
HybridGaussianFactor mixtureFactor({X(1), X(2)}, {m1}, factors);
|
HybridGaussianFactor mixtureFactor({X(1), X(2)}, {m1}, factors);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue