Major change, elimination functions are now passed an "Eliminate function", so you can select at run-time which factorization method is used (symbolic, QR, etc...).

release/4.3a0
Frank Dellaert 2011-03-24 19:27:12 +00:00
parent ba8cfe2554
commit 5c193422af
56 changed files with 2078 additions and 1832 deletions

176
.cproject
View File

@ -676,6 +676,14 @@
<useDefaultCommand>true</useDefaultCommand> <useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders> <runAllBuilders>true</runAllBuilders>
</target> </target>
<target name="check" path="build/gtsam/nonlinear" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments>
<buildTarget>check</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="tests/testGeneralSFMFactor.run" path="build/gtsam/slam" targetID="org.eclipse.cdt.build.MakeTargetBuilder"> <target name="tests/testGeneralSFMFactor.run" path="build/gtsam/slam" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand> <buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments> <buildArguments>-j2</buildArguments>
@ -692,6 +700,22 @@
<useDefaultCommand>true</useDefaultCommand> <useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders> <runAllBuilders>true</runAllBuilders>
</target> </target>
<target name="all" path="build/gtsam/slam" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments>
<buildTarget>all</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="check" path="build/gtsam/slam" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments>
<buildTarget>check</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="check" path="build/geometry" targetID="org.eclipse.cdt.build.MakeTargetBuilder"> <target name="check" path="build/geometry" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand> <buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments> <buildArguments>-j2</buildArguments>
@ -756,6 +780,22 @@
<useDefaultCommand>true</useDefaultCommand> <useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders> <runAllBuilders>true</runAllBuilders>
</target> </target>
<target name="tests/testSymbolicFactorGraph.run" path="build/gtsam/inference" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments>
<buildTarget>tests/testSymbolicFactorGraph.run</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="tests/testSymbolicBayesNet.run" path="build/gtsam/inference" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments>
<buildTarget>tests/testSymbolicBayesNet.run</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="vSFMexample.run" path="build/examples/vSLAMexample" targetID="org.eclipse.cdt.build.MakeTargetBuilder"> <target name="vSFMexample.run" path="build/examples/vSLAMexample" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand> <buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments> <buildArguments>-j2</buildArguments>
@ -820,14 +860,6 @@
<useDefaultCommand>true</useDefaultCommand> <useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders> <runAllBuilders>true</runAllBuilders>
</target> </target>
<target name="testGaussianFactorGraph" path="build/tests" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments>
<buildTarget>testGaussianFactorGraph</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="testGaussianJunctionTree" path="build/tests" targetID="org.eclipse.cdt.build.MakeTargetBuilder"> <target name="testGaussianJunctionTree" path="build/tests" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand> <buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments> <buildArguments>-j2</buildArguments>
@ -876,6 +908,14 @@
<useDefaultCommand>true</useDefaultCommand> <useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders> <runAllBuilders>true</runAllBuilders>
</target> </target>
<target name="testNonlinearFactor.run" path="build/tests" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments>
<buildTarget>testNonlinearFactor.run</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="SimpleRotation.run" path="examples" targetID="org.eclipse.cdt.build.MakeTargetBuilder"> <target name="SimpleRotation.run" path="examples" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand> <buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments> <buildArguments>-j2</buildArguments>
@ -1411,6 +1451,22 @@
<useDefaultCommand>true</useDefaultCommand> <useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders> <runAllBuilders>true</runAllBuilders>
</target> </target>
<target name="testVirtual.run" path="build/gtsam/base" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments>
<buildTarget>testVirtual.run</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="tests/timeVirtual.run" path="build/gtsam/base" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments>
<buildTarget>tests/timeVirtual.run</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="tests/testVectorValues.run" path="build/gtsam/linear" targetID="org.eclipse.cdt.build.MakeTargetBuilder"> <target name="tests/testVectorValues.run" path="build/gtsam/linear" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand> <buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments> <buildArguments>-j2</buildArguments>
@ -1443,6 +1499,22 @@
<useDefaultCommand>true</useDefaultCommand> <useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders> <runAllBuilders>true</runAllBuilders>
</target> </target>
<target name="check" path="build/gtsam/linear" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments>
<buildTarget>check</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="tests/testGaussianFactorGraph.run" path="build/gtsam/linear" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments>
<buildTarget>tests/testGaussianFactorGraph.run</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="SimpleRotation.run" path="build/examples" targetID="org.eclipse.cdt.build.MakeTargetBuilder"> <target name="SimpleRotation.run" path="build/examples" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand> <buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments> <buildArguments>-j2</buildArguments>
@ -2359,6 +2431,14 @@
<useDefaultCommand>true</useDefaultCommand> <useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders> <runAllBuilders>true</runAllBuilders>
</target> </target>
<target name="check" path="build/gtsam/nonlinear" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments>
<buildTarget>check</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="tests/testGeneralSFMFactor.run" path="build/gtsam/slam" targetID="org.eclipse.cdt.build.MakeTargetBuilder"> <target name="tests/testGeneralSFMFactor.run" path="build/gtsam/slam" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand> <buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments> <buildArguments>-j2</buildArguments>
@ -2375,6 +2455,22 @@
<useDefaultCommand>true</useDefaultCommand> <useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders> <runAllBuilders>true</runAllBuilders>
</target> </target>
<target name="all" path="build/gtsam/slam" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments>
<buildTarget>all</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="check" path="build/gtsam/slam" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments>
<buildTarget>check</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="check" path="build/geometry" targetID="org.eclipse.cdt.build.MakeTargetBuilder"> <target name="check" path="build/geometry" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand> <buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments> <buildArguments>-j2</buildArguments>
@ -2439,6 +2535,22 @@
<useDefaultCommand>true</useDefaultCommand> <useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders> <runAllBuilders>true</runAllBuilders>
</target> </target>
<target name="tests/testSymbolicFactorGraph.run" path="build/gtsam/inference" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments>
<buildTarget>tests/testSymbolicFactorGraph.run</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="tests/testSymbolicBayesNet.run" path="build/gtsam/inference" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments>
<buildTarget>tests/testSymbolicBayesNet.run</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="vSFMexample.run" path="build/examples/vSLAMexample" targetID="org.eclipse.cdt.build.MakeTargetBuilder"> <target name="vSFMexample.run" path="build/examples/vSLAMexample" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand> <buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments> <buildArguments>-j2</buildArguments>
@ -2503,14 +2615,6 @@
<useDefaultCommand>true</useDefaultCommand> <useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders> <runAllBuilders>true</runAllBuilders>
</target> </target>
<target name="testGaussianFactorGraph" path="build/tests" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments>
<buildTarget>testGaussianFactorGraph</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="testGaussianJunctionTree" path="build/tests" targetID="org.eclipse.cdt.build.MakeTargetBuilder"> <target name="testGaussianJunctionTree" path="build/tests" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand> <buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments> <buildArguments>-j2</buildArguments>
@ -2559,6 +2663,14 @@
<useDefaultCommand>true</useDefaultCommand> <useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders> <runAllBuilders>true</runAllBuilders>
</target> </target>
<target name="testNonlinearFactor.run" path="build/tests" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments>
<buildTarget>testNonlinearFactor.run</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="SimpleRotation.run" path="examples" targetID="org.eclipse.cdt.build.MakeTargetBuilder"> <target name="SimpleRotation.run" path="examples" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand> <buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments> <buildArguments>-j2</buildArguments>
@ -3094,6 +3206,22 @@
<useDefaultCommand>true</useDefaultCommand> <useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders> <runAllBuilders>true</runAllBuilders>
</target> </target>
<target name="testVirtual.run" path="build/gtsam/base" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments>
<buildTarget>testVirtual.run</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="tests/timeVirtual.run" path="build/gtsam/base" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments>
<buildTarget>tests/timeVirtual.run</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="tests/testVectorValues.run" path="build/gtsam/linear" targetID="org.eclipse.cdt.build.MakeTargetBuilder"> <target name="tests/testVectorValues.run" path="build/gtsam/linear" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand> <buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments> <buildArguments>-j2</buildArguments>
@ -3126,6 +3254,22 @@
<useDefaultCommand>true</useDefaultCommand> <useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders> <runAllBuilders>true</runAllBuilders>
</target> </target>
<target name="check" path="build/gtsam/linear" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments>
<buildTarget>check</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="tests/testGaussianFactorGraph.run" path="build/gtsam/linear" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments>
<buildTarget>tests/testGaussianFactorGraph.run</buildTarget>
<stopOnError>true</stopOnError>
<useDefaultCommand>true</useDefaultCommand>
<runAllBuilders>true</runAllBuilders>
</target>
<target name="SimpleRotation.run" path="build/examples" targetID="org.eclipse.cdt.build.MakeTargetBuilder"> <target name="SimpleRotation.run" path="build/examples" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
<buildCommand>make</buildCommand> <buildCommand>make</buildCommand>
<buildArguments>-j2</buildArguments> <buildArguments>-j2</buildArguments>

View File

@ -97,6 +97,7 @@ namespace gtsam {
double tol_; double tol_;
equals_star(double tol = 1e-9) : tol_(tol) {} equals_star(double tol = 1e-9) : tol_(tol) {}
bool operator()(const boost::shared_ptr<V>& expected, const boost::shared_ptr<V>& actual) { bool operator()(const boost::shared_ptr<V>& expected, const boost::shared_ptr<V>& actual) {
if (!actual || !expected) return false;
return (actual->equals(*expected, tol_)); return (actual->equals(*expected, tol_));
} }
}; };

View File

@ -280,8 +280,8 @@ namespace gtsam {
// TODO, why do we actually return a shared pointer, why does eliminate? // TODO, why do we actually return a shared pointer, why does eliminate?
/* ************************************************************************* */ /* ************************************************************************* */
template<class CONDITIONAL> template<class CONDITIONAL>
BayesNet<CONDITIONAL> BayesNet<CONDITIONAL> BayesTree<CONDITIONAL>::Clique::shortcut(shared_ptr R,
BayesTree<CONDITIONAL>::Clique::shortcut(shared_ptr R) { Eliminate function) {
static const bool debug = false; static const bool debug = false;
@ -296,17 +296,17 @@ namespace gtsam {
} }
// The root conditional // The root conditional
FactorGraph<typename CONDITIONAL::FactorType> p_R(*R); FactorGraph<FactorType> p_R(*R);
// The parent clique has a CONDITIONAL for each frontal node in Fp // The parent clique has a CONDITIONAL for each frontal node in Fp
// so we can obtain P(Fp|Sp) in factor graph form // so we can obtain P(Fp|Sp) in factor graph form
FactorGraph<typename CONDITIONAL::FactorType> p_Fp_Sp(*parent); FactorGraph<FactorType> p_Fp_Sp(*parent);
// If not the base case, obtain the parent shortcut P(Sp|R) as factors // If not the base case, obtain the parent shortcut P(Sp|R) as factors
FactorGraph<typename CONDITIONAL::FactorType> p_Sp_R(parent->shortcut(R)); FactorGraph<FactorType> p_Sp_R(parent->shortcut(R, function));
// now combine P(Cp|R) = P(Fp|Sp) * P(Sp|R) // now combine P(Cp|R) = P(Fp|Sp) * P(Sp|R)
FactorGraph<typename CONDITIONAL::FactorType> p_Cp_R; FactorGraph<FactorType> p_Cp_R;
p_Cp_R.push_back(p_R); p_Cp_R.push_back(p_R);
p_Cp_R.push_back(p_Fp_Sp); p_Cp_R.push_back(p_Fp_Sp);
p_Cp_R.push_back(p_Sp_R); p_Cp_R.push_back(p_Sp_R);
@ -345,9 +345,10 @@ namespace gtsam {
vector<Index>(variablesAtBack.begin(), variablesAtBack.end()), vector<Index>(variablesAtBack.begin(), variablesAtBack.end()),
R->back()->key() + 1); R->back()->key() + 1);
Permutation::shared_ptr toBackInverse(toBack.inverse()); Permutation::shared_ptr toBackInverse(toBack.inverse());
BOOST_FOREACH(const typename CONDITIONAL::FactorType::shared_ptr& factor, p_Cp_R) { BOOST_FOREACH(const typename FactorType::shared_ptr& factor, p_Cp_R) {
factor->permuteWithInverse(*toBackInverse); } factor->permuteWithInverse(*toBackInverse); }
typename BayesNet<CONDITIONAL>::shared_ptr eliminated(EliminationTree<typename CONDITIONAL::FactorType>::Create(p_Cp_R)->eliminate()); typename BayesNet<CONDITIONAL>::shared_ptr eliminated(EliminationTree<
FactorType>::Create(p_Cp_R)->eliminate(function));
// Take only the conditionals for p(S|R). We check for each variable being // Take only the conditionals for p(S|R). We check for each variable being
// in the separator set because if some separator variables overlap with // in the separator set because if some separator variables overlap with
@ -380,34 +381,37 @@ namespace gtsam {
// Because the root clique could be very big. // Because the root clique could be very big.
/* ************************************************************************* */ /* ************************************************************************* */
template<class CONDITIONAL> template<class CONDITIONAL>
FactorGraph<typename CONDITIONAL::FactorType> BayesTree<CONDITIONAL>::Clique::marginal(shared_ptr R) { FactorGraph<typename CONDITIONAL::FactorType> BayesTree<CONDITIONAL>::Clique::marginal(
shared_ptr R, Eliminate function) {
// If we are the root, just return this root // If we are the root, just return this root
// NOTE: immediately cast to a factor graph // NOTE: immediately cast to a factor graph
if (R.get()==this) return *R; if (R.get()==this) return *R;
// Combine P(F|S), P(S|R), and P(R) // Combine P(F|S), P(S|R), and P(R)
BayesNet<CONDITIONAL> p_FSR = this->shortcut(R); BayesNet<CONDITIONAL> p_FSR = this->shortcut(R, function);
p_FSR.push_front(*this); p_FSR.push_front(*this);
p_FSR.push_back(*R); p_FSR.push_back(*R);
assertInvariants(); assertInvariants();
return *GenericSequentialSolver<typename CONDITIONAL::FactorType>(p_FSR).jointFactorGraph(keys()); GenericSequentialSolver<FactorType> solver(p_FSR);
return *solver.jointFactorGraph(keys(), function);
} }
/* ************************************************************************* */ /* ************************************************************************* */
// P(C1,C2) = \int_R P(F1|S1) P(S1|R) P(F2|S1) P(S2|R) P(R) // P(C1,C2) = \int_R P(F1|S1) P(S1|R) P(F2|S1) P(S2|R) P(R)
/* ************************************************************************* */ /* ************************************************************************* */
template<class CONDITIONAL> template<class CONDITIONAL>
FactorGraph<typename CONDITIONAL::FactorType> BayesTree<CONDITIONAL>::Clique::joint(shared_ptr C2, shared_ptr R) { FactorGraph<typename CONDITIONAL::FactorType> BayesTree<CONDITIONAL>::Clique::joint(
shared_ptr C2, shared_ptr R, Eliminate function) {
// For now, assume neither is the root // For now, assume neither is the root
// Combine P(F1|S1), P(S1|R), P(F2|S2), P(S2|R), and P(R) // Combine P(F1|S1), P(S1|R), P(F2|S2), P(S2|R), and P(R)
FactorGraph<typename CONDITIONAL::FactorType> joint; FactorGraph<FactorType> joint;
if (!isRoot()) joint.push_back(*this); // P(F1|S1) if (!isRoot()) joint.push_back(*this); // P(F1|S1)
if (!isRoot()) joint.push_back(shortcut(R)); // P(S1|R) if (!isRoot()) joint.push_back(shortcut(R, function)); // P(S1|R)
if (!C2->isRoot()) joint.push_back(*C2); // P(F2|S2) if (!C2->isRoot()) joint.push_back(*C2); // P(F2|S2)
if (!C2->isRoot()) joint.push_back(C2->shortcut(R)); // P(S2|R) if (!C2->isRoot()) joint.push_back(C2->shortcut(R, function)); // P(S2|R)
joint.push_back(*R); // P(R) joint.push_back(*R); // P(R)
// Find the keys of both C1 and C2 // Find the keys of both C1 and C2
vector<Index> keys1(keys()); vector<Index> keys1(keys());
@ -420,7 +424,8 @@ namespace gtsam {
vector<Index> keys12vector; keys12vector.reserve(keys12.size()); vector<Index> keys12vector; keys12vector.reserve(keys12.size());
keys12vector.insert(keys12vector.begin(), keys12.begin(), keys12.end()); keys12vector.insert(keys12vector.begin(), keys12.begin(), keys12.end());
assertInvariants(); assertInvariants();
return *GenericSequentialSolver<typename CONDITIONAL::FactorType>(joint).jointFactorGraph(keys12vector); GenericSequentialSolver<FactorType> solver(joint);
return *solver.jointFactorGraph(keys12vector, function);
} }
/* ************************************************************************* */ /* ************************************************************************* */
@ -729,53 +734,59 @@ namespace gtsam {
// First finds clique marginal then marginalizes that // First finds clique marginal then marginalizes that
/* ************************************************************************* */ /* ************************************************************************* */
template<class CONDITIONAL> template<class CONDITIONAL>
typename CONDITIONAL::FactorType::shared_ptr BayesTree<CONDITIONAL>::marginalFactor(Index key) const { typename CONDITIONAL::FactorType::shared_ptr BayesTree<CONDITIONAL>::marginalFactor(
Index key, Eliminate function) const {
// get clique containing key // get clique containing key
sharedClique clique = (*this)[key]; sharedClique clique = (*this)[key];
// calculate or retrieve its marginal // calculate or retrieve its marginal
FactorGraph<typename CONDITIONAL::FactorType> cliqueMarginal = clique->marginal(root_); FactorGraph<FactorType> cliqueMarginal = clique->marginal(root_,function);
return GenericSequentialSolver<typename CONDITIONAL::FactorType>(cliqueMarginal).marginalFactor(key); return GenericSequentialSolver<FactorType> (cliqueMarginal).marginalFactor(
key, function);
} }
/* ************************************************************************* */ /* ************************************************************************* */
template<class CONDITIONAL> template<class CONDITIONAL>
typename BayesNet<CONDITIONAL>::shared_ptr BayesTree<CONDITIONAL>::marginalBayesNet(Index key) const { typename BayesNet<CONDITIONAL>::shared_ptr BayesTree<CONDITIONAL>::marginalBayesNet(
Index key, Eliminate function) const {
// calculate marginal as a factor graph // calculate marginal as a factor graph
FactorGraph<typename CONDITIONAL::FactorType> fg; FactorGraph<FactorType> fg;
fg.push_back(this->marginalFactor(key)); fg.push_back(this->marginalFactor(key,function));
// eliminate factor graph marginal to a Bayes net // eliminate factor graph marginal to a Bayes net
return GenericSequentialSolver<typename CONDITIONAL::FactorType>(fg).eliminate(); return GenericSequentialSolver<FactorType>(fg).eliminate(function);
} }
/* ************************************************************************* */ /* ************************************************************************* */
// Find two cliques, their joint, then marginalizes // Find two cliques, their joint, then marginalizes
/* ************************************************************************* */ /* ************************************************************************* */
template<class CONDITIONAL> template<class CONDITIONAL>
typename FactorGraph<typename CONDITIONAL::FactorType>::shared_ptr typename FactorGraph<typename CONDITIONAL::FactorType>::shared_ptr BayesTree<
BayesTree<CONDITIONAL>::joint(Index key1, Index key2) const { CONDITIONAL>::joint(Index key1, Index key2, Eliminate function) const {
// get clique C1 and C2 // get clique C1 and C2
sharedClique C1 = (*this)[key1], C2 = (*this)[key2]; sharedClique C1 = (*this)[key1], C2 = (*this)[key2];
// calculate joint // calculate joint
FactorGraph<typename CONDITIONAL::FactorType> p_C1C2(C1->joint(C2, root_)); FactorGraph<FactorType> p_C1C2(C1->joint(C2, root_, function));
// eliminate remaining factor graph to get requested joint // eliminate remaining factor graph to get requested joint
vector<Index> key12(2); key12[0] = key1; key12[1] = key2; vector<Index> key12(2); key12[0] = key1; key12[1] = key2;
return GenericSequentialSolver<typename CONDITIONAL::FactorType>(p_C1C2).jointFactorGraph(key12); GenericSequentialSolver<FactorType> solver(p_C1C2);
return solver.jointFactorGraph(key12,function);
} }
/* ************************************************************************* */ /* ************************************************************************* */
template<class CONDITIONAL> template<class CONDITIONAL>
typename BayesNet<CONDITIONAL>::shared_ptr BayesTree<CONDITIONAL>::jointBayesNet(Index key1, Index key2) const { typename BayesNet<CONDITIONAL>::shared_ptr BayesTree<CONDITIONAL>::jointBayesNet(
Index key1, Index key2, Eliminate function) const {
// eliminate factor graph marginal to a Bayes net // eliminate factor graph marginal to a Bayes net
return GenericSequentialSolver<typename CONDITIONAL::FactorType>(*this->joint(key1, key2)).eliminate(); return GenericSequentialSolver<FactorType> (
*this->joint(key1, key2, function)).eliminate(function);
} }
/* ************************************************************************* */ /* ************************************************************************* */

View File

@ -46,6 +46,8 @@ namespace gtsam {
typedef boost::shared_ptr<BayesTree<CONDITIONAL> > shared_ptr; typedef boost::shared_ptr<BayesTree<CONDITIONAL> > shared_ptr;
typedef boost::shared_ptr<CONDITIONAL> sharedConditional; typedef boost::shared_ptr<CONDITIONAL> sharedConditional;
typedef boost::shared_ptr<BayesNet<CONDITIONAL> > sharedBayesNet; typedef boost::shared_ptr<BayesNet<CONDITIONAL> > sharedBayesNet;
typedef typename CONDITIONAL::FactorType FactorType;
typedef typename FactorGraph<FactorType>::Eliminate Eliminate;
/** /**
* A Clique in the tree is an incomplete Bayes net: the variables * A Clique in the tree is an incomplete Bayes net: the variables
@ -63,7 +65,7 @@ namespace gtsam {
weak_ptr parent_; weak_ptr parent_;
std::list<shared_ptr> children_; std::list<shared_ptr> children_;
std::list<Index> separator_; /** separator keys */ std::list<Index> separator_; /** separator keys */
typename CONDITIONAL::FactorType::shared_ptr cachedFactor_; typename FactorType::shared_ptr cachedFactor_;
friend class BayesTree<CONDITIONAL>; friend class BayesTree<CONDITIONAL>;
@ -96,7 +98,7 @@ namespace gtsam {
size_t treeSize() const; size_t treeSize() const;
/** Access the cached factor (this is a hack) */ /** Access the cached factor (this is a hack) */
typename CONDITIONAL::FactorType::shared_ptr& cachedFactor() { return cachedFactor_; } typename FactorType::shared_ptr& cachedFactor() { return cachedFactor_; }
/** print this node and entire subtree below it */ /** print this node and entire subtree below it */
void printTree(const std::string& indent="") const; void printTree(const std::string& indent="") const;
@ -113,13 +115,13 @@ namespace gtsam {
/** return the conditional P(S|Root) on the separator given the root */ /** return the conditional P(S|Root) on the separator given the root */
// TODO: create a cached version // TODO: create a cached version
BayesNet<CONDITIONAL> shortcut(shared_ptr root); BayesNet<CONDITIONAL> shortcut(shared_ptr root, Eliminate function);
/** return the marginal P(C) of the clique */ /** return the marginal P(C) of the clique */
FactorGraph<typename CONDITIONAL::FactorType> marginal(shared_ptr root); FactorGraph<FactorType> marginal(shared_ptr root, Eliminate function);
/** return the joint P(C1,C2), where C1==this. TODO: not a method? */ /** return the joint P(C1,C2), where C1==this. TODO: not a method? */
FactorGraph<typename CONDITIONAL::FactorType> joint(shared_ptr C2, shared_ptr root); FactorGraph<FactorType> joint(shared_ptr C2, shared_ptr root, Eliminate function);
}; // \struct Clique }; // \struct Clique
@ -262,20 +264,24 @@ namespace gtsam {
CliqueData getCliqueData() const; CliqueData getCliqueData() const;
/** return marginal on any variable */ /** return marginal on any variable */
typename CONDITIONAL::FactorType::shared_ptr marginalFactor(Index key) const; typename CONDITIONAL::FactorType::shared_ptr marginalFactor(Index key,
Eliminate function) const;
/** /**
* return marginal on any variable, as a Bayes Net * return marginal on any variable, as a Bayes Net
* NOTE: this function calls marginal, and then eliminates it into a Bayes Net * NOTE: this function calls marginal, and then eliminates it into a Bayes Net
* This is more expensive than the above function * This is more expensive than the above function
*/ */
typename BayesNet<CONDITIONAL>::shared_ptr marginalBayesNet(Index key) const; typename BayesNet<CONDITIONAL>::shared_ptr marginalBayesNet(Index key,
Eliminate function) const;
/** return joint on two variables */ /** return joint on two variables */
typename FactorGraph<typename CONDITIONAL::FactorType>::shared_ptr joint(Index key1, Index key2) const; typename FactorGraph<FactorType>::shared_ptr joint(Index key1, Index key2,
Eliminate function) const;
/** return joint on two variables as a BayesNet */ /** return joint on two variables as a BayesNet */
typename BayesNet<CONDITIONAL>::shared_ptr jointBayesNet(Index key1, Index key2) const; typename BayesNet<CONDITIONAL>::shared_ptr jointBayesNet(Index key1,
Index key2, Eliminate function) const;
/** /**
* Read only with side effects * Read only with side effects

View File

@ -24,10 +24,8 @@
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/range/iterator_range.hpp> #include <boost/range/iterator_range.hpp>
#include <boost/serialization/nvp.hpp> #include <boost/serialization/nvp.hpp>
#include <gtsam/base/types.h>
#include <gtsam/base/Testable.h> #include <gtsam/base/Testable.h>
#include <gtsam/inference/Factor.h> #include <gtsam/inference/Factor.h>
#include <gtsam/inference/Permutation.h>
namespace gtsam { namespace gtsam {
@ -168,18 +166,6 @@ public:
/** print */ /** print */
void print(const std::string& s = "Conditional") const; void print(const std::string& s = "Conditional") const;
/** Permute the variables when only separator variables need to be permuted.
* Returns true if any reordered variables appeared in the separator and
* false if not.
*/
bool permuteSeparatorWithInverse(const Permutation& inversePermutation);
/**
* Permutes the Conditional, but for efficiency requires the permutation
* to already be inverted.
*/
void permuteWithInverse(const Permutation& inversePermutation);
private: private:
/** Serialization function */ /** Serialization function */
friend class boost::serialization::access; friend class boost::serialization::access;
@ -200,37 +186,4 @@ void Conditional<KEY>::print(const std::string& s) const {
std::cout << ")" << std::endl; std::cout << ")" << std::endl;
} }
/* ************************************************************************* */ } // gtsam
template<typename KEY>
bool Conditional<KEY>::permuteSeparatorWithInverse(const Permutation& inversePermutation) {
#ifndef NDEBUG
BOOST_FOREACH(Key key, frontals()) { assert(key == inversePermutation[key]); }
#endif
bool parentChanged = false;
BOOST_FOREACH(Key& parent, parents()) {
Key newParent = inversePermutation[parent];
if(parent != newParent) {
parentChanged = true;
parent = newParent;
}
}
assertInvariants();
return parentChanged;
}
/* ************************************************************************* */
template<typename KEY>
void Conditional<KEY>::permuteWithInverse(const Permutation& inversePermutation) {
// The permutation may not move the separators into the frontals
#ifndef NDEBUG
BOOST_FOREACH(const Key frontal, this->frontals()) {
BOOST_FOREACH(const Key separator, this->parents()) {
assert(inversePermutation[frontal] < inversePermutation[separator]);
}
}
#endif
FactorType::permuteWithInverse(inversePermutation);
assertInvariants();
}
}

View File

@ -27,8 +27,8 @@ namespace gtsam {
/* ************************************************************************* */ /* ************************************************************************* */
template<class FACTOR> template<class FACTOR>
typename EliminationTree<FACTOR>::sharedFactor typename EliminationTree<FACTOR>::sharedFactor EliminationTree<FACTOR>::eliminate_(
EliminationTree<FACTOR>::eliminate_(Conditionals& conditionals) const { Eliminate function, Conditionals& conditionals) const {
static const bool debug = false; static const bool debug = false;
@ -43,11 +43,11 @@ EliminationTree<FACTOR>::eliminate_(Conditionals& conditionals) const {
// for all subtrees, eliminate into Bayes net and a separator factor, added to [factors] // for all subtrees, eliminate into Bayes net and a separator factor, added to [factors]
BOOST_FOREACH(const shared_ptr& child, subTrees_) { BOOST_FOREACH(const shared_ptr& child, subTrees_) {
factors.push_back(child->eliminate_(conditionals)); } factors.push_back(child->eliminate_(function, conditionals)); }
// Combine all factors (from this node and from subtrees) into a joint factor // Combine all factors (from this node and from subtrees) into a joint factor
pair<typename BayesNet::shared_ptr, typename FACTOR::shared_ptr> eliminated( pair<typename BayesNet::shared_ptr, typename FACTOR::shared_ptr>
FACTOR::CombineAndEliminate(factors, 1)); eliminated(function(factors, 1));
conditionals[this->key_] = eliminated.first->front(); conditionals[this->key_] = eliminated.first->front();
if(debug) cout << "Eliminated " << this->key_ << " to get:\n"; if(debug) cout << "Eliminated " << this->key_ << " to get:\n";
@ -57,39 +57,6 @@ EliminationTree<FACTOR>::eliminate_(Conditionals& conditionals) const {
return eliminated.second; return eliminated.second;
} }
/* ************************************************************************* */
// This is the explicit specialization for symbolic factors, i.e. IndexFactor
template<> inline FastSet<Index> EliminationTree<IndexFactor>::eliminateSymbolic_(Conditionals& conditionals) const {
static const bool debug = false;
if(debug) cout << "ETree: eliminating " << this->key_ << endl;
FastSet<Index> variables;
BOOST_FOREACH(const sharedFactor& factor, factors_) {
variables.insert(factor->begin(), factor->end());
}
BOOST_FOREACH(const shared_ptr& child, subTrees_) {
sharedFactor factor(child->eliminate_(conditionals));
variables.insert(factor->begin(), factor->end());
}
conditionals[this->key_] = IndexConditional::FromRange(variables.begin(), variables.end(), 1);
variables.erase(variables.begin());
if(debug) cout << "Eliminated " << this->key_ << " to get:\n";
if(debug) conditionals[this->key_]->print("Conditional: ");
return variables;
}
/* ************************************************************************* */
// This non-specialized version cannot be called.
template<class FACTOR> FastSet<Index>
EliminationTree<FACTOR>::eliminateSymbolic_(Conditionals& conditionals) const {
throw invalid_argument("symbolic eliminate should never be called from a non-IndexFactor EliminationTree");
return FastSet<Index>();
}
/* ************************************************************************* */ /* ************************************************************************* */
template<class FACTOR> template<class FACTOR>
vector<Index> EliminationTree<FACTOR>::ComputeParents(const VariableIndex& structure) { vector<Index> EliminationTree<FACTOR>::ComputeParents(const VariableIndex& structure) {
@ -126,8 +93,9 @@ vector<Index> EliminationTree<FACTOR>::ComputeParents(const VariableIndex& struc
/* ************************************************************************* */ /* ************************************************************************* */
template<class FACTOR> template<class FACTOR>
template<class DERIVEDFACTOR> template<class DERIVEDFACTOR>
typename EliminationTree<FACTOR>::shared_ptr typename EliminationTree<FACTOR>::shared_ptr EliminationTree<FACTOR>::Create(
EliminationTree<FACTOR>::Create(const FactorGraph<DERIVEDFACTOR>& factorGraph, const VariableIndex& structure) { const FactorGraph<DERIVEDFACTOR>& factorGraph,
const VariableIndex& structure) {
static const bool debug = false; static const bool debug = false;
@ -218,12 +186,12 @@ bool EliminationTree<FACTORGRAPH>::equals(const EliminationTree<FACTORGRAPH>& ex
/* ************************************************************************* */ /* ************************************************************************* */
template<class FACTOR> template<class FACTOR>
typename EliminationTree<FACTOR>::BayesNet::shared_ptr typename EliminationTree<FACTOR>::BayesNet::shared_ptr
EliminationTree<FACTOR>::eliminate() const { EliminationTree<FACTOR>::eliminate(Eliminate function) const {
// call recursive routine // call recursive routine
tic(1, "ET recursive eliminate"); tic(1, "ET recursive eliminate");
Conditionals conditionals(this->key_ + 1); Conditionals conditionals(this->key_ + 1);
(void)eliminate_(conditionals); (void)eliminate_(function, conditionals);
toc(1, "ET recursive eliminate"); toc(1, "ET recursive eliminate");
// Add conditionals to BayesNet // Add conditionals to BayesNet
@ -238,28 +206,4 @@ EliminationTree<FACTOR>::eliminate() const {
return bayesNet; return bayesNet;
} }
/* ************************************************************************* */
// Specialization for symbolic elimination that calls the optimized eliminateSymbolic_
template<>
inline EliminationTree<IndexFactor>::BayesNet::shared_ptr
EliminationTree<IndexFactor>::eliminate() const {
// call recursive routine
tic(1, "ET recursive eliminate");
Conditionals conditionals(this->key_ + 1);
(void)eliminateSymbolic_(conditionals);
toc(1, "ET recursive eliminate");
// Add conditionals to BayesNet
tic(2, "assemble BayesNet");
BayesNet::shared_ptr bayesNet(new BayesNet);
BOOST_FOREACH(const BayesNet::sharedConditional& conditional, conditionals) {
if(conditional)
bayesNet->push_back(conditional);
}
toc(2, "assemble BayesNet");
return bayesNet;
}
} }

View File

@ -42,6 +42,9 @@ public:
typedef boost::shared_ptr<EliminationTree<FACTOR> > shared_ptr; typedef boost::shared_ptr<EliminationTree<FACTOR> > shared_ptr;
typedef gtsam::BayesNet<typename FACTOR::ConditionalType> BayesNet; typedef gtsam::BayesNet<typename FACTOR::ConditionalType> BayesNet;
/** typedef for an eliminate subroutine */
typedef typename FactorGraph<FACTOR>::Eliminate Eliminate;
private: private:
typedef FastList<sharedFactor> Factors; typedef FastList<sharedFactor> Factors;
@ -70,13 +73,7 @@ private:
/** /**
* Recursive routine that eliminates the factors arranged in an elimination tree * Recursive routine that eliminates the factors arranged in an elimination tree
*/ */
sharedFactor eliminate_(Conditionals& conditionals) const; sharedFactor eliminate_(Eliminate function, Conditionals& conditionals) const;
/**
* Special optimized eliminate for symbolic factors. Will not compile if
* called in a non-IndexFactor EliminationTree.
*/
FastSet<Index> eliminateSymbolic_(Conditionals& conditionals) const;
// Allow access to constructor and add methods for testing purposes // Allow access to constructor and add methods for testing purposes
friend class ::EliminationTreeTester; friend class ::EliminationTreeTester;
@ -101,7 +98,7 @@ public:
bool equals(const EliminationTree& other, double tol = 1e-9) const; bool equals(const EliminationTree& other, double tol = 1e-9) const;
/** Eliminate the factors to a Bayes Net */ /** Eliminate the factors to a Bayes Net */
typename BayesNet::shared_ptr eliminate() const; typename BayesNet::shared_ptr eliminate(Eliminate function) const;
}; };
} }

View File

@ -18,99 +18,81 @@
#pragma once #pragma once
#include <gtsam/inference/Factor.h> #include <iostream>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/make_shared.hpp> #include <boost/make_shared.hpp>
#include <boost/iterator/transform_iterator.hpp> #include <gtsam/inference/Factor.h>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/lambda.hpp>
#include <iostream>
namespace gtsam { namespace gtsam {
/* ************************************************************************* */ /* ************************************************************************* */
template<typename KEY> template<typename KEY>
Factor<KEY>::Factor(const Factor<KEY>& f) : keys_(f.keys_) { assertInvariants(); } Factor<KEY>::Factor(const Factor<KEY>& f) :
keys_(f.keys_) {
assertInvariants();
}
/* ************************************************************************* */ /* ************************************************************************* */
template<typename KEY> template<typename KEY>
Factor<KEY>::Factor(const ConditionalType& c) : keys_(c.keys()) { assertInvariants(); } Factor<KEY>::Factor(const ConditionalType& c) :
keys_(c.keys()) {
assertInvariants();
}
/* ************************************************************************* */ /* ************************************************************************* */
template<typename KEY> template<typename KEY>
void Factor<KEY>::assertInvariants() const { void Factor<KEY>::assertInvariants() const {
#ifndef NDEBUG #ifndef NDEBUG
// Check that keys are all unique // Check that keys are all unique
std::multiset<Key> nonunique(keys_.begin(), keys_.end()); std::multiset<Key> nonunique(keys_.begin(), keys_.end());
std::set<Key> unique(keys_.begin(), keys_.end()); std::set<Key> unique(keys_.begin(), keys_.end());
assert(nonunique.size() == unique.size() && std::equal(nonunique.begin(), nonunique.end(), unique.begin())); assert(nonunique.size() == unique.size() && std::equal(nonunique.begin(), nonunique.end(), unique.begin()));
#endif #endif
} }
/* ************************************************************************* */ /* ************************************************************************* */
template<typename KEY> template<typename KEY>
void Factor<KEY>::print(const std::string& s) const { void Factor<KEY>::print(const std::string& s) const {
std::cout << s << " "; std::cout << s << " ";
BOOST_FOREACH(KEY key, keys_) std::cout << " " << key; BOOST_FOREACH(KEY key, keys_)
std::cout << std::endl; std::cout << " " << key;
} std::cout << std::endl;
}
/* ************************************************************************* */ /* ************************************************************************* */
template<typename KEY> template<typename KEY>
bool Factor<KEY>::equals(const This& other, double tol) const { bool Factor<KEY>::equals(const This& other, double tol) const {
return keys_ == other.keys_; return keys_ == other.keys_;
} }
/* ************************************************************************* */ /* ************************************************************************* */
template<typename KEY> #ifdef TRACK_ELIMINATE
template<class DERIVED> template<typename KEY>
typename DERIVED::shared_ptr Factor<KEY>::Combine(const FactorGraph<DERIVED>& factors, const FastMap<Key, std::vector<Key> >& variableSlots) { template<class COND>
typedef const FastMap<Key, std::vector<Key> > VariableSlots; typename COND::shared_ptr Factor<KEY>::eliminateFirst() {
typedef typeof(boost::lambda::bind(&VariableSlots::value_type::first, boost::lambda::_1)) FirstGetter; assert(!keys_.empty());
typedef boost::transform_iterator< assertInvariants();
FirstGetter, typename VariableSlots::const_iterator, KEY eliminated = keys_.front();
KEY, KEY> IndexIterator; keys_.erase(keys_.begin());
FirstGetter firstGetter(boost::lambda::bind(&VariableSlots::value_type::first, boost::lambda::_1)); assertInvariants();
IndexIterator keysBegin(variableSlots.begin(), firstGetter); return typename COND::shared_ptr(new COND(eliminated, keys_));
IndexIterator keysEnd(variableSlots.end(), firstGetter); }
return typename DERIVED::shared_ptr(new DERIVED(keysBegin, keysEnd));
}
/* ************************************************************************* */ /* ************************************************************************* */
template<typename KEY> template<typename KEY>
template<class CONDITIONAL> template<class COND>
typename CONDITIONAL::shared_ptr Factor<KEY>::eliminateFirst() { typename BayesNet<COND>::shared_ptr Factor<KEY>::eliminate(size_t nrFrontals) {
assert(!keys_.empty()); assert(keys_.size() >= nrFrontals);
assertInvariants(); assertInvariants();
KEY eliminated = keys_.front(); typename BayesNet<COND>::shared_ptr fragment(new BayesNet<COND> ());
keys_.erase(keys_.begin()); const_iterator it = this->begin();
assertInvariants(); for (KEY n = 0; n < nrFrontals; ++n, ++it)
return typename CONDITIONAL::shared_ptr(new CONDITIONAL(eliminated, keys_)); fragment->push_back(COND::FromRange(it, const_iterator(this->end()), 1));
} if (nrFrontals > 0) keys_.assign(fragment->back()->beginParents(),
fragment->back()->endParents());
/* ************************************************************************* */ assertInvariants();
template<typename KEY> return fragment;
template<class CONDITIONAL> }
typename BayesNet<CONDITIONAL>::shared_ptr Factor<KEY>::eliminate(size_t nrFrontals) { #endif
assert(keys_.size() >= nrFrontals);
assertInvariants();
typename BayesNet<CONDITIONAL>::shared_ptr fragment(new BayesNet<CONDITIONAL>());
const_iterator nextFrontal = this->begin();
for(KEY n = 0; n < nrFrontals; ++n, ++nextFrontal)
fragment->push_back(CONDITIONAL::FromRange(
nextFrontal, const_iterator(this->end()), 1));
if(nrFrontals > 0)
keys_.assign(fragment->back()->beginParents(), fragment->back()->endParents());
assertInvariants();
return fragment;
}
/* ************************************************************************* */
template<typename KEY>
void Factor<KEY>::permuteWithInverse(const Permutation& inversePermutation) {
BOOST_FOREACH(KEY& key, keys_) { key = inversePermutation[key]; }
assertInvariants();
}
} }

View File

@ -21,15 +21,14 @@
#pragma once #pragma once
#include <vector>
#include <map> #include <map>
#include <set>
#include <vector>
#include <boost/utility.hpp> // for noncopyable #include <boost/utility.hpp> // for noncopyable
#include <boost/serialization/nvp.hpp> #include <boost/serialization/nvp.hpp>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <gtsam/base/types.h>
#include <gtsam/base/Testable.h> #include <gtsam/base/Testable.h>
#include <gtsam/base/FastMap.h> #include <gtsam/base/FastMap.h>
#include <gtsam/inference/inference.h>
namespace gtsam { namespace gtsam {
@ -117,10 +116,7 @@ public:
keys_.push_back(key); keys_.push_back(key);
assertInvariants(); } assertInvariants(); }
/** Create a combined joint factor (new style for EliminationTree). */ #ifdef TRACK_ELIMINATE
template<class DERIVED>
static typename DERIVED::shared_ptr Combine(const FactorGraph<DERIVED>& factors, const FastMap<Key, std::vector<Key> >& variableSlots);
/** /**
* eliminate the first variable involved in this factor * eliminate the first variable involved in this factor
* @return a conditional on the eliminated variable * @return a conditional on the eliminated variable
@ -133,12 +129,7 @@ public:
*/ */
template<class CONDITIONAL> template<class CONDITIONAL>
typename BayesNet<CONDITIONAL>::shared_ptr eliminate(size_t nrFrontals = 1); typename BayesNet<CONDITIONAL>::shared_ptr eliminate(size_t nrFrontals = 1);
#endif
/**
* Permutes the factor, but for efficiency requires the permutation
* to already be inverted.
*/
void permuteWithInverse(const Permutation& inversePermutation);
/** iterators */ /** iterators */
const_iterator begin() const { return keys_.begin(); } const_iterator begin() const { return keys_.begin(); }

View File

@ -30,7 +30,10 @@
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/tuple/tuple.hpp> #include <boost/tuple/tuple.hpp>
#include <boost/format.hpp> #include <boost/format.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/graph/prim_minimum_spanning_tree.hpp> #include <boost/graph/prim_minimum_spanning_tree.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <gtsam/inference/FactorGraph.h> #include <gtsam/inference/FactorGraph.h>
#include <gtsam/inference/graph-inl.h> #include <gtsam/inference/graph-inl.h>
@ -112,5 +115,21 @@ namespace gtsam {
return fg; return fg;
} }
/* ************************************************************************* */
template<class DERIVED, class KEY>
typename DERIVED::shared_ptr Combine(const FactorGraph<DERIVED>& factors,
const FastMap<KEY, std::vector<KEY> >& variableSlots) {
typedef const FastMap<KEY, std::vector<KEY> > VariableSlots;
typedef typeof(boost::lambda::bind(&VariableSlots::value_type::first, boost::lambda::_1))
FirstGetter;
typedef boost::transform_iterator<FirstGetter,
typename VariableSlots::const_iterator, KEY, KEY> IndexIterator;
FirstGetter firstGetter(boost::lambda::bind(
&VariableSlots::value_type::first, boost::lambda::_1));
IndexIterator keysBegin(variableSlots.begin(), firstGetter);
IndexIterator keysEnd(variableSlots.end(), firstGetter);
return typename DERIVED::shared_ptr(new DERIVED(keysBegin, keysEnd));
}
/* ************************************************************************* */ /* ************************************************************************* */
} // namespace gtsam } // namespace gtsam

View File

@ -24,8 +24,10 @@
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/serialization/nvp.hpp> #include <boost/serialization/nvp.hpp>
#include <boost/function.hpp>
#include <gtsam/base/types.h> #include <gtsam/base/types.h>
#include <gtsam/base/FastMap.h>
#include <gtsam/base/Testable.h> #include <gtsam/base/Testable.h>
#include <gtsam/inference/BayesNet.h> #include <gtsam/inference/BayesNet.h>
#include <gtsam/inference/graph.h> #include <gtsam/inference/graph.h>
@ -47,6 +49,14 @@ namespace gtsam {
typedef typename std::vector<sharedFactor>::iterator iterator; typedef typename std::vector<sharedFactor>::iterator iterator;
typedef typename std::vector<sharedFactor>::const_iterator const_iterator; typedef typename std::vector<sharedFactor>::const_iterator const_iterator;
/** typedef for elimination result */
typedef std::pair<
typename BayesNet<typename FACTOR::ConditionalType>::shared_ptr,
typename FACTOR::shared_ptr> EliminationResult;
/** typedef for an eliminate subroutine */
typedef boost::function<EliminationResult(const FactorGraph<FACTOR>&, size_t)> Eliminate;
protected: protected:
/** Collection of factors */ /** Collection of factors */
@ -176,6 +186,11 @@ namespace gtsam {
} }
}; // FactorGraph }; // FactorGraph
/** Create a combined joint factor (new style for EliminationTree). */
template<class DERIVED, class KEY>
typename DERIVED::shared_ptr Combine(const FactorGraph<DERIVED>& factors,
const FastMap<KEY, std::vector<KEY> >& variableSlots);
/** /**
* static function that combines two factor graphs * static function that combines two factor graphs
* @param const &fg1 Linear factor graph * @param const &fg1 Linear factor graph

View File

@ -48,34 +48,37 @@ void GenericMultifrontalSolver<FACTOR, JUNCTIONTREE>::replaceFactors(const typen
/* ************************************************************************* */ /* ************************************************************************* */
template<class FACTOR, class JUNCTIONTREE> template<class FACTOR, class JUNCTIONTREE>
typename JUNCTIONTREE::BayesTree::shared_ptr typename JUNCTIONTREE::BayesTree::shared_ptr GenericMultifrontalSolver<
GenericMultifrontalSolver<FACTOR, JUNCTIONTREE>::eliminate() const { FACTOR, JUNCTIONTREE>::eliminate(
typename JUNCTIONTREE::BayesTree::shared_ptr bayesTree(new typename JUNCTIONTREE::BayesTree); typename FactorGraph<FACTOR>::Eliminate function) const {
bayesTree->insert(junctionTree_->eliminate()); typename JUNCTIONTREE::BayesTree::shared_ptr bayesTree(
return bayesTree; new typename JUNCTIONTREE::BayesTree);
bayesTree->insert(junctionTree_->eliminate(function));
return bayesTree;
} }
/* ************************************************************************* */ /* ************************************************************************* */
template<class FACTOR, class JUNCTIONTREE> template<class FACTOR, class JUNCTIONTREE>
typename FactorGraph<FACTOR>::shared_ptr typename FactorGraph<FACTOR>::shared_ptr GenericMultifrontalSolver<FACTOR,
GenericMultifrontalSolver<FACTOR, JUNCTIONTREE>::jointFactorGraph(const std::vector<Index>& js) const { JUNCTIONTREE>::jointFactorGraph(const std::vector<Index>& js,
Eliminate function) const {
// We currently have code written only for computing the // We currently have code written only for computing the
if(js.size() != 2) if (js.size() != 2) throw domain_error(
throw domain_error( "*MultifrontalSolver::joint(js) currently can only compute joint marginals\n"
"*MultifrontalSolver::joint(js) currently can only compute joint marginals\n" "for exactly two variables. You can call marginal to compute the\n"
"for exactly two variables. You can call marginal to compute the\n" "marginal for one variable. *SequentialSolver::joint(js) can compute the\n"
"marginal for one variable. *SequentialSolver::joint(js) can compute the\n" "joint marginal over any number of variables, so use that if necessary.\n");
"joint marginal over any number of variables, so use that if necessary.\n");
return eliminate()->joint(js[0], js[1]); return eliminate(function)->joint(js[0], js[1], function);
} }
/* ************************************************************************* */ /* ************************************************************************* */
template<class FACTOR, class JUNCTIONTREE> template<class FACTOR, class JUNCTIONTREE>
typename FACTOR::shared_ptr GenericMultifrontalSolver<FACTOR, JUNCTIONTREE>::marginalFactor(Index j) const { typename FACTOR::shared_ptr GenericMultifrontalSolver<FACTOR, JUNCTIONTREE>::marginalFactor(
return eliminate()->marginalFactor(j); Index j, Eliminate function) const {
return eliminate(function)->marginalFactor(j, function);
} }
} }

View File

@ -44,9 +44,11 @@ protected:
// Junction tree that performs elimination. // Junction tree that performs elimination.
typename JUNCTIONTREE::shared_ptr junctionTree_; typename JUNCTIONTREE::shared_ptr junctionTree_;
public: public:
typedef typename FactorGraph<FACTOR>::shared_ptr sharedGraph;
typedef typename FactorGraph<FACTOR>::Eliminate Eliminate;
/** /**
* Construct the solver for a factor graph. This builds the junction * Construct the solver for a factor graph. This builds the junction
* tree, which does the symbolic elimination, identifies the cliques, * tree, which does the symbolic elimination, identifies the cliques,
@ -59,33 +61,35 @@ public:
* VariableIndex. The solver will store these pointers, so this constructor * VariableIndex. The solver will store these pointers, so this constructor
* is the fastest. * is the fastest.
*/ */
GenericMultifrontalSolver(const typename FactorGraph<FACTOR>::shared_ptr& factorGraph, const VariableIndex::shared_ptr& variableIndex); GenericMultifrontalSolver(const sharedGraph& factorGraph,
const VariableIndex::shared_ptr& variableIndex);
/** /**
* Replace the factor graph with a new one having the same structure. The * Replace the factor graph with a new one having the same structure. The
* This function can be used if the numerical part of the factors changes, * This function can be used if the numerical part of the factors changes,
* such as during relinearization or adjusting of noise models. * such as during relinearization or adjusting of noise models.
*/ */
void replaceFactors(const typename FactorGraph<FACTOR>::shared_ptr& factorGraph); void replaceFactors(const sharedGraph& factorGraph);
/** /**
* Eliminate the factor graph sequentially. Uses a column elimination tree * Eliminate the factor graph sequentially. Uses a column elimination tree
* to recursively eliminate. * to recursively eliminate.
*/ */
typename JUNCTIONTREE::BayesTree::shared_ptr eliminate() const; typename JUNCTIONTREE::BayesTree::shared_ptr
eliminate(Eliminate function) const;
/** /**
* Compute the marginal joint over a set of variables, by integrating out * Compute the marginal joint over a set of variables, by integrating out
* all of the other variables. This function returns the result as a factor * all of the other variables. This function returns the result as a factor
* graph. * graph.
*/ */
typename FactorGraph<FACTOR>::shared_ptr jointFactorGraph(const std::vector<Index>& js) const; sharedGraph jointFactorGraph(const std::vector<Index>& js, Eliminate function) const;
/** /**
* Compute the marginal density over a variable, by integrating out * Compute the marginal density over a variable, by integrating out
* all of the other variables. This function returns the result as a factor. * all of the other variables. This function returns the result as a factor.
*/ */
typename FACTOR::shared_ptr marginalFactor(Index j) const; typename FACTOR::shared_ptr marginalFactor(Index j, Eliminate function) const;
}; };

View File

@ -22,6 +22,7 @@
#include <gtsam/inference/Factor-inl.h> #include <gtsam/inference/Factor-inl.h>
#include <gtsam/inference/EliminationTree-inl.h> #include <gtsam/inference/EliminationTree-inl.h>
#include <gtsam/inference/BayesNet-inl.h> #include <gtsam/inference/BayesNet-inl.h>
#include <gtsam/inference/inference.h>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
@ -48,9 +49,9 @@ namespace gtsam {
/* ************************************************************************* */ /* ************************************************************************* */
template<class FACTOR> template<class FACTOR>
void GenericSequentialSolver<FACTOR>::print(const std::string& s) const { void GenericSequentialSolver<FACTOR>::print(const std::string& s) const {
this->factors_->print(s+" factors:"); this->factors_->print(s + " factors:");
this->structure_->print(s+" structure:\n"); this->structure_->print(s + " structure:\n");
this->eliminationTree_->print(s+" etree:"); this->eliminationTree_->print(s + " etree:");
} }
/* ************************************************************************* */ /* ************************************************************************* */
@ -77,15 +78,17 @@ namespace gtsam {
/* ************************************************************************* */ /* ************************************************************************* */
template<class FACTOR> template<class FACTOR>
typename BayesNet<typename FACTOR::ConditionalType>::shared_ptr // typename BayesNet<typename FACTOR::ConditionalType>::shared_ptr //
GenericSequentialSolver<FACTOR>::eliminate() const { GenericSequentialSolver<FACTOR>::eliminate(
return eliminationTree_->eliminate(); typename EliminationTree<FACTOR>::Eliminate function) const {
return eliminationTree_->eliminate(function);
} }
/* ************************************************************************* */ /* ************************************************************************* */
template<class FACTOR> template<class FACTOR>
typename FactorGraph<FACTOR>::shared_ptr // typename FactorGraph<FACTOR>::shared_ptr //
GenericSequentialSolver<FACTOR>::jointFactorGraph( GenericSequentialSolver<FACTOR>::jointFactorGraph(
const std::vector<Index>& js) const { const std::vector<Index>& js,
typename EliminationTree<FACTOR>::Eliminate function) const {
// Compute a COLAMD permutation with the marginal variable constrained to the end. // Compute a COLAMD permutation with the marginal variable constrained to the end.
Permutation::shared_ptr permutation(Inference::PermutationCOLAMD( Permutation::shared_ptr permutation(Inference::PermutationCOLAMD(
@ -100,7 +103,7 @@ namespace gtsam {
// Eliminate all variables // Eliminate all variables
typename BayesNet<typename FACTOR::ConditionalType>::shared_ptr bayesNet( typename BayesNet<typename FACTOR::ConditionalType>::shared_ptr bayesNet(
EliminationTree<FACTOR>::Create(*factors_)->eliminate()); EliminationTree<FACTOR>::Create(*factors_)->eliminate(function));
// Undo the permuation on the original factors and on the structure. // Undo the permuation on the original factors and on the structure.
BOOST_FOREACH(const typename FACTOR::shared_ptr& factor, *factors_) BOOST_FOREACH(const typename FACTOR::shared_ptr& factor, *factors_)
@ -125,13 +128,14 @@ namespace gtsam {
/* ************************************************************************* */ /* ************************************************************************* */
template<class FACTOR> template<class FACTOR>
typename FACTOR::shared_ptr // typename FACTOR::shared_ptr //
GenericSequentialSolver<FACTOR>::marginalFactor(Index j) const { GenericSequentialSolver<FACTOR>::marginalFactor(Index j,
typename EliminationTree<FACTOR>::Eliminate function) const {
// Create a container for the one variable index // Create a container for the one variable index
vector<Index> js(1); vector<Index> js(1);
js[0] = j; js[0] = j;
// Call joint and return the only factor in the factor graph it returns // Call joint and return the only factor in the factor graph it returns
return (*this->jointFactorGraph(js))[0]; return (*this->jointFactorGraph(js, function))[0];
} }
} // namespace gtsam } // namespace gtsam

View File

@ -27,7 +27,8 @@
namespace gtsam { namespace gtsam {
template<class FACTOR> template<class FACTOR>
class GenericSequentialSolver : public Testable<GenericSequentialSolver<FACTOR> > { class GenericSequentialSolver: public Testable<
GenericSequentialSolver<FACTOR> > {
protected: protected:
@ -57,11 +58,11 @@ namespace gtsam {
const typename FactorGraph<FACTOR>::shared_ptr& factorGraph, const typename FactorGraph<FACTOR>::shared_ptr& factorGraph,
const VariableIndex::shared_ptr& variableIndex); const VariableIndex::shared_ptr& variableIndex);
/** Print to cout */ /** Print to cout */
void print(const std::string& name = "GenericSequentialSolver: ") const; void print(const std::string& name = "GenericSequentialSolver: ") const;
/** Test whether is equal to another */ /** Test whether is equal to another */
bool equals(const GenericSequentialSolver& other, double tol = 1e-9) const; bool equals(const GenericSequentialSolver& other, double tol = 1e-9) const;
/** /**
* Replace the factor graph with a new one having the same structure. The * Replace the factor graph with a new one having the same structure. The
@ -76,7 +77,7 @@ namespace gtsam {
* to recursively eliminate. * to recursively eliminate.
*/ */
typename BayesNet<typename FACTOR::ConditionalType>::shared_ptr typename BayesNet<typename FACTOR::ConditionalType>::shared_ptr
eliminate() const; eliminate(typename EliminationTree<FACTOR>::Eliminate function) const;
/** /**
* Compute the marginal joint over a set of variables, by integrating out * Compute the marginal joint over a set of variables, by integrating out
@ -84,13 +85,15 @@ namespace gtsam {
* graph. * graph.
*/ */
typename FactorGraph<FACTOR>::shared_ptr jointFactorGraph( typename FactorGraph<FACTOR>::shared_ptr jointFactorGraph(
const std::vector<Index>& js) const; const std::vector<Index>& js,
typename EliminationTree<FACTOR>::Eliminate function) const;
/** /**
* Compute the marginal Gaussian density over a variable, by integrating out * Compute the marginal Gaussian density over a variable, by integrating out
* all of the other variables. This function returns the result as a factor. * all of the other variables. This function returns the result as a factor.
*/ */
typename FACTOR::shared_ptr marginalFactor(Index j) const; typename FACTOR::shared_ptr marginalFactor(Index j,
typename EliminationTree<FACTOR>::Eliminate function) const;
}; // GenericSequentialSolver }; // GenericSequentialSolver

View File

@ -41,19 +41,20 @@ namespace gtsam {
/* ************************************************************************* */ /* ************************************************************************* */
template<class CONDITIONAL> template<class CONDITIONAL>
template<class FACTORGRAPH> template<class FG> void ISAM<CONDITIONAL>::update_internal(
void ISAM<CONDITIONAL>::update_internal(const FACTORGRAPH& newFactors, Cliques& orphans) { const FG& newFactors, Cliques& orphans, typename FG::Eliminate function) {
// Remove the contaminated part of the Bayes tree // Remove the contaminated part of the Bayes tree
BayesNet<CONDITIONAL> bn; BayesNet<CONDITIONAL> bn;
removeTop(newFactors.keys(), bn, orphans); removeTop(newFactors.keys(), bn, orphans);
FACTORGRAPH factors(bn); FG factors(bn);
// add the factors themselves // add the factors themselves
factors.push_back(newFactors); factors.push_back(newFactors);
// eliminate into a Bayes net // eliminate into a Bayes net
typename BayesNet<CONDITIONAL>::shared_ptr bayesNet = GenericSequentialSolver<typename CONDITIONAL::FactorType>(factors).eliminate(); GenericSequentialSolver<typename CONDITIONAL::FactorType> solver(factors);
typename BayesNet<CONDITIONAL>::shared_ptr bayesNet = solver.eliminate(function);
// insert conditionals back in, straight into the topless bayesTree // insert conditionals back in, straight into the topless bayesTree
typename BayesNet<CONDITIONAL>::const_reverse_iterator rit; typename BayesNet<CONDITIONAL>::const_reverse_iterator rit;
@ -61,17 +62,17 @@ namespace gtsam {
this->insert(*rit); this->insert(*rit);
// add orphans to the bottom of the new tree // add orphans to the bottom of the new tree
BOOST_FOREACH(sharedClique orphan, orphans) { BOOST_FOREACH(sharedClique orphan, orphans)
this->insert(orphan); this->insert(orphan);
}
} }
/* ************************************************************************* */
template<class CONDITIONAL> template<class CONDITIONAL>
template<class FACTORGRAPH> template<class FG>
void ISAM<CONDITIONAL>::update(const FACTORGRAPH& newFactors) { void ISAM<CONDITIONAL>::update(const FG& newFactors,
typename FG::Eliminate function) {
Cliques orphans; Cliques orphans;
this->update_internal(newFactors, orphans); this->update_internal(newFactors, orphans, function);
} }
} }

View File

@ -52,10 +52,12 @@ namespace gtsam {
/** /**
* iSAM. (update_internal provides access to list of orphans for drawing purposes) * iSAM. (update_internal provides access to list of orphans for drawing purposes)
*/ */
template<class FACTORGRAPH> template<class FG>
void update_internal(const FACTORGRAPH& newFactors, Cliques& orphans); void update_internal(const FG& newFactors, Cliques& orphans,
template<class FACTORGRAPH> typename FG::Eliminate function);
void update(const FACTORGRAPH& newFactors);
template<class FG>
void update(const FG& newFactors, typename FG::Eliminate function);
}; // ISAM }; // ISAM

View File

@ -41,4 +41,37 @@ namespace gtsam {
#endif #endif
} }
/* ************************************************************************* */
bool IndexConditional::permuteSeparatorWithInverse(const Permutation& inversePermutation) {
#ifndef NDEBUG
BOOST_FOREACH(Key key, frontals()) { assert(key == inversePermutation[key]); }
#endif
bool parentChanged = false;
BOOST_FOREACH(Key& parent, parents()) {
Key newParent = inversePermutation[parent];
if(parent != newParent) {
parentChanged = true;
parent = newParent;
}
}
assertInvariants();
return parentChanged;
}
/* ************************************************************************* */
void IndexConditional::permuteWithInverse(const Permutation& inversePermutation) {
// The permutation may not move the separators into the frontals
#ifndef NDEBUG
BOOST_FOREACH(const Key frontal, this->frontals()) {
BOOST_FOREACH(const Key separator, this->parents()) {
assert(inversePermutation[frontal] < inversePermutation[separator]);
}
}
#endif
BOOST_FOREACH(Index& key, keys_)
key = inversePermutation[key];
assertInvariants();
}
/* ************************************************************************* */
} }

View File

@ -18,8 +18,10 @@
#pragma once #pragma once
#include <gtsam/base/types.h>
#include <gtsam/inference/Conditional.h> #include <gtsam/inference/Conditional.h>
#include <gtsam/inference/IndexFactor.h> #include <gtsam/inference/IndexFactor.h>
#include <gtsam/inference/Permutation.h>
namespace gtsam { namespace gtsam {
@ -80,6 +82,18 @@ namespace gtsam {
/** Convert to a factor */ /** Convert to a factor */
IndexFactor::shared_ptr toFactor() const { return IndexFactor::shared_ptr(new IndexFactor(*this)); } IndexFactor::shared_ptr toFactor() const { return IndexFactor::shared_ptr(new IndexFactor(*this)); }
/** Permute the variables when only separator variables need to be permuted.
* Returns true if any reordered variables appeared in the separator and
* false if not.
*/
bool permuteSeparatorWithInverse(const Permutation& inversePermutation);
/**
* Permutes the Conditional, but for efficiency requires the permutation
* to already be inverted.
*/
void permuteWithInverse(const Permutation& inversePermutation);
}; };
} }

View File

@ -16,76 +16,57 @@
* @created Oct 17, 2010 * @created Oct 17, 2010
*/ */
#include <gtsam/base/FastSet.h>
#include <gtsam/inference/Factor-inl.h>
#include <gtsam/inference/IndexFactor.h> #include <gtsam/inference/IndexFactor.h>
#include <gtsam/inference/Factor-inl.h>
#include <gtsam/inference/IndexConditional.h> #include <gtsam/inference/IndexConditional.h>
#include <gtsam/inference/VariableSlots.h>
using namespace std; using namespace std;
namespace gtsam { namespace gtsam {
template class Factor<Index>; template class Factor<Index> ;
/* ************************************************************************* */ /* ************************************************************************* */
void IndexFactor::assertInvariants() const { void IndexFactor::assertInvariants() const {
Base::assertInvariants(); Base::assertInvariants();
#ifndef NDEBUG //#ifndef NDEBUG
#ifndef GTSAM_NO_ENFORCE_ORDERING //#ifndef GTSAM_NO_ENFORCE_ORDERING
std::set<Index> uniqueSorted(keys_.begin(), keys_.end()); // std::set<Index> uniqueSorted(keys_.begin(), keys_.end());
assert(uniqueSorted.size() == keys_.size() && std::equal(uniqueSorted.begin(), uniqueSorted.end(), keys_.begin())); // assert(uniqueSorted.size() == keys_.size() && std::equal(uniqueSorted.begin(), uniqueSorted.end(), keys_.begin()));
//#endif
//#endif
}
/* ************************************************************************* */
IndexFactor::IndexFactor(const IndexConditional& c) :
Base(c) {
assertInvariants();
}
/* ************************************************************************* */
#ifdef TRACK_ELIMINATE
boost::shared_ptr<IndexConditional> IndexFactor::eliminateFirst() {
boost::shared_ptr<IndexConditional> result(Base::eliminateFirst<
IndexConditional>());
assertInvariants();
return result;
}
/* ************************************************************************* */
boost::shared_ptr<BayesNet<IndexConditional> > IndexFactor::eliminate(
size_t nrFrontals) {
boost::shared_ptr<BayesNet<IndexConditional> > result(Base::eliminate<
IndexConditional>(nrFrontals));
assertInvariants();
return result;
}
#endif #endif
#endif
}
/* ************************************************************************* */ /* ************************************************************************* */
IndexFactor::IndexFactor(const IndexConditional& c): Base(c) { void IndexFactor::permuteWithInverse(const Permutation& inversePermutation) {
assertInvariants(); BOOST_FOREACH(Index& key, keys_)
} key = inversePermutation[key];
assertInvariants();
/* ************************************************************************* */ }
pair<BayesNet<IndexConditional>::shared_ptr, IndexFactor::shared_ptr> IndexFactor::CombineAndEliminate( /* ************************************************************************* */
const FactorGraph<This>& factors, size_t nrFrontals) { } // gtsam
FastSet<Index> variables;
BOOST_FOREACH(const shared_ptr& factor, factors) {
BOOST_FOREACH(Index var, *factor) {
variables.insert(var); } }
if(variables.size() < 1)
throw invalid_argument("IndexFactor::CombineAndEliminate called on factors with zero total variables.");
pair<BayesNet<ConditionalType>::shared_ptr, shared_ptr> result;
result.first.reset(new BayesNet<IndexConditional>());
FastSet<Index>::const_iterator var;
for(var = variables.begin(); result.first->size() < nrFrontals; ++var)
result.first->push_back(IndexConditional::FromRange(var, variables.end(), 1));
result.second.reset(new IndexFactor(var, variables.end()));
return result;
}
/* ************************************************************************* */
IndexFactor::shared_ptr IndexFactor::Combine(
const FactorGraph<This>& factors, const FastMap<Index, std::vector<Index> >& variableSlots) {
IndexFactor::shared_ptr combined(Base::Combine<This>(factors, variableSlots));
combined->assertInvariants();
return combined;
}
/* ************************************************************************* */
boost::shared_ptr<IndexConditional> IndexFactor::eliminateFirst() {
boost::shared_ptr<IndexConditional> result(Base::eliminateFirst<IndexConditional>());
assertInvariants();
return result;
}
/* ************************************************************************* */
boost::shared_ptr<BayesNet<IndexConditional> > IndexFactor::eliminate(size_t nrFrontals) {
boost::shared_ptr<BayesNet<IndexConditional> > result(Base::eliminate<IndexConditional>(nrFrontals));
assertInvariants();
return result;
}
}

View File

@ -19,93 +19,111 @@
#pragma once #pragma once
#include <gtsam/inference/Factor.h> #include <gtsam/inference/Factor.h>
#include <gtsam/inference/Permutation.h>
namespace gtsam { namespace gtsam {
// Forward declaration of IndexConditional // Forward declaration of IndexConditional
class IndexConditional; class IndexConditional;
/** /**
* IndexFactor serves two purposes. It is the base class for all linear * IndexFactor serves two purposes. It is the base class for all linear
* factors (GaussianFactor, JacobianFactor, HessianFactor), and also * factors (GaussianFactor, JacobianFactor, HessianFactor), and also
* functions as a symbolic factor with Index keys, used to do symbolic * functions as a symbolic factor with Index keys, used to do symbolic
* elimination by JunctionTree. * elimination by JunctionTree.
* *
* This class provides symbolic elimination, via the CombineAndEliminate * It derives from Factor with a key type of Index, an unsigned integer.
* function. Combine and eliminate can also be called separately, but for */
* this and derived classes calling them separately generally does extra class IndexFactor: public Factor<Index> {
* work.
*
* It derives from Factor with a key type of Index, which is an unsigned
* integer.
*/
class IndexFactor : public Factor<Index> {
protected: protected:
// Internal function for checking class invariants (sorted keys for this factor) // Internal function for checking class invariants (sorted keys for this factor)
void assertInvariants() const; void assertInvariants() const;
public: public:
typedef IndexFactor This; typedef IndexFactor This;
typedef Factor<Index> Base; typedef Factor<Index> Base;
/** Elimination produces an IndexConditional */ /** Elimination produces an IndexConditional */
typedef IndexConditional ConditionalType; typedef IndexConditional ConditionalType;
/** Overriding the shared_ptr typedef */ /** Overriding the shared_ptr typedef */
typedef boost::shared_ptr<IndexFactor> shared_ptr; typedef boost::shared_ptr<IndexFactor> shared_ptr;
/** Copy constructor */ /** Copy constructor */
IndexFactor(const This& f) : Base(f) { assertInvariants(); } IndexFactor(const This& f) :
Base(f) {
assertInvariants();
}
/** Construct from derived type */ /** Construct from derived type */
IndexFactor(const IndexConditional& c); IndexFactor(const IndexConditional& c);
/** Constructor from a collection of keys */ /** Constructor from a collection of keys */
template<class KeyIterator> IndexFactor(KeyIterator beginKey, KeyIterator endKey) : template<class KeyIterator> IndexFactor(KeyIterator beginKey,
Base(beginKey, endKey) { assertInvariants(); } KeyIterator endKey) :
Base(beginKey, endKey) {
assertInvariants();
}
/** Default constructor for I/O */ /** Default constructor for I/O */
IndexFactor() { assertInvariants(); } IndexFactor() {
assertInvariants();
}
/** Construct unary factor */ /** Construct unary factor */
IndexFactor(Index j) : Base(j) { assertInvariants(); } IndexFactor(Index j) :
Base(j) {
assertInvariants();
}
/** Construct binary factor */ /** Construct binary factor */
IndexFactor(Index j1, Index j2) : Base(j1, j2) { assertInvariants(); } IndexFactor(Index j1, Index j2) :
Base(j1, j2) {
assertInvariants();
}
/** Construct ternary factor */ /** Construct ternary factor */
IndexFactor(Index j1, Index j2, Index j3) : Base(j1, j2, j3) { assertInvariants(); } IndexFactor(Index j1, Index j2, Index j3) :
Base(j1, j2, j3) {
assertInvariants();
}
/** Construct 4-way factor */ /** Construct 4-way factor */
IndexFactor(Index j1, Index j2, Index j3, Index j4) : Base(j1, j2, j3, j4) { assertInvariants(); } IndexFactor(Index j1, Index j2, Index j3, Index j4) :
Base(j1, j2, j3, j4) {
assertInvariants();
}
/** Construct n-way factor */ /** Construct n-way factor */
IndexFactor(const std::set<Index>& js) : Base(js) { assertInvariants(); } IndexFactor(const std::set<Index>& js) :
Base(js) {
assertInvariants();
}
/** #ifdef TRACK_ELIMINATE
* Combine and eliminate several factors. /**
*/ * eliminate the first variable involved in this factor
static std::pair<BayesNet<ConditionalType>::shared_ptr, shared_ptr> CombineAndEliminate( * @return a conditional on the eliminated variable
const FactorGraph<This>& factors, size_t nrFrontals=1); */
boost::shared_ptr<ConditionalType> eliminateFirst();
/** Create a combined joint factor (new style for EliminationTree). */ /** eliminate the first nrFrontals frontal variables.*/
static shared_ptr boost::shared_ptr<BayesNet<ConditionalType> > eliminate(size_t nrFrontals =
Combine(const FactorGraph<This>& factors, const FastMap<Index, std::vector<Index> >& variableSlots); 1);
#endif
/** /**
* eliminate the first variable involved in this factor * Permutes the factor, but for efficiency requires the permutation
* @return a conditional on the eliminated variable * to already be inverted.
*/ */
boost::shared_ptr<ConditionalType> eliminateFirst(); void permuteWithInverse(const Permutation& inversePermutation);
/** virtual ~IndexFactor() {
* eliminate the first nrFrontals frontal variables. }
*/
boost::shared_ptr<BayesNet<ConditionalType> > eliminate(size_t nrFrontals = 1);
}; }; // IndexFactor
} }

View File

@ -40,10 +40,11 @@ namespace gtsam {
void JunctionTree<FG>::construct(const FG& fg, const VariableIndex& variableIndex) { void JunctionTree<FG>::construct(const FG& fg, const VariableIndex& variableIndex) {
tic(1, "JT Constructor"); tic(1, "JT Constructor");
tic(1, "JT symbolic ET"); tic(1, "JT symbolic ET");
const typename EliminationTree<IndexFactor>::shared_ptr symETree(EliminationTree<IndexFactor>::Create(fg, variableIndex)); const typename EliminationTree<IndexFactor>::shared_ptr symETree =
EliminationTree<IndexFactor>::Create(fg, variableIndex);
toc(1, "JT symbolic ET"); toc(1, "JT symbolic ET");
tic(2, "JT symbolic eliminate"); tic(2, "JT symbolic eliminate");
SymbolicBayesNet::shared_ptr sbn = symETree->eliminate(); SymbolicBayesNet::shared_ptr sbn = symETree->eliminate(&EliminateSymbolic);
toc(2, "JT symbolic eliminate"); toc(2, "JT symbolic eliminate");
tic(3, "symbolic BayesTree"); tic(3, "symbolic BayesTree");
SymbolicBayesTree sbt(*sbn); SymbolicBayesTree sbt(*sbn);
@ -148,9 +149,11 @@ namespace gtsam {
} }
/* ************************************************************************* */ /* ************************************************************************* */
template <class FG> template<class FG>
pair<typename JunctionTree<FG>::BayesTree::sharedClique, typename FG::sharedFactor> pair<typename JunctionTree<FG>::BayesTree::sharedClique,
JunctionTree<FG>::eliminateOneClique(const boost::shared_ptr<const Clique>& current, bool cache) const { typename FG::sharedFactor> JunctionTree<FG>::eliminateOneClique(
typename FG::Eliminate function,
const boost::shared_ptr<const Clique>& current, bool cache) const {
FG fg; // factor graph will be assembled from local factors and marginalized children FG fg; // factor graph will be assembled from local factors and marginalized children
fg.reserve(current->size() + current->children().size()); fg.reserve(current->size() + current->children().size());
@ -160,7 +163,7 @@ namespace gtsam {
list<typename BayesTree::sharedClique> children; list<typename BayesTree::sharedClique> children;
BOOST_FOREACH(const boost::shared_ptr<const Clique>& child, current->children()) { BOOST_FOREACH(const boost::shared_ptr<const Clique>& child, current->children()) {
pair<typename BayesTree::sharedClique, typename FG::sharedFactor> tree_factor( pair<typename BayesTree::sharedClique, typename FG::sharedFactor> tree_factor(
eliminateOneClique(child, cache)); eliminateOneClique(function, child, cache));
children.push_back(tree_factor.first); children.push_back(tree_factor.first);
fg.push_back(tree_factor.second); fg.push_back(tree_factor.second);
} }
@ -171,8 +174,10 @@ namespace gtsam {
// Now that we know which factors and variables, and where variables // Now that we know which factors and variables, and where variables
// come from and go to, create and eliminate the new joint factor. // come from and go to, create and eliminate the new joint factor.
tic(2, "CombineAndEliminate"); tic(2, "CombineAndEliminate");
pair<typename BayesNet<typename FG::FactorType::ConditionalType>::shared_ptr, typename FG::sharedFactor> eliminated( pair<
FG::FactorType::CombineAndEliminate(fg, current->frontal.size())); typename BayesNet<typename FG::FactorType::ConditionalType>::shared_ptr,
typename FG::sharedFactor> eliminated(function(fg,
current->frontal.size()));
toc(2, "CombineAndEliminate"); toc(2, "CombineAndEliminate");
assert(std::equal(eliminated.second->begin(), eliminated.second->end(), current->separator.begin())); assert(std::equal(eliminated.second->begin(), eliminated.second->end(), current->separator.begin()));
@ -193,17 +198,19 @@ namespace gtsam {
} }
/* ************************************************************************* */ /* ************************************************************************* */
template <class FG> template<class FG>
typename JunctionTree<FG>::BayesTree::sharedClique JunctionTree<FG>::eliminate(bool cache) const { typename JunctionTree<FG>::BayesTree::sharedClique JunctionTree<FG>::eliminate(
if(this->root()) { typename FG::Eliminate function, bool cache) const {
tic(2,"JT eliminate"); if (this->root()) {
pair<typename BayesTree::sharedClique, typename FG::sharedFactor> ret = this->eliminateOneClique(this->root(), cache); tic(2, "JT eliminate");
if (ret.second->size() != 0) pair<typename BayesTree::sharedClique, typename FG::sharedFactor> ret =
throw runtime_error("JuntionTree::eliminate: elimination failed because of factors left over!"); this->eliminateOneClique(function, this->root(), cache);
toc(2,"JT eliminate"); if (ret.second->size() != 0) throw runtime_error(
return ret.first; "JuntionTree::eliminate: elimination failed because of factors left over!");
} else toc(2, "JT eliminate");
return typename BayesTree::sharedClique(); return ret.first;
} } else
return typename BayesTree::sharedClique();
}
} //namespace gtsam } //namespace gtsam

View File

@ -27,6 +27,7 @@
#include <gtsam/inference/BayesTree.h> #include <gtsam/inference/BayesTree.h>
#include <gtsam/inference/ClusterTree.h> #include <gtsam/inference/ClusterTree.h>
#include <gtsam/inference/IndexConditional.h> #include <gtsam/inference/IndexConditional.h>
#include <gtsam/inference/VariableIndex.h>
namespace gtsam { namespace gtsam {
@ -64,7 +65,8 @@ namespace gtsam {
// recursive elimination function // recursive elimination function
std::pair<typename BayesTree::sharedClique, typename FG::sharedFactor> std::pair<typename BayesTree::sharedClique, typename FG::sharedFactor>
eliminateOneClique(const boost::shared_ptr<const Clique>& clique, bool cache=false) const; eliminateOneClique(typename FG::Eliminate function,
const boost::shared_ptr<const Clique>& clique, bool cache = false) const;
// internal constructor // internal constructor
void construct(const FG& fg, const VariableIndex& variableIndex); void construct(const FG& fg, const VariableIndex& variableIndex);
@ -80,7 +82,8 @@ namespace gtsam {
JunctionTree(const FG& fg, const VariableIndex& variableIndex); JunctionTree(const FG& fg, const VariableIndex& variableIndex);
// eliminate the factors in the subgraphs // eliminate the factors in the subgraphs
typename BayesTree::sharedClique eliminate(bool cache=false) const; typename BayesTree::sharedClique eliminate(typename FG::Eliminate function,
bool cache = false) const;
}; // JunctionTree }; // JunctionTree

View File

@ -16,19 +16,15 @@
* Author: Frank Dellaert * Author: Frank Dellaert
*/ */
#include <iostream>
#include <fstream>
#include <boost/format.hpp>
#include <boost/foreach.hpp>
#include <gtsam/inference/SymbolicFactorGraph.h> #include <gtsam/inference/SymbolicFactorGraph.h>
#include <gtsam/inference/FactorGraph-inl.h>
#include <gtsam/inference/BayesNet-inl.h> #include <gtsam/inference/BayesNet-inl.h>
#include <gtsam/inference/IndexFactor.h>
#include <gtsam/inference/EliminationTree-inl.h> #include <gtsam/inference/EliminationTree-inl.h>
using namespace std;
namespace gtsam { namespace gtsam {
using namespace std;
// Explicitly instantiate so we don't have to include everywhere // Explicitly instantiate so we don't have to include everywhere
template class FactorGraph<IndexFactor>; template class FactorGraph<IndexFactor>;
template class BayesNet<IndexConditional>; template class BayesNet<IndexConditional>;
@ -71,13 +67,37 @@ namespace gtsam {
return keys; return keys;
} }
/* ************************************************************************* */
IndexFactor::shared_ptr CombineSymbolic(
const FactorGraph<IndexFactor>& factors, const FastMap<Index,
std::vector<Index> >& variableSlots) {
IndexFactor::shared_ptr combined(Combine<IndexFactor, Index> (factors,
variableSlots));
// combined->assertInvariants();
return combined;
}
// /* ************************************************************************* */ /* ************************************************************************* */
// SymbolicBayesNet pair<BayesNet<IndexConditional>::shared_ptr, IndexFactor::shared_ptr> //
// SymbolicFactorGraph::eliminateFrontals(const Ordering& ordering) EliminateSymbolic(const FactorGraph<IndexFactor>& factors, size_t nrFrontals) {
// {
// return Inference::Eliminate(ordering); FastSet<Index> keys;
// } BOOST_FOREACH(const IndexFactor::shared_ptr& factor, factors)
BOOST_FOREACH(Index var, *factor)
keys.insert(var);
if (keys.size() < 1) throw invalid_argument(
"IndexFactor::CombineAndEliminate called on factors with no variables.");
pair<BayesNet<IndexConditional>::shared_ptr, IndexFactor::shared_ptr> result;
result.first.reset(new BayesNet<IndexConditional> ());
FastSet<Index>::const_iterator it;
for (it = keys.begin(); result.first->size() < nrFrontals; ++it)
result.first->push_back(IndexConditional::FromRange(it, keys.end(), 1));
result.second.reset(new IndexFactor(it, keys.end()));
return result;
}
/* ************************************************************************* */ /* ************************************************************************* */
} }

View File

@ -18,72 +18,75 @@
#pragma once #pragma once
#include <string>
#include <list>
#include <gtsam/base/types.h>
#include <gtsam/base/FastSet.h>
#include <gtsam/inference/FactorGraph.h>
#include <gtsam/inference/IndexFactor.h>
#include <gtsam/inference/BayesNet.h> #include <gtsam/inference/BayesNet.h>
#include <gtsam/inference/IndexConditional.h> #include <gtsam/inference/IndexConditional.h>
#include <gtsam/inference/EliminationTree.h> #include <gtsam/inference/EliminationTree.h>
namespace gtsam { namespace gtsam {
typedef BayesNet<IndexConditional> SymbolicBayesNet; typedef BayesNet<IndexConditional> SymbolicBayesNet;
typedef EliminationTree<IndexFactor> SymbolicEliminationTree; typedef EliminationTree<IndexFactor> SymbolicEliminationTree;
/** Symbolic IndexFactor Graph */ /** Symbolic IndexFactor Graph */
class SymbolicFactorGraph: public FactorGraph<IndexFactor> { class SymbolicFactorGraph: public FactorGraph<IndexFactor> {
public: public:
/** Construct empty factor graph */ /** Construct empty factor graph */
SymbolicFactorGraph() {} SymbolicFactorGraph() {
}
/** Construct from a BayesNet */ /** Construct from a BayesNet */
SymbolicFactorGraph(const BayesNet<IndexConditional>& bayesNet); SymbolicFactorGraph(const BayesNet<IndexConditional>& bayesNet);
/** Push back unary factor */ /** Push back unary factor */
void push_factor(Index key); void push_factor(Index key);
/** Push back binary factor */ /** Push back binary factor */
void push_factor(Index key1, Index key2); void push_factor(Index key1, Index key2);
/** Push back ternary factor */ /** Push back ternary factor */
void push_factor(Index key1, Index key2, Index key3); void push_factor(Index key1, Index key2, Index key3);
/** Push back 4-way factor */ /** Push back 4-way factor */
void push_factor(Index key1, Index key2, Index key3, Index key4); void push_factor(Index key1, Index key2, Index key3, Index key4);
/** /**
* Construct from a factor graph of any type * Construct from a factor graph of any type
*/ */
template<class FACTOR> template<class FACTOR>
SymbolicFactorGraph(const FactorGraph<FACTOR>& fg); SymbolicFactorGraph(const FactorGraph<FACTOR>& fg);
/** /**
* Return the set of variables involved in the factors (computes a set * Return the set of variables involved in the factors (computes a set
* union). * union).
*/ */
FastSet<Index> keys() const; FastSet<Index> keys() const;
};
/** /** Create a combined joint factor (new style for EliminationTree). */
* Same as eliminate in the SymbolicFactorGraph case IndexFactor::shared_ptr CombineSymbolic(
*/ const FactorGraph<IndexFactor>& factors, const FastMap<Index,
// SymbolicBayesNet eliminateFrontals(const Ordering& ordering); std::vector<Index> >& variableSlots);
};
/* Template function implementation */ /**
template<class FACTOR> * CombineAndEliminate provides symbolic elimination.
SymbolicFactorGraph::SymbolicFactorGraph(const FactorGraph<FACTOR>& fg) { * Combine and eliminate can also be called separately, but for this and
for (size_t i = 0; i < fg.size(); i++) { * derived classes calling them separately generally does extra work.
if(fg[i]) { */
IndexFactor::shared_ptr factor(new IndexFactor(*fg[i])); std::pair<BayesNet<IndexConditional>::shared_ptr, IndexFactor::shared_ptr>
push_back(factor); EliminateSymbolic(const FactorGraph<IndexFactor>&, size_t nrFrontals = 1);
} else
push_back(IndexFactor::shared_ptr()); /* Template function implementation */
} template<class FACTOR>
} SymbolicFactorGraph::SymbolicFactorGraph(const FactorGraph<FACTOR>& fg) {
for (size_t i = 0; i < fg.size(); i++) {
if (fg[i]) {
IndexFactor::shared_ptr factor(new IndexFactor(*fg[i]));
push_back(factor);
} else
push_back(IndexFactor::shared_ptr());
}
}
} // namespace gtsam } // namespace gtsam

View File

@ -89,7 +89,8 @@ TEST(EliminationTree, eliminate )
fg.push_factor(3, 4); fg.push_factor(3, 4);
// eliminate // eliminate
SymbolicBayesNet actual = *SymbolicSequentialSolver(fg).eliminate(); SymbolicBayesNet actual = *SymbolicSequentialSolver(fg).eliminate(
&EliminateSymbolic);
CHECK(assert_equal(expected,actual)); CHECK(assert_equal(expected,actual));
} }

View File

@ -82,9 +82,10 @@ TEST( JunctionTree, eliminate)
fg.push_factor(x3,x4); fg.push_factor(x3,x4);
SymbolicJunctionTree jt(fg); SymbolicJunctionTree jt(fg);
SymbolicBayesTree::sharedClique actual = jt.eliminate(); SymbolicBayesTree::sharedClique actual = jt.eliminate(&EliminateSymbolic);
BayesNet<IndexConditional> bn(*SymbolicSequentialSolver(fg).eliminate()); BayesNet<IndexConditional> bn(*SymbolicSequentialSolver(fg).eliminate(
&EliminateSymbolic));
SymbolicBayesTree expected(bn); SymbolicBayesTree expected(bn);
// cout << "BT from JT:\n"; // cout << "BT from JT:\n";

View File

@ -21,8 +21,8 @@ using namespace boost::assign;
#include <CppUnitLite/TestHarness.h> #include <CppUnitLite/TestHarness.h>
//#define GTSAM_MAGIC_KEY #include <gtsam/inference/IndexConditional.h>
#ifdef ALL
#include <gtsam/inference/SymbolicFactorGraph.h> #include <gtsam/inference/SymbolicFactorGraph.h>
using namespace std; using namespace std;
@ -100,6 +100,7 @@ TEST( SymbolicBayesNet, combine )
CHECK(assert_equal(expected,p_ABC)); CHECK(assert_equal(expected,p_ABC));
} }
#endif
/* ************************************************************************* */ /* ************************************************************************* */
int main() { int main() {

View File

@ -45,6 +45,7 @@ TEST(SymbolicFactor, constructor) {
} }
/* ************************************************************************* */ /* ************************************************************************* */
#ifdef TRACK_ELIMINATE
TEST(SymbolicFactor, eliminate) { TEST(SymbolicFactor, eliminate) {
vector<Index> keys; keys += 2, 3, 4, 6, 7, 9, 10, 11; vector<Index> keys; keys += 2, 3, 4, 6, 7, 9, 10, 11;
IndexFactor actual(keys.begin(), keys.end()); IndexFactor actual(keys.begin(), keys.end());
@ -62,9 +63,9 @@ TEST(SymbolicFactor, eliminate) {
CHECK(assert_equal(**fragmentCond++, *expected1)); CHECK(assert_equal(**fragmentCond++, *expected1));
CHECK(assert_equal(**fragmentCond++, *expected2)); CHECK(assert_equal(**fragmentCond++, *expected2));
} }
#endif
/* ************************************************************************* */ /* ************************************************************************* */
TEST(SymbolicFactor, CombineAndEliminate) { TEST(SymbolicFactor, EliminateSymbolic) {
SymbolicFactorGraph factors; SymbolicFactorGraph factors;
factors.push_factor(2,4,6); factors.push_factor(2,4,6);
factors.push_factor(1,2,5); factors.push_factor(1,2,5);
@ -88,7 +89,7 @@ TEST(SymbolicFactor, CombineAndEliminate) {
BayesNet<IndexConditional>::shared_ptr actual_bn; BayesNet<IndexConditional>::shared_ptr actual_bn;
IndexFactor::shared_ptr actual_factor; IndexFactor::shared_ptr actual_factor;
boost::tie(actual_bn, actual_factor) = IndexFactor::CombineAndEliminate(factors, 4); boost::tie(actual_bn, actual_factor) = EliminateSymbolic(factors, 4);
CHECK(assert_equal(expected_bn, *actual_bn)); CHECK(assert_equal(expected_bn, *actual_bn));
CHECK(assert_equal(expected_factor, *actual_factor)); CHECK(assert_equal(expected_factor, *actual_factor));

View File

@ -16,188 +16,16 @@
* @author Richard Roberts, Christian Potthast * @author Richard Roberts, Christian Potthast
*/ */
#include <gtsam/base/debug.h>
#include <gtsam/base/timing.h>
#include <gtsam/linear/GaussianFactor.h> #include <gtsam/linear/GaussianFactor.h>
#include <gtsam/linear/GaussianBayesNet.h> #include <gtsam/linear/GaussianConditional.h>
#include <gtsam/linear/JacobianFactor.h>
#include <gtsam/linear/HessianFactor.h>
#include <gtsam/inference/FactorGraph-inl.h>
#include <boost/shared_ptr.hpp>
#include <stdexcept>
using namespace std;
namespace gtsam { namespace gtsam {
/* ************************************************************************* */ using namespace std;
GaussianFactor::GaussianFactor(const GaussianConditional& c) : IndexFactor(c) {}
/* ************************************************************************* */ /* ************************************************************************* */
pair<GaussianBayesNet::shared_ptr, GaussianFactor::shared_ptr> GaussianFactor::CombineAndEliminate( GaussianFactor::GaussianFactor(const GaussianConditional& c) :
const FactorGraph<GaussianFactor>& factors, size_t nrFrontals, SolveMethod solveMethod) { IndexFactor(c) {
}
const bool debug = ISDEBUG("GaussianFactor::CombineAndEliminate");
// If any JacobianFactors have constrained noise models, we have to convert
// all factors to JacobianFactors. Otherwise, we can convert all factors
// to HessianFactors. This is because QR can handle constrained noise
// models but Cholesky cannot.
// Decide whether to use QR or Cholesky
bool useQR;
if(solveMethod == SOLVE_QR) {
useQR = true;
} else if(solveMethod == SOLVE_PREFER_CHOLESKY) {
// Check if any JacobianFactors have constrained noise models.
useQR = false;
BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, factors) {
JacobianFactor::shared_ptr jacobianFactor(boost::dynamic_pointer_cast<JacobianFactor>(factor));
if(jacobianFactor && jacobianFactor->get_model()->isConstrained()) {
useQR = true;
break;
}
}
}
// Convert all factors to the appropriate type and call the type-specific CombineAndEliminate.
if(useQR) {
if(debug) cout << "Using QR:";
tic(1, "convert to Jacobian");
FactorGraph<JacobianFactor> jacobianFactors;
jacobianFactors.reserve(factors.size());
BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, factors) {
if(factor) {
JacobianFactor::shared_ptr jacobianFactor(boost::dynamic_pointer_cast<JacobianFactor>(factor));
if(jacobianFactor) {
jacobianFactors.push_back(jacobianFactor);
if(debug) jacobianFactor->print("Existing JacobianFactor: ");
} else {
HessianFactor::shared_ptr hessianFactor(boost::dynamic_pointer_cast<HessianFactor>(factor));
if(!hessianFactor) throw std::invalid_argument(
"In GaussianFactor::CombineAndEliminate, factor is neither a JacobianFactor nor a HessianFactor.");
jacobianFactors.push_back(JacobianFactor::shared_ptr(new JacobianFactor(*hessianFactor)));
if(debug) {
cout << "Converted HessianFactor to JacobianFactor:\n";
hessianFactor->print("HessianFactor: ");
jacobianFactors.back()->print("JacobianFactor: ");
}
}
}
}
toc(1, "convert to Jacobian");
tic(2, "Jacobian CombineAndEliminate");
pair<GaussianBayesNet::shared_ptr, GaussianFactor::shared_ptr> ret(
JacobianFactor::CombineAndEliminate(jacobianFactors, nrFrontals));
toc(2, "Jacobian CombineAndEliminate");
return ret;
} else {
const bool checkCholesky = ISDEBUG("GaussianFactor::CombineAndEliminate Check Cholesky");
// FactorGraph<HessianFactor> hessianFactors;
// tic(1, "convert to Hessian");
// hessianFactors.reserve(factors.size());
// BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, factors) {
// if(factor) {
// HessianFactor::shared_ptr hessianFactor(boost::dynamic_pointer_cast<HessianFactor>(factor));
// if(hessianFactor)
// hessianFactors.push_back(hessianFactor);
// else {
// JacobianFactor::shared_ptr jacobianFactor(boost::dynamic_pointer_cast<JacobianFactor>(factor));
// if(!jacobianFactor) throw std::invalid_argument(
// "In GaussianFactor::CombineAndEliminate, factor is neither a JacobianFactor nor a HessianFactor.");
// HessianFactor::shared_ptr convertedHessianFactor;
// try {
// convertedHessianFactor.reset(new HessianFactor(*jacobianFactor));
// if(checkCholesky)
// if(!assert_equal(HessianFactor(*jacobianFactor), HessianFactor(JacobianFactor(*convertedHessianFactor)), 1e-3))
// throw runtime_error("Conversion between Jacobian and Hessian incorrect");
// } catch(const exception& e) {
// cout << "Exception converting to Hessian: " << e.what() << endl;
// jacobianFactor->print("jacobianFactor: ");
// convertedHessianFactor->print("convertedHessianFactor: ");
// SETDEBUG("choleskyPartial", true);
// SETDEBUG("choleskyCareful", true);
// HessianFactor(JacobianFactor(*convertedHessianFactor)).print("Jacobian->Hessian->Jacobian->Hessian: ");
// throw;
// }
// hessianFactors.push_back(convertedHessianFactor);
// }
// }
// }
// toc(1, "convert to Hessian");
pair<GaussianBayesNet::shared_ptr, GaussianFactor::shared_ptr> ret;
try {
tic(2, "Hessian CombineAndEliminate");
ret = HessianFactor::CombineAndEliminate(factors, nrFrontals);
toc(2, "Hessian CombineAndEliminate");
} catch(const exception& e) {
cout << "Exception in HessianFactor::CombineAndEliminate: " << e.what() << endl;
SETDEBUG("HessianFactor::CombineAndEliminate", true);
SETDEBUG("updateATA", true);
SETDEBUG("JacobianFactor::eliminate", true);
SETDEBUG("JacobianFactor::Combine", true);
SETDEBUG("choleskyPartial", true);
factors.print("Combining factors: ");
HessianFactor::CombineAndEliminate(factors, nrFrontals);
throw;
}
if(checkCholesky) {
pair<GaussianBayesNet::shared_ptr, GaussianFactor::shared_ptr> expected;
FactorGraph<JacobianFactor> jacobianFactors;
try {
// Compare with QR
jacobianFactors.reserve(factors.size());
BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, factors) {
if(factor) {
JacobianFactor::shared_ptr jacobianFactor(boost::dynamic_pointer_cast<JacobianFactor>(factor));
if(jacobianFactor)
jacobianFactors.push_back(jacobianFactor);
else {
HessianFactor::shared_ptr hessianFactor(boost::dynamic_pointer_cast<HessianFactor>(factor));
if(!hessianFactor) throw std::invalid_argument(
"In GaussianFactor::CombineAndEliminate, factor is neither a JacobianFactor nor a HessianFactor.");
JacobianFactor::shared_ptr convertedJacobianFactor(new JacobianFactor(*hessianFactor));
// if(!assert_equal(*hessianFactor, HessianFactor(*convertedJacobianFactor), 1e-3))
// throw runtime_error("Conversion between Jacobian and Hessian incorrect");
jacobianFactors.push_back(convertedJacobianFactor);
}
}
}
expected = JacobianFactor::CombineAndEliminate(jacobianFactors, nrFrontals);
} catch(...) {
cout << "Exception in QR" << endl;
throw;
}
HessianFactor actual_factor(*ret.second);
HessianFactor expected_factor(*expected.second);
if(!assert_equal(*expected.first, *ret.first, 100.0) || !assert_equal(expected_factor, actual_factor, 1.0)) {
cout << "Cholesky and QR do not agree" << endl;
SETDEBUG("HessianFactor::CombineAndEliminate", true);
SETDEBUG("updateATA", true);
SETDEBUG("JacobianFactor::eliminate", true);
SETDEBUG("JacobianFactor::Combine", true);
jacobianFactors.print("Jacobian Factors: ");
JacobianFactor::CombineAndEliminate(jacobianFactors, nrFrontals);
HessianFactor::CombineAndEliminate(factors, nrFrontals);
factors.print("Combining factors: ");
throw runtime_error("Cholesky and QR do not agree");
}
}
return ret;
}
}
} }

View File

@ -20,9 +20,7 @@
#pragma once #pragma once
#include <gtsam/inference/FactorGraph.h>
#include <gtsam/inference/IndexFactor.h> #include <gtsam/inference/IndexFactor.h>
#include <gtsam/linear/Errors.h>
#include <string> #include <string>
#include <utility> #include <utility>
@ -75,8 +73,6 @@ namespace gtsam {
public: public:
enum SolveMethod { SOLVE_QR, SOLVE_PREFER_CHOLESKY };
typedef GaussianConditional ConditionalType; typedef GaussianConditional ConditionalType;
typedef boost::shared_ptr<GaussianFactor> shared_ptr; typedef boost::shared_ptr<GaussianFactor> shared_ptr;
@ -96,40 +92,6 @@ namespace gtsam {
*/ */
virtual void permuteWithInverse(const Permutation& inversePermutation) = 0; virtual void permuteWithInverse(const Permutation& inversePermutation) = 0;
/**
* Combine and eliminate several factors.
*/
static std::pair<boost::shared_ptr<BayesNet<GaussianConditional> >, shared_ptr> CombineAndEliminate(
const FactorGraph<GaussianFactor>& factors, size_t nrFrontals=1, SolveMethod solveMethod=SOLVE_QR);
}; // GaussianFactor }; // GaussianFactor
/** unnormalized error */
template<class FACTOR>
double gaussianError(const FactorGraph<FACTOR>& fg, const VectorValues& x) {
double total_error = 0.;
BOOST_FOREACH(const typename FACTOR::shared_ptr& factor, fg) {
total_error += factor->error(x);
}
return total_error;
}
/** return A*x-b */
template<class FACTOR>
Errors gaussianErrors(const FactorGraph<FACTOR>& fg, const VectorValues& x) {
return *gaussianErrors_(fg, x);
}
/** shared pointer version */
template<class FACTOR>
boost::shared_ptr<Errors> gaussianErrors_(const FactorGraph<FACTOR>& fg, const VectorValues& x) {
boost::shared_ptr<Errors> e(new Errors);
BOOST_FOREACH(const typename FACTOR::shared_ptr& factor, fg) {
e->push_back(factor->error_vector(x));
}
return e;
}
} // namespace gtsam } // namespace gtsam

View File

@ -14,126 +14,482 @@
* @brief Linear Factor Graph where all factors are Gaussians * @brief Linear Factor Graph where all factors are Gaussians
* @author Kai Ni * @author Kai Ni
* @author Christian Potthast * @author Christian Potthast
* @author Richard Roberts
* @author Frank Dellaert
*/ */
#include <vector> #include <gtsam/base/debug.h>
#include <gtsam/base/timing.h>
#include <boost/foreach.hpp> #include <gtsam/inference/VariableSlots.h>
#include <boost/make_shared.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/numeric/ublas/lu.hpp>
#include <boost/numeric/ublas/io.hpp>
#include <gtsam/linear/GaussianFactorGraph.h> #include <gtsam/linear/GaussianFactorGraph.h>
#include <gtsam/inference/FactorGraph-inl.h> #include <gtsam/inference/FactorGraph-inl.h>
#include <gtsam/linear/iterative.h>
#include <gtsam/linear/HessianFactor.h>
using namespace std; using namespace std;
using namespace gtsam; using namespace gtsam;
// trick from some reading group
#define FOREACH_PAIR( KEY, VAL, COL) BOOST_FOREACH (boost::tie(KEY,VAL),COL)
namespace gtsam { namespace gtsam {
// Explicitly instantiate so we don't have to include everywhere
INSTANTIATE_FACTOR_GRAPH(GaussianFactor)
;
// Explicitly instantiate so we don't have to include everywhere /* ************************************************************************* */
INSTANTIATE_FACTOR_GRAPH(GaussianFactor); GaussianFactorGraph::GaussianFactorGraph(const GaussianBayesNet& CBN) :
FactorGraph<GaussianFactor> (CBN) {
}
/* ************************************************************************* */
GaussianFactorGraph::Keys GaussianFactorGraph::keys() const {
FastSet<Index> keys;
BOOST_FOREACH(const sharedFactor& factor, *this)
if (factor) keys.insert(factor->begin(), factor->end());
return keys;
}
/* ************************************************************************* */
void GaussianFactorGraph::permuteWithInverse(
const Permutation& inversePermutation) {
BOOST_FOREACH(const sharedFactor& factor, factors_)
{
factor->permuteWithInverse(inversePermutation);
}
}
/* ************************************************************************* */
void GaussianFactorGraph::combine(const GaussianFactorGraph &lfg) {
for (const_iterator factor = lfg.factors_.begin(); factor
!= lfg.factors_.end(); factor++) {
push_back(*factor);
}
}
/* ************************************************************************* */
GaussianFactorGraph GaussianFactorGraph::combine2(
const GaussianFactorGraph& lfg1, const GaussianFactorGraph& lfg2) {
// create new linear factor graph equal to the first one
GaussianFactorGraph fg = lfg1;
// add the second factors_ in the graph
for (const_iterator factor = lfg2.factors_.begin(); factor
!= lfg2.factors_.end(); factor++) {
fg.push_back(*factor);
}
return fg;
}
/* ************************************************************************* */
std::vector<boost::tuple<size_t, size_t, double> > GaussianFactorGraph::sparseJacobian(
const std::vector<size_t>& columnIndices) const {
std::vector<boost::tuple<size_t, size_t, double> > entries;
size_t i = 0;
BOOST_FOREACH(const sharedFactor& factor, *this) {
// Convert to JacobianFactor if necessary
JacobianFactor::shared_ptr jacobianFactor(
boost::dynamic_pointer_cast<JacobianFactor>(factor));
if (!jacobianFactor) {
HessianFactor::shared_ptr hessian(boost::dynamic_pointer_cast<
HessianFactor>(factor));
if (hessian)
jacobianFactor.reset(new JacobianFactor(*hessian));
else
throw invalid_argument(
"GaussianFactorGraph contains a factor that is neither a JacobianFactor nor a HessianFactor.");
}
// Add entries, adjusting the row index i
std::vector<boost::tuple<size_t, size_t, double> > factorEntries(
jacobianFactor->sparse(columnIndices));
entries.reserve(entries.size() + factorEntries.size());
for (size_t entry = 0; entry < factorEntries.size(); ++entry)
entries.push_back(boost::make_tuple(
factorEntries[entry].get<0> () + i, factorEntries[entry].get<
1> (), factorEntries[entry].get<2> ()));
// Increment row index
i += jacobianFactor->size1();
}
return entries;
}
// VectorValues GaussianFactorGraph::allocateVectorValuesb() const {
// std::vector<size_t> dimensions(size()) ;
// Index i = 0 ;
// BOOST_FOREACH( const sharedFactor& factor, factors_) {
// dimensions[i] = factor->numberOfRows() ;
// i++;
// }
//
// return VectorValues(dimensions) ;
// }
//
// void GaussianFactorGraph::getb(VectorValues &b) const {
// Index i = 0 ;
// BOOST_FOREACH( const sharedFactor& factor, factors_) {
// b[i] = factor->getb();
// i++;
// }
// }
//
// VectorValues GaussianFactorGraph::getb() const {
// VectorValues b = allocateVectorValuesb() ;
// getb(b) ;
// return b ;
// }
/* ************************************************************************* */ /* ************************************************************************* */
GaussianFactorGraph::GaussianFactorGraph(const GaussianBayesNet& CBN) : // Helper functions for Combine
FactorGraph<GaussianFactor> (CBN) { static boost::tuple<vector<size_t>, size_t, size_t> countDims(const std::vector<JacobianFactor::shared_ptr>& factors, const VariableSlots& variableSlots) {
} #ifndef NDEBUG
vector<size_t> varDims(variableSlots.size(), numeric_limits<size_t>::max());
#else
vector<size_t> varDims(variableSlots.size());
#endif
size_t m = 0;
size_t n = 0;
{
Index jointVarpos = 0;
BOOST_FOREACH(const VariableSlots::value_type& slots, variableSlots) {
/* ************************************************************************* */ assert(slots.second.size() == factors.size());
GaussianFactorGraph::Keys GaussianFactorGraph::keys() const {
FastSet<Index> keys;
BOOST_FOREACH(const sharedFactor& factor, *this) {
if(factor) keys.insert(factor->begin(), factor->end()); }
return keys;
}
/* ************************************************************************* */ Index sourceFactorI = 0;
void GaussianFactorGraph::permuteWithInverse(const Permutation& inversePermutation) { BOOST_FOREACH(const Index sourceVarpos, slots.second) {
BOOST_FOREACH(const sharedFactor& factor, factors_) { if(sourceVarpos < numeric_limits<Index>::max()) {
factor->permuteWithInverse(inversePermutation); const JacobianFactor& sourceFactor = *factors[sourceFactorI];
} size_t vardim = sourceFactor.getDim(sourceFactor.begin() + sourceVarpos);
} #ifndef NDEBUG
if(varDims[jointVarpos] == numeric_limits<size_t>::max()) {
/* ************************************************************************* */ varDims[jointVarpos] = vardim;
void GaussianFactorGraph::combine(const GaussianFactorGraph &lfg){ n += vardim;
for(const_iterator factor=lfg.factors_.begin(); factor!=lfg.factors_.end(); factor++){ } else
push_back(*factor); assert(varDims[jointVarpos] == vardim);
} #else
} varDims[jointVarpos] = vardim;
n += vardim;
/* ************************************************************************* */ break;
GaussianFactorGraph GaussianFactorGraph::combine2(const GaussianFactorGraph& lfg1, #endif
const GaussianFactorGraph& lfg2) { }
++ sourceFactorI;
// create new linear factor graph equal to the first one }
GaussianFactorGraph fg = lfg1; ++ jointVarpos;
}
// add the second factors_ in the graph BOOST_FOREACH(const JacobianFactor::shared_ptr& factor, factors) {
for (const_iterator factor = lfg2.factors_.begin(); factor m += factor->size1();
!= lfg2.factors_.end(); factor++) {
fg.push_back(*factor);
}
return fg;
}
/* ************************************************************************* */
std::vector<boost::tuple<size_t,size_t,double> >
GaussianFactorGraph::sparseJacobian(const std::vector<size_t>& columnIndices) const {
std::vector<boost::tuple<size_t,size_t,double> > entries;
size_t i = 0;
BOOST_FOREACH(const sharedFactor& factor, *this) {
// Convert to JacobianFactor if necessary
JacobianFactor::shared_ptr jacobianFactor(boost::dynamic_pointer_cast<JacobianFactor>(factor));
if(!jacobianFactor) {
HessianFactor::shared_ptr hessianFactor(boost::dynamic_pointer_cast<HessianFactor>(factor));
if(hessianFactor)
jacobianFactor.reset(new JacobianFactor(*hessianFactor));
else
throw invalid_argument("GaussianFactorGraph contains a factor that is neither a JacobianFactor nor a HessianFactor.");
} }
// Add entries, adjusting the row index i
std::vector<boost::tuple<size_t,size_t,double> > factorEntries(jacobianFactor->sparse(columnIndices));
entries.reserve(entries.size() + factorEntries.size());
for(size_t entry=0; entry<factorEntries.size(); ++entry)
entries.push_back(boost::make_tuple(factorEntries[entry].get<0>()+i, factorEntries[entry].get<1>(), factorEntries[entry].get<2>()));
// Increment row index
i += jacobianFactor->size1();
} }
return entries; return boost::make_tuple(varDims, m, n);
} }
// VectorValues GaussianFactorGraph::allocateVectorValuesb() const { /* ************************************************************************* */
// std::vector<size_t> dimensions(size()) ; JacobianFactor::shared_ptr CombineJacobians(
// Index i = 0 ; const FactorGraph<JacobianFactor>& factors,
// BOOST_FOREACH( const sharedFactor& factor, factors_) { const VariableSlots& variableSlots) {
// dimensions[i] = factor->numberOfRows() ;
// i++; const bool debug = ISDEBUG("CombineJacobians");
// } if (debug) factors.print("Combining factors: ");
// if (debug) variableSlots.print();
// return VectorValues(dimensions) ;
// } if (debug) cout << "Determine dimensions" << endl;
// tic(1, "countDims");
// void GaussianFactorGraph::getb(VectorValues &b) const { vector<size_t> varDims;
// Index i = 0 ; size_t m, n;
// BOOST_FOREACH( const sharedFactor& factor, factors_) { boost::tie(varDims, m, n) = countDims(factors, variableSlots);
// b[i] = factor->getb(); if (debug) {
// i++; cout << "Dims: " << m << " x " << n << "\n";
// } BOOST_FOREACH(const size_t dim, varDims) cout << dim << " ";
// } cout << endl;
// }
// VectorValues GaussianFactorGraph::getb() const { toc(1, "countDims");
// VectorValues b = allocateVectorValuesb() ;
// getb(b) ; if (debug) cout << "Sort rows" << endl;
// return b ; tic(2, "sort rows");
// } vector<JacobianFactor::_RowSource> rowSources;
rowSources.reserve(m);
bool anyConstrained = false;
for (size_t sourceFactorI = 0; sourceFactorI < factors.size(); ++sourceFactorI) {
const JacobianFactor& sourceFactor(*factors[sourceFactorI]);
sourceFactor.collectInfo(sourceFactorI, rowSources);
if (sourceFactor.isConstrained()) anyConstrained = true;
}
assert(rowSources.size() == m);
std::sort(rowSources.begin(), rowSources.end());
toc(2, "sort rows");
if (debug) cout << "Allocate new factor" << endl;
tic(3, "allocate");
JacobianFactor::shared_ptr combined(new JacobianFactor());
combined->allocate(variableSlots, varDims, m);
Vector sigmas(m);
toc(3, "allocate");
if (debug) cout << "Copy rows" << endl;
tic(4, "copy rows");
Index combinedSlot = 0;
BOOST_FOREACH(const VariableSlots::value_type& varslot, variableSlots) {
for (size_t row = 0; row < m; ++row) {
const JacobianFactor::_RowSource& info(rowSources[row]);
const JacobianFactor& source(*factors[info.factorI]);
size_t sourceRow = info.factorRowI;
Index sourceSlot = varslot.second[info.factorI];
combined->copyRow(source, sourceRow, sourceSlot, row, combinedSlot);
}
++combinedSlot;
}
toc(4, "copy rows");
if (debug) cout << "Copy rhs (b), sigma, and firstNonzeroBlocks" << endl;
tic(5, "copy vectors");
for (size_t row = 0; row < m; ++row) {
const JacobianFactor::_RowSource& info(rowSources[row]);
const JacobianFactor& source(*factors[info.factorI]);
const size_t sourceRow = info.factorRowI;
combined->getb()(row) = source.getb()(sourceRow);
sigmas(row) = source.get_model()->sigmas()(sourceRow);
}
combined->copyFNZ(m, variableSlots.size(),rowSources);
toc(5, "copy vectors");
if (debug) cout << "Create noise model from sigmas" << endl;
tic(6, "noise model");
combined->setModel( anyConstrained,sigmas);
toc(6, "noise model");
if (debug) cout << "Assert Invariants" << endl;
combined->assertInvariants();
return combined;
}
/* ************************************************************************* */
GaussianFactorGraph::EliminationResult EliminateJacobians(const FactorGraph<
JacobianFactor>& factors, size_t nrFrontals) {
tic(1, "Combine");
JacobianFactor::shared_ptr jointFactor =
CombineJacobians(factors, VariableSlots(factors));
toc(1, "Combine");
tic(2, "eliminate");
GaussianBayesNet::shared_ptr gbn(jointFactor->eliminate(nrFrontals));
toc(2, "eliminate");
return make_pair(gbn, jointFactor);
}
/* ************************************************************************* */
static FastMap<Index, SlotEntry> findScatterAndDims//
(const FactorGraph<GaussianFactor>& factors) {
static const bool debug = false;
// The "scatter" is a map from global variable indices to slot indices in the
// union of involved variables. We also include the dimensionality of the
// variable.
Scatter scatter;
// First do the set union.
BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, factors) {
for(GaussianFactor::const_iterator variable = factor->begin(); variable != factor->end(); ++variable) {
scatter.insert(make_pair(*variable, SlotEntry(0, factor->getDim(variable))));
}
}
// Next fill in the slot indices (we can only get these after doing the set
// union.
size_t slot = 0;
BOOST_FOREACH(Scatter::value_type& var_slot, scatter) {
var_slot.second.slot = (slot ++);
if(debug)
cout << "scatter[" << var_slot.first << "] = (slot " << var_slot.second.slot << ", dim " << var_slot.second.dimension << ")" << endl;
}
return scatter;
}
/* ************************************************************************* */
GaussianFactorGraph::EliminationResult EliminateCholesky(const FactorGraph<
GaussianFactor>& factors, size_t nrFrontals) {
const bool debug = ISDEBUG("EliminateCholesky");
// Find the scatter and variable dimensions
tic(1, "find scatter");
Scatter scatter(findScatterAndDims(factors));
toc(1, "find scatter");
// Pull out keys and dimensions
tic(2, "keys");
vector<Index> keys(scatter.size());
vector<size_t> dimensions(scatter.size() + 1);
BOOST_FOREACH(const Scatter::value_type& var_slot, scatter) {
keys[var_slot.second.slot] = var_slot.first;
dimensions[var_slot.second.slot] = var_slot.second.dimension;
}
// This is for the r.h.s. vector
dimensions.back() = 1;
toc(2, "keys");
// Form Ab' * Ab
tic(3, "combine");
HessianFactor::shared_ptr //
combinedFactor(new HessianFactor(factors, dimensions, scatter));
toc(3, "combine");
// Do Cholesky, note that after this, the lower triangle still contains
// some untouched non-zeros that should be zero. We zero them while
// extracting submatrices next.
tic(4, "partial Cholesky");
combinedFactor->partialCholesky(nrFrontals);
toc(4, "partial Cholesky");
// Extract conditionals and fill in details of the remaining factor
tic(5, "split");
GaussianBayesNet::shared_ptr conditionals =
combinedFactor->splitEliminatedFactor(nrFrontals, keys);
if (debug) {
conditionals->print("Extracted conditionals: ");
combinedFactor->print("Eliminated factor (L piece): ");
}
toc(5, "split");
combinedFactor->assertInvariants();
return make_pair(conditionals, combinedFactor);
}
/* ************************************************************************* */
static FactorGraph<JacobianFactor> convertToJacobians(const FactorGraph<
GaussianFactor>& factors) {
typedef JacobianFactor J;
typedef HessianFactor H;
const bool debug = ISDEBUG("convertToJacobians");
FactorGraph<J> jacobians;
jacobians.reserve(factors.size());
BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, factors)
if (factor) {
J::shared_ptr jacobian(boost::dynamic_pointer_cast<J>(factor));
if (jacobian) {
jacobians.push_back(jacobian);
if (debug) jacobian->print("Existing JacobianFactor: ");
} else {
H::shared_ptr hessian(boost::dynamic_pointer_cast<H>(factor));
if (!hessian) throw std::invalid_argument(
"convertToJacobians: factor is neither a JacobianFactor nor a HessianFactor.");
J::shared_ptr converted(new J(*hessian));
if (debug) {
if (!assert_equal(*hessian, HessianFactor(*converted), 1e-3)) throw runtime_error(
"convertToJacobians: Conversion between Jacobian and Hessian incorrect");
cout << "Converted HessianFactor to JacobianFactor:\n";
hessian->print("HessianFactor: ");
converted->print("JacobianFactor: ");
}
jacobians.push_back(converted);
}
}
return jacobians;
}
/* ************************************************************************* */
GaussianFactorGraph::EliminationResult EliminateQR(const FactorGraph<
GaussianFactor>& factors, size_t nrFrontals) {
const bool debug = ISDEBUG("EliminateQR");
// Convert all factors to the appropriate type and call the type-specific EliminateGaussian.
if (debug) cout << "Using QR:";
tic(1, "convert to Jacobian");
FactorGraph<JacobianFactor> jacobians = convertToJacobians(factors);
toc(1, "convert to Jacobian");
tic(2, "Jacobian EliminateGaussian");
GaussianBayesNet::shared_ptr bn;
GaussianFactor::shared_ptr factor;
boost::tie(bn, factor) = EliminateJacobians(jacobians, nrFrontals);
toc(2, "Jacobian EliminateGaussian");
return make_pair(bn, factor);
} // EliminateQR
/* ************************************************************************* */
GaussianFactorGraph::EliminationResult EliminatePreferCholesky(
const FactorGraph<GaussianFactor>& factors, size_t nrFrontals) {
typedef JacobianFactor J;
typedef HessianFactor H;
// If any JacobianFactors have constrained noise models, we have to convert
// all factors to JacobianFactors. Otherwise, we can convert all factors
// to HessianFactors. This is because QR can handle constrained noise
// models but Cholesky cannot.
// Decide whether to use QR or Cholesky
// Check if any JacobianFactors have constrained noise models.
bool useQR = false;
useQR = false;
BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, factors) {
J::shared_ptr jacobian(boost::dynamic_pointer_cast<J>(factor));
if (jacobian && jacobian->get_model()->isConstrained()) {
useQR = true;
break;
}
}
// Convert all factors to the appropriate type
// and call the type-specific EliminateGaussian.
if (useQR) return EliminateQR(factors, nrFrontals);
GaussianFactorGraph::EliminationResult ret;
try {
tic(2, "EliminateCholesky");
ret = EliminateCholesky(factors, nrFrontals);
toc(2, "EliminateCholesky");
} catch (const exception& e) {
cout << "Exception in EliminateCholesky: " << e.what() << endl;
SETDEBUG("EliminateCholesky", true);
SETDEBUG("updateATA", true);
SETDEBUG("JacobianFactor::eliminate", true);
SETDEBUG("JacobianFactor::Combine", true);
SETDEBUG("choleskyPartial", true);
factors.print("Combining factors: ");
EliminateCholesky(factors, nrFrontals);
throw;
}
const bool checkCholesky = ISDEBUG("EliminateGaussian Check Cholesky");
if (checkCholesky) {
GaussianFactorGraph::EliminationResult expected;
FactorGraph<J> jacobians = convertToJacobians(factors);
try {
// Compare with QR
expected = EliminateJacobians(jacobians, nrFrontals);
} catch (...) {
cout << "Exception in QR" << endl;
throw;
}
H actual_factor(*ret.second);
H expected_factor(*expected.second);
if (!assert_equal(*expected.first, *ret.first, 100.0) || !assert_equal(
expected_factor, actual_factor, 1.0)) {
cout << "Cholesky and QR do not agree" << endl;
SETDEBUG("EliminateCholesky", true);
SETDEBUG("updateATA", true);
SETDEBUG("JacobianFactor::eliminate", true);
SETDEBUG("JacobianFactor::Combine", true);
jacobians.print("Jacobian Factors: ");
EliminateJacobians(jacobians, nrFrontals);
EliminateCholesky(factors, nrFrontals);
factors.print("Combining factors: ");
throw runtime_error("Cholesky and QR do not agree");
}
}
return ret;
} // EliminatePreferCholesky
} // namespace gtsam } // namespace gtsam

View File

@ -15,6 +15,8 @@
* @author Kai Ni * @author Kai Ni
* @author Christian Potthast * @author Christian Potthast
* @author Alireza Fathi * @author Alireza Fathi
* @author Richard Roberts
* @author Frank Dellaert
*/ */
#pragma once #pragma once
@ -25,13 +27,40 @@
#include <gtsam/base/FastSet.h> #include <gtsam/base/FastSet.h>
#include <gtsam/inference/FactorGraph.h> #include <gtsam/inference/FactorGraph.h>
#include <gtsam/linear/Errors.h> #include <gtsam/linear/Errors.h>
#include <gtsam/linear/GaussianFactor.h>
#include <gtsam/linear/JacobianFactor.h> #include <gtsam/linear/JacobianFactor.h>
#include <gtsam/linear/HessianFactor.h>
#include <gtsam/linear/GaussianBayesNet.h> #include <gtsam/linear/GaussianBayesNet.h>
#include <gtsam/linear/SharedDiagonal.h>
namespace gtsam { namespace gtsam {
class SharedDiagonal;
/** unnormalized error */
template<class FACTOR>
double gaussianError(const FactorGraph<FACTOR>& fg, const VectorValues& x) {
double total_error = 0.;
BOOST_FOREACH(const typename FACTOR::shared_ptr& factor, fg) {
total_error += factor->error(x);
}
return total_error;
}
/** return A*x-b */
template<class FACTOR>
Errors gaussianErrors(const FactorGraph<FACTOR>& fg, const VectorValues& x) {
return *gaussianErrors_(fg, x);
}
/** shared pointer version */
template<class FACTOR>
boost::shared_ptr<Errors> gaussianErrors_(const FactorGraph<FACTOR>& fg, const VectorValues& x) {
boost::shared_ptr<Errors> e(new Errors);
BOOST_FOREACH(const typename FACTOR::shared_ptr& factor, fg) {
e->push_back(factor->error_vector(x));
}
return e;
}
/** /**
* A Linear Factor Graph is a factor graph where all factors are Gaussian, i.e. * A Linear Factor Graph is a factor graph where all factors are Gaussian, i.e.
* Factor == GaussianFactor * Factor == GaussianFactor
@ -138,4 +167,26 @@ namespace gtsam {
}; };
/**
* Combine and eliminate several factors.
*/
JacobianFactor::shared_ptr CombineJacobians(
const FactorGraph<JacobianFactor>& factors,
const VariableSlots& variableSlots);
GaussianFactorGraph::EliminationResult EliminateJacobians(const FactorGraph<
JacobianFactor>& factors, size_t nrFrontals = 1);
GaussianFactorGraph::EliminationResult EliminateHessians(const FactorGraph<
HessianFactor>& factors, size_t nrFrontals = 1);
GaussianFactorGraph::EliminationResult EliminateQR(const FactorGraph<
GaussianFactor>& factors, size_t nrFrontals = 1);
GaussianFactorGraph::EliminationResult EliminatePreferCholesky(const FactorGraph<
GaussianFactor>& factors, size_t nrFrontals = 1);
GaussianFactorGraph::EliminationResult EliminateCholesky(const FactorGraph<
GaussianFactor>& factors, size_t nrFrontals = 1);
} // namespace gtsam } // namespace gtsam

View File

@ -28,14 +28,27 @@ namespace ublas = boost::numeric::ublas;
namespace gtsam { namespace gtsam {
/* ************************************************************************* */
GaussianFactor::shared_ptr GaussianISAM::marginalFactor(Index j) const {
return Super::marginalFactor(j, &EliminateQR);
}
/* ************************************************************************* */
BayesNet<GaussianConditional>::shared_ptr GaussianISAM::marginalBayesNet(Index j) const {
return Super::marginalBayesNet(j, &EliminateQR);
}
/* ************************************************************************* */ /* ************************************************************************* */
std::pair<Vector, Matrix> GaussianISAM::marginal(Index j) const { std::pair<Vector, Matrix> GaussianISAM::marginal(Index j) const {
GaussianFactor::shared_ptr factor = this->marginalFactor(j); GaussianConditional::shared_ptr conditional = marginalBayesNet(j)->front();
FactorGraph<GaussianFactor> graph; Matrix R = conditional->get_R();
graph.push_back(factor); return make_pair(conditional->get_d(), inverse(ublas::prod(ublas::trans(R), R)));
GaussianConditional::shared_ptr conditional = GaussianFactor::CombineAndEliminate(graph,1).first->front(); }
Matrix R = conditional->get_R();
return make_pair(conditional->get_d(), inverse(ublas::prod(ublas::trans(R), R))); /* ************************************************************************* */
BayesNet<GaussianConditional>::shared_ptr GaussianISAM::jointBayesNet(
Index key1, Index key2) const {
return Super::jointBayesNet(key1, key2, &EliminateQR);
} }
/* ************************************************************************* */ /* ************************************************************************* */
@ -60,4 +73,10 @@ VectorValues optimize(const GaussianISAM& bayesTree) {
return result; return result;
} }
/* ************************************************************************* */
BayesNet<GaussianConditional> GaussianISAM::shortcut(sharedClique clique, sharedClique root) {
return clique->shortcut(root,&EliminateQR);
}
/* ************************************************************************* */
} /// namespace gtsam } /// namespace gtsam

View File

@ -19,29 +19,30 @@
#pragma once #pragma once
#include <gtsam/linear/GaussianBayesNet.h>
#include <gtsam/linear/GaussianFactor.h>
#include <gtsam/inference/ISAM.h> #include <gtsam/inference/ISAM.h>
#include <gtsam/linear/GaussianBayesNet.h>
#include <gtsam/linear/GaussianFactorGraph.h>
namespace gtsam { namespace gtsam {
class GaussianISAM : public ISAM<GaussianConditional> { class GaussianISAM : public ISAM<GaussianConditional> {
typedef ISAM<GaussianConditional> Super;
std::deque<size_t, boost::fast_pool_allocator<size_t> > dims_; std::deque<size_t, boost::fast_pool_allocator<size_t> > dims_;
public: public:
/** Create an empty Bayes Tree */ /** Create an empty Bayes Tree */
GaussianISAM() : ISAM<GaussianConditional>() {} GaussianISAM() : Super() {}
/** Create a Bayes Tree from a Bayes Net */ /** Create a Bayes Tree from a Bayes Net */
GaussianISAM(const GaussianBayesNet& bayesNet) : ISAM<GaussianConditional>(bayesNet) {} GaussianISAM(const GaussianBayesNet& bayesNet) : Super(bayesNet) {}
/** Override update_internal to also keep track of variable dimensions. */ /** Override update_internal to also keep track of variable dimensions. */
template<class FACTORGRAPH> template<class FACTORGRAPH>
void update_internal(const FACTORGRAPH& newFactors, Cliques& orphans) { void update_internal(const FACTORGRAPH& newFactors, Cliques& orphans) {
ISAM<GaussianConditional>::update_internal(newFactors, orphans); Super::update_internal(newFactors, orphans, &EliminateQR);
// update dimensions // update dimensions
BOOST_FOREACH(const typename FACTORGRAPH::sharedFactor& factor, newFactors) { BOOST_FOREACH(const typename FACTORGRAPH::sharedFactor& factor, newFactors) {
@ -63,15 +64,22 @@ public:
} }
void clear() { void clear() {
ISAM<GaussianConditional>::clear(); Super::clear();
dims_.clear(); dims_.clear();
} }
friend VectorValues optimize(const GaussianISAM&); friend VectorValues optimize(const GaussianISAM&);
/** return marginal on any variable */ /** return marginal on any variable as a factor, Bayes net, or mean/cov */
GaussianFactor::shared_ptr marginalFactor(Index j) const;
BayesNet<GaussianConditional>::shared_ptr marginalBayesNet(Index key) const;
std::pair<Vector,Matrix> marginal(Index key) const; std::pair<Vector,Matrix> marginal(Index key) const;
/** return joint between two variables, as a Bayes net */
BayesNet<GaussianConditional>::shared_ptr jointBayesNet(Index key1, Index key2) const;
/** return the conditional P(S|Root) on the separator given the root */
static BayesNet<GaussianConditional> shortcut(sharedClique clique, sharedClique root);
}; };
// recursively optimize this conditional and all subtrees // recursively optimize this conditional and all subtrees

View File

@ -34,9 +34,6 @@ namespace gtsam {
using namespace std; using namespace std;
/* ************************************************************************* */ /* ************************************************************************* */
/**
* GaussianJunctionTree
*/
void GaussianJunctionTree::btreeBackSubstitute(const boost::shared_ptr<const BayesTree::Clique>& current, VectorValues& config) const { void GaussianJunctionTree::btreeBackSubstitute(const boost::shared_ptr<const BayesTree::Clique>& current, VectorValues& config) const {
// solve the bayes net in the current node // solve the bayes net in the current node
GaussianBayesNet::const_reverse_iterator it = current->rbegin(); GaussianBayesNet::const_reverse_iterator it = current->rbegin();
@ -64,10 +61,10 @@ namespace gtsam {
} }
/* ************************************************************************* */ /* ************************************************************************* */
VectorValues GaussianJunctionTree::optimize() const { VectorValues GaussianJunctionTree::optimize(Eliminate function) const {
tic(1, "GJT eliminate"); tic(1, "GJT eliminate");
// eliminate from leaves to the root // eliminate from leaves to the root
boost::shared_ptr<const BayesTree::Clique> rootClique(this->eliminate()); boost::shared_ptr<const BayesTree::Clique> rootClique(this->eliminate(function));
toc(1, "GJT eliminate"); toc(1, "GJT eliminate");
// Allocate solution vector // Allocate solution vector
@ -84,4 +81,5 @@ namespace gtsam {
return result; return result;
} }
/* ************************************************************************* */
} //namespace gtsam } //namespace gtsam

View File

@ -32,10 +32,12 @@ namespace gtsam {
* GaussianJunctionTree that does the optimization * GaussianJunctionTree that does the optimization
*/ */
class GaussianJunctionTree: public JunctionTree<GaussianFactorGraph> { class GaussianJunctionTree: public JunctionTree<GaussianFactorGraph> {
public: public:
typedef boost::shared_ptr<GaussianJunctionTree> shared_ptr; typedef boost::shared_ptr<GaussianJunctionTree> shared_ptr;
typedef JunctionTree<GaussianFactorGraph> Base; typedef JunctionTree<GaussianFactorGraph> Base;
typedef Base::sharedClique sharedClique; typedef Base::sharedClique sharedClique;
typedef GaussianFactorGraph::Eliminate Eliminate;
protected: protected:
// back-substitute in topological sort order (parents first) // back-substitute in topological sort order (parents first)
@ -53,7 +55,8 @@ namespace gtsam {
GaussianJunctionTree(const GaussianFactorGraph& fg, const VariableIndex& variableIndex) : Base(fg, variableIndex) {} GaussianJunctionTree(const GaussianFactorGraph& fg, const VariableIndex& variableIndex) : Base(fg, variableIndex) {}
// optimize the linear graph // optimize the linear graph
VectorValues optimize() const; VectorValues optimize(Eliminate function) const;
}; // GaussianJunctionTree }; // GaussianJunctionTree
} // namespace gtsam } // namespace gtsam

View File

@ -48,32 +48,32 @@ void GaussianMultifrontalSolver::replaceFactors(const FactorGraph<GaussianFactor
/* ************************************************************************* */ /* ************************************************************************* */
BayesTree<GaussianConditional>::shared_ptr GaussianMultifrontalSolver::eliminate() const { BayesTree<GaussianConditional>::shared_ptr GaussianMultifrontalSolver::eliminate() const {
return Base::eliminate(); return Base::eliminate(&EliminateQR);
} }
/* ************************************************************************* */ /* ************************************************************************* */
VectorValues::shared_ptr GaussianMultifrontalSolver::optimize() const { VectorValues::shared_ptr GaussianMultifrontalSolver::optimize() const {
tic(2,"optimize"); tic(2,"optimize");
VectorValues::shared_ptr values(new VectorValues(junctionTree_->optimize())); VectorValues::shared_ptr values(new VectorValues(junctionTree_->optimize(&EliminateQR)));
toc(2,"optimize"); toc(2,"optimize");
return values; return values;
} }
/* ************************************************************************* */ /* ************************************************************************* */
GaussianFactorGraph::shared_ptr GaussianMultifrontalSolver::jointFactorGraph(const std::vector<Index>& js) const { GaussianFactorGraph::shared_ptr GaussianMultifrontalSolver::jointFactorGraph(const std::vector<Index>& js) const {
return GaussianFactorGraph::shared_ptr(new GaussianFactorGraph(*Base::jointFactorGraph(js))); return GaussianFactorGraph::shared_ptr(new GaussianFactorGraph(*Base::jointFactorGraph(js,&EliminateQR)));
} }
/* ************************************************************************* */ /* ************************************************************************* */
GaussianFactor::shared_ptr GaussianMultifrontalSolver::marginalFactor(Index j) const { GaussianFactor::shared_ptr GaussianMultifrontalSolver::marginalFactor(Index j) const {
return Base::marginalFactor(j); return Base::marginalFactor(j,&EliminateQR);
} }
/* ************************************************************************* */ /* ************************************************************************* */
std::pair<Vector, Matrix> GaussianMultifrontalSolver::marginalCovariance(Index j) const { std::pair<Vector, Matrix> GaussianMultifrontalSolver::marginalCovariance(Index j) const {
FactorGraph<GaussianFactor> fg; FactorGraph<GaussianFactor> fg;
fg.push_back(Base::marginalFactor(j)); fg.push_back(Base::marginalFactor(j,&EliminateQR));
GaussianConditional::shared_ptr conditional = GaussianFactor::CombineAndEliminate(fg,1).first->front(); GaussianConditional::shared_ptr conditional = EliminateQR(fg,1).first->front();
Matrix R = conditional->get_R(); Matrix R = conditional->get_R();
return make_pair(conditional->get_d(), inverse(ublas::prod(ublas::trans(R), R))); return make_pair(conditional->get_d(), inverse(ublas::prod(ublas::trans(R), R)));
} }

View File

@ -49,7 +49,7 @@ void GaussianSequentialSolver::replaceFactors(const FactorGraph<GaussianFactor>:
/* ************************************************************************* */ /* ************************************************************************* */
GaussianBayesNet::shared_ptr GaussianSequentialSolver::eliminate() const { GaussianBayesNet::shared_ptr GaussianSequentialSolver::eliminate() const {
return Base::eliminate(); return Base::eliminate(&EliminateQR);
} }
/* ************************************************************************* */ /* ************************************************************************* */
@ -82,20 +82,23 @@ VectorValues::shared_ptr GaussianSequentialSolver::optimize() const {
/* ************************************************************************* */ /* ************************************************************************* */
GaussianFactor::shared_ptr GaussianSequentialSolver::marginalFactor(Index j) const { GaussianFactor::shared_ptr GaussianSequentialSolver::marginalFactor(Index j) const {
return Base::marginalFactor(j); return Base::marginalFactor(j,&EliminateQR);
}
std::pair<Vector, Matrix> GaussianSequentialSolver::marginalCovariance(Index j) const {
FactorGraph<GaussianFactor> fg;
fg.push_back(Base::marginalFactor(j));
GaussianConditional::shared_ptr conditional = GaussianFactor::CombineAndEliminate(fg,1).first->front();
Matrix R = conditional->get_R();
return make_pair(conditional->get_d(), inverse(ublas::prod(ublas::trans(R), R)));
} }
/* ************************************************************************* */ /* ************************************************************************* */
GaussianFactorGraph::shared_ptr GaussianSequentialSolver::jointFactorGraph(const std::vector<Index>& js) const { std::pair<Vector, Matrix> GaussianSequentialSolver::marginalCovariance(Index j) const {
return GaussianFactorGraph::shared_ptr(new GaussianFactorGraph(*Base::jointFactorGraph(js))); FactorGraph<GaussianFactor> fg;
fg.push_back(Base::marginalFactor(j, &EliminateQR));
GaussianConditional::shared_ptr conditional = EliminateQR(fg, 1).first->front();
Matrix R = conditional->get_R();
return make_pair(conditional->get_d(), inverse(ublas::prod(ublas::trans(R),R)));
}
/* ************************************************************************* */
GaussianFactorGraph::shared_ptr
GaussianSequentialSolver::jointFactorGraph(const std::vector<Index>& js) const {
return GaussianFactorGraph::shared_ptr(new GaussianFactorGraph(
*Base::jointFactorGraph(js, &EliminateQR)));
} }
} }

View File

@ -173,6 +173,40 @@ namespace gtsam {
} }
/* ************************************************************************* */ /* ************************************************************************* */
HessianFactor::HessianFactor(const FactorGraph<GaussianFactor>& factors,
const vector<size_t>& dimensions, const Scatter& scatter) :
info_(matrix_) {
const bool debug = ISDEBUG("EliminateCholesky");
// Form Ab' * Ab
tic(1, "allocate");
info_.resize(dimensions.begin(), dimensions.end(), false);
toc(1, "allocate");
tic(2, "zero");
ublas::noalias(matrix_) = ublas::zero_matrix<double>(matrix_.size1(),matrix_.size2());
toc(2, "zero");
tic(3, "update");
BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, factors)
{
shared_ptr hessian(boost::dynamic_pointer_cast<HessianFactor>(factor));
if (hessian)
updateATA(*hessian, scatter);
else {
JacobianFactor::shared_ptr jacobianFactor(boost::dynamic_pointer_cast<JacobianFactor>(factor));
if (jacobianFactor)
updateATA(*jacobianFactor, scatter);
else
throw invalid_argument("GaussianFactor is neither Hessian nor Jacobian");
}
}
toc(3, "update");
if (debug) gtsam::print(matrix_, "Ab' * Ab: ");
assertInvariants();
}
/* ************************************************************************* */
void HessianFactor::print(const std::string& s) const { void HessianFactor::print(const std::string& s) const {
cout << s << "\n"; cout << s << "\n";
cout << " keys: "; cout << " keys: ";
@ -202,36 +236,6 @@ namespace gtsam {
2.0*ublas::inner_prod(c.vector(), info_.rangeColumn(0, this->size(), this->size(), 0)); 2.0*ublas::inner_prod(c.vector(), info_.rangeColumn(0, this->size(), this->size(), 0));
} }
/* ************************************************************************* */
static FastMap<Index, SlotEntry> findScatterAndDims(const FactorGraph<GaussianFactor>& factors) {
static const bool debug = false;
// The "scatter" is a map from global variable indices to slot indices in the
// union of involved variables. We also include the dimensionality of the
// variable.
Scatter scatter;
// First do the set union.
BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, factors) {
for(GaussianFactor::const_iterator variable = factor->begin(); variable != factor->end(); ++variable) {
scatter.insert(make_pair(*variable, SlotEntry(0, factor->getDim(variable))));
}
}
// Next fill in the slot indices (we can only get these after doing the set
// union.
size_t slot = 0;
BOOST_FOREACH(Scatter::value_type& var_slot, scatter) {
var_slot.second.slot = (slot ++);
if(debug)
cout << "scatter[" << var_slot.first << "] = (slot " << var_slot.second.slot << ", dim " << var_slot.second.dimension << ")" << endl;
}
return scatter;
}
void HessianFactor::updateATA(const HessianFactor& update, const Scatter& scatter) { void HessianFactor::updateATA(const HessianFactor& update, const Scatter& scatter) {
// This function updates 'combined' with the information in 'update'. // This function updates 'combined' with the information in 'update'.
@ -433,7 +437,14 @@ void HessianFactor::updateATA(const JacobianFactor& update, const Scatter& scatt
// toc(2, "update"); // toc(2, "update");
} }
GaussianBayesNet::shared_ptr HessianFactor::splitEliminatedFactor(size_t nrFrontals, const vector<Index>& keys) { /* ************************************************************************* */
void HessianFactor::partialCholesky(size_t nrFrontals) {
choleskyPartial(matrix_, info_.offset(nrFrontals));
}
/* ************************************************************************* */
GaussianBayesNet::shared_ptr
HessianFactor::splitEliminatedFactor(size_t nrFrontals, const vector<Index>& keys) {
static const bool debug = false; static const bool debug = false;
@ -482,75 +493,4 @@ GaussianBayesNet::shared_ptr HessianFactor::splitEliminatedFactor(size_t nrFront
return conditionals; return conditionals;
} }
/* ************************************************************************* */ } // gtsam
pair<GaussianBayesNet::shared_ptr, HessianFactor::shared_ptr> HessianFactor::CombineAndEliminate(
const FactorGraph<GaussianFactor>& factors, size_t nrFrontals) {
const bool debug = ISDEBUG("HessianFactor::CombineAndEliminate");
// Find the scatter and variable dimensions
tic(1, "find scatter");
Scatter scatter(findScatterAndDims(factors));
toc(1, "find scatter");
// Pull out keys and dimensions
tic(2, "keys");
vector<Index> keys(scatter.size());
vector<size_t> dimensions(scatter.size() + 1);
BOOST_FOREACH(const Scatter::value_type& var_slot, scatter) {
keys[var_slot.second.slot] = var_slot.first;
dimensions[var_slot.second.slot] = var_slot.second.dimension;
}
// This is for the r.h.s. vector
dimensions.back() = 1;
toc(2, "keys");
// Form Ab' * Ab
tic(3, "combine");
tic(1, "allocate");
HessianFactor::shared_ptr combinedFactor(new HessianFactor());
combinedFactor->info_.resize(dimensions.begin(), dimensions.end(), false);
toc(1, "allocate");
tic(2, "zero");
ublas::noalias(combinedFactor->matrix_) = ublas::zero_matrix<double>(combinedFactor->matrix_.size1(), combinedFactor->matrix_.size2());
toc(2, "zero");
tic(3, "update");
BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, factors) {
HessianFactor::shared_ptr hessianFactor(boost::dynamic_pointer_cast<HessianFactor>(factor));
if(hessianFactor)
combinedFactor->updateATA(*hessianFactor, scatter);
else {
JacobianFactor::shared_ptr jacobianFactor(boost::dynamic_pointer_cast<JacobianFactor>(factor));
if(jacobianFactor)
combinedFactor->updateATA(*jacobianFactor, scatter);
else
throw invalid_argument("GaussianFactor is neither Hessian nor Jacobian");
}
}
toc(3, "update");
if(debug) gtsam::print(combinedFactor->matrix_, "Ab' * Ab: ");
toc(3, "combine");
// Do Cholesky, note that after this, the lower triangle still contains
// some untouched non-zeros that should be zero. We zero them while
// extracting submatrices next.
tic(4, "partial Cholesky");
choleskyPartial(combinedFactor->matrix_, combinedFactor->info_.offset(nrFrontals));
if(debug) gtsam::print(combinedFactor->matrix_, "chol(Ab' * Ab): ");
toc(4, "partial Cholesky");
// Extract conditionals and fill in details of the remaining factor
tic(5, "split");
GaussianBayesNet::shared_ptr conditionals(combinedFactor->splitEliminatedFactor(nrFrontals, keys));
if(debug) {
conditionals->print("Extracted conditionals: ");
combinedFactor->print("Eliminated factor (L piece): ");
}
toc(5, "split");
combinedFactor->assertInvariants();
return make_pair(conditionals, combinedFactor);
}
}

View File

@ -20,6 +20,7 @@
#include <gtsam/base/Matrix.h> #include <gtsam/base/Matrix.h>
#include <gtsam/base/blockMatrices.h> #include <gtsam/base/blockMatrices.h>
#include <gtsam/inference/FactorGraph.h>
#include <gtsam/linear/GaussianFactor.h> #include <gtsam/linear/GaussianFactor.h>
// Forward declarations for friend unit tests // Forward declarations for friend unit tests
@ -49,8 +50,6 @@ namespace gtsam {
InfoMatrix matrix_; // The full information matrix [A b]^T * [A b] InfoMatrix matrix_; // The full information matrix [A b]^T * [A b]
BlockInfo info_; // The block view of the full information matrix. BlockInfo info_; // The block view of the full information matrix.
void assertInvariants() const;
boost::shared_ptr<BayesNet<GaussianConditional> > splitEliminatedFactor(size_t nrFrontals, const std::vector<Index>& keys);
void updateATA(const JacobianFactor& update, const Scatter& scatter); void updateATA(const JacobianFactor& update, const Scatter& scatter);
void updateATA(const HessianFactor& update, const Scatter& scatter); void updateATA(const HessianFactor& update, const Scatter& scatter);
@ -96,7 +95,12 @@ namespace gtsam {
/** Convert from a JacobianFactor or HessianFactor (computes A^T * A) */ /** Convert from a JacobianFactor or HessianFactor (computes A^T * A) */
HessianFactor(const GaussianFactor& factor); HessianFactor(const GaussianFactor& factor);
virtual ~HessianFactor() {} /** Special constructor used in EliminateCholesky */
HessianFactor(const FactorGraph<GaussianFactor>& factors,
const std::vector<size_t>& dimensions, const Scatter& scatter);
virtual ~HessianFactor() {
}
// Implementing Testable interface // Implementing Testable interface
virtual void print(const std::string& s = "") const; virtual void print(const std::string& s = "") const;
@ -121,13 +125,7 @@ namespace gtsam {
* variable. The order of the variables within the factor is not changed. * variable. The order of the variables within the factor is not changed.
*/ */
virtual void permuteWithInverse(const Permutation& inversePermutation) { virtual void permuteWithInverse(const Permutation& inversePermutation) {
Factor<Index>::permuteWithInverse(inversePermutation); } IndexFactor::permuteWithInverse(inversePermutation); }
/**
* Combine and eliminate several factors.
*/
static std::pair<boost::shared_ptr<BayesNet<GaussianConditional> >, shared_ptr> CombineAndEliminate(
const FactorGraph<GaussianFactor>& factors, size_t nrFrontals=1);
// Friend unit test classes // Friend unit test classes
friend class ::ConversionConstructorHessianFactorTest; friend class ::ConversionConstructorHessianFactorTest;
@ -135,6 +133,21 @@ namespace gtsam {
// Friend JacobianFactor for conversion // Friend JacobianFactor for conversion
friend class JacobianFactor; friend class JacobianFactor;
// used in eliminateCholesky:
/**
* Do Cholesky. Note that after this, the lower triangle still contains
* some untouched non-zeros that should be zero. We zero them while
* extracting submatrices in splitEliminatedFactor. Frank says :-(
*/
void partialCholesky(size_t nrFrontals);
/** split partially eliminated factor */
boost::shared_ptr<BayesNet<GaussianConditional> > splitEliminatedFactor(
size_t nrFrontals, const std::vector<Index>& keys);
/** assert invariants */
void assertInvariants() const;
}; };
} }

View File

@ -493,175 +493,68 @@ namespace gtsam {
} }
/* ************************************************************************* */ /* ************************************************************************* */
/* Used internally by JacobianFactor::Combine for sorting */ void JacobianFactor::collectInfo(size_t index, vector<_RowSource>& rowSources) const {
struct _RowSource { assertInvariants();
size_t firstNonzeroVar; for (size_t row = 0; row < size1(); ++row) {
size_t factorI; Index firstNonzeroVar;
size_t factorRowI; if (firstNonzeroBlocks_[row] < size()) {
_RowSource(size_t _firstNonzeroVar, size_t _factorI, size_t _factorRowI) : firstNonzeroVar = keys_[firstNonzeroBlocks_[row]];
firstNonzeroVar(_firstNonzeroVar), factorI(_factorI), factorRowI(_factorRowI) {} } else if (firstNonzeroBlocks_[row] == size()) {
bool operator<(const _RowSource& o) const { return firstNonzeroVar < o.firstNonzeroVar; } firstNonzeroVar = back() + 1;
}; } else {
assert(false);
}
rowSources.push_back(_RowSource(firstNonzeroVar, index, row));
}
}
/* ************************************************************************* */ /* ************************************************************************* */
// Helper functions for Combine void JacobianFactor::allocate(const VariableSlots& variableSlots, vector<
static boost::tuple<vector<size_t>, size_t, size_t> countDims(const std::vector<JacobianFactor::shared_ptr>& factors, const VariableSlots& variableSlots) { size_t>& varDims, size_t m) {
#ifndef NDEBUG keys_.resize(variableSlots.size());
vector<size_t> varDims(variableSlots.size(), numeric_limits<size_t>::max()); std::transform(variableSlots.begin(), variableSlots.end(), keys_.begin(),
#else bind(&VariableSlots::const_iterator::value_type::first,
vector<size_t> varDims(variableSlots.size()); boost::lambda::_1));
#endif varDims.push_back(1);
size_t m = 0; Ab_.copyStructureFrom(BlockAb(matrix_, varDims.begin(), varDims.end(), m));
size_t n = 0; firstNonzeroBlocks_.resize(m);
{ }
Index jointVarpos = 0;
BOOST_FOREACH(const VariableSlots::value_type& slots, variableSlots) {
assert(slots.second.size() == factors.size());
Index sourceFactorI = 0;
BOOST_FOREACH(const Index sourceVarpos, slots.second) {
if(sourceVarpos < numeric_limits<Index>::max()) {
const JacobianFactor& sourceFactor = *factors[sourceFactorI];
size_t vardim = sourceFactor.getDim(sourceFactor.begin() + sourceVarpos);
#ifndef NDEBUG
if(varDims[jointVarpos] == numeric_limits<size_t>::max()) {
varDims[jointVarpos] = vardim;
n += vardim;
} else
assert(varDims[jointVarpos] == vardim);
#else
varDims[jointVarpos] = vardim;
n += vardim;
break;
#endif
}
++ sourceFactorI;
}
++ jointVarpos;
}
BOOST_FOREACH(const JacobianFactor::shared_ptr& factor, factors) {
m += factor->size1();
}
}
return boost::make_tuple(varDims, m, n);
}
/* ************************************************************************* */ /* ************************************************************************* */
JacobianFactor::shared_ptr JacobianFactor::Combine(const FactorGraph<JacobianFactor>& factors, const VariableSlots& variableSlots) { void JacobianFactor::copyRow(const JacobianFactor& source, Index sourceRow,
size_t sourceSlot, size_t row, Index slot) {
const bool debug = ISDEBUG("JacobianFactor::Combine"); ABlock combinedBlock(Ab_(slot));
if (sourceSlot != numeric_limits<Index>::max()) {
if(debug) factors.print("Combining factors: "); if (source.firstNonzeroBlocks_[sourceRow] <= sourceSlot) {
const constABlock sourceBlock(source.Ab_(sourceSlot));
if(debug) variableSlots.print(); ublas::noalias(ublas::row(combinedBlock, row)) = ublas::row(
sourceBlock, sourceRow);
// Determine dimensions } else
tic(1, "countDims"); ublas::noalias(ublas::row(combinedBlock, row)) = ublas::zero_vector<
vector<size_t> varDims; double>(combinedBlock.size2());
size_t m; } else
size_t n; ublas::noalias(ublas::row(combinedBlock, row)) = ublas::zero_vector<
boost::tie(varDims, m, n) = countDims(factors, variableSlots); double>(combinedBlock.size2());
if(debug) { }
cout << "Dims: " << m << " x " << n << "\n";
BOOST_FOREACH(const size_t dim, varDims) { cout << dim << " "; }
cout << endl;
}
toc(1, "countDims");
// Sort rows
tic(2, "sort rows");
vector<_RowSource> rowSources; rowSources.reserve(m);
bool anyConstrained = false;
for(size_t sourceFactorI = 0; sourceFactorI < factors.size(); ++sourceFactorI) {
const JacobianFactor& sourceFactor(*factors[sourceFactorI]);
sourceFactor.assertInvariants();
for(size_t sourceFactorRow = 0; sourceFactorRow < sourceFactor.size1(); ++sourceFactorRow) {
Index firstNonzeroVar;
if(sourceFactor.firstNonzeroBlocks_[sourceFactorRow] < sourceFactor.size())
firstNonzeroVar = sourceFactor.keys_[sourceFactor.firstNonzeroBlocks_[sourceFactorRow]];
else if(sourceFactor.firstNonzeroBlocks_[sourceFactorRow] == sourceFactor.size())
firstNonzeroVar = sourceFactor.back() + 1;
else
assert(false);
rowSources.push_back(_RowSource(firstNonzeroVar, sourceFactorI, sourceFactorRow));
}
if(sourceFactor.model_->isConstrained()) anyConstrained = true;
}
assert(rowSources.size() == m);
std::sort(rowSources.begin(), rowSources.end());
toc(2, "sort rows");
// Allocate new factor
tic(3, "allocate");
shared_ptr combined(new JacobianFactor());
combined->keys_.resize(variableSlots.size());
std::transform(variableSlots.begin(), variableSlots.end(), combined->keys_.begin(), bind(&VariableSlots::const_iterator::value_type::first, boost::lambda::_1));
varDims.push_back(1);
combined->Ab_.copyStructureFrom(BlockAb(combined->matrix_, varDims.begin(), varDims.end(), m));
combined->firstNonzeroBlocks_.resize(m);
Vector sigmas(m);
toc(3, "allocate");
// Copy rows
tic(4, "copy rows");
Index combinedSlot = 0;
BOOST_FOREACH(const VariableSlots::value_type& varslot, variableSlots) {
for(size_t row = 0; row < m; ++row) {
const Index sourceSlot = varslot.second[rowSources[row].factorI];
ABlock combinedBlock(combined->Ab_(combinedSlot));
if(sourceSlot != numeric_limits<Index>::max()) {
const JacobianFactor& source(*factors[rowSources[row].factorI]);
const size_t sourceRow = rowSources[row].factorRowI;
if(source.firstNonzeroBlocks_[sourceRow] <= sourceSlot) {
const constABlock sourceBlock(source.Ab_(sourceSlot));
ublas::noalias(ublas::row(combinedBlock, row)) = ublas::row(sourceBlock, sourceRow);
} else
ublas::noalias(ublas::row(combinedBlock, row)) = ublas::zero_vector<double>(combinedBlock.size2());
} else
ublas::noalias(ublas::row(combinedBlock, row)) = ublas::zero_vector<double>(combinedBlock.size2());
}
++ combinedSlot;
}
toc(4, "copy rows");
// Copy rhs (b), sigma, and firstNonzeroBlocks
tic(5, "copy vectors");
Index firstNonzeroSlot = 0;
for(size_t row = 0; row < m; ++row) {
const JacobianFactor& source(*factors[rowSources[row].factorI]);
const size_t sourceRow = rowSources[row].factorRowI;
combined->getb()(row) = source.getb()(sourceRow);
sigmas(row) = source.get_model()->sigmas()(sourceRow);
while(firstNonzeroSlot < variableSlots.size() && rowSources[row].firstNonzeroVar > combined->keys_[firstNonzeroSlot])
++ firstNonzeroSlot;
combined->firstNonzeroBlocks_[row] = firstNonzeroSlot;
}
toc(5, "copy vectors");
// Create noise model from sigmas
tic(6, "noise model");
if(anyConstrained) combined->model_ = noiseModel::Constrained::MixedSigmas(sigmas);
else combined->model_ = noiseModel::Diagonal::Sigmas(sigmas);
toc(6, "noise model");
combined->assertInvariants();
return combined;
}
/* ************************************************************************* */ /* ************************************************************************* */
pair<GaussianBayesNet::shared_ptr, JacobianFactor::shared_ptr> JacobianFactor::CombineAndEliminate( void JacobianFactor::copyFNZ(size_t m, size_t n,
const FactorGraph<JacobianFactor>& factors, size_t nrFrontals) { vector<_RowSource>& rowSources) {
tic(1, "Combine"); Index i = 0;
shared_ptr jointFactor(Combine(factors, VariableSlots(factors))); for (size_t row = 0; row < m; ++row) {
toc(1, "Combine"); while (i < n && rowSources[row].firstNonzeroVar > keys_[i])
tic(2, "eliminate"); ++i;
GaussianBayesNet::shared_ptr gbn(jointFactor->eliminate(nrFrontals)); firstNonzeroBlocks_[row] = i;
toc(2, "eliminate"); }
return make_pair(gbn, jointFactor); }
}
/* ************************************************************************* */
void JacobianFactor::setModel(bool anyConstrained, const Vector& sigmas) {
if (anyConstrained)
model_ = noiseModel::Constrained::MixedSigmas(sigmas);
else
model_ = noiseModel::Diagonal::Sigmas(sigmas);
}
/* ************************************************************************* */ /* ************************************************************************* */
Errors operator*(const FactorGraph<JacobianFactor>& fg, const VectorValues& x) { Errors operator*(const FactorGraph<JacobianFactor>& fg, const VectorValues& x) {

View File

@ -21,6 +21,7 @@
#include <gtsam/base/Matrix.h> #include <gtsam/base/Matrix.h>
#include <gtsam/base/Vector.h> #include <gtsam/base/Vector.h>
#include <gtsam/base/blockMatrices.h> #include <gtsam/base/blockMatrices.h>
#include <gtsam/inference/FactorGraph.h>
#include <gtsam/linear/GaussianFactor.h> #include <gtsam/linear/GaussianFactor.h>
#include <gtsam/linear/SharedDiagonal.h> #include <gtsam/linear/SharedDiagonal.h>
#include <gtsam/linear/Errors.h> #include <gtsam/linear/Errors.h>
@ -58,10 +59,6 @@ namespace gtsam {
typedef BlockAb::Column BVector; typedef BlockAb::Column BVector;
typedef BlockAb::constColumn constBVector; typedef BlockAb::constColumn constBVector;
protected:
void assertInvariants() const;
static JacobianFactor::shared_ptr Combine(const FactorGraph<JacobianFactor>& factors, const VariableSlots& variableSlots);
public: public:
/** Copy constructor */ /** Copy constructor */
@ -116,6 +113,9 @@ namespace gtsam {
*/ */
bool empty() const { return Ab_.size1() == 0;} bool empty() const { return Ab_.size1() == 0;}
/** is noise model constrained ? */
bool isConstrained() const { return model_->isConstrained();}
/** 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
* todo: Remove this in favor of keeping track of dimensions with variables? * todo: Remove this in favor of keeping track of dimensions with variables?
*/ */
@ -194,12 +194,6 @@ namespace gtsam {
* model. */ * model. */
JacobianFactor whiten() const; JacobianFactor whiten() const;
/**
* Combine and eliminate several factors.
*/
static std::pair<boost::shared_ptr<BayesNet<GaussianConditional> >, shared_ptr> CombineAndEliminate(
const FactorGraph<JacobianFactor>& factors, size_t nrFrontals=1);
boost::shared_ptr<GaussianConditional> eliminateFirst(); boost::shared_ptr<GaussianConditional> eliminateFirst();
boost::shared_ptr<BayesNet<GaussianConditional> > eliminate(size_t nrFrontals = 1); boost::shared_ptr<BayesNet<GaussianConditional> > eliminate(size_t nrFrontals = 1);
@ -210,8 +204,43 @@ namespace gtsam {
// Friend unit tests (see also forward declarations above) // Friend unit tests (see also forward declarations above)
friend class ::Combine2GaussianFactorTest; friend class ::Combine2GaussianFactorTest;
friend class ::eliminateFrontalsGaussianFactorTest; friend class ::eliminateFrontalsGaussianFactorTest;
};
/* Used by ::CombineJacobians for sorting */
struct _RowSource {
size_t firstNonzeroVar;
size_t factorI;
size_t factorRowI;
_RowSource(size_t _firstNonzeroVar, size_t _factorI, size_t _factorRowI) :
firstNonzeroVar(_firstNonzeroVar), factorI(_factorI), factorRowI(_factorRowI) {}
bool operator<(const _RowSource& o) const {
return firstNonzeroVar < o.firstNonzeroVar;
}
};
// following methods all used in CombineJacobians:
// Many imperative, perhaps all need to be combined in constructor
/** Collect information on Jacobian rows */
void collectInfo(size_t index, std::vector<_RowSource>& rowSources) const;
/** allocate space */
void allocate(const VariableSlots& variableSlots,
std::vector<size_t>& varDims, size_t m);
/** copy a slot from source */
void copyRow(const JacobianFactor& source,
Index sourceRow, size_t sourceSlot, size_t row, Index slot);
/** copy firstNonzeroBlocks structure */
void copyFNZ(size_t m, size_t n, std::vector<_RowSource>& rowSources);
/** set noiseModel correctly */
void setModel(bool anyConstrained, const Vector& sigmas);
/** Assert invariants after elimination */
void assertInvariants() const;
}; // JacobianFactor
/** return A*x */ /** return A*x */
Errors operator*(const FactorGraph<JacobianFactor>& fg, const VectorValues& x); Errors operator*(const FactorGraph<JacobianFactor>& fg, const VectorValues& x);
@ -237,5 +266,5 @@ namespace gtsam {
void multiply(const FactorGraph<JacobianFactor>& fg, const VectorValues &x, VectorValues &r); void multiply(const FactorGraph<JacobianFactor>& fg, const VectorValues &x, VectorValues &r);
void transposeMultiply(const FactorGraph<JacobianFactor>& fg, const VectorValues &r, VectorValues &x); void transposeMultiply(const FactorGraph<JacobianFactor>& fg, const VectorValues &r, VectorValues &x);
} } // gtsam

View File

@ -31,7 +31,7 @@ sources += GaussianJunctionTree.cpp
sources += GaussianConditional.cpp GaussianBayesNet.cpp sources += GaussianConditional.cpp GaussianBayesNet.cpp
sources += GaussianISAM.cpp sources += GaussianISAM.cpp
check_PROGRAMS += tests/testHessianFactor tests/testGaussianFactor tests/testGaussianConditional check_PROGRAMS += tests/testHessianFactor tests/testGaussianFactor tests/testGaussianConditional
check_PROGRAMS += tests/testGaussianJunctionTree check_PROGRAMS += tests/testGaussianFactorGraph tests/testGaussianJunctionTree
# Iterative Methods # Iterative Methods
headers += iterative-inl.h headers += iterative-inl.h

View File

@ -18,6 +18,7 @@
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <gtsam/linear/SubgraphPreconditioner.h> #include <gtsam/linear/SubgraphPreconditioner.h>
#include <gtsam/linear/JacobianFactor.h> #include <gtsam/linear/JacobianFactor.h>
#include <gtsam/linear/GaussianFactorGraph.h>
#include <gtsam/inference/FactorGraph-inl.h> #include <gtsam/inference/FactorGraph-inl.h>
using namespace std; using namespace std;

View File

@ -80,7 +80,8 @@ void SubgraphSolver<GRAPH,LINEAR,VALUES>::replaceFactors(const typename LINEAR::
// theta_bar_ = composePoses<GRAPH, Constraint, Pose, Values> (T_, tree, theta0[root]); // theta_bar_ = composePoses<GRAPH, Constraint, Pose, Values> (T_, tree, theta0[root]);
LINEAR sacrificialAb1 = *Ab1; // duplicate !!!!! LINEAR sacrificialAb1 = *Ab1; // duplicate !!!!!
SubgraphPreconditioner::sharedBayesNet Rc1 = EliminationTree<GaussianFactor>::Create(sacrificialAb1)->eliminate(); SubgraphPreconditioner::sharedBayesNet Rc1 =
EliminationTree<GaussianFactor>::Create(sacrificialAb1)->eliminate(&EliminateQR);
SubgraphPreconditioner::sharedValues xbar = gtsam::optimize_(*Rc1); SubgraphPreconditioner::sharedValues xbar = gtsam::optimize_(*Rc1);
pc_ = boost::make_shared<SubgraphPreconditioner>( pc_ = boost::make_shared<SubgraphPreconditioner>(

View File

@ -16,32 +16,14 @@
* @author Frank Dellaert * @author Frank Dellaert
**/ **/
#include <iostream>
#include <vector>
#include <boost/tuple/tuple.hpp>
#include <boost/assign/std/list.hpp> // for operator +=
#include <boost/assign/std/set.hpp>
#include <boost/assign/std/map.hpp> // for insert
using namespace boost::assign;
#include <gtsam/base/TestableAssertions.h> #include <gtsam/base/TestableAssertions.h>
#include <CppUnitLite/TestHarness.h> #include <CppUnitLite/TestHarness.h>
//#define GTSAM_MAGIC_KEY
#include <gtsam/base/types.h>
#include <gtsam/base/Matrix.h>
#include <gtsam/linear/GaussianFactorGraph.h>
#include <gtsam/linear/SharedDiagonal.h>
#include <gtsam/linear/GaussianSequentialSolver.h>
#include <gtsam/linear/JacobianFactor.h> #include <gtsam/linear/JacobianFactor.h>
#include <gtsam/linear/HessianFactor.h> #include <gtsam/linear/GaussianConditional.h>
#include <gtsam/inference/VariableSlots.h>
using namespace std; using namespace std;
using namespace gtsam; using namespace gtsam;
using namespace boost;
namespace ublas = boost::numeric::ublas; namespace ublas = boost::numeric::ublas;
static const Index _x0_=0, _x1_=1, _x2_=2, _x3_=3, _x4_=4, _x_=5, _y_=6, _l1_=7, _l11_=8; static const Index _x0_=0, _x1_=1, _x2_=2, _x3_=3, _x4_=4, _x_=5, _y_=6, _l1_=7, _l11_=8;
@ -87,302 +69,37 @@ TEST(GaussianFactor, constructor2)
EXPECT(assert_equal(b, actualb)); EXPECT(assert_equal(b, actualb));
} }
///* ************************************************************************* */
//TEST(GaussianFactor, Combine)
//{
// Matrix A00 = Matrix_(3,3,
// 1.0, 0.0, 0.0,
// 0.0, 1.0, 0.0,
// 0.0, 0.0, 1.0);
// Vector b0 = Vector_(3, 0.0, 0.0, 0.0);
// Vector s0 = Vector_(3, 0.0, 0.0, 0.0);
//
// Matrix A10 = Matrix_(3,3,
// 0.0, -2.0, -4.0,
// 2.0, 0.0, 2.0,
// 0.0, 0.0, -10.0);
// Matrix A11 = Matrix_(3,3,
// 2.0, 0.0, 0.0,
// 0.0, 2.0, 0.0,
// 0.0, 0.0, 10.0);
// Vector b1 = Vector_(3, 6.0, 2.0, 0.0);
// Vector s1 = Vector_(3, 1.0, 1.0, 1.0);
//
// Matrix A20 = Matrix_(3,3,
// 1.0, 0.0, 0.0,
// 0.0, 1.0, 0.0,
// 0.0, 0.0, 1.0);
// Vector b2 = Vector_(3, 0.0, 0.0, 0.0);
// Vector s2 = Vector_(3, 100.0, 100.0, 100.0);
//
// GaussianFactorGraph gfg;
// gfg.add(0, A00, b0, noiseModel::Diagonal::Sigmas(s0, true));
// gfg.add(0, A10, 1, A11, b1, noiseModel::Diagonal::Sigmas(s1, true));
// gfg.add(0, A20, b2, noiseModel::Diagonal::Sigmas(s2, true));
//
// GaussianVariableIndex varindex(gfg);
// vector<size_t> factors(3); factors[0]=0; factors[1]=1; factors[2]=2;
// vector<size_t> variables(2); variables[0]=0; variables[1]=1;
// vector<vector<size_t> > variablePositions(3);
// variablePositions[0].resize(1); variablePositions[0][0]=0;
// variablePositions[1].resize(2); variablePositions[1][0]=0; variablePositions[1][1]=1;
// variablePositions[2].resize(1); variablePositions[2][0]=0;
//
// JacobianFactor actual = *JacobianFactor::Combine(gfg, varindex, factors, variables, variablePositions);
//
// Matrix zero3x3 = zeros(3,3);
// Matrix A0 = gtsam::stack(3, &A00, &A10, &A20);
// Matrix A1 = gtsam::stack(3, &zero3x3, &A11, &zero3x3);
// Vector b = gtsam::concatVectors(3, &b0, &b1, &b2);
// Vector sigmas = gtsam::concatVectors(3, &s0, &s1, &s2);
//
// JacobianFactor expected(0, A0, 1, A1, b, noiseModel::Diagonal::Sigmas(sigmas, true));
//
// EXPECT(assert_equal(expected, actual));
//}
/* ************************************************************************* */ /* ************************************************************************* */
TEST(GaussianFactor, Combine2) #ifdef BROKEN
TEST(GaussianFactor, operators )
{ {
Matrix A01 = Matrix_(3,3, Matrix I = eye(2);
1.0, 0.0, 0.0, Vector b = Vector_(2,0.2,-0.1);
0.0, 1.0, 0.0, JacobianFactor lf(_x1_, -I, _x2_, I, b, sigma0_1);
0.0, 0.0, 1.0);
Vector b0 = Vector_(3, 1.5, 1.5, 1.5);
Vector s0 = Vector_(3, 1.6, 1.6, 1.6);
Matrix A10 = Matrix_(3,3, VectorValues c;
2.0, 0.0, 0.0, c[_x1_] = Vector_(2,10.,20.);
0.0, 2.0, 0.0, c[_x2_] = Vector_(2,30.,60.);
0.0, 0.0, 2.0);
Matrix A11 = Matrix_(3,3,
-2.0, 0.0, 0.0,
0.0, -2.0, 0.0,
0.0, 0.0, -2.0);
Vector b1 = Vector_(3, 2.5, 2.5, 2.5);
Vector s1 = Vector_(3, 2.6, 2.6, 2.6);
Matrix A21 = Matrix_(3,3, // test A*x
3.0, 0.0, 0.0, Vector expectedE = Vector_(2,200.,400.), e = lf*c;
0.0, 3.0, 0.0, EXPECT(assert_equal(expectedE,e));
0.0, 0.0, 3.0);
Vector b2 = Vector_(3, 3.5, 3.5, 3.5);
Vector s2 = Vector_(3, 3.6, 3.6, 3.6);
GaussianFactorGraph gfg; // test A^e
gfg.add(1, A01, b0, noiseModel::Diagonal::Sigmas(s0, true)); VectorValues expectedX;
gfg.add(0, A10, 1, A11, b1, noiseModel::Diagonal::Sigmas(s1, true)); expectedX[_x1_] = Vector_(2,-2000.,-4000.);
gfg.add(1, A21, b2, noiseModel::Diagonal::Sigmas(s2, true)); expectedX[_x2_] = Vector_(2, 2000., 4000.);
EXPECT(assert_equal(expectedX,lf^e));
JacobianFactor actual = *JacobianFactor::Combine(*gfg.dynamicCastFactors<FactorGraph<JacobianFactor> >(), VariableSlots(gfg)); // test transposeMultiplyAdd
VectorValues x;
Matrix zero3x3 = zeros(3,3); x[_x1_] = Vector_(2, 1.,2.);
Matrix A0 = gtsam::stack(3, &A10, &zero3x3, &zero3x3); x[_x2_] = Vector_(2, 3.,4.);
Matrix A1 = gtsam::stack(3, &A11, &A01, &A21); VectorValues expectedX2 = x + 0.1 * (lf^e);
Vector b = gtsam::concatVectors(3, &b1, &b0, &b2); lf.transposeMultiplyAdd(0.1,e,x);
Vector sigmas = gtsam::concatVectors(3, &s1, &s0, &s2); EXPECT(assert_equal(expectedX2,x));
JacobianFactor expected(0, A0, 1, A1, b, noiseModel::Diagonal::Sigmas(sigmas, true));
EXPECT(assert_equal(expected, actual));
} }
#endif
/* ************************************************************************* */
TEST_UNSAFE(GaussianFactor, CombineAndEliminate)
{
Matrix A01 = Matrix_(3,3,
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0);
Vector b0 = Vector_(3, 1.5, 1.5, 1.5);
Vector s0 = Vector_(3, 1.6, 1.6, 1.6);
Matrix A10 = Matrix_(3,3,
2.0, 0.0, 0.0,
0.0, 2.0, 0.0,
0.0, 0.0, 2.0);
Matrix A11 = Matrix_(3,3,
-2.0, 0.0, 0.0,
0.0, -2.0, 0.0,
0.0, 0.0, -2.0);
Vector b1 = Vector_(3, 2.5, 2.5, 2.5);
Vector s1 = Vector_(3, 2.6, 2.6, 2.6);
Matrix A21 = Matrix_(3,3,
3.0, 0.0, 0.0,
0.0, 3.0, 0.0,
0.0, 0.0, 3.0);
Vector b2 = Vector_(3, 3.5, 3.5, 3.5);
Vector s2 = Vector_(3, 3.6, 3.6, 3.6);
GaussianFactorGraph gfg;
gfg.add(1, A01, b0, noiseModel::Diagonal::Sigmas(s0, true));
gfg.add(0, A10, 1, A11, b1, noiseModel::Diagonal::Sigmas(s1, true));
gfg.add(1, A21, b2, noiseModel::Diagonal::Sigmas(s2, true));
Matrix zero3x3 = zeros(3,3);
Matrix A0 = gtsam::stack(3, &A10, &zero3x3, &zero3x3);
Matrix A1 = gtsam::stack(3, &A11, &A01, &A21);
Vector b = gtsam::concatVectors(3, &b1, &b0, &b2);
Vector sigmas = gtsam::concatVectors(3, &s1, &s0, &s2);
JacobianFactor expectedFactor(0, A0, 1, A1, b, noiseModel::Diagonal::Sigmas(sigmas, true));
GaussianBayesNet expectedBN(*expectedFactor.eliminate(1));
pair<GaussianBayesNet::shared_ptr, JacobianFactor::shared_ptr> actualQR(JacobianFactor::CombineAndEliminate(
*gfg.dynamicCastFactors<FactorGraph<JacobianFactor> >(), 1));
EXPECT(assert_equal(expectedBN, *actualQR.first));
EXPECT(assert_equal(expectedFactor, *actualQR.second));
}
///* ************************************************************************* */
//TEST(GaussianFactor, operators )
//{
// Matrix I = eye(2);
// Vector b = Vector_(2,0.2,-0.1);
// JacobianFactor lf(_x1_, -I, _x2_, I, b, sigma0_1);
//
// VectorValues c;
// c.insert(_x1_,Vector_(2,10.,20.));
// c.insert(_x2_,Vector_(2,30.,60.));
//
// // test A*x
// Vector expectedE = Vector_(2,200.,400.), e = lf*c;
// EXPECT(assert_equal(expectedE,e));
//
// // test A^e
// VectorValues expectedX;
// expectedX.insert(_x1_,Vector_(2,-2000.,-4000.));
// expectedX.insert(_x2_,Vector_(2, 2000., 4000.));
// EXPECT(assert_equal(expectedX,lf^e));
//
// // test transposeMultiplyAdd
// VectorValues x;
// x.insert(_x1_,Vector_(2, 1.,2.));
// x.insert(_x2_,Vector_(2, 3.,4.));
// VectorValues expectedX2 = x + 0.1 * (lf^e);
// lf.transposeMultiplyAdd(0.1,e,x);
// EXPECT(assert_equal(expectedX2,x));
//}
///* ************************************************************************* */
//TEST( NonlinearFactorGraph, combine2){
// double sigma1 = 0.0957;
// Matrix A11(2,2);
// A11(0,0) = 1; A11(0,1) = 0;
// A11(1,0) = 0; A11(1,1) = 1;
// Vector b(2);
// b(0) = 2; b(1) = -1;
// JacobianFactor::shared_ptr f1(new JacobianFactor(_x1_, A11, b*sigma1, sharedSigma(2,sigma1)));
//
// double sigma2 = 0.5;
// A11(0,0) = 1; A11(0,1) = 0;
// A11(1,0) = 0; A11(1,1) = -1;
// b(0) = 4 ; b(1) = -5;
// JacobianFactor::shared_ptr f2(new JacobianFactor(_x1_, A11, b*sigma2, sharedSigma(2,sigma2)));
//
// double sigma3 = 0.25;
// A11(0,0) = 1; A11(0,1) = 0;
// A11(1,0) = 0; A11(1,1) = -1;
// b(0) = 3 ; b(1) = -88;
// JacobianFactor::shared_ptr f3(new JacobianFactor(_x1_, A11, b*sigma3, sharedSigma(2,sigma3)));
//
// // TODO: find a real sigma value for this example
// double sigma4 = 0.1;
// A11(0,0) = 6; A11(0,1) = 0;
// A11(1,0) = 0; A11(1,1) = 7;
// b(0) = 5 ; b(1) = -6;
// JacobianFactor::shared_ptr f4(new JacobianFactor(_x1_, A11*sigma4, b*sigma4, sharedSigma(2,sigma4)));
//
// vector<JacobianFactor::shared_ptr> lfg;
// lfg.push_back(f1);
// lfg.push_back(f2);
// lfg.push_back(f3);
// lfg.push_back(f4);
// JacobianFactor combined(lfg);
//
// Vector sigmas = Vector_(8, sigma1, sigma1, sigma2, sigma2, sigma3, sigma3, sigma4, sigma4);
// Matrix A22(8,2);
// A22(0,0) = 1; A22(0,1) = 0;
// A22(1,0) = 0; A22(1,1) = 1;
// A22(2,0) = 1; A22(2,1) = 0;
// A22(3,0) = 0; A22(3,1) = -1;
// A22(4,0) = 1; A22(4,1) = 0;
// A22(5,0) = 0; A22(5,1) = -1;
// A22(6,0) = 0.6; A22(6,1) = 0;
// A22(7,0) = 0; A22(7,1) = 0.7;
// Vector exb(8);
// exb(0) = 2*sigma1 ; exb(1) = -1*sigma1; exb(2) = 4*sigma2 ; exb(3) = -5*sigma2;
// exb(4) = 3*sigma3 ; exb(5) = -88*sigma3; exb(6) = 5*sigma4 ; exb(7) = -6*sigma4;
//
// vector<pair<Index, Matrix> > meas;
// meas.push_back(make_pair(_x1_, A22));
// JacobianFactor expected(meas, exb, sigmas);
// EXPECT(assert_equal(expected,combined));
//}
//
///* ************************************************************************* */
//TEST(GaussianFactor, linearFactorN){
// Matrix I = eye(2);
// vector<JacobianFactor::shared_ptr> f;
// SharedDiagonal model = sharedSigma(2,1.0);
// f.push_back(JacobianFactor::shared_ptr(new JacobianFactor(_x1_, I, Vector_(2,
// 10.0, 5.0), model)));
// f.push_back(JacobianFactor::shared_ptr(new JacobianFactor(_x1_, -10 * I,
// _x2_, 10 * I, Vector_(2, 1.0, -2.0), model)));
// f.push_back(JacobianFactor::shared_ptr(new JacobianFactor(_x2_, -10 * I,
// _x3_, 10 * I, Vector_(2, 1.5, -1.5), model)));
// f.push_back(JacobianFactor::shared_ptr(new JacobianFactor(_x3_, -10 * I,
// _x4_, 10 * I, Vector_(2, 2.0, -1.0), model)));
//
// JacobianFactor combinedFactor(f);
//
// vector<pair<Index, Matrix> > combinedMeasurement;
// combinedMeasurement.push_back(make_pair(_x1_, Matrix_(8,2,
// 1.0, 0.0,
// 0.0, 1.0,
// -10.0, 0.0,
// 0.0,-10.0,
// 0.0, 0.0,
// 0.0, 0.0,
// 0.0, 0.0,
// 0.0, 0.0)));
// combinedMeasurement.push_back(make_pair(_x2_, Matrix_(8,2,
// 0.0, 0.0,
// 0.0, 0.0,
// 10.0, 0.0,
// 0.0, 10.0,
// -10.0, 0.0,
// 0.0,-10.0,
// 0.0, 0.0,
// 0.0, 0.0)));
// combinedMeasurement.push_back(make_pair(_x3_, Matrix_(8,2,
// 0.0, 0.0,
// 0.0, 0.0,
// 0.0, 0.0,
// 0.0, 0.0,
// 10.0, 0.0,
// 0.0, 10.0,
// -10.0, 0.0,
// 0.0,-10.0)));
// combinedMeasurement.push_back(make_pair(_x4_, Matrix_(8,2,
// 0.0, 0.0,
// 0.0, 0.0,
// 0.0, 0.0,
// 0.0, 0.0,
// 0.0, 0.0,
// 0.0, 0.0,
// 10.0, 0.0,
// 0.0,10.0)));
// Vector b = Vector_(8,
// 10.0, 5.0, 1.0, -2.0, 1.5, -1.5, 2.0, -1.0);
//
// Vector sigmas = repeat(8,1.0);
// JacobianFactor expected(combinedMeasurement, b, sigmas);
// EXPECT(assert_equal(expected,combinedFactor));
//}
/* ************************************************************************* */ /* ************************************************************************* */
TEST(GaussianFactor, eliminate2 ) TEST(GaussianFactor, eliminate2 )
{ {
@ -451,155 +168,6 @@ TEST(GaussianFactor, eliminate2 )
EXPECT(assert_equal(expectedLF,*actualLF_QR,1e-3)); EXPECT(assert_equal(expectedLF,*actualLF_QR,1e-3));
} }
/* ************************************************************************* */
TEST(GaussianFactor, eliminateFrontals)
{
// Augmented Ab test case for whole factor graph
Matrix Ab = Matrix_(14,11,
4., 0., 1., 4., 1., 0., 3., 6., 8., 8., 1.,
9., 2., 0., 1., 6., 3., 9., 6., 6., 9., 4.,
5., 3., 7., 9., 5., 5., 9., 1., 3., 7., 0.,
5., 6., 5., 7., 9., 4., 0., 1., 1., 3., 5.,
0., 0., 4., 5., 6., 6., 7., 9., 4., 5., 4.,
0., 0., 9., 4., 8., 6., 2., 1., 4., 1., 6.,
0., 0., 6., 0., 4., 2., 4., 0., 1., 9., 6.,
0., 0., 6., 6., 4., 4., 5., 5., 5., 8., 6.,
0., 0., 0., 0., 8., 0., 9., 8., 2., 8., 0.,
0., 0., 0., 0., 0., 9., 4., 6., 3., 2., 0.,
0., 0., 0., 0., 1., 1., 9., 1., 5., 5., 3.,
0., 0., 0., 0., 1., 1., 3., 3., 2., 0., 5.,
0., 0., 0., 0., 0., 0., 0., 0., 2., 4., 6.,
0., 0., 0., 0., 0., 0., 0., 0., 6., 3., 4.);
// Create first factor (from pieces of Ab)
list<pair<Index, Matrix> > terms1;
terms1 +=
make_pair(3, Matrix(ublas::project(Ab, ublas::range(0,4), ublas::range(0,2)))),
make_pair(5, ublas::project(Ab, ublas::range(0,4), ublas::range(2,4))),
make_pair(7, ublas::project(Ab, ublas::range(0,4), ublas::range(4,6))),
make_pair(9, ublas::project(Ab, ublas::range(0,4), ublas::range(6,8))),
make_pair(11, ublas::project(Ab, ublas::range(0,4), ublas::range(8,10)));
Vector b1 = ublas::project(ublas::column(Ab, 10), ublas::range(0,4));
JacobianFactor::shared_ptr factor1(new JacobianFactor(terms1, b1, sharedSigma(4, 0.5)));
// Create second factor
list<pair<Index, Matrix> > terms2;
terms2 +=
make_pair(5, ublas::project(Ab, ublas::range(4,8), ublas::range(2,4))),
make_pair(7, ublas::project(Ab, ublas::range(4,8), ublas::range(4,6))),
make_pair(9, ublas::project(Ab, ublas::range(4,8), ublas::range(6,8))),
make_pair(11, ublas::project(Ab, ublas::range(4,8), ublas::range(8,10)));
Vector b2 = ublas::project(ublas::column(Ab, 10), ublas::range(4,8));
JacobianFactor::shared_ptr factor2(new JacobianFactor(terms2, b2, sharedSigma(4, 0.5)));
// Create third factor
list<pair<Index, Matrix> > terms3;
terms3 +=
make_pair(7, ublas::project(Ab, ublas::range(8,12), ublas::range(4,6))),
make_pair(9, ublas::project(Ab, ublas::range(8,12), ublas::range(6,8))),
make_pair(11, ublas::project(Ab, ublas::range(8,12), ublas::range(8,10)));
Vector b3 = ublas::project(ublas::column(Ab, 10), ublas::range(8,12));
JacobianFactor::shared_ptr factor3(new JacobianFactor(terms3, b3, sharedSigma(4, 0.5)));
// Create fourth factor
list<pair<Index, Matrix> > terms4;
terms4 +=
make_pair(11, ublas::project(Ab, ublas::range(12,14), ublas::range(8,10)));
Vector b4 = ublas::project(ublas::column(Ab, 10), ublas::range(12,14));
JacobianFactor::shared_ptr factor4(new JacobianFactor(terms4, b4, sharedSigma(2, 0.5)));
// Create factor graph
GaussianFactorGraph factors;
factors.push_back(factor1);
factors.push_back(factor2);
factors.push_back(factor3);
factors.push_back(factor4);
// Create combined factor
JacobianFactor combined(*JacobianFactor::Combine(*factors.dynamicCastFactors<FactorGraph<JacobianFactor> >(), VariableSlots(factors)));
// Copies factors as they will be eliminated in place
JacobianFactor actualFactor_QR = combined;
JacobianFactor actualFactor_Chol = combined;
// Expected augmented matrix, both GaussianConditional (first 6 rows) and remaining factor (next 4 rows)
Matrix R = 2.0*Matrix_(11,11,
-12.1244, -5.1962, -5.2786, -8.6603, -10.5573, -5.9385, -11.3820, -7.2581, -8.7427, -13.4440, -5.3611,
0., 4.6904, 5.0254, 5.5432, 5.5737, 3.0153, -3.0153, -3.5635, -3.9290, -2.7412, 2.1625,
0., 0., -13.8160, -8.7166, -10.2245, -8.8666, -8.7632, -5.2544, -6.9192, -10.5537, -9.3250,
0., 0., 0., 6.5033, -1.1453, 1.3179, 2.5768, 5.5503, 3.6524, 1.3491, -2.5676,
0., 0., 0., 0., -9.6242, -2.1148, -9.3509, -10.5846, -3.5366, -6.8561, -3.2277,
0., 0., 0., 0., 0., 9.7887, 4.3551, 5.7572, 2.7876, 0.1611, 1.1769,
0., 0., 0., 0., 0., 0., -11.1139, -0.6521, -2.1943, -7.5529, -0.9081,
0., 0., 0., 0., 0., 0., 0., -4.6479, -1.9367, -6.5170, -3.7685,
0., 0., 0., 0., 0., 0., 0., 0., 8.2503, 3.3757, 6.8476,
0., 0., 0., 0., 0., 0., 0., 0., 0., -5.7095, -0.0090,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., -7.1635);
// Expected conditional on first variable from first 2 rows of R
Matrix R1 = ublas::project(R, ublas::range(0,2), ublas::range(0,2));
list<pair<Index, Matrix> > cterms1;
cterms1 +=
make_pair(5, ublas::project(R, ublas::range(0,2), ublas::range(2,4))),
make_pair(7, ublas::project(R, ublas::range(0,2), ublas::range(4,6))),
make_pair(9, ublas::project(R, ublas::range(0,2), ublas::range(6,8))),
make_pair(11, ublas::project(R, ublas::range(0,2), ublas::range(8,10)));
Vector d1 = ublas::project(ublas::column(R, 10), ublas::range(0,2));
GaussianConditional::shared_ptr cond1(new GaussianConditional(3, d1, R1, cterms1, ones(2)));
// Expected conditional on second variable from next 2 rows of R
Matrix R2 = ublas::project(R, ublas::range(2,4), ublas::range(2,4));
list<pair<Index, Matrix> > cterms2;
cterms2 +=
make_pair(7, ublas::project(R, ublas::range(2,4), ublas::range(4,6))),
make_pair(9, ublas::project(R, ublas::range(2,4), ublas::range(6,8))),
make_pair(11, ublas::project(R, ublas::range(2,4), ublas::range(8,10)));
Vector d2 = ublas::project(ublas::column(R, 10), ublas::range(2,4));
GaussianConditional::shared_ptr cond2(new GaussianConditional(5, d2, R2, cterms2, ones(2)));
// Expected conditional on third variable from next 2 rows of R
Matrix R3 = ublas::project(R, ublas::range(4,6), ublas::range(4,6));
list<pair<Index, Matrix> > cterms3;
cterms3 +=
make_pair(9, ublas::project(R, ublas::range(4,6), ublas::range(6,8))),
make_pair(11, ublas::project(R, ublas::range(4,6), ublas::range(8,10)));
Vector d3 = ublas::project(ublas::column(R, 10), ublas::range(4,6));
GaussianConditional::shared_ptr cond3(new GaussianConditional(7, d3, R3, cterms3, ones(2)));
// Create expected Bayes net fragment from three conditionals above
GaussianBayesNet expectedFragment;
expectedFragment.push_back(cond1);
expectedFragment.push_back(cond2);
expectedFragment.push_back(cond3);
// Get expected matrices for remaining factor
Matrix Ae1 = ublas::project(R, ublas::range(6,10), ublas::range(6,8));
Matrix Ae2 = ublas::project(R, ublas::range(6,10), ublas::range(8,10));
Vector be = ublas::project(ublas::column(R, 10), ublas::range(6,10));
// Eliminate (3 frontal variables, 6 scalar columns) using QR !!!!
GaussianBayesNet actualFragment_QR = *actualFactor_QR.eliminate(3);
EXPECT(assert_equal(expectedFragment, actualFragment_QR, 0.001));
EXPECT(assert_equal(size_t(2), actualFactor_QR.keys().size()));
EXPECT(assert_equal(Index(9), actualFactor_QR.keys()[0]));
EXPECT(assert_equal(Index(11), actualFactor_QR.keys()[1]));
EXPECT(assert_equal(Ae1, actualFactor_QR.getA(actualFactor_QR.begin()), 0.001));
EXPECT(assert_equal(Ae2, actualFactor_QR.getA(actualFactor_QR.begin()+1), 0.001));
EXPECT(assert_equal(be, actualFactor_QR.getb(), 0.001));
EXPECT(assert_equal(ones(4), actualFactor_QR.get_model()->sigmas(), 0.001));
// Eliminate (3 frontal variables, 6 scalar columns) using Cholesky !!!!
// GaussianBayesNet actualFragment_Chol = *actualFactor_Chol.eliminate(3, JacobianFactor::SOLVE_CHOLESKY);
// EXPECT(assert_equal(expectedFragment, actualFragment_Chol, 0.001));
// EXPECT(assert_equal(size_t(2), actualFactor_Chol.keys().size()));
// EXPECT(assert_equal(Index(9), actualFactor_Chol.keys()[0]));
// EXPECT(assert_equal(Index(11), actualFactor_Chol.keys()[1]));
// EXPECT(assert_equal(Ae1, actualFactor_Chol.getA(actualFactor_Chol.begin()), 0.001)); ////
// EXPECT(linear_dependent(Ae2, actualFactor_Chol.getA(actualFactor_Chol.begin()+1), 0.001));
// EXPECT(assert_equal(be, actualFactor_Chol.getb(), 0.001)); ////
// EXPECT(assert_equal(ones(4), actualFactor_Chol.get_sigmas(), 0.001));
}
/* ************************************************************************* */ /* ************************************************************************* */
TEST(GaussianFactor, default_error ) TEST(GaussianFactor, default_error )
{ {
@ -610,28 +178,29 @@ TEST(GaussianFactor, default_error )
EXPECT(actual==0.0); EXPECT(actual==0.0);
} }
////* ************************************************************************* */ //* ************************************************************************* */
//TEST(GaussianFactor, eliminate_empty ) #ifdef BROKEN
//{ TEST(GaussianFactor, eliminate_empty )
// // create an empty factor {
// JacobianFactor f; // create an empty factor
// JacobianFactor f;
// // eliminate the empty factor
// GaussianConditional::shared_ptr actualCG;
// JacobianFactor::shared_ptr actualLF(new JacobianFactor(f));
// actualCG = actualLF->eliminateFirst();
//
// // expected Conditional Gaussian is just a parent-less node with P(x)=1
// GaussianConditional expectedCG(_x2_);
//
// // expected remaining factor is still empty :-)
// JacobianFactor expectedLF;
//
// // check if the result matches
// EXPECT(actualCG->equals(expectedCG));
// EXPECT(actualLF->equals(expectedLF));
//}
// eliminate the empty factor
GaussianConditional::shared_ptr actualCG;
JacobianFactor::shared_ptr actualLF(new JacobianFactor(f));
actualCG = actualLF->eliminateFirst();
// expected Conditional Gaussian is just a parent-less node with P(x)=1
GaussianConditional expectedCG(_x2_);
// expected remaining factor is still empty :-)
JacobianFactor expectedLF;
// check if the result matches
EXPECT(actualCG->equals(expectedCG));
EXPECT(actualLF->equals(expectedLF));
}
#endif
//* ************************************************************************* */ //* ************************************************************************* */
TEST(GaussianFactor, empty ) TEST(GaussianFactor, empty )
{ {
@ -648,29 +217,6 @@ void print(const list<T>& i) {
cout << endl; cout << endl;
} }
///* ************************************************************************* */
//TEST(GaussianFactor, tally_separator )
//{
// JacobianFactor f(_x1_, eye(2), _x2_, eye(2), _l1_, eye(2), ones(2), sigma0_1);
//
// std::set<Index> act1, act2, act3;
// f.tally_separator(_x1_, act1);
// f.tally_separator(_x2_, act2);
// f.tally_separator(_l1_, act3);
//
// EXPECT(act1.size() == 2);
// EXPECT(act1.count(_x2_) == 1);
// EXPECT(act1.count(_l1_) == 1);
//
// EXPECT(act2.size() == 2);
// EXPECT(act2.count(_x1_) == 1);
// EXPECT(act2.count(_l1_) == 1);
//
// EXPECT(act3.size() == 2);
// EXPECT(act3.count(_x1_) == 1);
// EXPECT(act3.count(_x2_) == 1);
//}
/* ************************************************************************* */ /* ************************************************************************* */
TEST(GaussianFactor, CONSTRUCTOR_GaussianConditional ) TEST(GaussianFactor, CONSTRUCTOR_GaussianConditional )
{ {
@ -690,22 +236,6 @@ TEST(GaussianFactor, CONSTRUCTOR_GaussianConditional )
EXPECT(assert_equal(expectedLF,actualLF,1e-5)); EXPECT(assert_equal(expectedLF,actualLF,1e-5));
} }
///* ************************************************************************* */
//TEST(GaussianFactor, CONSTRUCTOR_GaussianConditionalConstrained )
//{
// Matrix Ax = eye(2);
// Vector b = Vector_(2, 3.0, 5.0);
// SharedDiagonal noisemodel = noiseModel::Constrained::All(2);
// JacobianFactor::shared_ptr expected(new JacobianFactor(_x0_, Ax, b, noisemodel));
// GaussianFactorGraph graph;
// graph.push_back(expected);
//
// GaussianConditional::shared_ptr conditional = GaussianSequentialSolver::EliminateUntil(graph,_x0_+1);
// JacobianFactor actual(*conditional);
//
// EXPECT(assert_equal(*expected, actual));
//}
/* ************************************************************************* */ /* ************************************************************************* */
TEST ( JacobianFactor, constraint_eliminate1 ) TEST ( JacobianFactor, constraint_eliminate1 )
{ {
@ -768,103 +298,6 @@ TEST ( JacobianFactor, constraint_eliminate2 )
EXPECT(assert_equal(expectedCG, *actualCG, 1e-4)); EXPECT(assert_equal(expectedCG, *actualCG, 1e-4));
} }
/* ************************************************************************* */
TEST(GaussianFactor, permuteWithInverse)
{
Matrix A1 = Matrix_(2,2,
1.0, 2.0,
3.0, 4.0);
Matrix A2 = Matrix_(2,1,
5.0,
6.0);
Matrix A3 = Matrix_(2,3,
7.0, 8.0, 9.0,
10.0, 11.0, 12.0);
Vector b = Vector_(2, 13.0, 14.0);
Permutation inversePermutation(6);
inversePermutation[0] = 5;
inversePermutation[1] = 4;
inversePermutation[2] = 3;
inversePermutation[3] = 2;
inversePermutation[4] = 1;
inversePermutation[5] = 0;
JacobianFactor actual(1, A1, 3, A2, 5, A3, b, sharedSigma(2, 1.0));
GaussianFactorGraph actualFG; actualFG.push_back(JacobianFactor::shared_ptr(new JacobianFactor(actual)));
VariableIndex actualIndex(actualFG);
actual.permuteWithInverse(inversePermutation);
// actualIndex.permute(*inversePermutation.inverse());
JacobianFactor expected(0, A3, 2, A2, 4, A1, b, sharedSigma(2, 1.0));
GaussianFactorGraph expectedFG; expectedFG.push_back(JacobianFactor::shared_ptr(new JacobianFactor(expected)));
// GaussianVariableIndex expectedIndex(expectedFG);
EXPECT(assert_equal(expected, actual));
// // todo: fix this!!! VariableIndex should not hold slots
// for(Index j=0; j<actualIndex.size(); ++j) {
// BOOST_FOREACH( GaussianVariableIndex::mapped_factor_type& factor_pos, actualIndex[j]) {
// factor_pos.variablePosition = numeric_limits<Index>::max(); }
// }
// for(Index j=0; j<expectedIndex.size(); ++j) {
// BOOST_FOREACH( GaussianVariableIndex::mapped_factor_type& factor_pos, expectedIndex[j]) {
// factor_pos.variablePosition = numeric_limits<Index>::max(); }
// }
// EXPECT(assert_equal(expectedIndex, actualIndex));
}
///* ************************************************************************* */
//TEST(GaussianFactor, erase)
//{
// Vector b = Vector_(3, 1., 2., 3.);
// SharedDiagonal noise = noiseModel::Diagonal::Sigmas(Vector_(3,1.,1.,1.));
// std::list<std::pair<Index, Matrix> > terms;
// terms.push_back(make_pair(_x0_, eye(2)));
// terms.push_back(make_pair(_x1_, 2.*eye(2)));
//
// JacobianFactor actual(terms, b, noise);
// int erased = actual.erase_A(_x0_);
//
// LONGS_EQUAL(1, erased);
// JacobianFactor expected(_x1_, 2.*eye(2), b, noise);
// EXPECT(assert_equal(expected, actual));
//}
///* ************************************************************************* */
//TEST(GaussianFactor, eliminateMatrix)
//{
// Matrix Ab = Matrix_(3, 4,
// 1., 2., 0., 3.,
// 0., 4., 5., 6.,
// 0., 0., 7., 8.);
// SharedDiagonal model(Vector_(3, 0.5, 0.5, 0.5));
// Ordering frontals; frontals += _x1_, _x2_;
// Ordering separator; separator += _x3_;
// Dimensions dimensions;
// dimensions.insert(make_pair(_x1_, 1));
// dimensions.insert(make_pair(_x2_, 1));
// dimensions.insert(make_pair(_x3_, 1));
//
// JacobianFactor::shared_ptr factor;
// GaussianBayesNet bn;
// boost::tie(bn, factor) =
// JacobianFactor::eliminateMatrix(Ab, NULL, model, frontals, separator, dimensions);
//
// GaussianBayesNet bn_expected;
// GaussianBayesNet::sharedConditional conditional1(new GaussianConditional(_x1_, Vector_(1, 6.), Matrix_(1, 1, 2.),
// _x2_, Matrix_(1, 1, 4.), _x3_, Matrix_(1, 1, 0.), Vector_(1, 1.)));
// GaussianBayesNet::sharedConditional conditional2(new GaussianConditional(_x2_, Vector_(1, 12.), Matrix_(1, 1, 8.),
// _x3_, Matrix_(1, 1, 10.), Vector_(1, 1.)));
// bn_expected.push_back(conditional1);
// bn_expected.push_back(conditional2);
// EXPECT(assert_equal(bn_expected, bn));
//
// JacobianFactor factor_expected(_x3_, Matrix_(1, 1, 14.), Vector_(1, 16.), SharedDiagonal(Vector_(1, 1.)));
// EXPECT(assert_equal(factor_expected, *factor));
//}
/* ************************************************************************* */ /* ************************************************************************* */
int main() { TestResult tr; return TestRegistry::runAllTests(tr);} int main() { TestResult tr; return TestRegistry::runAllTests(tr);}
/* ************************************************************************* */ /* ************************************************************************* */

View File

@ -0,0 +1,536 @@
/* ----------------------------------------------------------------------------
* GTSAM Copyright 2010, Georgia Tech Research Corporation,
* Atlanta, Georgia 30332-0415
* All Rights Reserved
* Authors: Frank Dellaert, et al. (see THANKS for the full author list)
* See LICENSE for the license information
* -------------------------------------------------------------------------- */
/**
* @file testGaussianFactor.cpp
* @brief Unit tests for Linear Factor
* @author Christian Potthast
* @author Frank Dellaert
**/
#include <boost/assign/std/list.hpp> // for operator +=
using namespace boost::assign;
#include <gtsam/base/TestableAssertions.h>
#include <CppUnitLite/TestHarness.h>
#include <gtsam/base/debug.h>
#include <gtsam/inference/VariableSlots.h>
#include <gtsam/inference/VariableIndex.h>
#include <gtsam/linear/GaussianFactorGraph.h>
using namespace std;
using namespace gtsam;
using namespace boost;
namespace ublas = boost::numeric::ublas;
static const Index _x0_=0, _x1_=1, _x2_=2, _x3_=3, _x4_=4, _x_=5, _y_=6, _l1_=7, _l11_=8;
static SharedDiagonal
sigma0_1 = sharedSigma(2,0.1), sigma_02 = sharedSigma(2,0.2),
constraintModel = noiseModel::Constrained::All(2);
/* ************************************************************************* */
#ifdef BROKEN
TEST(GaussianFactor, Combine)
{
Matrix A00 = Matrix_(3,3,
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0);
Vector b0 = Vector_(3, 0.0, 0.0, 0.0);
Vector s0 = Vector_(3, 0.0, 0.0, 0.0);
Matrix A10 = Matrix_(3,3,
0.0, -2.0, -4.0,
2.0, 0.0, 2.0,
0.0, 0.0, -10.0);
Matrix A11 = Matrix_(3,3,
2.0, 0.0, 0.0,
0.0, 2.0, 0.0,
0.0, 0.0, 10.0);
Vector b1 = Vector_(3, 6.0, 2.0, 0.0);
Vector s1 = Vector_(3, 1.0, 1.0, 1.0);
Matrix A20 = Matrix_(3,3,
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0);
Vector b2 = Vector_(3, 0.0, 0.0, 0.0);
Vector s2 = Vector_(3, 100.0, 100.0, 100.0);
GaussianFactorGraph gfg;
gfg.add(0, A00, b0, noiseModel::Diagonal::Sigmas(s0, true));
gfg.add(0, A10, 1, A11, b1, noiseModel::Diagonal::Sigmas(s1, true));
gfg.add(0, A20, b2, noiseModel::Diagonal::Sigmas(s2, true));
GaussianVariableIndex varindex(gfg);
vector<size_t> factors(3); factors[0]=0; factors[1]=1; factors[2]=2;
vector<size_t> variables(2); variables[0]=0; variables[1]=1;
vector<vector<size_t> > variablePositions(3);
variablePositions[0].resize(1); variablePositions[0][0]=0;
variablePositions[1].resize(2); variablePositions[1][0]=0; variablePositions[1][1]=1;
variablePositions[2].resize(1); variablePositions[2][0]=0;
JacobianFactor actual = *JacobianFactor::Combine(gfg, varindex, factors, variables, variablePositions);
Matrix zero3x3 = zeros(3,3);
Matrix A0 = gtsam::stack(3, &A00, &A10, &A20);
Matrix A1 = gtsam::stack(3, &zero3x3, &A11, &zero3x3);
Vector b = gtsam::concatVectors(3, &b0, &b1, &b2);
Vector sigmas = gtsam::concatVectors(3, &s0, &s1, &s2);
JacobianFactor expected(0, A0, 1, A1, b, noiseModel::Diagonal::Sigmas(sigmas, true));
EXPECT(assert_equal(expected, actual));
}
#endif
/* ************************************************************************* */
TEST(GaussianFactorGraph, Combine2)
{
Matrix A01 = Matrix_(3,3,
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0);
Vector b0 = Vector_(3, 1.5, 1.5, 1.5);
Vector s0 = Vector_(3, 1.6, 1.6, 1.6);
Matrix A10 = Matrix_(3,3,
2.0, 0.0, 0.0,
0.0, 2.0, 0.0,
0.0, 0.0, 2.0);
Matrix A11 = Matrix_(3,3,
-2.0, 0.0, 0.0,
0.0, -2.0, 0.0,
0.0, 0.0, -2.0);
Vector b1 = Vector_(3, 2.5, 2.5, 2.5);
Vector s1 = Vector_(3, 2.6, 2.6, 2.6);
Matrix A21 = Matrix_(3,3,
3.0, 0.0, 0.0,
0.0, 3.0, 0.0,
0.0, 0.0, 3.0);
Vector b2 = Vector_(3, 3.5, 3.5, 3.5);
Vector s2 = Vector_(3, 3.6, 3.6, 3.6);
GaussianFactorGraph gfg;
gfg.add(1, A01, b0, noiseModel::Diagonal::Sigmas(s0, true));
gfg.add(0, A10, 1, A11, b1, noiseModel::Diagonal::Sigmas(s1, true));
gfg.add(1, A21, b2, noiseModel::Diagonal::Sigmas(s2, true));
JacobianFactor actual = *CombineJacobians(*gfg.dynamicCastFactors<FactorGraph<
JacobianFactor> > (), VariableSlots(gfg));
Matrix zero3x3 = zeros(3,3);
Matrix A0 = gtsam::stack(3, &A10, &zero3x3, &zero3x3);
Matrix A1 = gtsam::stack(3, &A11, &A01, &A21);
Vector b = gtsam::concatVectors(3, &b1, &b0, &b2);
Vector sigmas = gtsam::concatVectors(3, &s1, &s0, &s2);
JacobianFactor expected(0, A0, 1, A1, b, noiseModel::Diagonal::Sigmas(sigmas, true));
EXPECT(assert_equal(expected, actual));
}
/* ************************************************************************* */
TEST_UNSAFE(GaussianFactor, CombineAndEliminate)
{
Matrix A01 = Matrix_(3,3,
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0);
Vector b0 = Vector_(3, 1.5, 1.5, 1.5);
Vector s0 = Vector_(3, 1.6, 1.6, 1.6);
Matrix A10 = Matrix_(3,3,
2.0, 0.0, 0.0,
0.0, 2.0, 0.0,
0.0, 0.0, 2.0);
Matrix A11 = Matrix_(3,3,
-2.0, 0.0, 0.0,
0.0, -2.0, 0.0,
0.0, 0.0, -2.0);
Vector b1 = Vector_(3, 2.5, 2.5, 2.5);
Vector s1 = Vector_(3, 2.6, 2.6, 2.6);
Matrix A21 = Matrix_(3,3,
3.0, 0.0, 0.0,
0.0, 3.0, 0.0,
0.0, 0.0, 3.0);
Vector b2 = Vector_(3, 3.5, 3.5, 3.5);
Vector s2 = Vector_(3, 3.6, 3.6, 3.6);
GaussianFactorGraph gfg;
gfg.add(1, A01, b0, noiseModel::Diagonal::Sigmas(s0, true));
gfg.add(0, A10, 1, A11, b1, noiseModel::Diagonal::Sigmas(s1, true));
gfg.add(1, A21, b2, noiseModel::Diagonal::Sigmas(s2, true));
Matrix zero3x3 = zeros(3,3);
Matrix A0 = gtsam::stack(3, &A10, &zero3x3, &zero3x3);
Matrix A1 = gtsam::stack(3, &A11, &A01, &A21);
Vector b = gtsam::concatVectors(3, &b1, &b0, &b2);
Vector sigmas = gtsam::concatVectors(3, &s1, &s0, &s2);
JacobianFactor expectedFactor(0, A0, 1, A1, b, noiseModel::Diagonal::Sigmas(sigmas, true));
GaussianBayesNet expectedBN(*expectedFactor.eliminate(1));
GaussianBayesNet::shared_ptr actualBN;
GaussianFactor::shared_ptr actualFactor;
boost::tie(actualBN, actualFactor) = //
EliminateQR(*gfg.dynamicCastFactors<FactorGraph<JacobianFactor> > (), 1);
JacobianFactor::shared_ptr actualJacobian = boost::dynamic_pointer_cast<
JacobianFactor>(actualFactor);
EXPECT(assert_equal(expectedBN, *actualBN));
EXPECT(assert_equal(expectedFactor, *actualJacobian));
}
/* ************************************************************************* */
#ifdef BROKEN
TEST( NonlinearFactorGraph, combine2){
double sigma1 = 0.0957;
Matrix A11(2,2);
A11(0,0) = 1; A11(0,1) = 0;
A11(1,0) = 0; A11(1,1) = 1;
Vector b(2);
b(0) = 2; b(1) = -1;
JacobianFactor::shared_ptr f1(new JacobianFactor(_x1_, A11, b*sigma1, sharedSigma(2,sigma1)));
double sigma2 = 0.5;
A11(0,0) = 1; A11(0,1) = 0;
A11(1,0) = 0; A11(1,1) = -1;
b(0) = 4 ; b(1) = -5;
JacobianFactor::shared_ptr f2(new JacobianFactor(_x1_, A11, b*sigma2, sharedSigma(2,sigma2)));
double sigma3 = 0.25;
A11(0,0) = 1; A11(0,1) = 0;
A11(1,0) = 0; A11(1,1) = -1;
b(0) = 3 ; b(1) = -88;
JacobianFactor::shared_ptr f3(new JacobianFactor(_x1_, A11, b*sigma3, sharedSigma(2,sigma3)));
// TODO: find a real sigma value for this example
double sigma4 = 0.1;
A11(0,0) = 6; A11(0,1) = 0;
A11(1,0) = 0; A11(1,1) = 7;
b(0) = 5 ; b(1) = -6;
JacobianFactor::shared_ptr f4(new JacobianFactor(_x1_, A11*sigma4, b*sigma4, sharedSigma(2,sigma4)));
vector<JacobianFactor::shared_ptr> lfg;
lfg.push_back(f1);
lfg.push_back(f2);
lfg.push_back(f3);
lfg.push_back(f4);
JacobianFactor combined(lfg);
Vector sigmas = Vector_(8, sigma1, sigma1, sigma2, sigma2, sigma3, sigma3, sigma4, sigma4);
Matrix A22(8,2);
A22(0,0) = 1; A22(0,1) = 0;
A22(1,0) = 0; A22(1,1) = 1;
A22(2,0) = 1; A22(2,1) = 0;
A22(3,0) = 0; A22(3,1) = -1;
A22(4,0) = 1; A22(4,1) = 0;
A22(5,0) = 0; A22(5,1) = -1;
A22(6,0) = 0.6; A22(6,1) = 0;
A22(7,0) = 0; A22(7,1) = 0.7;
Vector exb(8);
exb(0) = 2*sigma1 ; exb(1) = -1*sigma1; exb(2) = 4*sigma2 ; exb(3) = -5*sigma2;
exb(4) = 3*sigma3 ; exb(5) = -88*sigma3; exb(6) = 5*sigma4 ; exb(7) = -6*sigma4;
vector<pair<Index, Matrix> > meas;
meas.push_back(make_pair(_x1_, A22));
JacobianFactor expected(meas, exb, sigmas);
EXPECT(assert_equal(expected,combined));
}
/* ************************************************************************* */
TEST(GaussianFactor, linearFactorN){
Matrix I = eye(2);
vector<JacobianFactor::shared_ptr> f;
SharedDiagonal model = sharedSigma(2,1.0);
f.push_back(JacobianFactor::shared_ptr(new JacobianFactor(_x1_, I, Vector_(2,
10.0, 5.0), model)));
f.push_back(JacobianFactor::shared_ptr(new JacobianFactor(_x1_, -10 * I,
_x2_, 10 * I, Vector_(2, 1.0, -2.0), model)));
f.push_back(JacobianFactor::shared_ptr(new JacobianFactor(_x2_, -10 * I,
_x3_, 10 * I, Vector_(2, 1.5, -1.5), model)));
f.push_back(JacobianFactor::shared_ptr(new JacobianFactor(_x3_, -10 * I,
_x4_, 10 * I, Vector_(2, 2.0, -1.0), model)));
JacobianFactor combinedFactor(f);
vector<pair<Index, Matrix> > combinedMeasurement;
combinedMeasurement.push_back(make_pair(_x1_, Matrix_(8,2,
1.0, 0.0,
0.0, 1.0,
-10.0, 0.0,
0.0,-10.0,
0.0, 0.0,
0.0, 0.0,
0.0, 0.0,
0.0, 0.0)));
combinedMeasurement.push_back(make_pair(_x2_, Matrix_(8,2,
0.0, 0.0,
0.0, 0.0,
10.0, 0.0,
0.0, 10.0,
-10.0, 0.0,
0.0,-10.0,
0.0, 0.0,
0.0, 0.0)));
combinedMeasurement.push_back(make_pair(_x3_, Matrix_(8,2,
0.0, 0.0,
0.0, 0.0,
0.0, 0.0,
0.0, 0.0,
10.0, 0.0,
0.0, 10.0,
-10.0, 0.0,
0.0,-10.0)));
combinedMeasurement.push_back(make_pair(_x4_, Matrix_(8,2,
0.0, 0.0,
0.0, 0.0,
0.0, 0.0,
0.0, 0.0,
0.0, 0.0,
0.0, 0.0,
10.0, 0.0,
0.0,10.0)));
Vector b = Vector_(8,
10.0, 5.0, 1.0, -2.0, 1.5, -1.5, 2.0, -1.0);
Vector sigmas = repeat(8,1.0);
JacobianFactor expected(combinedMeasurement, b, sigmas);
EXPECT(assert_equal(expected,combinedFactor));
}
#endif
/* ************************************************************************* */
TEST(GaussianFactor, eliminateFrontals)
{
// Augmented Ab test case for whole factor graph
Matrix Ab = Matrix_(14,11,
4., 0., 1., 4., 1., 0., 3., 6., 8., 8., 1.,
9., 2., 0., 1., 6., 3., 9., 6., 6., 9., 4.,
5., 3., 7., 9., 5., 5., 9., 1., 3., 7., 0.,
5., 6., 5., 7., 9., 4., 0., 1., 1., 3., 5.,
0., 0., 4., 5., 6., 6., 7., 9., 4., 5., 4.,
0., 0., 9., 4., 8., 6., 2., 1., 4., 1., 6.,
0., 0., 6., 0., 4., 2., 4., 0., 1., 9., 6.,
0., 0., 6., 6., 4., 4., 5., 5., 5., 8., 6.,
0., 0., 0., 0., 8., 0., 9., 8., 2., 8., 0.,
0., 0., 0., 0., 0., 9., 4., 6., 3., 2., 0.,
0., 0., 0., 0., 1., 1., 9., 1., 5., 5., 3.,
0., 0., 0., 0., 1., 1., 3., 3., 2., 0., 5.,
0., 0., 0., 0., 0., 0., 0., 0., 2., 4., 6.,
0., 0., 0., 0., 0., 0., 0., 0., 6., 3., 4.);
// Create first factor (from pieces of Ab)
list<pair<Index, Matrix> > terms1;
terms1 +=
make_pair(3, Matrix(ublas::project(Ab, ublas::range(0,4), ublas::range(0,2)))),
make_pair(5, ublas::project(Ab, ublas::range(0,4), ublas::range(2,4))),
make_pair(7, ublas::project(Ab, ublas::range(0,4), ublas::range(4,6))),
make_pair(9, ublas::project(Ab, ublas::range(0,4), ublas::range(6,8))),
make_pair(11, ublas::project(Ab, ublas::range(0,4), ublas::range(8,10)));
Vector b1 = ublas::project(ublas::column(Ab, 10), ublas::range(0,4));
JacobianFactor::shared_ptr factor1(new JacobianFactor(terms1, b1, sharedSigma(4, 0.5)));
// Create second factor
list<pair<Index, Matrix> > terms2;
terms2 +=
make_pair(5, ublas::project(Ab, ublas::range(4,8), ublas::range(2,4))),
make_pair(7, ublas::project(Ab, ublas::range(4,8), ublas::range(4,6))),
make_pair(9, ublas::project(Ab, ublas::range(4,8), ublas::range(6,8))),
make_pair(11, ublas::project(Ab, ublas::range(4,8), ublas::range(8,10)));
Vector b2 = ublas::project(ublas::column(Ab, 10), ublas::range(4,8));
JacobianFactor::shared_ptr factor2(new JacobianFactor(terms2, b2, sharedSigma(4, 0.5)));
// Create third factor
list<pair<Index, Matrix> > terms3;
terms3 +=
make_pair(7, ublas::project(Ab, ublas::range(8,12), ublas::range(4,6))),
make_pair(9, ublas::project(Ab, ublas::range(8,12), ublas::range(6,8))),
make_pair(11, ublas::project(Ab, ublas::range(8,12), ublas::range(8,10)));
Vector b3 = ublas::project(ublas::column(Ab, 10), ublas::range(8,12));
JacobianFactor::shared_ptr factor3(new JacobianFactor(terms3, b3, sharedSigma(4, 0.5)));
// Create fourth factor
list<pair<Index, Matrix> > terms4;
terms4 +=
make_pair(11, ublas::project(Ab, ublas::range(12,14), ublas::range(8,10)));
Vector b4 = ublas::project(ublas::column(Ab, 10), ublas::range(12,14));
JacobianFactor::shared_ptr factor4(new JacobianFactor(terms4, b4, sharedSigma(2, 0.5)));
// Create factor graph
GaussianFactorGraph factors;
factors.push_back(factor1);
factors.push_back(factor2);
factors.push_back(factor3);
factors.push_back(factor4);
// Create combined factor
JacobianFactor combined(*CombineJacobians(*factors.dynamicCastFactors<FactorGraph<
JacobianFactor> > (), VariableSlots(factors)));
// Copies factors as they will be eliminated in place
JacobianFactor actualFactor_QR = combined;
JacobianFactor actualFactor_Chol = combined;
// Expected augmented matrix, both GaussianConditional (first 6 rows) and remaining factor (next 4 rows)
Matrix R = 2.0*Matrix_(11,11,
-12.1244, -5.1962, -5.2786, -8.6603, -10.5573, -5.9385, -11.3820, -7.2581, -8.7427, -13.4440, -5.3611,
0., 4.6904, 5.0254, 5.5432, 5.5737, 3.0153, -3.0153, -3.5635, -3.9290, -2.7412, 2.1625,
0., 0., -13.8160, -8.7166, -10.2245, -8.8666, -8.7632, -5.2544, -6.9192, -10.5537, -9.3250,
0., 0., 0., 6.5033, -1.1453, 1.3179, 2.5768, 5.5503, 3.6524, 1.3491, -2.5676,
0., 0., 0., 0., -9.6242, -2.1148, -9.3509, -10.5846, -3.5366, -6.8561, -3.2277,
0., 0., 0., 0., 0., 9.7887, 4.3551, 5.7572, 2.7876, 0.1611, 1.1769,
0., 0., 0., 0., 0., 0., -11.1139, -0.6521, -2.1943, -7.5529, -0.9081,
0., 0., 0., 0., 0., 0., 0., -4.6479, -1.9367, -6.5170, -3.7685,
0., 0., 0., 0., 0., 0., 0., 0., 8.2503, 3.3757, 6.8476,
0., 0., 0., 0., 0., 0., 0., 0., 0., -5.7095, -0.0090,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., -7.1635);
// Expected conditional on first variable from first 2 rows of R
Matrix R1 = ublas::project(R, ublas::range(0,2), ublas::range(0,2));
list<pair<Index, Matrix> > cterms1;
cterms1 +=
make_pair(5, ublas::project(R, ublas::range(0,2), ublas::range(2,4))),
make_pair(7, ublas::project(R, ublas::range(0,2), ublas::range(4,6))),
make_pair(9, ublas::project(R, ublas::range(0,2), ublas::range(6,8))),
make_pair(11, ublas::project(R, ublas::range(0,2), ublas::range(8,10)));
Vector d1 = ublas::project(ublas::column(R, 10), ublas::range(0,2));
GaussianConditional::shared_ptr cond1(new GaussianConditional(3, d1, R1, cterms1, ones(2)));
// Expected conditional on second variable from next 2 rows of R
Matrix R2 = ublas::project(R, ublas::range(2,4), ublas::range(2,4));
list<pair<Index, Matrix> > cterms2;
cterms2 +=
make_pair(7, ublas::project(R, ublas::range(2,4), ublas::range(4,6))),
make_pair(9, ublas::project(R, ublas::range(2,4), ublas::range(6,8))),
make_pair(11, ublas::project(R, ublas::range(2,4), ublas::range(8,10)));
Vector d2 = ublas::project(ublas::column(R, 10), ublas::range(2,4));
GaussianConditional::shared_ptr cond2(new GaussianConditional(5, d2, R2, cterms2, ones(2)));
// Expected conditional on third variable from next 2 rows of R
Matrix R3 = ublas::project(R, ublas::range(4,6), ublas::range(4,6));
list<pair<Index, Matrix> > cterms3;
cterms3 +=
make_pair(9, ublas::project(R, ublas::range(4,6), ublas::range(6,8))),
make_pair(11, ublas::project(R, ublas::range(4,6), ublas::range(8,10)));
Vector d3 = ublas::project(ublas::column(R, 10), ublas::range(4,6));
GaussianConditional::shared_ptr cond3(new GaussianConditional(7, d3, R3, cterms3, ones(2)));
// Create expected Bayes net fragment from three conditionals above
GaussianBayesNet expectedFragment;
expectedFragment.push_back(cond1);
expectedFragment.push_back(cond2);
expectedFragment.push_back(cond3);
// Get expected matrices for remaining factor
Matrix Ae1 = ublas::project(R, ublas::range(6,10), ublas::range(6,8));
Matrix Ae2 = ublas::project(R, ublas::range(6,10), ublas::range(8,10));
Vector be = ublas::project(ublas::column(R, 10), ublas::range(6,10));
// Eliminate (3 frontal variables, 6 scalar columns) using QR !!!!
GaussianBayesNet actualFragment_QR = *actualFactor_QR.eliminate(3);
EXPECT(assert_equal(expectedFragment, actualFragment_QR, 0.001));
EXPECT(assert_equal(size_t(2), actualFactor_QR.keys().size()));
EXPECT(assert_equal(Index(9), actualFactor_QR.keys()[0]));
EXPECT(assert_equal(Index(11), actualFactor_QR.keys()[1]));
EXPECT(assert_equal(Ae1, actualFactor_QR.getA(actualFactor_QR.begin()), 0.001));
EXPECT(assert_equal(Ae2, actualFactor_QR.getA(actualFactor_QR.begin()+1), 0.001));
EXPECT(assert_equal(be, actualFactor_QR.getb(), 0.001));
EXPECT(assert_equal(ones(4), actualFactor_QR.get_model()->sigmas(), 0.001));
// Eliminate (3 frontal variables, 6 scalar columns) using Cholesky !!!!
#ifdef BROKEN
GaussianBayesNet actualFragment_Chol = *actualFactor_Chol.eliminate(3, JacobianFactor::SOLVE_CHOLESKY);
EXPECT(assert_equal(expectedFragment, actualFragment_Chol, 0.001));
EXPECT(assert_equal(size_t(2), actualFactor_Chol.keys().size()));
EXPECT(assert_equal(Index(9), actualFactor_Chol.keys()[0]));
EXPECT(assert_equal(Index(11), actualFactor_Chol.keys()[1]));
EXPECT(assert_equal(Ae1, actualFactor_Chol.getA(actualFactor_Chol.begin()), 0.001)); ////
EXPECT(linear_dependent(Ae2, actualFactor_Chol.getA(actualFactor_Chol.begin()+1), 0.001));
EXPECT(assert_equal(be, actualFactor_Chol.getb(), 0.001)); ////
EXPECT(assert_equal(ones(4), actualFactor_Chol.get_sigmas(), 0.001));
#endif
}
/* ************************************************************************* */
#ifdef BROKEN
TEST(GaussianFactor, CONSTRUCTOR_GaussianConditionalConstrained )
{
Matrix Ax = eye(2);
Vector b = Vector_(2, 3.0, 5.0);
SharedDiagonal noisemodel = noiseModel::Constrained::All(2);
JacobianFactor::shared_ptr expected(new JacobianFactor(_x0_, Ax, b, noisemodel));
GaussianFactorGraph graph;
graph.push_back(expected);
GaussianConditional::shared_ptr conditional = GaussianSequentialSolver::EliminateUntil(graph,_x0_+1);
JacobianFactor actual(*conditional);
EXPECT(assert_equal(*expected, actual));
}
#endif
/* ************************************************************************* */
TEST(GaussianFactor, permuteWithInverse)
{
Matrix A1 = Matrix_(2,2,
1.0, 2.0,
3.0, 4.0);
Matrix A2 = Matrix_(2,1,
5.0,
6.0);
Matrix A3 = Matrix_(2,3,
7.0, 8.0, 9.0,
10.0, 11.0, 12.0);
Vector b = Vector_(2, 13.0, 14.0);
Permutation inversePermutation(6);
inversePermutation[0] = 5;
inversePermutation[1] = 4;
inversePermutation[2] = 3;
inversePermutation[3] = 2;
inversePermutation[4] = 1;
inversePermutation[5] = 0;
JacobianFactor actual(1, A1, 3, A2, 5, A3, b, sharedSigma(2, 1.0));
GaussianFactorGraph actualFG; actualFG.push_back(JacobianFactor::shared_ptr(new JacobianFactor(actual)));
VariableIndex actualIndex(actualFG);
actual.permuteWithInverse(inversePermutation);
// actualIndex.permute(*inversePermutation.inverse());
JacobianFactor expected(0, A3, 2, A2, 4, A1, b, sharedSigma(2, 1.0));
GaussianFactorGraph expectedFG; expectedFG.push_back(JacobianFactor::shared_ptr(new JacobianFactor(expected)));
// GaussianVariableIndex expectedIndex(expectedFG);
EXPECT(assert_equal(expected, actual));
#ifdef BROKEN
// todo: fix this!!! VariableIndex should not hold slots
for(Index j=0; j<actualIndex.size(); ++j) {
BOOST_FOREACH( GaussianVariableIndex::mapped_factor_type& factor_pos, actualIndex[j]) {
factor_pos.variablePosition = numeric_limits<Index>::max(); }
}
for(Index j=0; j<expectedIndex.size(); ++j) {
BOOST_FOREACH( GaussianVariableIndex::mapped_factor_type& factor_pos, expectedIndex[j]) {
factor_pos.variablePosition = numeric_limits<Index>::max(); }
}
EXPECT(assert_equal(expectedIndex, actualIndex));
#endif
}
/* ************************************************************************* */
int main() { TestResult tr; return TestRegistry::runAllTests(tr);}
/* ************************************************************************* */

View File

@ -69,7 +69,7 @@ TEST( GaussianJunctionTree, eliminate )
{ {
GaussianFactorGraph fg = createChain(); GaussianFactorGraph fg = createChain();
GaussianJunctionTree junctionTree(fg); GaussianJunctionTree junctionTree(fg);
BayesTree<GaussianConditional>::sharedClique rootClique = junctionTree.eliminate(); BayesTree<GaussianConditional>::sharedClique rootClique = junctionTree.eliminate(&EliminateQR);
typedef BayesTree<GaussianConditional>::sharedConditional sharedConditional; typedef BayesTree<GaussianConditional>::sharedConditional sharedConditional;
Matrix two = Matrix_(1,1,2.); Matrix two = Matrix_(1,1,2.);
@ -90,7 +90,7 @@ TEST( GaussianJunctionTree, optimizeMultiFrontal )
GaussianFactorGraph fg = createChain(); GaussianFactorGraph fg = createChain();
GaussianJunctionTree tree(fg); GaussianJunctionTree tree(fg);
VectorValues actual = tree.optimize(); VectorValues actual = tree.optimize(&EliminateQR);
VectorValues expected(vector<size_t>(4,1)); VectorValues expected(vector<size_t>(4,1));
expected[x1] = Vector_(1, 0.); expected[x1] = Vector_(1, 0.);
expected[x2] = Vector_(1, 1.); expected[x2] = Vector_(1, 1.);

View File

@ -129,11 +129,13 @@ TEST(GaussianFactor, CombineAndEliminate)
JacobianFactor expectedFactor(0, A0, 1, A1, b, noiseModel::Diagonal::Sigmas(sigmas, true)); JacobianFactor expectedFactor(0, A0, 1, A1, b, noiseModel::Diagonal::Sigmas(sigmas, true));
GaussianBayesNet expectedBN(*expectedFactor.eliminate(1)); GaussianBayesNet expectedBN(*expectedFactor.eliminate(1));
pair<GaussianBayesNet::shared_ptr, HessianFactor::shared_ptr> actualCholesky(HessianFactor::CombineAndEliminate( GaussianFactorGraph::EliminationResult actualCholesky = EliminateCholesky(
*gfg.convertCastFactors<FactorGraph<HessianFactor> >(), 1)); *gfg.convertCastFactors<FactorGraph<HessianFactor> > (), 1);
HessianFactor::shared_ptr actualFactor = boost::dynamic_pointer_cast<
HessianFactor>(actualCholesky.second);
EXPECT(assert_equal(expectedBN, *actualCholesky.first, 1e-6)); EXPECT(assert_equal(expectedBN, *actualCholesky.first, 1e-6));
EXPECT(assert_equal(HessianFactor(expectedFactor), *actualCholesky.second, 1e-6)); EXPECT(assert_equal(HessianFactor(expectedFactor), *actualFactor, 1e-6));
} }
/* ************************************************************************* */ /* ************************************************************************* */
@ -177,8 +179,11 @@ TEST(GaussianFactor, eliminate2 )
HessianFactor::shared_ptr combinedLF_Chol(new HessianFactor(combined)); HessianFactor::shared_ptr combinedLF_Chol(new HessianFactor(combined));
FactorGraph<HessianFactor> combinedLFG_Chol; FactorGraph<HessianFactor> combinedLFG_Chol;
combinedLFG_Chol.push_back(combinedLF_Chol); combinedLFG_Chol.push_back(combinedLF_Chol);
pair<GaussianBayesNet::shared_ptr, HessianFactor::shared_ptr> actual_Chol =
HessianFactor::CombineAndEliminate(combinedLFG_Chol, 1); GaussianFactorGraph::EliminationResult actual_Chol = EliminateCholesky(
combinedLFG_Chol, 1);
HessianFactor::shared_ptr actualFactor = boost::dynamic_pointer_cast<
HessianFactor>(actual_Chol.second);
// create expected Conditional Gaussian // create expected Conditional Gaussian
double oldSigma = 0.0894427; // from when R was made unit double oldSigma = 0.0894427; // from when R was made unit
@ -203,7 +208,7 @@ TEST(GaussianFactor, eliminate2 )
)/sigma; )/sigma;
Vector b1 = Vector_(2,0.0,0.894427); Vector b1 = Vector_(2,0.0,0.894427);
JacobianFactor expectedLF(1, Bl1x1, b1, repeat(2,1.0)); JacobianFactor expectedLF(1, Bl1x1, b1, repeat(2,1.0));
EXPECT(assert_equal(HessianFactor(expectedLF), *actual_Chol.second, 1.5e-3)); EXPECT(assert_equal(HessianFactor(expectedLF), *actualFactor, 1.5e-3));
} }
/* ************************************************************************* */ /* ************************************************************************* */
@ -276,11 +281,13 @@ TEST(GaussianFactor, eliminateUnsorted) {
GaussianBayesNet::shared_ptr expected_bn; GaussianBayesNet::shared_ptr expected_bn;
GaussianFactor::shared_ptr expected_factor; GaussianFactor::shared_ptr expected_factor;
boost::tie(expected_bn, expected_factor) = GaussianFactor::CombineAndEliminate(sortedGraph, 1, GaussianFactor::SOLVE_PREFER_CHOLESKY); boost::tie(expected_bn, expected_factor) =
EliminatePreferCholesky(sortedGraph, 1);
GaussianBayesNet::shared_ptr actual_bn; GaussianBayesNet::shared_ptr actual_bn;
GaussianFactor::shared_ptr actual_factor; GaussianFactor::shared_ptr actual_factor;
boost::tie(actual_bn, actual_factor) = GaussianFactor::CombineAndEliminate(unsortedGraph, 1, GaussianFactor::SOLVE_PREFER_CHOLESKY); boost::tie(actual_bn, actual_factor) =
EliminatePreferCholesky(unsortedGraph, 1);
CHECK(assert_equal(*expected_bn, *actual_bn, 1e-10)); CHECK(assert_equal(*expected_bn, *actual_bn, 1e-10));
CHECK(assert_equal(*expected_factor, *actual_factor, 1e-10)); CHECK(assert_equal(*expected_factor, *actual_factor, 1e-10));

View File

@ -82,7 +82,7 @@ int main(int argc, char *argv[]) {
timer.restart(); timer.restart();
for(size_t trial=0; trial<nTrials; ++trial) { for(size_t trial=0; trial<nTrials; ++trial) {
// cout << "Trial " << trial << endl; // cout << "Trial " << trial << endl;
GaussianBayesNet::shared_ptr gbn(GaussianEliminationTree::Create(blockGfgs[trial])->eliminate()); GaussianBayesNet::shared_ptr gbn(GaussianEliminationTree::Create(blockGfgs[trial])->eliminate(&EliminateQR));
VectorValues soln(optimize(*gbn)); VectorValues soln(optimize(*gbn));
} }
blocksolve = timer.elapsed(); blocksolve = timer.elapsed();
@ -126,7 +126,7 @@ int main(int argc, char *argv[]) {
cout.flush(); cout.flush();
timer.restart(); timer.restart();
for(size_t trial=0; trial<nTrials; ++trial) { for(size_t trial=0; trial<nTrials; ++trial) {
GaussianBayesNet::shared_ptr gbn(GaussianEliminationTree::Create(combGfgs[trial])->eliminate()); GaussianBayesNet::shared_ptr gbn(GaussianEliminationTree::Create(combGfgs[trial])->eliminate(&EliminateQR));
VectorValues soln(optimize(*gbn)); VectorValues soln(optimize(*gbn));
} }
combsolve = timer.elapsed(); combsolve = timer.elapsed();

View File

@ -28,7 +28,8 @@ using namespace gtsam;
/* ************************************************************************* */ /* ************************************************************************* */
template<class Values> template<class Values>
void NonlinearISAM<Values>::update(const Factors& newFactors, const Values& initialValues) { void NonlinearISAM<Values>::update(const Factors& newFactors,
const Values& initialValues) {
if(newFactors.size() > 0) { if(newFactors.size() > 0) {

View File

@ -125,12 +125,12 @@ TEST( BayesTree, linear_smoother_shortcuts )
// Check the conditional P(Root|Root) // Check the conditional P(Root|Root)
GaussianBayesNet empty; GaussianBayesNet empty;
GaussianISAM::sharedClique R = bayesTree.root(); GaussianISAM::sharedClique R = bayesTree.root();
GaussianBayesNet actual1 = R->shortcut(R); GaussianBayesNet actual1 = GaussianISAM::shortcut(R,R);
CHECK(assert_equal(empty,actual1,tol)); CHECK(assert_equal(empty,actual1,tol));
// Check the conditional P(C2|Root) // Check the conditional P(C2|Root)
GaussianISAM::sharedClique C2 = bayesTree[ordering["x5"]]; GaussianISAM::sharedClique C2 = bayesTree[ordering["x5"]];
GaussianBayesNet actual2 = C2->shortcut(R); GaussianBayesNet actual2 = GaussianISAM::shortcut(C2,R);
CHECK(assert_equal(empty,actual2,tol)); CHECK(assert_equal(empty,actual2,tol));
// Check the conditional P(C3|Root) // Check the conditional P(C3|Root)
@ -139,7 +139,7 @@ TEST( BayesTree, linear_smoother_shortcuts )
GaussianBayesNet expected3; GaussianBayesNet expected3;
push_front(expected3,ordering["x5"], zero(2), eye(2)/sigma3, ordering["x6"], A56/sigma3, ones(2)); push_front(expected3,ordering["x5"], zero(2), eye(2)/sigma3, ordering["x6"], A56/sigma3, ones(2));
GaussianISAM::sharedClique C3 = bayesTree[ordering["x4"]]; GaussianISAM::sharedClique C3 = bayesTree[ordering["x4"]];
GaussianBayesNet actual3 = C3->shortcut(R); GaussianBayesNet actual3 = GaussianISAM::shortcut(C3,R);
CHECK(assert_equal(expected3,actual3,tol)); CHECK(assert_equal(expected3,actual3,tol));
// Check the conditional P(C4|Root) // Check the conditional P(C4|Root)
@ -148,7 +148,7 @@ TEST( BayesTree, linear_smoother_shortcuts )
GaussianBayesNet expected4; GaussianBayesNet expected4;
push_front(expected4, ordering["x4"], zero(2), eye(2)/sigma4, ordering["x6"], A46/sigma4, ones(2)); push_front(expected4, ordering["x4"], zero(2), eye(2)/sigma4, ordering["x6"], A46/sigma4, ones(2));
GaussianISAM::sharedClique C4 = bayesTree[ordering["x3"]]; GaussianISAM::sharedClique C4 = bayesTree[ordering["x3"]];
GaussianBayesNet actual4 = C4->shortcut(R); GaussianBayesNet actual4 = GaussianISAM::shortcut(C4,R);
CHECK(assert_equal(expected4,actual4,tol)); CHECK(assert_equal(expected4,actual4,tol));
} }
@ -264,19 +264,19 @@ TEST( BayesTree, balanced_smoother_shortcuts )
// Check the conditional P(Root|Root) // Check the conditional P(Root|Root)
GaussianBayesNet empty; GaussianBayesNet empty;
GaussianISAM::sharedClique R = bayesTree.root(); GaussianISAM::sharedClique R = bayesTree.root();
GaussianBayesNet actual1 = R->shortcut(R); GaussianBayesNet actual1 = GaussianISAM::shortcut(R,R);
CHECK(assert_equal(empty,actual1,tol)); CHECK(assert_equal(empty,actual1,tol));
// Check the conditional P(C2|Root) // Check the conditional P(C2|Root)
GaussianISAM::sharedClique C2 = bayesTree[ordering["x3"]]; GaussianISAM::sharedClique C2 = bayesTree[ordering["x3"]];
GaussianBayesNet actual2 = C2->shortcut(R); GaussianBayesNet actual2 = GaussianISAM::shortcut(C2,R);
CHECK(assert_equal(empty,actual2,tol)); CHECK(assert_equal(empty,actual2,tol));
// Check the conditional P(C3|Root), which should be equal to P(x2|x4) // Check the conditional P(C3|Root), which should be equal to P(x2|x4)
GaussianConditional::shared_ptr p_x2_x4 = chordalBayesNet[ordering["x2"]]; GaussianConditional::shared_ptr p_x2_x4 = chordalBayesNet[ordering["x2"]];
GaussianBayesNet expected3; expected3.push_back(p_x2_x4); GaussianBayesNet expected3; expected3.push_back(p_x2_x4);
GaussianISAM::sharedClique C3 = bayesTree[ordering["x1"]]; GaussianISAM::sharedClique C3 = bayesTree[ordering["x1"]];
GaussianBayesNet actual3 = C3->shortcut(R); GaussianBayesNet actual3 = GaussianISAM::shortcut(C3,R);
CHECK(assert_equal(expected3,actual3,tol)); CHECK(assert_equal(expected3,actual3,tol));
} }

View File

@ -91,7 +91,7 @@ TEST( GaussianJunctionTree, optimizeMultiFrontal )
// optimize the graph // optimize the graph
GaussianJunctionTree tree(fg); GaussianJunctionTree tree(fg);
VectorValues actual = tree.optimize(); VectorValues actual = tree.optimize(&EliminateQR);
// verify // verify
VectorValues expected(vector<size_t>(7,2)); // expected solution VectorValues expected(vector<size_t>(7,2)); // expected solution
@ -112,7 +112,7 @@ TEST( GaussianJunctionTree, optimizeMultiFrontal2)
// optimize the graph // optimize the graph
GaussianJunctionTree tree(fg); GaussianJunctionTree tree(fg);
VectorValues actual = tree.optimize(); VectorValues actual = tree.optimize(&EliminateQR);
// verify // verify
VectorValues expected = createCorrectDelta(ordering); // expected solution VectorValues expected = createCorrectDelta(ordering); // expected solution
@ -174,7 +174,7 @@ TEST(GaussianJunctionTree, slamlike) {
GaussianFactorGraph linearized = *fullgraph.linearize(init, ordering); GaussianFactorGraph linearized = *fullgraph.linearize(init, ordering);
GaussianJunctionTree gjt(linearized); GaussianJunctionTree gjt(linearized);
VectorValues deltaactual = gjt.optimize(); VectorValues deltaactual = gjt.optimize(&EliminateQR);
planarSLAM::Values actual = init.expmap(deltaactual, ordering); planarSLAM::Values actual = init.expmap(deltaactual, ordering);
GaussianBayesNet gbn = *GaussianSequentialSolver(linearized).eliminate(); GaussianBayesNet gbn = *GaussianSequentialSolver(linearized).eliminate();

View File

@ -56,7 +56,8 @@ TEST( SymbolicBayesNet, constructor )
SymbolicFactorGraph fg(factorGraph); SymbolicFactorGraph fg(factorGraph);
// eliminate it // eliminate it
SymbolicBayesNet actual = *SymbolicSequentialSolver(fg).eliminate(); SymbolicBayesNet actual = *SymbolicSequentialSolver(fg).eliminate(
&EliminateSymbolic);
CHECK(assert_equal(expected, actual)); CHECK(assert_equal(expected, actual));
} }

View File

@ -143,7 +143,7 @@ TEST( SymbolicFactorGraph, eliminate )
SymbolicFactorGraph fg(factorGraph); SymbolicFactorGraph fg(factorGraph);
// eliminate it // eliminate it
SymbolicBayesNet actual = *SymbolicSequentialSolver(fg).eliminate(); SymbolicBayesNet actual = *SymbolicSequentialSolver(fg).eliminate(&EliminateSymbolic);
CHECK(assert_equal(expected,actual)); CHECK(assert_equal(expected,actual));
} }