Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fan/prototype hybrid tr #42

Closed
wants to merge 42 commits into from
Closed

Fan/prototype hybrid tr #42

wants to merge 42 commits into from

Conversation

ProfFan
Copy link
Collaborator

@ProfFan ProfFan commented Mar 11, 2022

Prototyping a GTSAM-native hybrid graph that uses the CLG formulation described in Murphy02 and Salmeron18.

Multifrontal just works, though no actual functionality is added yet everything works.

I believe this is a better way to do hybrid, since everything now lies in accordance with other modules (discrete, linear, etc).

Also this is also how LinearContainerFactor is designed...

Copy link
Collaborator

@dellaert dellaert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t understand: is this a completely new framework? How does it relate to what we already have?

Copy link
Collaborator Author

@ProfFan ProfFan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me explain what is happening here.

In a historical perspective, when we merged in DCSAM code we started by making HybridFactorGraph there a FactorGraph<T> in GTSAM. However, that class is not designed in that way. If you look at that you can see that it is not a children of FactorGraph.

The native way in GTSAM how we make Factor graphs is by inheriting FactorGraph<DERIVED>. By doing this you automatically gets a container of DERIVED factors that comes with all the goodies. However, since the DCSAM version of HybridFactorGraph is not using this underlying storage, we have to work around the existing methods in FactorGraph, which is very tedious and error-prone.

A proper implementation, as I propose here, is to just use the underlying storage of FactorGraph and build logic only in the EliminateHybrid method. This allows us to have a minimal change in GTSAM to enable the same algorithms in DCSAM.

Actually, everything in this PR except the elimination functions are merely boilerplate: they 100% resembles their counterparts in linear and discrete.


namespace gtsam {

class CGMixtureFactor : HybridFactor {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be analogous to the current DCMixtureFactor

gtsam/hybrid/HybridBayesNet.h Show resolved Hide resolved

namespace gtsam {

// Instantiate base class
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to look at this

gtsam/hybrid/HybridBayesTree.h Show resolved Hide resolved
* - DiscreteConditional
* - GaussianMixture
* - GaussianConditional
*/
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HybridConditional is a type-erased wrapper for all:

  • DiscreteConditional
  • GaussianMixture
  • GaussianConditional

Gist is that by unifying all these types the only work need in HybridBayesTree is boilerplate (same to linear and discrete), the hard work (type-based dispatch) is offloaded to this class.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This eliminates the necessity of AbstractConditional, which is good because now we don't need to touch other modules, especially inference, at all.

gtsam/hybrid/HybridDiscreteFactor.h Show resolved Hide resolved
/**
* Base class for hybrid probabilistic factors
*/
class GTSAM_EXPORT HybridFactor: public Factor {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just the base for all hybrid factors


/* ************************************************************************ */
std::pair<HybridConditional::shared_ptr, HybridFactor::shared_ptr> //
EliminateHybrid(const HybridFactorGraph& factors,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we are in the Conditional Gaussian regime there are only
few cases:

  • continuous variable, we make a GM if there are hybrid factors;
  • continuous variable, we make a GF if there are no hybrid factors;
  • discrete variable, no continuous factor is allowed (escapes CG regime), so we panic
  • if discrete only we do the discrete elimination.

We can know which variable is discrete by querying the factors.

GTSAM_PRINT(*result.first);
}

TEST(HybridFactorGraph, eliminateMultifrontal) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By employing this scheme we don't need any special code for handling the templated JunctionTree and BayesTrees, so eliminateMultifrontal just work. In contrast, I spent tens of hours to make the old code to compile with JunctionTree and failed.

@ProfFan ProfFan requested a review from dellaert March 11, 2022 22:35
@dellaert
Copy link
Collaborator

OK, these explanations shed a lot of light, so thank you! I will do an in-depth look tomorrow, and then we can talk.

Copy link
Collaborator

@dellaert dellaert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took 40 minutes to review. Please address every comment by either implementing suggestion and resolving OR providing a rationale and not resolving.

gtsam/CMakeLists.txt Outdated Show resolved Hide resolved
gtsam/hybrid/CGMixtureFactor.cpp Outdated Show resolved Hide resolved
gtsam/hybrid/CGMixtureFactor.cpp Outdated Show resolved Hide resolved
typedef boost::shared_ptr<HybridFactor> shared_ptr; ///< shared_ptr to this class
typedef Factor Base; ///< Our base class

bool isDiscrete_ = false;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would each derived class not know this automatically?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to avoid the need to dynamic casts each time we need to know what is the type of one factor.

gtsam/hybrid/HybridFactor.h Show resolved Hide resolved
gtsam/hybrid/HybridFactorGraph.h Outdated Show resolved Hide resolved
gtsam/hybrid/HybridGaussianFactor.cpp Outdated Show resolved Hide resolved
gtsam/hybrid/HybridGaussianFactor.h Show resolved Hide resolved
gtsam/hybrid/tests/CMakeLists.txt Outdated Show resolved Hide resolved
gtsam/hybrid/CGMixtureFactor.h Outdated Show resolved Hide resolved
@ProfFan
Copy link
Collaborator Author

ProfFan commented Mar 24, 2022

@dellaert I now believe I have full multifrontal elimination working. The code still needs some cleaning up though.

BTW, I am now thinking a bit more about the decision to use DecisionTree as the base structure. Maybe a hash table keyed on the discrete assignment will be better both in performance and in difficulty of programming, if we have pruning?

@ProfFan
Copy link
Collaborator Author

ProfFan commented Mar 24, 2022

@dellaert @varunagrawal Feel free to play with the code while I add new unit tests :)

@ProfFan ProfFan requested a review from dellaert March 24, 2022 00:42
@varunagrawal
Copy link
Owner

Also, I guess it would be a good idea to add a massive comment on HybridConditional about how the type-erasure works? Basically explain why we typecast everything to HybridConditional in order to make things seamless.

Copy link
Collaborator

@dellaert dellaert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some comments

@@ -0,0 +1,273 @@
/* ----------------------------------------------------------------------------
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many tests should be in testHybridFactorGraph

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

X(0), Z_3x1, I_3x3, X(1), I_3x3),
boost::make_shared<GaussianConditional>(
X(0), Vector3::Ones(), I_3x3, X(1), I_3x3)));
GTSAM_PRINT(clgc);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Convert print to real tests.

X(0), Z_3x1, I_3x3, X(1), I_3x3),
boost::make_shared<GaussianConditional>(
X(0), Vector3::Ones(), I_3x3, X(1), I_3x3)));
GTSAM_PRINT(clgc);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use curly braces for discrete keys


DiscreteKey c1(C(1), 2);

hfg.add(JacobianFactor(X(0), I_3x3, Z_3x1));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't copy paste


HybridFactorGraph hfg;

hfg.add(JacobianFactor(X(0), I_3x3, X(1), -I_3x3, Z_3x1));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add comments to show example.

boost::shared_ptr<CliqueType> clique;

BayesTreeOrphanWrapper(const boost::shared_ptr<CliqueType>& clique)
: clique(clique) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make it a constructor for Base


#pragma once

#include <gtsam/discrete/DiscreteConditional.h>
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean them up

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check other headers

gtsam/hybrid/GaussianMixture.cpp Outdated Show resolved Hide resolved
gtsam/hybrid/GaussianMixture.cpp Outdated Show resolved Hide resolved
gtsam/hybrid/GaussianMixture.cpp Outdated Show resolved Hide resolved
gtsam/hybrid/GaussianMixture.h Outdated Show resolved Hide resolved
gtsam/hybrid/GaussianMixture.h Outdated Show resolved Hide resolved
gtsam/hybrid/HybridFactor.cpp Outdated Show resolved Hide resolved

/* ************************************************************************ */
std::pair<HybridConditional::shared_ptr, HybridFactor::shared_ptr> //
EliminateHybrid(const HybridFactorGraph &factors, const Ordering &frontalKeys) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should really consider breaking this method up into smaller chunks. There is already a logical demarcation.

gtsam/hybrid/HybridGaussianFactor.h Outdated Show resolved Hide resolved
@@ -0,0 +1,273 @@
/* ----------------------------------------------------------------------------
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

return {new_order, levels};
}

} // namespace gtsam
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a newline.

@dellaert
Copy link
Collaborator

@ProfFan after you address these relatively minor comments (please do so ASAP) please close this PR and create a PR from this branch directly to GTSAM develop (after merging in that develop).

@varunagrawal varunagrawal reopened this May 24, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants