GTSAM  4.0.2
C++ library for smoothing and mapping (SAM)
MixtureFactor.h
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 
20 #pragma once
21 
27 #include <gtsam/nonlinear/Symbol.h>
28 
29 #include <algorithm>
30 #include <cmath>
31 #include <limits>
32 #include <vector>
33 
34 namespace gtsam {
35 
47 class MixtureFactor : public HybridFactor {
48  public:
49  using Base = HybridFactor;
50  using This = MixtureFactor;
51  using shared_ptr = std::shared_ptr<MixtureFactor>;
52  using sharedFactor = std::shared_ptr<NonlinearFactor>;
53 
59 
60  private:
62  Factors factors_;
63  bool normalized_;
64 
65  public:
66  MixtureFactor() = default;
67 
78  const Factors& factors, bool normalized = false)
79  : Base(keys, discreteKeys), factors_(factors), normalized_(normalized) {}
80 
97  template <typename FACTOR>
99  const std::vector<std::shared_ptr<FACTOR>>& factors,
100  bool normalized = false)
101  : Base(keys, discreteKeys), normalized_(normalized) {
102  std::vector<NonlinearFactor::shared_ptr> nonlinear_factors;
103  KeySet continuous_keys_set(keys.begin(), keys.end());
104  KeySet factor_keys_set;
105  for (auto&& f : factors) {
106  // Insert all factor continuous keys in the continuous keys set.
107  std::copy(f->keys().begin(), f->keys().end(),
108  std::inserter(factor_keys_set, factor_keys_set.end()));
109 
110  if (auto nf = std::dynamic_pointer_cast<NonlinearFactor>(f)) {
111  nonlinear_factors.push_back(nf);
112  } else {
113  throw std::runtime_error(
114  "Factors passed into MixtureFactor need to be nonlinear!");
115  }
116  }
117  factors_ = Factors(discreteKeys, nonlinear_factors);
118 
119  if (continuous_keys_set != factor_keys_set) {
120  throw std::runtime_error(
121  "The specified continuous keys and the keys in the factors don't "
122  "match!");
123  }
124  }
125 
134  AlgebraicDecisionTree<Key> error(const Values& continuousValues) const {
135  // functor to convert from sharedFactor to double error value.
136  auto errorFunc = [continuousValues](const sharedFactor& factor) {
137  return factor->error(continuousValues);
138  };
139  DecisionTree<Key, double> errorTree(factors_, errorFunc);
140  return errorTree;
141  }
142 
150  double error(const Values& continuousValues,
151  const DiscreteValues& discreteValues) const {
152  // Retrieve the factor corresponding to the assignment in discreteValues.
153  auto factor = factors_(discreteValues);
154  // Compute the error for the selected factor
155  const double factorError = factor->error(continuousValues);
156  if (normalized_) return factorError;
157  return factorError + this->nonlinearFactorLogNormalizingConstant(
158  factor, continuousValues);
159  }
160 
167  double error(const HybridValues& values) const override {
168  return error(values.nonlinear(), values.discrete());
169  }
170 
176  size_t dim() const {
177  const auto assignments = DiscreteValues::CartesianProduct(discreteKeys_);
178  auto factor = factors_(assignments.at(0));
179  return factor->dim();
180  }
181 
184 
186  void print(
187  const std::string& s = "",
188  const KeyFormatter& keyFormatter = DefaultKeyFormatter) const override {
189  std::cout << (s.empty() ? "" : s + " ");
190  Base::print("", keyFormatter);
191  std::cout << "\nMixtureFactor\n";
192  auto valueFormatter = [](const sharedFactor& v) {
193  if (v) {
194  return "Nonlinear factor on " + std::to_string(v->size()) + " keys";
195  } else {
196  return std::string("nullptr");
197  }
198  };
199  factors_.print("", keyFormatter, valueFormatter);
200  }
201 
203  bool equals(const HybridFactor& other, double tol = 1e-9) const override {
204  // We attempt a dynamic cast from HybridFactor to MixtureFactor. If it
205  // fails, return false.
206  if (!dynamic_cast<const MixtureFactor*>(&other)) return false;
207 
208  // If the cast is successful, we'll properly construct a MixtureFactor
209  // object from `other`
210  const MixtureFactor& f(static_cast<const MixtureFactor&>(other));
211 
212  // Ensure that this MixtureFactor and `f` have the same `factors_`.
213  auto compare = [tol](const sharedFactor& a, const sharedFactor& b) {
214  return traits<NonlinearFactor>::Equals(*a, *b, tol);
215  };
216  if (!factors_.equals(f.factors_, compare)) return false;
217 
218  // If everything above passes, and the keys_, discreteKeys_ and normalized_
219  // member variables are identical, return true.
220  return (std::equal(keys_.begin(), keys_.end(), f.keys().begin()) &&
221  (discreteKeys_ == f.discreteKeys_) &&
222  (normalized_ == f.normalized_));
223  }
224 
226 
230  const Values& continuousValues,
231  const DiscreteValues& discreteValues) const {
232  auto factor = factors_(discreteValues);
233  return factor->linearize(continuousValues);
234  }
235 
237  std::shared_ptr<GaussianMixtureFactor> linearize(
238  const Values& continuousValues) const {
239  // functional to linearize each factor in the decision tree
240  auto linearizeDT = [continuousValues](const sharedFactor& factor) {
241  return factor->linearize(continuousValues);
242  };
243 
245  factors_, linearizeDT);
246 
247  return std::make_shared<GaussianMixtureFactor>(
248  continuousKeys_, discreteKeys_, linearized_factors);
249  }
250 
258  double nonlinearFactorLogNormalizingConstant(const sharedFactor& factor,
259  const Values& values) const {
260  // Information matrix (inverse covariance matrix) for the factor.
261  Matrix infoMat;
262 
263  // If this is a NoiseModelFactor, we'll use its noiseModel to
264  // otherwise noiseModelFactor will be nullptr
265  if (auto noiseModelFactor =
266  std::dynamic_pointer_cast<NoiseModelFactor>(factor)) {
267  // If dynamic cast to NoiseModelFactor succeeded, see if the noise model
268  // is Gaussian
269  auto noiseModel = noiseModelFactor->noiseModel();
270 
271  auto gaussianNoiseModel =
272  std::dynamic_pointer_cast<noiseModel::Gaussian>(noiseModel);
273  if (gaussianNoiseModel) {
274  // If the noise model is Gaussian, retrieve the information matrix
275  infoMat = gaussianNoiseModel->information();
276  } else {
277  // If the factor is not a Gaussian factor, we'll linearize it to get
278  // something with a normalized noise model
279  // TODO(kevin): does this make sense to do? I think maybe not in
280  // general? Should we just yell at the user?
281  auto gaussianFactor = factor->linearize(values);
282  infoMat = gaussianFactor->information();
283  }
284  }
285 
286  // Compute the (negative) log of the normalizing constant
287  return -(factor->dim() * log(2.0 * M_PI) / 2.0) -
288  (log(infoMat.determinant()) / 2.0);
289  }
290 };
291 
292 } // namespace gtsam
Definition: HybridValues.h:38
A set of GaussianFactors, indexed by a set of discrete keys.
DecisionTree< Key, sharedFactor > Factors
typedef for DecisionTree which has Keys as node labels and NonlinearFactor as leaf nodes...
Definition: MixtureFactor.h:58
Definition: HybridFactor.h:52
Factor Graph consisting of non-linear factors.
Definition: Factor.h:69
const DiscreteKeys & discreteKeys() const
Return the discrete keys for this factor.
Definition: HybridFactor.h:129
Definition: Group.h:43
MixtureFactor(const KeyVector &keys, const DiscreteKeys &discreteKeys, const std::vector< std::shared_ptr< FACTOR >> &factors, bool normalized=false)
Convenience constructor that generates the underlying factor decision tree for us.
Definition: MixtureFactor.h:98
KeyVector keys_
The keys involved in this factor.
Definition: Factor.h:87
MixtureFactor(const KeyVector &keys, const DiscreteKeys &discreteKeys, const Factors &factors, bool normalized=false)
Construct from Decision tree.
Definition: MixtureFactor.h:77
bool equals(const HybridFactor &other, double tol=1e-9) const override
Check equality.
Definition: MixtureFactor.h:203
static std::vector< DiscreteValues > CartesianProduct(const DiscreteKeys &keys)
Return a vector of DiscreteValues, one for each possible combination of values.
Definition: DiscreteValues.h:85
std::shared_ptr< HybridFactor > shared_ptr
shared_ptr to this class
Definition: HybridFactor.h:68
AlgebraicDecisionTree< Key > error(const Values &continuousValues) const
Compute error of the MixtureFactor as a tree.
Definition: MixtureFactor.h:134
void print(const std::string &s="HybridFactor\, const KeyFormatter &formatter=DefaultKeyFormatter) const override
print
Definition: NoiseModel.h:168
GaussianFactor::shared_ptr linearize(const Values &continuousValues, const DiscreteValues &discreteValues) const
Definition: MixtureFactor.h:229
void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const override
print to stdout
Definition: MixtureFactor.h:186
virtual Matrix information() const
Compute information matrix.
double nonlinearFactorLogNormalizingConstant(const sharedFactor &factor, const Values &values) const
Definition: MixtureFactor.h:258
Definition: DiscreteValues.h:34
HybridFactor()=default
Definition: Values.h:65
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
KeyVector continuousKeys_
Record continuous keys for book-keeping.
Definition: HybridFactor.h:62
std::shared_ptr< This > shared_ptr
shared_ptr to this class
Definition: GaussianFactor.h:42
Definition: chartTesting.h:28
void print(const std::string &s, const LabelFormatter &labelFormatter, const ValueFormatter &valueFormatter) const
GTSAM-style print.
Definition: DecisionTree-inl.h:872
FastVector< Key > KeyVector
Define collection type once and for all - also used in wrappers.
Definition: Key.h:86
double error(const Values &continuousValues, const DiscreteValues &discreteValues) const
Compute error of factor given both continuous and discrete values.
Definition: MixtureFactor.h:150
Non-linear factor base classes.
size_t dim() const
Get the dimension of the factor (number of rows on linearization). Returns the dimension of the first...
Definition: MixtureFactor.h:176
const DiscreteValues & discrete() const
Return the discrete values.
Definition: HybridValues.h:92
const KeyVector & keys() const
Access the factor&#39;s involved variable keys.
Definition: Factor.h:142
double error(const HybridValues &values) const override
Compute error of factor given hybrid values.
Definition: MixtureFactor.h:167
Implementation of a discrete conditional mixture factor.
Definition: MixtureFactor.h:47
const Values & nonlinear() const
Return the nonlinear values.
Definition: HybridValues.h:95
bool equal(const T &obj1, const T &obj2, double tol)
Definition: Testable.h:85
std::shared_ptr< GaussianMixtureFactor > linearize(const Values &continuousValues) const
Linearize all the continuous factors to get a GaussianMixtureFactor.
Definition: MixtureFactor.h:237
DiscreteKeys is a set of keys that can be assembled using the & operator.
Definition: DiscreteKey.h:41