support cloning (deep copy) for ISAM2
parent
58ace25e33
commit
e036dd460e
|
@ -81,6 +81,20 @@ namespace gtsam {
|
||||||
|
|
||||||
Clique(const sharedConditional& conditional);
|
Clique(const sharedConditional& conditional);
|
||||||
|
|
||||||
|
void cloneToBayesTree(BayesTree& newTree, shared_ptr parent_clique = shared_ptr()) const {
|
||||||
|
sharedConditional newConditional = sharedConditional(new CONDITIONAL(*conditional_));
|
||||||
|
sharedClique newClique = newTree.addClique(newConditional, parent_clique);
|
||||||
|
if (cachedFactor_)
|
||||||
|
newClique->cachedFactor_ = cachedFactor_->clone();
|
||||||
|
else newClique->cachedFactor_ = typename FactorType::shared_ptr();
|
||||||
|
if (!parent_clique) {
|
||||||
|
newTree.root_ = newClique;
|
||||||
|
}
|
||||||
|
BOOST_FOREACH(const shared_ptr& childClique, children_) {
|
||||||
|
childClique->cloneToBayesTree(newTree, newClique);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** print this node */
|
/** print this node */
|
||||||
void print(const std::string& s = "") const;
|
void print(const std::string& s = "") const;
|
||||||
|
|
||||||
|
@ -264,6 +278,11 @@ namespace gtsam {
|
||||||
/** check equality */
|
/** check equality */
|
||||||
bool equals(const BayesTree<CONDITIONAL>& other, double tol = 1e-9) const;
|
bool equals(const BayesTree<CONDITIONAL>& other, double tol = 1e-9) const;
|
||||||
|
|
||||||
|
/** deep copy from another tree */
|
||||||
|
void cloneTo(shared_ptr& newTree) const {
|
||||||
|
root_->cloneToBayesTree(*newTree);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find parent clique of a conditional. It will look at all parents and
|
* Find parent clique of a conditional. It will look at all parents and
|
||||||
* return the one with the lowest index in the ordering.
|
* return the one with the lowest index in the ordering.
|
||||||
|
|
|
@ -174,6 +174,13 @@ public:
|
||||||
/** Access the container through the permutation (const version) */
|
/** Access the container through the permutation (const version) */
|
||||||
const value_type& operator[](size_t index) const { return container_[permutation_[index]]; }
|
const value_type& operator[](size_t index) const { return container_[permutation_[index]]; }
|
||||||
|
|
||||||
|
/** Assignment operator for cloning in ISAM2 */
|
||||||
|
Permuted<CONTAINER> operator=(const Permuted<CONTAINER>& other) {
|
||||||
|
permutation_ = other.permutation_;
|
||||||
|
container_ = other.container_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
/** Permute this view by applying a permutation to the underlying permutation */
|
/** Permute this view by applying a permutation to the underlying permutation */
|
||||||
void permute(const Permutation& permutation) { assert(permutation.size() == this->size()); permutation_ = *permutation_.permute(permutation); }
|
void permute(const Permutation& permutation) { assert(permutation.size() == this->size()); permutation_ = *permutation_.permute(permutation); }
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,9 @@ namespace gtsam {
|
||||||
/** Return the dimension of the variable pointed to by the given key iterator */
|
/** Return the dimension of the variable pointed to by the given key iterator */
|
||||||
virtual size_t getDim(const_iterator variable) const = 0;
|
virtual size_t getDim(const_iterator variable) const = 0;
|
||||||
|
|
||||||
|
/** Clone a factor (make a deep copy) */
|
||||||
|
virtual GaussianFactor::shared_ptr clone() const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Permutes the GaussianFactor, but for efficiency requires the permutation
|
* Permutes the GaussianFactor, but for efficiency requires the permutation
|
||||||
* to already be inverted. This acts just as a change-of-name for each
|
* to already be inverted. This acts just as a change-of-name for each
|
||||||
|
|
|
@ -191,6 +191,12 @@ namespace gtsam {
|
||||||
/** Destructor */
|
/** Destructor */
|
||||||
virtual ~HessianFactor() {}
|
virtual ~HessianFactor() {}
|
||||||
|
|
||||||
|
/** Clone this JacobianFactor */
|
||||||
|
virtual GaussianFactor::shared_ptr clone() const {
|
||||||
|
return boost::static_pointer_cast<GaussianFactor>(
|
||||||
|
shared_ptr(new HessianFactor(*this)));
|
||||||
|
}
|
||||||
|
|
||||||
/** Print the factor for debugging and testing (implementing Testable) */
|
/** Print the factor for debugging and testing (implementing Testable) */
|
||||||
virtual void print(const std::string& s = "") const;
|
virtual void print(const std::string& s = "") const;
|
||||||
|
|
||||||
|
|
|
@ -136,6 +136,12 @@ namespace gtsam {
|
||||||
|
|
||||||
virtual ~JacobianFactor() {}
|
virtual ~JacobianFactor() {}
|
||||||
|
|
||||||
|
/** Clone this JacobianFactor */
|
||||||
|
virtual GaussianFactor::shared_ptr clone() const {
|
||||||
|
return boost::static_pointer_cast<GaussianFactor>(
|
||||||
|
shared_ptr(new JacobianFactor(*this)));
|
||||||
|
}
|
||||||
|
|
||||||
// Implementing Testable interface
|
// Implementing Testable interface
|
||||||
virtual void print(const std::string& s = "") const;
|
virtual void print(const std::string& s = "") const;
|
||||||
virtual bool equals(const GaussianFactor& lf, double tol = 1e-9) const;
|
virtual bool equals(const GaussianFactor& lf, double tol = 1e-9) const;
|
||||||
|
|
|
@ -27,12 +27,18 @@ namespace gtsam {
|
||||||
*/
|
*/
|
||||||
template <class VALUES, class GRAPH = NonlinearFactorGraph<VALUES> >
|
template <class VALUES, class GRAPH = NonlinearFactorGraph<VALUES> >
|
||||||
class GaussianISAM2 : public ISAM2<GaussianConditional, VALUES, GRAPH> {
|
class GaussianISAM2 : public ISAM2<GaussianConditional, VALUES, GRAPH> {
|
||||||
|
typedef ISAM2<GaussianConditional, VALUES, GRAPH> Base;
|
||||||
public:
|
public:
|
||||||
/** Create an empty ISAM2 instance */
|
/** Create an empty ISAM2 instance */
|
||||||
GaussianISAM2(const ISAM2Params& params) : ISAM2<GaussianConditional, VALUES, GRAPH>(params) {}
|
GaussianISAM2(const ISAM2Params& params) : ISAM2<GaussianConditional, VALUES, GRAPH>(params) {}
|
||||||
|
|
||||||
/** Create an empty ISAM2 instance using the default set of parameters (see ISAM2Params) */
|
/** Create an empty ISAM2 instance using the default set of parameters (see ISAM2Params) */
|
||||||
GaussianISAM2() : ISAM2<GaussianConditional, VALUES, GRAPH>() {}
|
GaussianISAM2() : ISAM2<GaussianConditional, VALUES, GRAPH>() {}
|
||||||
|
|
||||||
|
void cloneTo(boost::shared_ptr<GaussianISAM2>& newGaussianISAM2) const {
|
||||||
|
boost::shared_ptr<Base> isam2 = boost::static_pointer_cast<Base>(newGaussianISAM2);
|
||||||
|
Base::cloneTo(isam2);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// optimize the BayesTree, starting from the root
|
// optimize the BayesTree, starting from the root
|
||||||
|
|
|
@ -167,6 +167,27 @@ public:
|
||||||
/** Create an empty ISAM2 instance using the default set of parameters (see ISAM2Params) */
|
/** Create an empty ISAM2 instance using the default set of parameters (see ISAM2Params) */
|
||||||
ISAM2();
|
ISAM2();
|
||||||
|
|
||||||
|
void cloneTo(boost::shared_ptr<ISAM2>& newISAM2) const {
|
||||||
|
boost::shared_ptr<Base> bayesTree = boost::static_pointer_cast<Base>(newISAM2);
|
||||||
|
Base::cloneTo(bayesTree);
|
||||||
|
newISAM2->theta_ = theta_;
|
||||||
|
newISAM2->variableIndex_ = variableIndex_;
|
||||||
|
newISAM2->deltaUnpermuted_ = deltaUnpermuted_;
|
||||||
|
newISAM2->delta_ = delta_;
|
||||||
|
newISAM2->nonlinearFactors_ = nonlinearFactors_;
|
||||||
|
newISAM2->ordering_ = ordering_;
|
||||||
|
newISAM2->params_ = params_;
|
||||||
|
#ifndef NDEBUG
|
||||||
|
newISAM2->lastRelinVariables_ = lastRelinVariables_;
|
||||||
|
#endif
|
||||||
|
newISAM2->lastAffectedVariableCount = lastAffectedVariableCount;
|
||||||
|
newISAM2->lastAffectedFactorCount = lastAffectedFactorCount;
|
||||||
|
newISAM2->lastAffectedCliqueCount = lastAffectedCliqueCount;
|
||||||
|
newISAM2->lastAffectedMarkedCount = lastAffectedMarkedCount;
|
||||||
|
newISAM2->lastBacksubVariableCount = lastBacksubVariableCount;
|
||||||
|
newISAM2->lastNnzTop = lastNnzTop;
|
||||||
|
}
|
||||||
|
|
||||||
typedef typename BayesTree<CONDITIONAL>::sharedClique sharedClique; ///< Shared pointer to a clique
|
typedef typename BayesTree<CONDITIONAL>::sharedClique sharedClique; ///< Shared pointer to a clique
|
||||||
typedef typename BayesTree<CONDITIONAL>::Cliques Cliques; ///< List of Clique typedef from base class
|
typedef typename BayesTree<CONDITIONAL>::Cliques Cliques; ///< List of Clique typedef from base class
|
||||||
|
|
||||||
|
@ -235,6 +256,8 @@ public:
|
||||||
size_t lastBacksubVariableCount;
|
size_t lastBacksubVariableCount;
|
||||||
size_t lastNnzTop;
|
size_t lastNnzTop;
|
||||||
|
|
||||||
|
ISAM2Params params() const { return params_; }
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -292,6 +292,110 @@ TEST(ISAM2, slamlike_solution)
|
||||||
EXPECT(isam_check(fullgraph, fullinit, isam));
|
EXPECT(isam_check(fullgraph, fullinit, isam));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ************************************************************************* */
|
||||||
|
TEST_UNSAFE(ISAM2, clone) {
|
||||||
|
|
||||||
|
// Pose and landmark key types from planarSLAM
|
||||||
|
typedef planarSLAM::PoseKey PoseKey;
|
||||||
|
typedef planarSLAM::PointKey PointKey;
|
||||||
|
|
||||||
|
// Set up parameters
|
||||||
|
SharedDiagonal odoNoise = sharedSigmas(Vector_(3, 0.1, 0.1, M_PI/100.0));
|
||||||
|
SharedDiagonal brNoise = sharedSigmas(Vector_(2, M_PI/100.0, 0.1));
|
||||||
|
|
||||||
|
// These variables will be reused and accumulate factors and values
|
||||||
|
GaussianISAM2<planarSLAM::Values> isam(ISAM2Params(0.001, 0.0, 0, false, true));
|
||||||
|
planarSLAM::Values fullinit;
|
||||||
|
planarSLAM::Graph fullgraph;
|
||||||
|
|
||||||
|
// i keeps track of the time step
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
// Add a prior at time 0 and update isam
|
||||||
|
{
|
||||||
|
planarSLAM::Graph newfactors;
|
||||||
|
newfactors.addPrior(0, Pose2(0.0, 0.0, 0.0), odoNoise);
|
||||||
|
fullgraph.push_back(newfactors);
|
||||||
|
|
||||||
|
planarSLAM::Values init;
|
||||||
|
init.insert(PoseKey(0), Pose2(0.01, 0.01, 0.01));
|
||||||
|
fullinit.insert(PoseKey(0), Pose2(0.01, 0.01, 0.01));
|
||||||
|
|
||||||
|
isam.update(newfactors, init);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT(isam_check(fullgraph, fullinit, isam));
|
||||||
|
|
||||||
|
// Add odometry from time 0 to time 5
|
||||||
|
for( ; i<5; ++i) {
|
||||||
|
planarSLAM::Graph newfactors;
|
||||||
|
newfactors.addOdometry(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
||||||
|
fullgraph.push_back(newfactors);
|
||||||
|
|
||||||
|
planarSLAM::Values init;
|
||||||
|
init.insert(PoseKey(i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
||||||
|
fullinit.insert(PoseKey(i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
||||||
|
|
||||||
|
isam.update(newfactors, init);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add odometry from time 5 to 6 and landmark measurement at time 5
|
||||||
|
{
|
||||||
|
planarSLAM::Graph newfactors;
|
||||||
|
newfactors.addOdometry(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
||||||
|
newfactors.addBearingRange(i, 0, Rot2::fromAngle(M_PI/4.0), 5.0, brNoise);
|
||||||
|
newfactors.addBearingRange(i, 1, Rot2::fromAngle(-M_PI/4.0), 5.0, brNoise);
|
||||||
|
fullgraph.push_back(newfactors);
|
||||||
|
|
||||||
|
planarSLAM::Values init;
|
||||||
|
init.insert(PoseKey(i+1), Pose2(1.01, 0.01, 0.01));
|
||||||
|
init.insert(PointKey(0), Point2(5.0/sqrt(2.0), 5.0/sqrt(2.0)));
|
||||||
|
init.insert(PointKey(1), Point2(5.0/sqrt(2.0), -5.0/sqrt(2.0)));
|
||||||
|
fullinit.insert(PoseKey(i+1), Pose2(1.01, 0.01, 0.01));
|
||||||
|
fullinit.insert(PointKey(0), Point2(5.0/sqrt(2.0), 5.0/sqrt(2.0)));
|
||||||
|
fullinit.insert(PointKey(1), Point2(5.0/sqrt(2.0), -5.0/sqrt(2.0)));
|
||||||
|
|
||||||
|
isam.update(newfactors, init);
|
||||||
|
++ i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add odometry from time 6 to time 10
|
||||||
|
for( ; i<10; ++i) {
|
||||||
|
planarSLAM::Graph newfactors;
|
||||||
|
newfactors.addOdometry(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
||||||
|
fullgraph.push_back(newfactors);
|
||||||
|
|
||||||
|
planarSLAM::Values init;
|
||||||
|
init.insert(PoseKey(i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
||||||
|
fullinit.insert(PoseKey(i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
||||||
|
|
||||||
|
isam.update(newfactors, init);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add odometry from time 10 to 11 and landmark measurement at time 10
|
||||||
|
{
|
||||||
|
planarSLAM::Graph newfactors;
|
||||||
|
newfactors.addOdometry(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
||||||
|
newfactors.addBearingRange(i, 0, Rot2::fromAngle(M_PI/4.0 + M_PI/16.0), 4.5, brNoise);
|
||||||
|
newfactors.addBearingRange(i, 1, Rot2::fromAngle(-M_PI/4.0 + M_PI/16.0), 4.5, brNoise);
|
||||||
|
fullgraph.push_back(newfactors);
|
||||||
|
|
||||||
|
planarSLAM::Values init;
|
||||||
|
init.insert(PoseKey(i+1), Pose2(6.9, 0.1, 0.01));
|
||||||
|
fullinit.insert(PoseKey(i+1), Pose2(6.9, 0.1, 0.01));
|
||||||
|
|
||||||
|
isam.update(newfactors, init);
|
||||||
|
++ i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CLONING...
|
||||||
|
boost::shared_ptr<GaussianISAM2<planarSLAM::Values> > isam2
|
||||||
|
= boost::shared_ptr<GaussianISAM2<planarSLAM::Values> >(new GaussianISAM2<planarSLAM::Values>());
|
||||||
|
isam.cloneTo(isam2);
|
||||||
|
|
||||||
|
CHECK(assert_equal(isam, *isam2));
|
||||||
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
int main() { TestResult tr; return TestRegistry::runAllTests(tr);}
|
int main() { TestResult tr; return TestRegistry::runAllTests(tr);}
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
|
|
Loading…
Reference in New Issue