add templated at methods for FactorGraph so it can perform typecasting for us

release/4.3a0
Varun Agrawal 2023-10-06 12:34:49 -04:00
parent b78900563c
commit 790e3d515c
9 changed files with 39 additions and 32 deletions

View File

@ -42,8 +42,8 @@
#include <functional> #include <functional>
#include <iostream> #include <iostream>
#include <iterator> #include <iterator>
#include <vector>
#include <numeric> #include <numeric>
#include <vector>
#include "Switching.h" #include "Switching.h"
#include "TinyHybridExample.h" #include "TinyHybridExample.h"
@ -613,11 +613,11 @@ TEST(HybridGaussianFactorGraph, assembleGraphTree) {
// Create expected decision tree with two factor graphs: // Create expected decision tree with two factor graphs:
// Get mixture factor: // Get mixture factor:
auto mixture = std::dynamic_pointer_cast<GaussianMixtureFactor>(fg.at(0)); auto mixture = fg.at<GaussianMixtureFactor>(0);
CHECK(mixture); CHECK(mixture);
// Get prior factor: // Get prior factor:
const auto gf = std::dynamic_pointer_cast<HybridConditional>(fg.at(1)); const auto gf = fg.at<HybridConditional>(1);
CHECK(gf); CHECK(gf);
using GF = GaussianFactor::shared_ptr; using GF = GaussianFactor::shared_ptr;
const GF prior = gf->asGaussian(); const GF prior = gf->asGaussian();

View File

@ -310,6 +310,21 @@ class FactorGraph {
*/ */
sharedFactor& at(size_t i) { return factors_.at(i); } sharedFactor& at(size_t i) { return factors_.at(i); }
/** Get a specific factor by index and typecast to factor type F
* (this checks array bounds and may throw
* an exception, as opposed to operator[] which does not).
*/
template <typename F>
std::shared_ptr<F> at(size_t i) {
return std::dynamic_pointer_cast<F>(factors_.at(i));
}
/// Const version of templated `at` method.
template <typename F>
const std::shared_ptr<F> at(size_t i) const {
return std::dynamic_pointer_cast<F>(factors_.at(i));
}
/** Get a specific factor by index (this does not check array bounds, as /** Get a specific factor by index (this does not check array bounds, as
* opposed to at() which does). * opposed to at() which does).
*/ */

View File

@ -391,8 +391,7 @@ TEST(GaussianFactorGraph, clone) {
EXPECT(assert_equal(init_graph, actCloned)); // Same as the original version EXPECT(assert_equal(init_graph, actCloned)); // Same as the original version
// Apply an in-place change to init_graph and compare // Apply an in-place change to init_graph and compare
JacobianFactor::shared_ptr jacFactor0 = JacobianFactor::shared_ptr jacFactor0 = init_graph.at<JacobianFactor>(0);
std::dynamic_pointer_cast<JacobianFactor>(init_graph.at(0));
CHECK(jacFactor0); CHECK(jacFactor0);
jacFactor0->getA(jacFactor0->begin()) *= 7.; jacFactor0->getA(jacFactor0->begin()) *= 7.;
EXPECT(assert_inequal(init_graph, exp_graph)); EXPECT(assert_inequal(init_graph, exp_graph));

View File

@ -65,10 +65,9 @@ class GncOptimizer {
nfg_.resize(graph.size()); nfg_.resize(graph.size());
for (size_t i = 0; i < graph.size(); i++) { for (size_t i = 0; i < graph.size(); i++) {
if (graph[i]) { if (graph[i]) {
NoiseModelFactor::shared_ptr factor = std::dynamic_pointer_cast< NoiseModelFactor::shared_ptr factor = graph.at<NoiseModelFactor>(i);
NoiseModelFactor>(graph[i]); auto robust =
auto robust = std::dynamic_pointer_cast< std::dynamic_pointer_cast<noiseModel::Robust>(factor->noiseModel());
noiseModel::Robust>(factor->noiseModel());
// if the factor has a robust loss, we remove the robust loss // if the factor has a robust loss, we remove the robust loss
nfg_[i] = robust ? factor-> cloneWithNewNoiseModel(robust->noise()) : factor; nfg_[i] = robust ? factor-> cloneWithNewNoiseModel(robust->noise()) : factor;
} }
@ -401,11 +400,9 @@ class GncOptimizer {
newGraph.resize(nfg_.size()); newGraph.resize(nfg_.size());
for (size_t i = 0; i < nfg_.size(); i++) { for (size_t i = 0; i < nfg_.size(); i++) {
if (nfg_[i]) { if (nfg_[i]) {
auto factor = std::dynamic_pointer_cast< auto factor = nfg_.at<NoiseModelFactor>(i);
NoiseModelFactor>(nfg_[i]); auto noiseModel = std::dynamic_pointer_cast<noiseModel::Gaussian>(
auto noiseModel = factor->noiseModel());
std::dynamic_pointer_cast<noiseModel::Gaussian>(
factor->noiseModel());
if (noiseModel) { if (noiseModel) {
Matrix newInfo = weights[i] * noiseModel->information(); Matrix newInfo = weights[i] * noiseModel->information();
auto newNoiseModel = noiseModel::Gaussian::Information(newInfo); auto newNoiseModel = noiseModel::Gaussian::Information(newInfo);

View File

@ -372,9 +372,11 @@ TEST(ShonanAveraging2, noisyToyGraphWithHuber) {
// test that each factor is actually robust // test that each factor is actually robust
for (size_t i=0; i<=4; i++) { // note: last is the Gauge factor and is not robust for (size_t i=0; i<=4; i++) { // note: last is the Gauge factor and is not robust
const auto &robust = std::dynamic_pointer_cast<noiseModel::Robust>( const auto &robust = std::dynamic_pointer_cast<noiseModel::Robust>(
std::dynamic_pointer_cast<NoiseModelFactor>(graph[i])->noiseModel()); graph.at<NoiseModelFactor>(i)->noiseModel());
EXPECT(robust); // we expect the factors to be use a robust noise model (in particular, Huber) // we expect the factors to be use a robust noise model
// (in particular, Huber)
EXPECT(robust);
} }
// test result // test result

View File

@ -97,8 +97,7 @@ TEST(dataSet, load2D) {
auto model = noiseModel::Unit::Create(3); auto model = noiseModel::Unit::Create(3);
BetweenFactor<Pose2> expected(1, 0, Pose2(-0.99879, 0.0417574, -0.00818381), BetweenFactor<Pose2> expected(1, 0, Pose2(-0.99879, 0.0417574, -0.00818381),
model); model);
BetweenFactor<Pose2>::shared_ptr actual = BetweenFactor<Pose2>::shared_ptr actual = graph->at<BetweenFactor<Pose2>>(0);
std::dynamic_pointer_cast<BetweenFactor<Pose2>>(graph->at(0));
EXPECT(assert_equal(expected, *actual)); EXPECT(assert_equal(expected, *actual));
// Check binary measurements, Pose2 // Check binary measurements, Pose2
@ -113,9 +112,8 @@ TEST(dataSet, load2D) {
// // Check factor parsing // // Check factor parsing
const auto actualFactors = parseFactors<Pose2>(filename); const auto actualFactors = parseFactors<Pose2>(filename);
for (size_t i : {0, 1, 2, 3, 4, 5}) { for (size_t i : {0, 1, 2, 3, 4, 5}) {
EXPECT(assert_equal( EXPECT(assert_equal(*graph->at<BetweenFactor<Pose2>>(i), *actualFactors[i],
*std::dynamic_pointer_cast<BetweenFactor<Pose2>>(graph->at(i)), 1e-5));
*actualFactors[i], 1e-5));
} }
// Check pose parsing // Check pose parsing
@ -194,9 +192,8 @@ TEST(dataSet, readG2o3D) {
// Check factor parsing // Check factor parsing
const auto actualFactors = parseFactors<Pose3>(g2oFile); const auto actualFactors = parseFactors<Pose3>(g2oFile);
for (size_t i : {0, 1, 2, 3, 4, 5}) { for (size_t i : {0, 1, 2, 3, 4, 5}) {
EXPECT(assert_equal( EXPECT(assert_equal(*expectedGraph.at<BetweenFactor<Pose3>>(i),
*std::dynamic_pointer_cast<BetweenFactor<Pose3>>(expectedGraph[i]), *actualFactors[i], 1e-5));
*actualFactors[i], 1e-5));
} }
// Check pose parsing // Check pose parsing

View File

@ -183,13 +183,10 @@ class LoopyBelief {
// accumulate unary factors // accumulate unary factors
if (graph.at(factorIndex)->size() == 1) { if (graph.at(factorIndex)->size() == 1) {
if (!prodOfUnaries) if (!prodOfUnaries)
prodOfUnaries = std::dynamic_pointer_cast<DecisionTreeFactor>( prodOfUnaries = graph.at<DecisionTreeFactor>(factorIndex);
graph.at(factorIndex));
else else
prodOfUnaries = std::make_shared<DecisionTreeFactor>( prodOfUnaries = std::make_shared<DecisionTreeFactor>(
*prodOfUnaries * *prodOfUnaries * (*graph.at<DecisionTreeFactor>(factorIndex)));
(*std::dynamic_pointer_cast<DecisionTreeFactor>(
graph.at(factorIndex))));
} }
} }

View File

@ -87,7 +87,7 @@ TEST(NonlinearClusterTree, Clusters) {
Ordering ordering; Ordering ordering;
ordering.push_back(x1); ordering.push_back(x1);
const auto [bn, fg] = gfg->eliminatePartialSequential(ordering); const auto [bn, fg] = gfg->eliminatePartialSequential(ordering);
auto expectedFactor = std::dynamic_pointer_cast<HessianFactor>(fg->at(0)); auto expectedFactor = fg->at<HessianFactor>(0);
if (!expectedFactor) if (!expectedFactor)
throw std::runtime_error("Expected HessianFactor"); throw std::runtime_error("Expected HessianFactor");

View File

@ -323,7 +323,7 @@ TEST( NonlinearFactor, cloneWithNewNoiseModel )
// create actual // create actual
NonlinearFactorGraph actual; NonlinearFactorGraph actual;
SharedNoiseModel noise2 = noiseModel::Isotropic::Sigma(2,sigma2); SharedNoiseModel noise2 = noiseModel::Isotropic::Sigma(2,sigma2);
actual.push_back( std::dynamic_pointer_cast<NoiseModelFactor>(nfg[0])->cloneWithNewNoiseModel(noise2) ); actual.push_back(nfg.at<NoiseModelFactor>(0)->cloneWithNewNoiseModel(noise2));
// check it's all good // check it's all good
CHECK(assert_equal(expected, actual)); CHECK(assert_equal(expected, actual));