BetweenFactorEM.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 
16 #pragma once
17 
18 #include <ostream>
19 
20 #include <gtsam/base/Testable.h>
21 #include <gtsam/base/Lie.h>
25 
26 namespace gtsam {
27 
33 template<class VALUE>
35 
36 public:
37 
38  typedef VALUE T;
39 
40 private:
41 
44 
47 
52 
53  double prior_inlier_;
55 
57 
61 
62 public:
63 
64  // shorthand for a smart pointer to a factor
65  typedef typename std::shared_ptr<BetweenFactorEM> shared_ptr;
66 
69  }
70 
73  const SharedGaussian& model_inlier, const SharedGaussian& model_outlier,
74  const double prior_inlier, const double prior_outlier,
75  const bool flag_bump_up_near_zero_probs = false) :
76  Base(KeyVector{key1, key2}), key1_(key1), key2_(key2), measured_(
77  measured), model_inlier_(model_inlier), model_outlier_(model_outlier), prior_inlier_(
78  prior_inlier), prior_outlier_(prior_outlier), flag_bump_up_near_zero_probs_(
79  flag_bump_up_near_zero_probs) {
80  }
81 
82  ~BetweenFactorEM() override {
83  }
84 
88  void print(const std::string& s, const KeyFormatter& keyFormatter =
89  DefaultKeyFormatter) const override {
90  std::cout << s << "BetweenFactorEM(" << keyFormatter(key1_) << ","
91  << keyFormatter(key2_) << ")\n";
92  measured_.print(" measured: ");
93  model_inlier_->print(" noise model inlier: ");
94  model_outlier_->print(" noise model outlier: ");
95  std::cout << "(prior_inlier, prior_outlier_) = (" << prior_inlier_ << ","
96  << prior_outlier_ << ")\n";
97  // Base::print(s, keyFormatter);
98  }
99 
101  bool equals(const NonlinearFactor& f, double tol = 1e-9) const override {
102  const This *t = dynamic_cast<const This*>(&f);
103 
104  if (t && Base::equals(f))
105  return key1_ == t->key1_ && key2_ == t->key2_
106  &&
107  // model_inlier_->equals(t->model_inlier_ ) && // TODO: fix here
108  // model_outlier_->equals(t->model_outlier_ ) &&
109  prior_outlier_ == t->prior_outlier_
110  && prior_inlier_ == t->prior_inlier_ && measured_.equals(t->measured_);
111  else
112  return false;
113  }
114 
117  /* ************************************************************************* */
118  double error(const Values &x) const override {
119  return whitenedError(x).squaredNorm();
120  }
121 
122  /* ************************************************************************* */
128  /* This version of linearize recalculates the noise model each time */
129  std::shared_ptr<GaussianFactor> linearize(const Values &x) const override {
130  // Only linearize if the factor is active
131  if (!this->active(x))
132  return std::shared_ptr<JacobianFactor>();
133 
134  //std::cout<<"About to linearize"<<std::endl;
135  Matrix A1, A2;
136  std::vector<Matrix> A(this->size());
137  Vector b = -whitenedError(x, A);
138  A1 = A[0];
139  A2 = A[1];
140 
142  new JacobianFactor(key1_, A1, key2_, A2, b,
143  noiseModel::Unit::Create(b.size())));
144  }
145 
146  /* ************************************************************************* */
148  OptionalMatrixVecType H = nullptr) const {
149 
150  bool debug = true;
151 
152  const T& p1 = x.at<T>(key1_);
153  const T& p2 = x.at<T>(key2_);
154 
155  Matrix H1, H2;
156 
157  T hx = p1.between(p2, H1, H2); // h(x)
158  // manifold equivalent of h(x)-z -> log(z,h(x))
159 
160  Vector err = measured_.localCoordinates(hx);
161 
162  // Calculate indicator probabilities (inlier and outlier)
163  Vector p_inlier_outlier = calcIndicatorProb(x);
164  double p_inlier = p_inlier_outlier[0];
165  double p_outlier = p_inlier_outlier[1];
166 
167  Vector err_wh_inlier = model_inlier_->whiten(err);
168  Vector err_wh_outlier = model_outlier_->whiten(err);
169 
170  Matrix invCov_inlier = model_inlier_->R().transpose() * model_inlier_->R();
171  Matrix invCov_outlier = model_outlier_->R().transpose()
172  * model_outlier_->R();
173 
174  Vector err_wh_eq;
175  err_wh_eq.resize(err_wh_inlier.rows() * 2);
176  err_wh_eq << sqrt(p_inlier) * err_wh_inlier.array(), sqrt(p_outlier)
177  * err_wh_outlier.array();
178 
179  if (H) {
180  // stack Jacobians for the two indicators for each of the key
181 
182  Matrix H1_inlier = sqrt(p_inlier) * model_inlier_->Whiten(H1);
183  Matrix H1_outlier = sqrt(p_outlier) * model_outlier_->Whiten(H1);
184  Matrix H1_aug = stack(2, &H1_inlier, &H1_outlier);
185 
186  Matrix H2_inlier = sqrt(p_inlier) * model_inlier_->Whiten(H2);
187  Matrix H2_outlier = sqrt(p_outlier) * model_outlier_->Whiten(H2);
188  Matrix H2_aug = stack(2, &H2_inlier, &H2_outlier);
189 
190  (*H)[0].resize(H1_aug.rows(), H1_aug.cols());
191  (*H)[1].resize(H2_aug.rows(), H2_aug.cols());
192 
193  (*H)[0] = H1_aug;
194  (*H)[1] = H2_aug;
195  }
196 
197  if (debug) {
198  // std::cout<<"unwhitened error: "<<err[0]<<" "<<err[1]<<" "<<err[2]<<std::endl;
199  // std::cout<<"err_wh_inlier: "<<err_wh_inlier[0]<<" "<<err_wh_inlier[1]<<" "<<err_wh_inlier[2]<<std::endl;
200  // std::cout<<"err_wh_outlier: "<<err_wh_outlier[0]<<" "<<err_wh_outlier[1]<<" "<<err_wh_outlier[2]<<std::endl;
201  //
202  // std::cout<<"p_inlier, p_outlier, sumP: "<<p_inlier<<" "<<p_outlier<<" " << sumP << std::endl;
203  //
204  // std::cout<<"prior_inlier_, prior_outlier_: "<<prior_inlier_<<" "<<prior_outlier_<< std::endl;
205  //
206  // double s_inl = -0.5 * err_wh_inlier.dot(err_wh_inlier);
207  // double s_outl = -0.5 * err_wh_outlier.dot(err_wh_outlier);
208  // std::cout<<"s_inl, s_outl: "<<s_inl<<" "<<s_outl<<std::endl;
209  //
210  // std::cout<<"norm of invCov_inlier, invCov_outlier: "<<invCov_inlier.norm()<<" "<<invCov_outlier.norm()<<std::endl;
211  // double q_inl = invCov_inlier.norm() * exp( -0.5 * err_wh_inlier.dot(err_wh_inlier) );
212  // double q_outl = invCov_outlier.norm() * exp( -0.5 * err_wh_outlier.dot(err_wh_outlier) );
213  // std::cout<<"q_inl, q_outl: "<<q_inl<<" "<<q_outl<<std::endl;
214 
215  // Matrix Cov_inlier = invCov_inlier.inverse();
216  // Matrix Cov_outlier = invCov_outlier.inverse();
217  // std::cout<<"Cov_inlier: "<<std::endl<<
218  // Cov_inlier(0,0) << " " << Cov_inlier(0,1) << " " << Cov_inlier(0,2) <<std::endl<<
219  // Cov_inlier(1,0) << " " << Cov_inlier(1,1) << " " << Cov_inlier(1,2) <<std::endl<<
220  // Cov_inlier(2,0) << " " << Cov_inlier(2,1) << " " << Cov_inlier(2,2) <<std::endl;
221  // std::cout<<"Cov_outlier: "<<std::endl<<
222  // Cov_outlier(0,0) << " " << Cov_outlier(0,1) << " " << Cov_outlier(0,2) <<std::endl<<
223  // Cov_outlier(1,0) << " " << Cov_outlier(1,1) << " " << Cov_outlier(1,2) <<std::endl<<
224  // Cov_outlier(2,0) << " " << Cov_outlier(2,1) << " " << Cov_outlier(2,2) <<std::endl;
225  // std::cout<<"===="<<std::endl;
226  }
227 
228  return err_wh_eq;
229  }
230 
231  // A function overload that takes a vector of matrices and passes it to the
232  // function above which uses a pointer to a vector instead.
233  Vector whitenedError(const Values& x, std::vector<Matrix>& H) const {
234  return whitenedError(x, &H);
235  }
236 
237  /* ************************************************************************* */
239 
240  bool debug = false;
241 
242  Vector err = unwhitenedError(x);
243 
244  // Calculate indicator probabilities (inlier and outlier)
245  Vector err_wh_inlier = model_inlier_->whiten(err);
246  Vector err_wh_outlier = model_outlier_->whiten(err);
247 
248  Matrix invCov_inlier = model_inlier_->R().transpose() * model_inlier_->R();
249  Matrix invCov_outlier = model_outlier_->R().transpose()
250  * model_outlier_->R();
251 
252  double p_inlier = prior_inlier_ * std::sqrt(invCov_inlier.determinant())
253  * exp(-0.5 * err_wh_inlier.dot(err_wh_inlier));
254  double p_outlier = prior_outlier_ * std::sqrt(invCov_outlier.determinant())
255  * exp(-0.5 * err_wh_outlier.dot(err_wh_outlier));
256 
257  if (debug) {
258  std::cout << "in calcIndicatorProb. err_unwh: " << err[0] << ", "
259  << err[1] << ", " << err[2] << std::endl;
260  std::cout << "in calcIndicatorProb. err_wh_inlier: " << err_wh_inlier[0]
261  << ", " << err_wh_inlier[1] << ", " << err_wh_inlier[2] << std::endl;
262  std::cout << "in calcIndicatorProb. err_wh_inlier.dot(err_wh_inlier): "
263  << err_wh_inlier.dot(err_wh_inlier) << std::endl;
264  std::cout << "in calcIndicatorProb. err_wh_outlier.dot(err_wh_outlier): "
265  << err_wh_outlier.dot(err_wh_outlier) << std::endl;
266 
267  std::cout
268  << "in calcIndicatorProb. p_inlier, p_outlier before normalization: "
269  << p_inlier << ", " << p_outlier << std::endl;
270  }
271 
272  double sumP = p_inlier + p_outlier;
273  p_inlier /= sumP;
274  p_outlier /= sumP;
275 
276  if (flag_bump_up_near_zero_probs_) {
277  // Bump up near-zero probabilities (as in linerFlow.h)
278  double minP = 0.05; // == 0.1 / 2 indicator variables
279  if (p_inlier < minP || p_outlier < minP) {
280  if (p_inlier < minP)
281  p_inlier = minP;
282  if (p_outlier < minP)
283  p_outlier = minP;
284  sumP = p_inlier + p_outlier;
285  p_inlier /= sumP;
286  p_outlier /= sumP;
287  }
288  }
289 
290  return (Vector(2) << p_inlier, p_outlier).finished();
291  }
292 
293  /* ************************************************************************* */
294  Vector unwhitenedError(const Values& x) const {
295 
296  const T& p1 = x.at<T>(key1_);
297  const T& p2 = x.at<T>(key2_);
298 
299  Matrix H1, H2;
300 
301  T hx = p1.between(p2, H1, H2); // h(x)
302 
303  return measured_.localCoordinates(hx);
304  }
305 
306  /* ************************************************************************* */
308  flag_bump_up_near_zero_probs_ = flag;
309  }
310 
311  /* ************************************************************************* */
314  }
315 
316  /* ************************************************************************* */
318  return model_inlier_;
319  }
320 
321  /* ************************************************************************* */
323  return model_outlier_;
324  }
325 
326  /* ************************************************************************* */
328  return (model_inlier_->R().transpose() * model_inlier_->R()).inverse();
329  }
330 
331  /* ************************************************************************* */
333  return (model_outlier_->R().transpose() * model_outlier_->R()).inverse();
334  }
335 
336  /* ************************************************************************* */
338  const NonlinearFactorGraph& graph) {
339  /* Update model_inlier_ and model_outlier_ to account for uncertainty in robot trajectories
340  * (note these are given in the E step, where indicator probabilities are calculated).
341  *
342  * Principle: R += [H1 H2] * joint_cov12 * [H1 H2]', where H1, H2 are Jacobians of the
343  * unwhitened error w.r.t. states, and R is the measurement covariance (inlier or outlier modes).
344  *
345  * TODO: improve efficiency (info form)
346  */
347 
348  // get joint covariance of the involved states
349  KeyVector Keys;
350  Keys.push_back(key1_);
351  Keys.push_back(key2_);
352  Marginals marginals(graph, values, Marginals::QR);
353  JointMarginal joint_marginal12 = marginals.jointMarginalCovariance(Keys);
354  Matrix cov1 = joint_marginal12(key1_, key1_);
355  Matrix cov2 = joint_marginal12(key2_, key2_);
356  Matrix cov12 = joint_marginal12(key1_, key2_);
357 
358  updateNoiseModels_givenCovs(values, cov1, cov2, cov12);
359  }
360 
361  /* ************************************************************************* */
363  const Matrix& cov1, const Matrix& cov2, const Matrix& cov12) {
364  /* Update model_inlier_ and model_outlier_ to account for uncertainty in robot trajectories
365  * (note these are given in the E step, where indicator probabilities are calculated).
366  *
367  * Principle: R += [H1 H2] * joint_cov12 * [H1 H2]', where H1, H2 are Jacobians of the
368  * unwhitened error w.r.t. states, and R is the measurement covariance (inlier or outlier modes).
369  *
370  * TODO: improve efficiency (info form)
371  */
372 
373  const T& p1 = values.at<T>(key1_);
374  const T& p2 = values.at<T>(key2_);
375 
376  Matrix H1, H2;
377  p1.between(p2, H1, H2); // h(x)
378 
379  Matrix H;
380  H.resize(H1.rows(), H1.rows() + H2.rows());
381  H << H1, H2; // H = [H1 H2]
382 
383  Matrix joint_cov;
384  joint_cov.resize(cov1.rows() + cov2.rows(), cov1.cols() + cov2.cols());
385  joint_cov << cov1, cov12, cov12.transpose(), cov2;
386 
387  Matrix cov_state = H * joint_cov * H.transpose();
388 
389  // model_inlier_->print("before:");
390 
391  // update inlier and outlier noise models
392  Matrix covRinlier =
393  (model_inlier_->R().transpose() * model_inlier_->R()).inverse();
394  model_inlier_ = noiseModel::Gaussian::Covariance(
395  covRinlier + cov_state);
396 
397  Matrix covRoutlier =
398  (model_outlier_->R().transpose() * model_outlier_->R()).inverse();
399  model_outlier_ = noiseModel::Gaussian::Covariance(
400  covRoutlier + cov_state);
401 
402  // model_inlier_->print("after:");
403  // std::cout<<"covRinlier + cov_state: "<<covRinlier + cov_state<<std::endl;
404  }
405 
406  /* ************************************************************************* */
408  const VALUE& measured() const {
409  return measured_;
410  }
411 
412  size_t dim() const override {
413  return model_inlier_->R().rows() + model_inlier_->R().cols();
414  }
415 
416 private:
417 
418 #ifdef GTSAM_ENABLE_BOOST_SERIALIZATION
419 
420  friend class boost::serialization::access;
421  template<class ARCHIVE>
422  void serialize(ARCHIVE & ar, const unsigned int /*version*/) {
423  ar
424  & boost::serialization::make_nvp("NonlinearFactor",
425  boost::serialization::base_object<Base>(*this));
426  ar & BOOST_SERIALIZATION_NVP(measured_);
427  }
428 #endif
429 };
430 // \class BetweenFactorEM
431 
433 template<class VALUE>
434 struct traits<BetweenFactorEM<VALUE> > : public Testable<BetweenFactorEM<VALUE> > {};
435 
436 } // namespace gtsam
SharedGaussian get_model_outlier() const
static Matrix A1
std::vector< Matrix > * OptionalMatrixVecType
Vector whitenedError(const Values &x, std::vector< Matrix > &H) const
bool get_flag_bump_up_near_zero_probs() const
SharedGaussian get_model_inlier() const
static shared_ptr Covariance(const Matrix &covariance, bool smart=true)
Definition: NoiseModel.cpp:114
Concept check for values that can be used in unit tests.
Vector3f p1
std::string serialize(const T &input)
serializes to a string
const ValueType at(Key j) const
Definition: Values-inl.h:204
size_t size() const
Definition: Factor.h:159
Eigen::MatrixXd Matrix
Definition: base/Matrix.h:39
A factor with a quadratic error function - a Gaussian.
SharedGaussian model_outlier_
leaf::MyValues values
Matrix get_model_inlier_cov() const
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy y set format x g set format y g set format x2 g set format y2 g set format z g set angles radians set nogrid set key title set key left top Right noreverse box linetype linewidth samplen spacing width set nolabel set noarrow set nologscale set logscale x set set pointsize set encoding default set nopolar set noparametric set set set set surface set nocontour set clabel set mapping cartesian set nohidden3d set cntrparam order set cntrparam linear set cntrparam levels auto set cntrparam points set size set set xzeroaxis lt lw set x2zeroaxis lt lw set yzeroaxis lt lw set y2zeroaxis lt lw set tics in set ticslevel set tics set mxtics default set mytics default set mx2tics default set my2tics default set xtics border mirror norotate autofreq set ytics border mirror norotate autofreq set ztics border nomirror norotate autofreq set nox2tics set noy2tics set timestamp bottom norotate set rrange [*:*] noreverse nowriteback set trange [*:*] noreverse nowriteback set urange [*:*] noreverse nowriteback set vrange [*:*] noreverse nowriteback set xlabel matrix size set x2label set timefmt d m y n H
#define GTSAM_CONCEPT_TESTABLE_TYPE(T)
Definition: Testable.h:177
const VALUE & measured() const
NonlinearFactorGraph graph
void set_flag_bump_up_near_zero_probs(bool flag)
static const KeyFormatter DefaultKeyFormatter
Definition: Key.h:43
EIGEN_DEVICE_FUNC const InverseReturnType inverse() const
static constexpr bool debug
NonlinearFactor Base
static shared_ptr Create(size_t dim)
Definition: NoiseModel.h:610
EIGEN_DEVICE_FUNC const ExpReturnType exp() const
virtual bool equals(const NonlinearFactor &f, double tol=1e-9) const
JointMarginal jointMarginalCovariance(const KeyVector &variables) const
Definition: Marginals.cpp:138
void updateNoiseModels_givenCovs(const Values &values, const Matrix &cov1, const Matrix &cov2, const Matrix &cov12)
Eigen::VectorXd Vector
Definition: Vector.h:38
const Symbol key1('v', 1)
Matrix get_model_outlier_cov() const
Vector whitenedError(const Values &x, OptionalMatrixVecType H=nullptr) const
Matrix stack(size_t nrMatrices,...)
Definition: Matrix.cpp:395
SharedGaussian model_inlier_
BetweenFactorEM(Key key1, Key key2, const VALUE &measured, const SharedGaussian &model_inlier, const SharedGaussian &model_outlier, const double prior_inlier, const double prior_outlier, const bool flag_bump_up_near_zero_probs=false)
Point2(* f)(const Point3 &, OptionalJacobian< 2, 3 >)
Array< double, 1, 3 > e(1./3., 0.5, 2.)
RealScalar s
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
const G & b
Definition: Group.h:86
Base class and basic functions for Lie types.
std::shared_ptr< This > shared_ptr
shared_ptr to this class
void updateNoiseModels(const Values &values, const NonlinearFactorGraph &graph)
traits
Definition: chartTesting.h:28
#define GTSAM_CONCEPT_LIE_TYPE(T)
Definition: Lie.h:373
Non-linear factor base classes.
virtual bool active(const Values &) const
size_t dim() const override
bool equals(const NonlinearFactor &f, double tol=1e-9) const override
static Point3 p2
BetweenFactorEM< VALUE > This
A class for computing marginals in a NonlinearFactorGraph.
Jet< T, N > sqrt(const Jet< T, N > &f)
Definition: jet.h:418
const G double tol
Definition: Group.h:86
Vector unwhitenedError(const Values &x) const
FastVector< Key > KeyVector
Define collection type once and for all - also used in wrappers.
Definition: Key.h:86
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy x
std::uint64_t Key
Integer nonlinear key type.
Definition: types.h:102
std::shared_ptr< BetweenFactorEM > shared_ptr
Marginals marginals(graph, result)
void print(const std::string &s, const KeyFormatter &keyFormatter=DefaultKeyFormatter) const override
std::shared_ptr< GaussianFactor > linearize(const Values &x) const override
noiseModel::Gaussian::shared_ptr SharedGaussian
Definition: NoiseModel.h:742
Point2 t(10, 10)
double error(const Values &x) const override
const Symbol key2('v', 2)
bool equals(const This &other, double tol=1e-9) const
check equality
Definition: Factor.cpp:42
Vector calcIndicatorProb(const Values &x) const


gtsam
Author(s):
autogenerated on Tue Jul 4 2023 02:33:58