HybridGaussianConditional.cpp
Go to the documentation of this file.
1 /* ----------------------------------------------------------------------------
2 
3  * GTSAM Copyright 2010, Georgia Tech Research Corporation,
4  * Atlanta, Georgia 30332-0415
5  * All Rights Reserved
6  * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
7 
8  * See LICENSE for the license information
9 
10  * -------------------------------------------------------------------------- */
11 
21 #include <gtsam/base/utilities.h>
29 
30 #include <cstddef>
31 
32 namespace gtsam {
33 /* *******************************************************************************/
35  std::optional<size_t> nrFrontals;
38 
41  : minNegLogConstant(std::numeric_limits<double>::infinity()) {
42  auto func = [this](const GaussianConditional::shared_ptr &c)
44  double value = 0.0;
45  if (c) {
46  if (!nrFrontals.has_value()) {
47  nrFrontals = c->nrFrontals();
48  }
49  value = c->negLogConstant();
51  }
52  return {std::dynamic_pointer_cast<GaussianFactor>(c), value};
53  };
55  if (!nrFrontals.has_value()) {
56  throw std::runtime_error(
57  "HybridGaussianConditional: need at least one frontal variable.");
58  }
59  }
60 };
61 
62 /* *******************************************************************************/
64  const DiscreteKeys &discreteParents,
66  const ConstructorHelper &helper)
67  : BaseFactor(discreteParents, helper.pairs),
68  BaseConditional(*helper.nrFrontals),
69  conditionals_(conditionals),
70  negLogConstant_(helper.minNegLogConstant) {}
71 
73  const DiscreteKeys &discreteParents,
75  : HybridGaussianConditional(discreteParents, conditionals,
77 
79  const DiscreteKey &discreteParent,
80  const std::vector<GaussianConditional::shared_ptr> &conditionals)
81  : HybridGaussianConditional(DiscreteKeys{discreteParent},
82  Conditionals({discreteParent}, conditionals)) {}
83 
84 /* *******************************************************************************/
87  return conditionals_;
88 }
89 
90 /* *******************************************************************************/
92  const {
93  auto wrap = [this](const GaussianConditional::shared_ptr &gc) {
94  // First check if conditional has not been pruned
95  if (gc) {
96  const double Cgm_Kgcm = gc->negLogConstant() - this->negLogConstant_;
97  // If there is a difference in the covariances, we need to account for
98  // that since the error is dependent on the mode.
99  if (Cgm_Kgcm > 0.0) {
100  // We add a constant factor which will be used when computing
101  // the probability of the discrete variables.
102  Vector c(1);
103  c << std::sqrt(2.0 * Cgm_Kgcm);
104  auto constantFactor = std::make_shared<JacobianFactor>(c);
105  return GaussianFactorGraph{gc, constantFactor};
106  }
107  }
108  return GaussianFactorGraph{gc};
109  };
110  return {conditionals_, wrap};
111 }
112 
113 /* *******************************************************************************/
115  size_t total = 0;
116  conditionals_.visit([&total](const GaussianFactor::shared_ptr &node) {
117  if (node) total += 1;
118  });
119  return total;
120 }
121 
122 /* *******************************************************************************/
124  const DiscreteValues &discreteValues) const {
125  auto &ptr = conditionals_(discreteValues);
126  if (!ptr) return nullptr;
127  auto conditional = std::dynamic_pointer_cast<GaussianConditional>(ptr);
128  if (conditional)
129  return conditional;
130  else
131  throw std::logic_error(
132  "A HybridGaussianConditional unexpectedly contained a non-conditional");
133 }
134 
135 /* *******************************************************************************/
137  double tol) const {
138  const This *e = dynamic_cast<const This *>(&lf);
139  if (e == nullptr) return false;
140 
141  // This will return false if either conditionals_ is empty or e->conditionals_
142  // is empty, but not if both are empty or both are not empty:
143  if (conditionals_.empty() ^ e->conditionals_.empty()) return false;
144 
145  // Check the base and the factors:
146  return BaseFactor::equals(*e, tol) &&
147  conditionals_.equals(e->conditionals_,
150  return f1->equals(*(f2), tol);
151  });
152 }
153 
154 /* *******************************************************************************/
155 void HybridGaussianConditional::print(const std::string &s,
156  const KeyFormatter &formatter) const {
157  std::cout << (s.empty() ? "" : s + "\n");
158  if (isContinuous()) std::cout << "Continuous ";
159  if (isDiscrete()) std::cout << "Discrete ";
160  if (isHybrid()) std::cout << "Hybrid ";
162  std::cout << " Discrete Keys = ";
163  for (auto &dk : discreteKeys()) {
164  std::cout << "(" << formatter(dk.first) << ", " << dk.second << "), ";
165  }
166  std::cout << std::endl
167  << " logNormalizationConstant: " << -negLogConstant() << std::endl
168  << std::endl;
170  "", [&](Key k) { return formatter(k); },
171  [&](const GaussianConditional::shared_ptr &gf) -> std::string {
172  RedirectCout rd;
173  if (gf && !gf->empty()) {
174  gf->print("", formatter);
175  return rd.str();
176  } else {
177  return "nullptr";
178  }
179  });
180 }
181 
182 /* ************************************************************************* */
184  // Get all parent keys:
185  const auto range = parents();
186  KeyVector continuousParentKeys(range.begin(), range.end());
187  // Loop over all discrete keys:
188  for (const auto &discreteKey : discreteKeys()) {
189  const Key key = discreteKey.first;
190  // remove that key from continuousParentKeys:
191  continuousParentKeys.erase(std::remove(continuousParentKeys.begin(),
192  continuousParentKeys.end(), key),
193  continuousParentKeys.end());
194  }
195  return continuousParentKeys;
196 }
197 
198 /* ************************************************************************* */
200  const VectorValues &given) const {
201  for (auto &&kv : given) {
202  if (given.find(kv.first) == given.end()) {
203  return false;
204  }
205  }
206  return true;
207 }
208 
209 /* ************************************************************************* */
210 std::shared_ptr<HybridGaussianFactor> HybridGaussianConditional::likelihood(
211  const VectorValues &given) const {
212  if (!allFrontalsGiven(given)) {
213  throw std::runtime_error(
214  "HybridGaussianConditional::likelihood: given values are missing some "
215  "frontals.");
216  }
217 
218  const DiscreteKeys discreteParentKeys = discreteKeys();
219  const KeyVector continuousParentKeys = continuousParents();
220  const HybridGaussianFactor::FactorValuePairs likelihoods(
222  [&](const GaussianConditional::shared_ptr &conditional)
224  const auto likelihood_m = conditional->likelihood(given);
225  const double Cgm_Kgcm = conditional->negLogConstant() - negLogConstant_;
226  if (Cgm_Kgcm == 0.0) {
227  return {likelihood_m, 0.0};
228  } else {
229  // Add a constant to the likelihood in case the noise models
230  // are not all equal.
231  return {likelihood_m, Cgm_Kgcm};
232  }
233  });
234  return std::make_shared<HybridGaussianFactor>(discreteParentKeys,
235  likelihoods);
236 }
237 
238 /* ************************************************************************* */
239 std::set<DiscreteKey> DiscreteKeysAsSet(const DiscreteKeys &discreteKeys) {
240  std::set<DiscreteKey> s(discreteKeys.begin(), discreteKeys.end());
241  return s;
242 }
243 
244 /* ************************************************************************* */
252 std::function<GaussianConditional::shared_ptr(
253  const Assignment<Key> &, const GaussianConditional::shared_ptr &)>
255  // Get the discrete keys as sets for the decision tree
256  // and the hybrid gaussian conditional.
257  auto discreteProbsKeySet = DiscreteKeysAsSet(discreteProbs.discreteKeys());
258  auto hybridGaussianCondKeySet = DiscreteKeysAsSet(this->discreteKeys());
259 
260  auto pruner = [discreteProbs, discreteProbsKeySet, hybridGaussianCondKeySet](
261  const Assignment<Key> &choices,
262  const GaussianConditional::shared_ptr &conditional)
264  // typecast so we can use this to get probability value
265  const DiscreteValues values(choices);
266 
267  // Case where the hybrid gaussian conditional has the same
268  // discrete keys as the decision tree.
269  if (hybridGaussianCondKeySet == discreteProbsKeySet) {
270  if (discreteProbs(values) == 0.0) {
271  // empty aka null pointer
272  std::shared_ptr<GaussianConditional> null;
273  return null;
274  } else {
275  return conditional;
276  }
277  } else {
278  std::vector<DiscreteKey> set_diff;
279  std::set_difference(
280  discreteProbsKeySet.begin(), discreteProbsKeySet.end(),
281  hybridGaussianCondKeySet.begin(), hybridGaussianCondKeySet.end(),
282  std::back_inserter(set_diff));
283 
284  const std::vector<DiscreteValues> assignments =
286  for (const DiscreteValues &assignment : assignments) {
287  DiscreteValues augmented_values(values);
288  augmented_values.insert(assignment);
289 
290  // If any one of the sub-branches are non-zero,
291  // we need this conditional.
292  if (discreteProbs(augmented_values) > 0.0) {
293  return conditional;
294  }
295  }
296  // If we are here, it means that all the sub-branches are 0,
297  // so we prune.
298  return nullptr;
299  }
300  };
301  return pruner;
302 }
303 
304 /* *******************************************************************************/
306  // Functional which loops over all assignments and create a set of
307  // GaussianConditionals
308  auto pruner = prunerFunc(discreteProbs);
309 
310  auto pruned_conditionals = conditionals_.apply(pruner);
311  conditionals_.root_ = pruned_conditionals.root_;
312 }
313 
314 /* *******************************************************************************/
316  const VectorValues &continuousValues) const {
317  // functor to calculate (double) logProbability value from
318  // GaussianConditional.
319  auto probFunc =
320  [continuousValues](const GaussianConditional::shared_ptr &conditional) {
321  if (conditional) {
322  return conditional->logProbability(continuousValues);
323  } else {
324  // Return arbitrarily small logProbability if conditional is null
325  // Conditional is null if it is pruned out.
326  return -1e20;
327  }
328  };
329  return DecisionTree<Key, double>(conditionals_, probFunc);
330 }
331 
332 /* *******************************************************************************/
334  const HybridValues &values) const {
335  auto conditional = conditionals_(values.discrete());
336  return conditional->logProbability(values.continuous());
337 }
338 
339 /* *******************************************************************************/
341  auto conditional = conditionals_(values.discrete());
342  return conditional->evaluate(values.continuous());
343 }
344 
345 } // namespace gtsam
gtsam::Conditional::print
void print(const std::string &s="Conditional", const KeyFormatter &formatter=DefaultKeyFormatter) const
Definition: Conditional-inst.h:30
gtsam::HybridGaussianConditional::ConstructorHelper
Definition: HybridGaussianConditional.cpp:34
GaussianFactorGraph.h
Linear Factor Graph where all factors are Gaussians.
gtsam::DecisionTreeFactor
Definition: DecisionTreeFactor.h:44
gtsam::HybridValues
Definition: HybridValues.h:37
test_constructor::f1
auto f1
Definition: testHybridNonlinearFactor.cpp:56
HybridGaussianConditional.h
A hybrid conditional in the Conditional Linear Gaussian scheme.
s
RealScalar s
Definition: level1_cplx_impl.h:126
e
Array< double, 1, 3 > e(1./3., 0.5, 2.)
gtsam::HybridGaussianConditional::conditionals_
Conditionals conditionals_
a decision tree of Gaussian conditionals.
Definition: HybridGaussianConditional.h:66
gtsam::DecisionTree::empty
bool empty() const
Check if tree is empty.
Definition: DecisionTree.h:269
c
Scalar Scalar * c
Definition: benchVecAdd.cpp:17
gtsam::DecisionTree::equals
bool equals(const DecisionTree &other, const CompareFunc &compare=&DefaultCompare) const
Definition: DecisionTree-inl.h:899
gtsam::HybridFactor::isDiscrete
bool isDiscrete() const
True if this is a factor of discrete variables only.
Definition: HybridFactor.h:122
gtsam::RedirectCout
Definition: base/utilities.h:16
gtsam::HybridFactor
Definition: HybridFactor.h:54
wrap
mxArray * wrap(const Class &value)
Definition: matlab.h:126
formatter
const KeyFormatter & formatter
Definition: treeTraversal-inst.h:204
f2
double f2(const Vector2 &x)
Definition: testNumericalDerivative.cpp:56
gtsam::DiscreteKeys
DiscreteKeys is a set of keys that can be assembled using the & operator.
Definition: DiscreteKey.h:41
gtsam::DecisionTree::print
void print(const std::string &s, const LabelFormatter &labelFormatter, const ValueFormatter &valueFormatter) const
GTSAM-style print.
Definition: DecisionTree-inl.h:905
GaussianBayesNet.h
Chordal Bayes Net, the result of eliminating a factor graph.
gtsam::HybridFactor::isHybrid
bool isHybrid() const
True is this is a Discrete-Continuous factor.
Definition: HybridFactor.h:128
gtsam::HybridGaussianConditional::ConstructorHelper::minNegLogConstant
double minNegLogConstant
Definition: HybridGaussianConditional.cpp:37
gtsam::Vector
Eigen::VectorXd Vector
Definition: Vector.h:38
gtsam::KeyVector
FastVector< Key > KeyVector
Define collection type once and for all - also used in wrappers.
Definition: Key.h:92
HybridGaussianFactor.h
A set of GaussianFactors, indexed by a set of discrete keys.
utilities.h
equal_constants::conditionals
const std::vector< GaussianConditional::shared_ptr > conditionals
Definition: testHybridGaussianConditional.cpp:50
gtsam::AlgebraicDecisionTree< Key >
gtsam::range
Double_ range(const Point2_ &p, const Point2_ &q)
Definition: slam/expressions.h:30
gtsam::GaussianFactorGraph
Definition: GaussianFactorGraph.h:73
gtsam::HybridGaussianConditional::logProbability
AlgebraicDecisionTree< Key > logProbability(const VectorValues &continuousValues) const
Compute logProbability of the HybridGaussianConditional as a tree.
Definition: HybridGaussianConditional.cpp:315
gtsam::HybridGaussianConditional::evaluate
double evaluate(const HybridValues &values) const override
Calculate probability density for given values.
Definition: HybridGaussianConditional.cpp:340
gtsam::DecisionTree::root_
NodePtr root_
A DecisionTree just contains the root. TODO(dellaert): make protected.
Definition: DecisionTree.h:150
gtsam::GaussianFactorValuePair
std::pair< GaussianFactor::shared_ptr, double > GaussianFactorValuePair
Alias for pair of GaussianFactor::shared_pointer and a double value.
Definition: HybridGaussianFactor.h:37
gtsam::VectorValues
Definition: VectorValues.h:74
gtsam::DiscreteValues::CartesianProduct
static std::vector< DiscreteValues > CartesianProduct(const DiscreteKeys &keys)
Return a vector of DiscreteValues, one for each possible combination of values.
Definition: DiscreteValues.h:85
gtsam::KeyFormatter
std::function< std::string(Key)> KeyFormatter
Typedef for a function to format a key, i.e. to convert it to a string.
Definition: Key.h:35
gtsam::HybridGaussianConditional::nrComponents
size_t nrComponents() const
Returns the total number of continuous components.
Definition: HybridGaussianConditional.cpp:114
gtsam::GaussianFactor::shared_ptr
std::shared_ptr< This > shared_ptr
shared_ptr to this class
Definition: GaussianFactor.h:42
gtsam::HybridGaussianConditional
A conditional of gaussian conditionals indexed by discrete variables, as part of a Bayes Network....
Definition: HybridGaussianConditional.h:53
gtsam::DecisionTree::visit
void visit(Func f) const
Visit all leaves in depth-first fashion.
Definition: DecisionTree-inl.h:769
gtsam::HybridGaussianConditional::ConstructorHelper::ConstructorHelper
ConstructorHelper(const Conditionals &conditionals)
Compute all variables needed for the private constructor below.
Definition: HybridGaussianConditional.cpp:40
gtsam::HybridGaussianConditional::prune
void prune(const DecisionTreeFactor &discreteProbs)
Prune the decision tree of Gaussian factors as per the discrete discreteProbs.
Definition: HybridGaussianConditional.cpp:305
gtsam::Assignment< Key >
gtsam::HybridGaussianConditional::continuousParents
KeyVector continuousParents() const
Returns the continuous keys among the parents.
Definition: HybridGaussianConditional.cpp:183
gtsam::HybridFactor::isContinuous
bool isContinuous() const
True if this is a factor of continuous variables only.
Definition: HybridFactor.h:125
gtsam::Conditional
Definition: Conditional.h:63
gtsam::DecisionTree::apply
DecisionTree apply(const Unary &op) const
Definition: DecisionTree-inl.h:922
gtsam::HybridGaussianConditional::ConstructorHelper::nrFrontals
std::optional< size_t > nrFrontals
Definition: HybridGaussianConditional.cpp:35
gtsam::HybridGaussianConditional::likelihood
std::shared_ptr< HybridGaussianFactor > likelihood(const VectorValues &given) const
Definition: HybridGaussianConditional.cpp:210
gtsam::Conditional< HybridGaussianFactor, HybridGaussianConditional >::parents
Parents parents() const
Definition: Conditional.h:148
gtsam::HybridGaussianFactor::equals
bool equals(const HybridFactor &lf, double tol=1e-9) const override
equals
Definition: HybridGaussianFactor.cpp:144
key
const gtsam::Symbol key('X', 0)
gtsam::HybridGaussianConditional::asGaussianFactorGraphTree
GaussianFactorGraphTree asGaussianFactorGraphTree() const
Convert to a DecisionTree of Gaussian factor graphs.
Definition: HybridGaussianConditional.cpp:91
gtsam::DecisionTree< Key, GaussianFactorValuePair >
gtsam::DiscreteKeysAsSet
std::set< DiscreteKey > DiscreteKeysAsSet(const DiscreteKeys &discreteKeys)
Return the DiscreteKey vector as a set.
Definition: HybridGaussianConditional.cpp:239
gtsam::HybridGaussianConditional::Conditionals
DecisionTree< Key, GaussianConditional::shared_ptr > Conditionals
typedef for Decision Tree of Gaussian Conditionals
Definition: HybridGaussianConditional.h:63
gtsam
traits
Definition: chartTesting.h:28
DiscreteValues.h
gtsam::HybridGaussianFactor::FactorValuePairs
DecisionTree< Key, GaussianFactorValuePair > FactorValuePairs
typedef for Decision Tree of Gaussian factors and arbitrary value.
Definition: HybridGaussianFactor.h:68
gtsam::DiscreteValues
Definition: DiscreteValues.h:34
leaf::values
leaf::MyValues values
gtsam::HybridGaussianConditional::operator()
GaussianConditional::shared_ptr operator()(const DiscreteValues &discreteValues) const
Return the conditional Gaussian for the given discrete assignment.
Definition: HybridGaussianConditional.cpp:123
gtsam::DiscreteKey
std::pair< Key, size_t > DiscreteKey
Definition: DiscreteKey.h:38
std
Definition: BFloat16.h:88
gtsam::HybridGaussianConditional::allFrontalsGiven
bool allFrontalsGiven(const VectorValues &given) const
Check whether given has values for all frontal keys.
Definition: HybridGaussianConditional.cpp:199
gtsam::DiscreteValues::insert
std::pair< iterator, bool > insert(const value_type &value)
Definition: DiscreteValues.h:68
gtsam::HybridGaussianConditional::equals
bool equals(const HybridFactor &lf, double tol=1e-9) const override
Test equality with base HybridFactor.
Definition: HybridGaussianConditional.cpp:136
gtsam::HybridGaussianFactor
Implementation of a discrete-conditioned hybrid factor. Implements a joint discrete-continuous factor...
Definition: HybridGaussianFactor.h:59
gtsam::HybridGaussianConditional::conditionals
const Conditionals & conditionals() const
Getter for the underlying Conditionals DecisionTree.
Definition: HybridGaussianConditional.cpp:86
gtsam::GaussianConditional::shared_ptr
std::shared_ptr< This > shared_ptr
shared_ptr to this class
Definition: GaussianConditional.h:46
gtsam::HybridGaussianConditional::negLogConstant_
double negLogConstant_
Definition: HybridGaussianConditional.h:70
gtsam::HybridGaussianConditional::prunerFunc
std::function< GaussianConditional::shared_ptr(const Assignment< Key > &, const GaussianConditional::shared_ptr &)> prunerFunc(const DecisionTreeFactor &prunedProbabilities)
Helper function to get the pruner functional.
Definition: HybridGaussianConditional.cpp:254
min
#define min(a, b)
Definition: datatypes.h:19
gtsam::HybridGaussianConditional::negLogConstant
double negLogConstant() const override
Return log normalization constant in negative log space.
Definition: HybridGaussianConditional.h:136
gtsam::tol
const G double tol
Definition: Group.h:79
gtsam::HybridGaussianConditional::HybridGaussianConditional
HybridGaussianConditional()=default
Default constructor, mainly for serialization.
gtsam::DiscreteFactor::discreteKeys
DiscreteKeys discreteKeys() const
Return all the discrete keys associated with this factor.
Definition: DiscreteFactor.cpp:32
func
Definition: benchGeometry.cpp:23
gtsam::HybridGaussianConditional::ConstructorHelper::pairs
HybridGaussianFactor::FactorValuePairs pairs
Definition: HybridGaussianConditional.cpp:36
gtsam::Key
std::uint64_t Key
Integer nonlinear key type.
Definition: types.h:97
HybridValues.h
gtsam::HybridFactor::discreteKeys
const DiscreteKeys & discreteKeys() const
Return the discrete keys for this factor.
Definition: HybridFactor.h:134
test_callbacks.value
value
Definition: test_callbacks.py:160
gtsam::HybridGaussianConditional::print
void print(const std::string &s="HybridGaussianConditional\n", const KeyFormatter &formatter=DefaultKeyFormatter) const override
Print utility.
Definition: HybridGaussianConditional.cpp:155
ceres::sqrt
Jet< T, N > sqrt(const Jet< T, N > &f)
Definition: jet.h:418
gtsam::RedirectCout::str
std::string str() const
return the string
Definition: utilities.cpp:5
Conditional-inst.h


gtsam
Author(s):
autogenerated on Sat Sep 28 2024 03:00:50