Caught some stragglers using boost::optional<Ordering>

release/4.3a0
Gerry Chen 2019-10-20 03:20:14 -04:00
parent 1733f3ac98
commit 4877bdb4f3
9 changed files with 131 additions and 42 deletions

View File

@ -46,16 +46,25 @@ DiscreteConditional::DiscreteConditional(const size_t nrFrontals,
/* ******************************************************************************** */ /* ******************************************************************************** */
DiscreteConditional::DiscreteConditional(const DecisionTreeFactor& joint, DiscreteConditional::DiscreteConditional(const DecisionTreeFactor& joint,
const DecisionTreeFactor& marginal, const boost::optional<Ordering>& orderedKeys) : const DecisionTreeFactor& marginal) :
BaseFactor( BaseFactor(
ISDEBUG("DiscreteConditional::COUNT") ? joint : joint / marginal), BaseConditional( ISDEBUG("DiscreteConditional::COUNT") ? joint : joint / marginal), BaseConditional(
joint.size()-marginal.size()) { joint.size()-marginal.size()) {
if (ISDEBUG("DiscreteConditional::DiscreteConditional")) if (ISDEBUG("DiscreteConditional::DiscreteConditional"))
cout << (firstFrontalKey()) << endl; //TODO Print all keys cout << (firstFrontalKey()) << endl; //TODO Print all keys
if (orderedKeys) { }
keys_.clear();
keys_.insert(keys_.end(), orderedKeys->begin(), orderedKeys->end()); /* ******************************************************************************** */
} DiscreteConditional::DiscreteConditional(const DecisionTreeFactor& joint,
const DecisionTreeFactor& marginal, const Ordering& orderedKeys) :
BaseFactor(
ISDEBUG("DiscreteConditional::COUNT") ? joint : joint / marginal), BaseConditional(
joint.size()-marginal.size()) {
if (ISDEBUG("DiscreteConditional::DiscreteConditional"))
cout << (firstFrontalKey()) << endl; //TODO Print all keys
keys_.clear();
keys_.insert(keys_.end(), orderedKeys.begin(), orderedKeys.end());
} }
/* ******************************************************************************** */ /* ******************************************************************************** */

View File

@ -60,7 +60,11 @@ public:
/** construct P(X|Y)=P(X,Y)/P(Y) from P(X,Y) and P(Y) */ /** construct P(X|Y)=P(X,Y)/P(Y) from P(X,Y) and P(Y) */
DiscreteConditional(const DecisionTreeFactor& joint, DiscreteConditional(const DecisionTreeFactor& joint,
const DecisionTreeFactor& marginal, const boost::optional<Ordering>& orderedKeys = boost::none); const DecisionTreeFactor& marginal);
/** construct P(X|Y)=P(X,Y)/P(Y) from P(X,Y) and P(Y) */
DiscreteConditional(const DecisionTreeFactor& joint,
const DecisionTreeFactor& marginal, const Ordering& orderedKeys);
/** /**
* Combine several conditional into a single one. * Combine several conditional into a single one.

View File

@ -34,8 +34,7 @@ string SlotEntry::toString() const {
} }
/* ************************************************************************* */ /* ************************************************************************* */
void Scatter::ScatterHelper(const GaussianFactorGraph& gfg, size_t sortStart) { void Scatter::setDimensions(const GaussianFactorGraph& gfg, size_t sortStart) {
// Now, find dimensions of variables and/or extend
for (const auto& factor : gfg) { for (const auto& factor : gfg) {
if (!factor) if (!factor)
continue; continue;
@ -66,7 +65,7 @@ void Scatter::ScatterHelper(const GaussianFactorGraph& gfg, size_t sortStart) {
Scatter::Scatter(const GaussianFactorGraph& gfg) { Scatter::Scatter(const GaussianFactorGraph& gfg) {
gttic(Scatter_Constructor); gttic(Scatter_Constructor);
ScatterHelper(gfg, 0); setDimensions(gfg, 0);
} }
/* ************************************************************************* */ /* ************************************************************************* */
@ -79,7 +78,7 @@ Scatter::Scatter(const GaussianFactorGraph& gfg,
add(key, 0); add(key, 0);
} }
ScatterHelper(gfg, ordering.size()); setDimensions(gfg, ordering.size());
} }
/* ************************************************************************* */ /* ************************************************************************* */

View File

@ -64,7 +64,7 @@ class Scatter : public FastVector<SlotEntry> {
/// Helper function for constructors, adds/finds dimensions of variables and /// Helper function for constructors, adds/finds dimensions of variables and
// sorts starting from sortStart // sorts starting from sortStart
void ScatterHelper(const GaussianFactorGraph& gfg, size_t sortStart); void setDimensions(const GaussianFactorGraph& gfg, size_t sortStart);
/// Find the SlotEntry with the right key (linear time worst case) /// Find the SlotEntry with the right key (linear time worst case)
iterator find(Key key); iterator find(Key key);

View File

@ -344,23 +344,31 @@ GaussianFactorGraph::shared_ptr NonlinearFactorGraph::linearize(const Values& li
} }
/* ************************************************************************* */ /* ************************************************************************* */
static Scatter scatterFromValues(const Values& values, boost::optional<Ordering&> ordering) { static Scatter scatterFromValues(const Values& values) {
gttic(scatterFromValues); gttic(scatterFromValues);
Scatter scatter; Scatter scatter;
scatter.reserve(values.size()); scatter.reserve(values.size());
if (!ordering) { // use "natural" ordering with keys taken from the initial values
// use "natural" ordering with keys taken from the initial values for (const auto& key_value : values) {
for (const auto& key_value : values) { scatter.add(key_value.key, key_value.value.dim());
scatter.add(key_value.key, key_value.value.dim()); }
}
} else { return scatter;
// copy ordering into keys and lookup dimension in values, is O(n*log n) }
for (Key key : *ordering) {
const Value& value = values.at(key); /* ************************************************************************* */
scatter.add(key, value.dim()); static Scatter scatterFromValues(const Values& values, const Ordering& ordering) {
} gttic(scatterFromValues);
Scatter scatter;
scatter.reserve(values.size());
// copy ordering into keys and lookup dimension in values, is O(n*log n)
for (Key key : ordering) {
const Value& value = values.at(key);
scatter.add(key, value.dim());
} }
return scatter; return scatter;
@ -368,7 +376,15 @@ static Scatter scatterFromValues(const Values& values, boost::optional<Ordering&
/* ************************************************************************* */ /* ************************************************************************* */
HessianFactor::shared_ptr NonlinearFactorGraph::linearizeToHessianFactor( HessianFactor::shared_ptr NonlinearFactorGraph::linearizeToHessianFactor(
const Values& values, boost::optional<Ordering&> ordering, const Dampen& dampen) const { const Values& values, const Dampen& dampen) const {
KeyVector keys = values.keys();
Ordering defaultOrdering(keys);
return linearizeToHessianFactor(values, defaultOrdering, dampen);
}
/* ************************************************************************* */
HessianFactor::shared_ptr NonlinearFactorGraph::linearizeToHessianFactor(
const Values& values, const Ordering& ordering, const Dampen& dampen) const {
gttic(NonlinearFactorGraph_linearizeToHessianFactor); gttic(NonlinearFactorGraph_linearizeToHessianFactor);
Scatter scatter = scatterFromValues(values, ordering); Scatter scatter = scatterFromValues(values, ordering);
@ -395,7 +411,16 @@ HessianFactor::shared_ptr NonlinearFactorGraph::linearizeToHessianFactor(
/* ************************************************************************* */ /* ************************************************************************* */
Values NonlinearFactorGraph::updateCholesky(const Values& values, Values NonlinearFactorGraph::updateCholesky(const Values& values,
boost::optional<Ordering&> ordering, const Dampen& dampen) const {
gttic(NonlinearFactorGraph_updateCholesky);
auto hessianFactor = linearizeToHessianFactor(values, dampen);
VectorValues delta = hessianFactor->solve();
return values.retract(delta);
}
/* ************************************************************************* */
Values NonlinearFactorGraph::updateCholesky(const Values& values,
const Ordering& ordering,
const Dampen& dampen) const { const Dampen& dampen) const {
gttic(NonlinearFactorGraph_updateCholesky); gttic(NonlinearFactorGraph_updateCholesky);
auto hessianFactor = linearizeToHessianFactor(values, ordering, dampen); auto hessianFactor = linearizeToHessianFactor(values, ordering, dampen);

View File

@ -149,17 +149,31 @@ namespace gtsam {
* Instead of producing a GaussianFactorGraph, pre-allocate and linearize directly * Instead of producing a GaussianFactorGraph, pre-allocate and linearize directly
* into a HessianFactor. Avoids the many mallocs and pointer indirection in constructing * into a HessianFactor. Avoids the many mallocs and pointer indirection in constructing
* a new graph, and hence useful in case a dense solve is appropriate for your problem. * a new graph, and hence useful in case a dense solve is appropriate for your problem.
* An optional ordering can be given that still decides how the Hessian is laid out.
* An optional lambda function can be used to apply damping on the filled Hessian. * An optional lambda function can be used to apply damping on the filled Hessian.
* No parallelism is exploited, because all the factors write in the same memory. * No parallelism is exploited, because all the factors write in the same memory.
*/ */
boost::shared_ptr<HessianFactor> linearizeToHessianFactor( boost::shared_ptr<HessianFactor> linearizeToHessianFactor(
const Values& values, boost::optional<Ordering&> ordering = boost::none, const Values& values, const Dampen& dampen = nullptr) const;
const Dampen& dampen = nullptr) const;
/**
* Instead of producing a GaussianFactorGraph, pre-allocate and linearize directly
* into a HessianFactor. Avoids the many mallocs and pointer indirection in constructing
* a new graph, and hence useful in case a dense solve is appropriate for your problem.
* An ordering is given that still decides how the Hessian is laid out.
* An optional lambda function can be used to apply damping on the filled Hessian.
* No parallelism is exploited, because all the factors write in the same memory.
*/
boost::shared_ptr<HessianFactor> linearizeToHessianFactor(
const Values& values, const Ordering& ordering, const Dampen& dampen = nullptr) const;
/// Linearize and solve in one pass. /// Linearize and solve in one pass.
/// Calls linearizeToHessianFactor, densely solves the normal equations, and updates the values. /// Calls linearizeToHessianFactor, densely solves the normal equations, and updates the values.
Values updateCholesky(const Values& values, boost::optional<Ordering&> ordering = boost::none, Values updateCholesky(const Values& values,
const Dampen& dampen = nullptr) const;
/// Linearize and solve in one pass.
/// Calls linearizeToHessianFactor, densely solves the normal equations, and updates the values.
Values updateCholesky(const Values& values, const Ordering& ordering,
const Dampen& dampen = nullptr) const; const Dampen& dampen = nullptr) const;
/// Clone() performs a deep-copy of the graph, including all of the factors /// Clone() performs a deep-copy of the graph, including all of the factors

View File

@ -82,7 +82,7 @@ public:
}; };
LinearSolverType linearSolverType; ///< The type of linear solver to use in the nonlinear optimizer LinearSolverType linearSolverType; ///< The type of linear solver to use in the nonlinear optimizer
boost::optional<Ordering> ordering; ///< The variable elimination ordering, or empty to use COLAMD (default: empty) boost::optional<Ordering> ordering; ///< The optional variable elimination ordering, or empty to use COLAMD (default: empty)
IterativeOptimizationParameters::shared_ptr iterativeParams; ///< The container for iterativeOptimization parameters. used in CG Solvers. IterativeOptimizationParameters::shared_ptr iterativeParams; ///< The container for iterativeOptimization parameters. used in CG Solvers.
inline bool isMultifrontal() const { inline bool isMultifrontal() const {

View File

@ -46,21 +46,26 @@ class NonlinearClusterTree : public ClusterTree<NonlinearFactorGraph> {
// linearize local custer factors straight into hessianFactor, which is returned // linearize local custer factors straight into hessianFactor, which is returned
// If no ordering given, uses colamd // If no ordering given, uses colamd
HessianFactor::shared_ptr linearizeToHessianFactor( HessianFactor::shared_ptr linearizeToHessianFactor(
const Values& values, boost::optional<Ordering> ordering = boost::none, const Values& values,
const NonlinearFactorGraph::Dampen& dampen = nullptr) const { const NonlinearFactorGraph::Dampen& dampen = nullptr) const {
if (!ordering) Ordering ordering;
ordering.reset(Ordering::ColamdConstrainedFirst(factors, orderedFrontalKeys, true)); ordering = Ordering::ColamdConstrainedFirst(factors, orderedFrontalKeys, true);
return factors.linearizeToHessianFactor(values, *ordering, dampen); return factors.linearizeToHessianFactor(values, ordering, dampen);
} }
// Recursively eliminate subtree rooted at this Cluster into a Bayes net and factor on parent // linearize local custer factors straight into hessianFactor, which is returned
// If no ordering given, uses colamd
HessianFactor::shared_ptr linearizeToHessianFactor(
const Values& values, const Ordering& ordering,
const NonlinearFactorGraph::Dampen& dampen = nullptr) const {
return factors.linearizeToHessianFactor(values, ordering, dampen);
}
// Helper function: recursively eliminate subtree rooted at this Cluster into a Bayes net and factor on parent
// TODO(frank): Use TBB to support deep trees and parallelism // TODO(frank): Use TBB to support deep trees and parallelism
std::pair<GaussianBayesNet, HessianFactor::shared_ptr> linearizeAndEliminate( std::pair<GaussianBayesNet, HessianFactor::shared_ptr> linearizeAndEliminate(
const Values& values, boost::optional<Ordering> ordering = boost::none, const Values& values,
const NonlinearFactorGraph::Dampen& dampen = nullptr) const { const HessianFactor::shared_ptr& localFactor) const {
// Linearize and create HessianFactor f(front,separator)
HessianFactor::shared_ptr localFactor = linearizeToHessianFactor(values, ordering, dampen);
// Get contributions f(front) from children, as well as p(children|front) // Get contributions f(front) from children, as well as p(children|front)
GaussianBayesNet bayesNet; GaussianBayesNet bayesNet;
for (const auto& child : children) { for (const auto& child : children) {
@ -72,12 +77,45 @@ class NonlinearClusterTree : public ClusterTree<NonlinearFactorGraph> {
return {bayesNet, localFactor}; return {bayesNet, localFactor};
} }
// Recursively eliminate subtree rooted at this Cluster into a Bayes net and factor on parent
// TODO(frank): Use TBB to support deep trees and parallelism
std::pair<GaussianBayesNet, HessianFactor::shared_ptr> linearizeAndEliminate(
const Values& values,
const NonlinearFactorGraph::Dampen& dampen = nullptr) const {
// Linearize and create HessianFactor f(front,separator)
HessianFactor::shared_ptr localFactor = linearizeToHessianFactor(values, dampen);
return linearizeAndEliminate(values, localFactor);
}
// Recursively eliminate subtree rooted at this Cluster into a Bayes net and factor on parent
// TODO(frank): Use TBB to support deep trees and parallelism
std::pair<GaussianBayesNet, HessianFactor::shared_ptr> linearizeAndEliminate(
const Values& values, const Ordering& ordering,
const NonlinearFactorGraph::Dampen& dampen = nullptr) const {
// Linearize and create HessianFactor f(front,separator)
HessianFactor::shared_ptr localFactor = linearizeToHessianFactor(values, ordering, dampen);
return linearizeAndEliminate(values, localFactor);
}
// Recursively eliminate subtree rooted at this Cluster // Recursively eliminate subtree rooted at this Cluster
// Version that updates existing Bayes net and returns a new Hessian factor on parent clique // Version that updates existing Bayes net and returns a new Hessian factor on parent clique
// It is possible to pass in a nullptr for the bayesNet if only interested in the new factor // It is possible to pass in a nullptr for the bayesNet if only interested in the new factor
HessianFactor::shared_ptr linearizeAndEliminate( HessianFactor::shared_ptr linearizeAndEliminate(
const Values& values, GaussianBayesNet* bayesNet, const Values& values, GaussianBayesNet* bayesNet,
boost::optional<Ordering> ordering = boost::none, const NonlinearFactorGraph::Dampen& dampen = nullptr) const {
auto bayesNet_newFactor_pair = linearizeAndEliminate(values, dampen);
if (bayesNet) {
bayesNet->push_back(bayesNet_newFactor_pair.first);
}
return bayesNet_newFactor_pair.second;
}
// Recursively eliminate subtree rooted at this Cluster
// Version that updates existing Bayes net and returns a new Hessian factor on parent clique
// It is possible to pass in a nullptr for the bayesNet if only interested in the new factor
HessianFactor::shared_ptr linearizeAndEliminate(
const Values& values, GaussianBayesNet* bayesNet,
const Ordering& ordering,
const NonlinearFactorGraph::Dampen& dampen = nullptr) const { const NonlinearFactorGraph::Dampen& dampen = nullptr) const {
auto bayesNet_newFactor_pair = linearizeAndEliminate(values, ordering, dampen); auto bayesNet_newFactor_pair = linearizeAndEliminate(values, ordering, dampen);
if (bayesNet) { if (bayesNet) {

View File

@ -198,7 +198,7 @@ TEST(NonlinearFactorGraph, UpdateCholesky) {
} }
} }
}; };
EXPECT(assert_equal(initial, fg.updateCholesky(initial, boost::none, dampen), 1e-6)); EXPECT(assert_equal(initial, fg.updateCholesky(initial, dampen), 1e-6));
} }
/* ************************************************************************* */ /* ************************************************************************* */