gtsam  3.2.1
gtsam
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ImplicitSchurFactor.h
Go to the documentation of this file.
1 
8 #pragma once
9 
13 #include <boost/foreach.hpp>
14 #include <boost/make_shared.hpp>
15 #include <iostream>
16 
17 namespace gtsam {
18 
22 template<size_t D> //
24 
25 public:
27  typedef boost::shared_ptr<This> shared_ptr;
28 
29 protected:
30 
31  typedef Eigen::Matrix<double, 2, D> Matrix2D;
32  typedef Eigen::Matrix<double, 2, 3> Matrix23;
33  typedef Eigen::Matrix<double, D, D> MatrixDD;
34  typedef std::pair<Key, Matrix2D> KeyMatrix2D;
35 
36  std::vector<KeyMatrix2D> Fblocks_;
37  Matrix3 PointCovariance_;
38  Matrix E_;
39  Vector b_;
40 
41 public:
42 
45  }
46 
48  ImplicitSchurFactor(const std::vector<KeyMatrix2D>& Fblocks, const Matrix& E,
49  const Matrix3& P, const Vector& b) :
50  Fblocks_(Fblocks), PointCovariance_(P), E_(E), b_(b) {
51  initKeys();
52  }
53 
55  void initKeys() {
56  keys_.reserve(Fblocks_.size());
57  BOOST_FOREACH(const KeyMatrix2D& it, Fblocks_)
58  keys_.push_back(it.first);
59  }
60 
63  }
64 
65  // Write access, only use for construction!
66 
67  inline std::vector<KeyMatrix2D>& Fblocks() {
68  return Fblocks_;
69  }
70 
71  inline Matrix3& PointCovariance() {
72  return PointCovariance_;
73  }
74 
75  inline Matrix& E() {
76  return E_;
77  }
78 
79  inline Vector& b() {
80  return b_;
81  }
82 
84  inline const Matrix3& getPointCovariance() const {
85  return PointCovariance_;
86  }
87 
89  void print(const std::string& s = "",
90  const KeyFormatter& keyFormatter = DefaultKeyFormatter) const {
91  std::cout << " ImplicitSchurFactor " << std::endl;
92  Factor::print(s);
93  std::cout << " PointCovariance_ \n" << PointCovariance_ << std::endl;
94  std::cout << " E_ \n" << E_ << std::endl;
95  std::cout << " b_ \n" << b_.transpose() << std::endl;
96  }
97 
99  bool equals(const GaussianFactor& lf, double tol) const {
100  if (!dynamic_cast<const ImplicitSchurFactor*>(&lf))
101  return false;
102  else {
103  return false;
104  }
105  }
106 
108  virtual DenseIndex getDim(const_iterator variable) const {
109  return D;
110  }
111 
112  virtual Matrix augmentedJacobian() const {
113  throw std::runtime_error(
114  "ImplicitSchurFactor::augmentedJacobian non implemented");
115  return Matrix();
116  }
117  virtual std::pair<Matrix, Vector> jacobian() const {
118  throw std::runtime_error("ImplicitSchurFactor::jacobian non implemented");
119  return std::make_pair(Matrix(), Vector());
120  }
121  virtual Matrix augmentedInformation() const {
122  throw std::runtime_error(
123  "ImplicitSchurFactor::augmentedInformation non implemented");
124  return Matrix();
125  }
126  virtual Matrix information() const {
127  throw std::runtime_error(
128  "ImplicitSchurFactor::information non implemented");
129  return Matrix();
130  }
131 
133  virtual VectorValues hessianDiagonal() const {
134  // diag(Hessian) = diag(F' * (I - E * PointCov * E') * F);
135  VectorValues d;
136 
137  for (size_t pos = 0; pos < size(); ++pos) { // for each camera
138  Key j = keys_[pos];
139 
140  // Calculate Fj'*Ej for the current camera (observing a single point)
141  // D x 3 = (D x 2) * (2 x 3)
142  const Matrix2D& Fj = Fblocks_[pos].second;
143  Eigen::Matrix<double, D, 3> FtE = Fj.transpose()
144  * E_.block<2, 3>(2 * pos, 0);
145 
146  Eigen::Matrix<double, D, 1> dj;
147  for (size_t k = 0; k < D; ++k) { // for each diagonal element of the camera hessian
148  // Vector column_k_Fj = Fj.col(k);
149  dj(k) = Fj.col(k).squaredNorm(); // dot(column_k_Fj, column_k_Fj);
150  // Vector column_k_FtE = FtE.row(k);
151  // (1 x 1) = (1 x 3) * (3 * 3) * (3 x 1)
152  dj(k) -= FtE.row(k) * PointCovariance_ * FtE.row(k).transpose();
153  }
154  d.insert(j, dj);
155  }
156  return d;
157  }
158 
163  void hessianDiagonal(double* d) const {
164  // diag(Hessian) = diag(F' * (I - E * PointCov * E') * F);
165  // Use eigen magic to access raw memory
166  typedef Eigen::Matrix<double, D, 1> DVector;
167  typedef Eigen::Map<DVector> DMap;
168 
169  for (size_t pos = 0; pos < size(); ++pos) { // for each camera in the factor
170  Key j = keys_[pos];
171 
172  // Calculate Fj'*Ej for the current camera (observing a single point)
173  // D x 3 = (D x 2) * (2 x 3)
174  const Matrix2D& Fj = Fblocks_[pos].second;
175  Eigen::Matrix<double, D, 3> FtE = Fj.transpose()
176  * E_.block<2, 3>(2 * pos, 0);
177 
178  DVector dj;
179  for (size_t k = 0; k < D; ++k) { // for each diagonal element of the camera hessian
180  dj(k) = Fj.col(k).squaredNorm();
181  // (1 x 1) = (1 x 3) * (3 * 3) * (3 x 1)
182  dj(k) -= FtE.row(k) * PointCovariance_ * FtE.row(k).transpose();
183  }
184  DMap(d + D * j) += dj;
185  }
186  }
187 
189  virtual std::map<Key, Matrix> hessianBlockDiagonal() const {
190  std::map<Key, Matrix> blocks;
191  // F'*(I - E*P*E')*F
192  for (size_t pos = 0; pos < size(); ++pos) {
193  Key j = keys_[pos];
194  // F'*F - F'*E*P*E'*F (9*2)*(2*9) - (9*2)*(2*3)*(3*3)*(3*2)*(2*9)
195  const Matrix2D& Fj = Fblocks_[pos].second;
196  // Eigen::Matrix<double, D, 3> FtE = Fj.transpose()
197  // * E_.block<2, 3>(2 * pos, 0);
198  // blocks[j] = Fj.transpose() * Fj
199  // - FtE * PointCovariance_ * FtE.transpose();
200 
201  const Matrix23& Ej = E_.block<2, 3>(2 * pos, 0);
202  blocks[j] = Fj.transpose() * (Fj - Ej * PointCovariance_ * Ej.transpose() * Fj);
203 
204  // F'*(I - E*P*E')*F, TODO: this should work, but it does not :-(
205  // static const Eigen::Matrix<double, 2, 2> I2 = eye(2);
206  // Eigen::Matrix<double, 2, 2> Q = //
207  // I2 - E_.block<2, 3>(2 * pos, 0) * PointCovariance_ * E_.block<2, 3>(2 * pos, 0).transpose();
208  // blocks[j] = Fj.transpose() * Q * Fj;
209  }
210  return blocks;
211  }
212 
214  return boost::make_shared<ImplicitSchurFactor<D> >(Fblocks_,
216  throw std::runtime_error("ImplicitSchurFactor::clone non implemented");
217  }
218  virtual bool empty() const {
219  return false;
220  }
221 
223  return boost::make_shared<ImplicitSchurFactor<D> >(Fblocks_,
225  throw std::runtime_error("ImplicitSchurFactor::negate non implemented");
226  }
227 
228  // Raw Vector version of y += F'*alpha*(I - E*P*E')*F*x, for testing
229  static
230  void multiplyHessianAdd(const Matrix& F, const Matrix& E,
231  const Matrix& PointCovariance, double alpha, const Vector& x, Vector& y) {
232  Vector e1 = F * x;
233  Vector d1 = E.transpose() * e1;
234  Vector d2 = PointCovariance * d1;
235  Vector e2 = E * d2;
236  Vector e3 = alpha * (e1 - e2);
237  y += F.transpose() * e3;
238  }
239 
240  typedef std::vector<Vector2> Error2s;
241 
245  void projectError2(const Error2s& e1, Error2s& e2) const {
246 
247  // d1 = E.transpose() * (e1-2*b) = (3*2m)*2m
248  Vector3 d1;
249  d1.setZero();
250  for (size_t k = 0; k < size(); k++)
251  d1 += E_.block < 2, 3 > (2 * k, 0).transpose() * (e1[k] - 2 * b_.segment < 2 > (k * 2));
252 
253  // d2 = E.transpose() * e1 = (3*2m)*2m
254  Vector3 d2 = PointCovariance_ * d1;
255 
256  // e3 = alpha*(e1 - E*d2) = 1*[2m-(2m*3)*3]
257  for (size_t k = 0; k < size(); k++)
258  e2[k] = e1[k] - 2 * b_.segment < 2 > (k * 2) - E_.block < 2, 3 > (2 * k, 0) * d2;
259  }
260 
261  /*
262  * This definition matches the linearized error in the Hessian Factor:
263  * LinError(x) = x'*H*x - 2*x'*eta + f
264  * with:
265  * H = F' * (I-E'*P*E) * F = F' * Q * F
266  * eta = F' * (I-E'*P*E) * b = F' * Q * b
267  * f = nonlinear error
268  * (x'*H*x - 2*x'*eta + f) = x'*F'*Q*F*x - 2*x'*F'*Q *b + f = x'*F'*Q*(F*x - 2*b) + f
269  */
270  virtual double error(const VectorValues& x) const {
271 
272  // resize does not do malloc if correct size
273  e1.resize(size());
274  e2.resize(size());
275 
276  // e1 = F * x - b = (2m*dm)*dm
277  for (size_t k = 0; k < size(); ++k)
278  e1[k] = Fblocks_[k].second * x.at(keys_[k]);
279  projectError2(e1, e2);
280 
281  double result = 0;
282  for (size_t k = 0; k < size(); ++k)
283  result += dot(e1[k], e2[k]);
284 
285  double f = b_.squaredNorm();
286  return 0.5 * (result + f);
287  }
288 
289  // needed to be GaussianFactor - (I - E*P*E')*(F*x - b)
290  // This is wrong and does not match the definition in Hessian,
291  // but it matches the definition of the Jacobian factor (JF)
292  double errorJF(const VectorValues& x) const {
293 
294  // resize does not do malloc if correct size
295  e1.resize(size());
296  e2.resize(size());
297 
298  // e1 = F * x - b = (2m*dm)*dm
299  for (size_t k = 0; k < size(); ++k)
300  e1[k] = Fblocks_[k].second * x.at(keys_[k]) - b_.segment < 2 > (k * 2);
301  projectError(e1, e2);
302 
303  double result = 0;
304  for (size_t k = 0; k < size(); ++k)
305  result += dot(e2[k], e2[k]);
306 
307  // std::cout << "implicitFactor::error result " << result << std::endl;
308  return 0.5 * result;
309  }
313  void projectError(const Error2s& e1, Error2s& e2) const {
314 
315  // d1 = E.transpose() * e1 = (3*2m)*2m
316  Vector3 d1;
317  d1.setZero();
318  for (size_t k = 0; k < size(); k++)
319  d1 += E_.block < 2, 3 > (2 * k, 0).transpose() * e1[k];
320 
321  // d2 = E.transpose() * e1 = (3*2m)*2m
322  Vector3 d2 = PointCovariance_ * d1;
323 
324  // e3 = alpha*(e1 - E*d2) = 1*[2m-(2m*3)*3]
325  for (size_t k = 0; k < size(); k++)
326  e2[k] = e1[k] - E_.block < 2, 3 > (2 * k, 0) * d2;
327  }
328 
330  mutable Error2s e1, e2;
331 
336  void multiplyHessianAdd(double alpha, const double* x, double* y) const {
337 
338  // Use eigen magic to access raw memory
339  typedef Eigen::Matrix<double, D, 1> DVector;
340  typedef Eigen::Map<DVector> DMap;
341  typedef Eigen::Map<const DVector> ConstDMap;
342 
343  // resize does not do malloc if correct size
344  e1.resize(size());
345  e2.resize(size());
346 
347  // e1 = F * x = (2m*dm)*dm
348  size_t k = 0;
349  BOOST_FOREACH(const KeyMatrix2D& it, Fblocks_) {
350  Key key = it.first;
351  e1[k++] = it.second * ConstDMap(x + D * key);
352  }
353 
354  projectError(e1, e2);
355 
356  // y += F.transpose()*e2 = (2d*2m)*2m
357  k = 0;
358  BOOST_FOREACH(const KeyMatrix2D& it, Fblocks_) {
359  Key key = it.first;
360  DMap(y + D * key) += it.second.transpose() * alpha * e2[k++];
361  }
362  }
363 
364  void multiplyHessianAdd(double alpha, const double* x, double* y,
365  std::vector<size_t> keys) const {
366  }
367  ;
368 
372  void multiplyHessianAdd(double alpha, const VectorValues& x,
373  VectorValues& y) const {
374 
375  // resize does not do malloc if correct size
376  e1.resize(size());
377  e2.resize(size());
378 
379  // e1 = F * x = (2m*dm)*dm
380  for (size_t k = 0; k < size(); ++k)
381  e1[k] = Fblocks_[k].second * x.at(keys_[k]);
382 
383  projectError(e1, e2);
384 
385  // y += F.transpose()*e2 = (2d*2m)*2m
386  for (size_t k = 0; k < size(); ++k) {
387  Key key = keys_[k];
388  static const Vector empty;
389  std::pair<VectorValues::iterator, bool> it = y.tryInsert(key, empty);
390  Vector& yi = it.first->second;
391  // Create the value as a zero vector if it does not exist.
392  if (it.second)
393  yi = Vector::Zero(Fblocks_[k].second.cols());
394  yi += Fblocks_[k].second.transpose() * alpha * e2[k];
395  }
396  }
397 
401  void multiplyHessianDummy(double alpha, const VectorValues& x,
402  VectorValues& y) const {
403 
404  BOOST_FOREACH(const KeyMatrix2D& Fi, Fblocks_) {
405  static const Vector empty;
406  Key key = Fi.first;
407  std::pair<VectorValues::iterator, bool> it = y.tryInsert(key, empty);
408  Vector& yi = it.first->second;
409  yi = x.at(key);
410  }
411  }
412 
417  // calculate Q*b
418  e1.resize(size());
419  e2.resize(size());
420  for (size_t k = 0; k < size(); k++)
421  e1[k] = b_.segment < 2 > (2 * k);
422  projectError(e1, e2);
423 
424  // g = F.transpose()*e2
425  VectorValues g;
426  for (size_t k = 0; k < size(); ++k) {
427  Key key = keys_[k];
428  g.insert(key, -Fblocks_[k].second.transpose() * e2[k]);
429  }
430 
431  // return it
432  return g;
433  }
434 
438  void gradientAtZero(double* d) const {
439 
440  // Use eigen magic to access raw memory
441  typedef Eigen::Matrix<double, D, 1> DVector;
442  typedef Eigen::Map<DVector> DMap;
443 
444  // calculate Q*b
445  e1.resize(size());
446  e2.resize(size());
447  for (size_t k = 0; k < size(); k++)
448  e1[k] = b_.segment < 2 > (2 * k);
449  projectError(e1, e2);
450 
451  for (size_t k = 0; k < size(); ++k) { // for each camera in the factor
452  Key j = keys_[k];
453  DMap(d + D * j) += -Fblocks_[k].second.transpose() * e2[k];
454  }
455  }
456 
457 };
458 // ImplicitSchurFactor
459 
460 }
461 
Vector b_
2m-dimensional RHS vector
Definition: ImplicitSchurFactor.h:39
void hessianDiagonal(double *d) const
add the contribution of this factor to the diagonal of the hessian d(output) = d(input) + deltaHessia...
Definition: ImplicitSchurFactor.h:163
virtual std::pair< Matrix, Vector > jacobian() const
Return the dense Jacobian and right-hand-side , with the noise models baked into A and b...
Definition: ImplicitSchurFactor.h:117
Vector & at(Key j)
Read/write access to the vector value with key j, throws std::out_of_range if j does not exist...
Definition: VectorValues.h:147
boost::shared_ptr< This > shared_ptr
shared_ptr to this class
Definition: ImplicitSchurFactor.h:27
virtual Matrix augmentedInformation() const
Return the augmented information matrix represented by this GaussianFactor.
Definition: ImplicitSchurFactor.h:121
double dot(const V1 &a, const V2 &b)
Dot product.
Definition: Vector.h:259
void projectError(const Error2s &e1, Error2s &e2) const
Calculate corrected error Q*e = (I - E*P*E')*e.
Definition: ImplicitSchurFactor.h:313
std::vector< KeyMatrix2D > Fblocks_
All 2*D F blocks (one for each camera)
Definition: ImplicitSchurFactor.h:36
virtual VectorValues hessianDiagonal() const
Return the diagonal of the Hessian for this factor.
Definition: ImplicitSchurFactor.h:133
ImplicitSchurFactor(const std::vector< KeyMatrix2D > &Fblocks, const Matrix &E, const Matrix3 &P, const Vector &b)
Construct from blcoks of F, E, inv(E'*E), and RHS vector b.
Definition: ImplicitSchurFactor.h:48
void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const
print
Definition: ImplicitSchurFactor.h:89
void initKeys()
initialize keys from Fblocks
Definition: ImplicitSchurFactor.h:55
Matrix E_
The 2m*3 E Jacobian with respect to the point.
Definition: ImplicitSchurFactor.h:38
std::pair< Key, Matrix2D > KeyMatrix2D
named F block
Definition: ImplicitSchurFactor.h:34
Eigen::Matrix< double, D, D > MatrixDD
camera hessian
Definition: ImplicitSchurFactor.h:33
ImplicitSchurFactor.
Definition: ImplicitSchurFactor.h:23
const Matrix3 & getPointCovariance() const
Get matrix P.
Definition: ImplicitSchurFactor.h:84
ImplicitSchurFactor This
Typedef to this class.
Definition: ImplicitSchurFactor.h:26
FastVector< Key > keys_
The keys involved in this factor.
Definition: Factor.h:69
Factor Graph Values.
bool equals(const GaussianFactor &lf, double tol) const
equals
Definition: ImplicitSchurFactor.h:99
const FastVector< Key > & keys() const
Access the factor's involved variable keys.
Definition: Factor.h:115
Error2s e1
Scratch space for multiplyHessianAdd.
Definition: ImplicitSchurFactor.h:330
void print(const std::string &s="Factor", const KeyFormatter &formatter=DefaultKeyFormatter) const
print
Definition: Factor.cpp:30
virtual double error(const VectorValues &x) const
Print for testable.
Definition: ImplicitSchurFactor.h:270
void multiplyHessianAdd(double alpha, const double *x, double *y) const
double* Hessian-vector multiply, i.e.
Definition: ImplicitSchurFactor.h:336
void multiplyHessianAdd(double alpha, const VectorValues &x, VectorValues &y) const
Hessian-vector multiply, i.e.
Definition: ImplicitSchurFactor.h:372
virtual std::map< Key, Matrix > hessianBlockDiagonal() const
Return the block diagonal of the Hessian for this factor.
Definition: ImplicitSchurFactor.h:189
Eigen::Matrix< double, 2, D > Matrix2D
type of an F block
Definition: ImplicitSchurFactor.h:31
virtual DenseIndex getDim(const_iterator variable) const
Degrees of freedom of camera.
Definition: ImplicitSchurFactor.h:108
virtual bool empty() const
Test whether the factor is empty.
Definition: ImplicitSchurFactor.h:218
size_t Key
Integer nonlinear key type.
Definition: types.h:59
ImplicitSchurFactor()
Constructor.
Definition: ImplicitSchurFactor.h:44
ptrdiff_t DenseIndex
The index type for Eigen objects.
Definition: types.h:74
size_t size() const
Definition: Factor.h:126
boost::shared_ptr< This > shared_ptr
shared_ptr to this class
Definition: GaussianFactor.h:39
void gradientAtZero(double *d) const
Calculate gradient, which is -F'Q*b, see paper - RAW MEMORY ACCESS.
Definition: ImplicitSchurFactor.h:438
virtual Matrix augmentedJacobian() const
Return a dense Jacobian matrix, augmented with b with the noise models baked into A and b...
Definition: ImplicitSchurFactor.h:112
This class represents a collection of vector-valued variables associated each with a unique integer i...
Definition: VectorValues.h:89
void multiplyHessianDummy(double alpha, const VectorValues &x, VectorValues &y) const
Dummy version to measure overhead of key access.
Definition: ImplicitSchurFactor.h:401
virtual ~ImplicitSchurFactor()
Destructor.
Definition: ImplicitSchurFactor.h:62
virtual GaussianFactor::shared_ptr clone() const
Clone a factor (make a deep copy)
Definition: ImplicitSchurFactor.h:213
iterator insert(Key j, const Vector &value)
Insert a vector value with key j.
Definition: VectorValues.h:183
VectorValues gradientAtZero() const
Calculate gradient, which is -F'Q*b, see paper.
Definition: ImplicitSchurFactor.h:416
void projectError2(const Error2s &e1, Error2s &e2) const
Calculate corrected error Q*(e-2*b) = (I - E*P*E')*(e-2*b)
Definition: ImplicitSchurFactor.h:245
void multiplyHessianAdd(double alpha, const double *x, double *y, std::vector< size_t > keys) const
y += alpha * A'*A*x
Definition: ImplicitSchurFactor.h:364
virtual GaussianFactor::shared_ptr negate() const
Construct the corresponding anti-factor to negate information stored stored in this factor...
Definition: ImplicitSchurFactor.h:222
std::pair< iterator, bool > tryInsert(Key j, const Vector &value)
insert that mimics the STL map insert - if the value already exists, the map is not modified and an i...
Definition: VectorValues.h:210
boost::function< std::string(Key)> KeyFormatter
Typedef for a function to format a key, i.e. to convert it to a string.
Definition: types.h:62
Linear Factor Graph where all factors are Gaussians.
FastVector< Key >::const_iterator const_iterator
Const iterator over keys.
Definition: Factor.h:64
Matrix3 PointCovariance_
the 3*3 matrix P = inv(E'E) (2*2 if degenerate)
Definition: ImplicitSchurFactor.h:37
virtual Matrix information() const
Return the non-augmented information matrix represented by this GaussianFactor.
Definition: ImplicitSchurFactor.h:126
An abstract virtual base class for JacobianFactor and HessianFactor.
Definition: GaussianFactor.h:35