gtsam  4.0.0
gtsam
ExpressionFactor.h
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 
24 #include <gtsam/base/Testable.h>
25 #include <numeric>
26 
27 namespace gtsam {
28 
33 template<typename T>
34 class ExpressionFactor: public NoiseModelFactor {
35  BOOST_CONCEPT_ASSERT((IsTestable<T>));
36 
37 protected:
38 
39  typedef ExpressionFactor<T> This;
40  static const int Dim = traits<T>::dimension;
41 
44  FastVector<int> dims_;
45 
46 
47  public:
48  typedef boost::shared_ptr<ExpressionFactor<T> > shared_ptr;
49 
58  const T& measurement, const Expression<T>& expression)
59  : NoiseModelFactor(noiseModel), measured_(measurement) {
61  }
62 
64  virtual ~ExpressionFactor() {}
65 
67  const T& measured() const { return measured_; }
68 
70  void print(const std::string& s = "",
71  const KeyFormatter& keyFormatter = DefaultKeyFormatter) const {
72  NoiseModelFactor::print(s, keyFormatter);
73  traits<T>::Print(measured_, "ExpressionFactor with measurement: ");
74  }
75 
77  bool equals(const NonlinearFactor& f, double tol) const {
78  const ExpressionFactor* p = dynamic_cast<const ExpressionFactor*>(&f);
79  return p && NoiseModelFactor::equals(f, tol) &&
80  traits<T>::Equals(measured_, p->measured_, tol) &&
81  dims_ == p->dims_;
82  }
83 
89  virtual Vector unwhitenedError(const Values& x,
90  boost::optional<std::vector<Matrix>&> H = boost::none) const {
91  if (H) {
92  const T value = expression_.valueAndDerivatives(x, keys_, dims_, *H);
93  // NOTE(hayk): Doing the reverse, AKA Local(measured_, value) is not correct here
94  // because it would use the tangent space of the measurement instead of the value.
95  return -traits<T>::Local(value, measured_);
96  } else {
97  const T value = expression_.value(x);
98  return -traits<T>::Local(value, measured_);
99  }
100  }
101 
102  virtual boost::shared_ptr<GaussianFactor> linearize(const Values& x) const {
103  // Only linearize if the factor is active
104  if (!active(x))
105  return boost::shared_ptr<JacobianFactor>();
106 
107  // In case noise model is constrained, we need to provide a noise model
108  SharedDiagonal noiseModel;
109  if (noiseModel_ && noiseModel_->isConstrained()) {
110  noiseModel = boost::static_pointer_cast<noiseModel::Constrained>(
111  noiseModel_)->unit();
112  }
113 
114  // Create a writeable JacobianFactor in advance
115  boost::shared_ptr<JacobianFactor> factor(
116  new JacobianFactor(keys_, dims_, Dim, noiseModel));
117 
118  // Wrap keys and VerticalBlockMatrix into structure passed to expression_
119  VerticalBlockMatrix& Ab = factor->matrixObject();
120  internal::JacobianMap jacobianMap(keys_, Ab);
121 
122  // Zero out Jacobian so we can simply add to it
123  Ab.matrix().setZero();
124 
125  // Get value and Jacobians, writing directly into JacobianFactor
126  T value = expression_.valueAndJacobianMap(x, jacobianMap); // <<< Reverse AD happens here !
127 
128  // Evaluate error and set RHS vector b
129  Ab(size()).col(0) = traits<T>::Local(value, measured_);
130 
131  // Whiten the corresponding system, Ab already contains RHS
132  if (noiseModel_) {
133  Vector b = Ab(size()).col(0); // need b to be valid for Robust noise models
134  noiseModel_->WhitenSystem(Ab.matrix(), b);
135  }
136 
137  return factor;
138  }
139 
141  virtual gtsam::NonlinearFactor::shared_ptr clone() const {
142  return boost::static_pointer_cast<gtsam::NonlinearFactor>(
143  gtsam::NonlinearFactor::shared_ptr(new This(*this)));
144  }
145 
146 protected:
147  ExpressionFactor() {}
149 
151  ExpressionFactor(const SharedNoiseModel& noiseModel, const T& measurement)
152  : NoiseModelFactor(noiseModel), measured_(measurement) {
153  // Not properly initialized yet, need to call initialize
154  }
155 
158  if (!noiseModel_)
159  throw std::invalid_argument("ExpressionFactor: no NoiseModel.");
160  if (noiseModel_->dim() != Dim)
161  throw std::invalid_argument(
162  "ExpressionFactor was created with a NoiseModel of incorrect dimension.");
164 
165  // Get keys and dimensions for Jacobian matrices
166  // An Expression is assumed unmutable, so we do this now
167  if (keys_.empty()) {
168  // This is the case when called in ExpressionFactor Constructor.
169  // We then take the keys from the expression in sorted order.
170  boost::tie(keys_, dims_) = expression_.keysAndDims();
171  } else {
172  // This happens with classes derived from BinaryExpressionFactor etc.
173  // In that case, the keys_ are already defined and we just need to grab
174  // the dimensions in the correct order.
175  std::map<Key, int> keyedDims;
176  expression_.dims(keyedDims);
177  for (Key key : keys_) dims_.push_back(keyedDims[key]);
178  }
179  }
180 
183  virtual Expression<T> expression() const {
184  throw std::runtime_error("ExpressionFactor::expression not provided: cannot deserialize.");
185  }
186 
187 private:
189  template <class Archive>
190  void save(Archive& ar, const unsigned int /*version*/) const {
191  ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(NoiseModelFactor);
192  ar << boost::serialization::make_nvp("measured_", this->measured_);
193  }
194 
197  template <class Archive>
198  void load(Archive& ar, const unsigned int /*version*/) {
199  ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(NoiseModelFactor);
200  ar >> boost::serialization::make_nvp("measured_", this->measured_);
201  this->initialize(expression());
202  }
203 
204  // Indicate that we implement save/load separately, and be friendly to boost
205  BOOST_SERIALIZATION_SPLIT_MEMBER()
206 
207  friend class boost::serialization::access;
208 
209  // Alignment, see https://eigen.tuxfamily.org/dox/group__TopicStructHavingEigenMembers.html
210  enum { NeedsToAlign = (sizeof(T) % 16) == 0 };
211  public:
212  EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign)
213 };
214 // ExpressionFactor
215 
217 template <typename T>
218 struct traits<ExpressionFactor<T> > : public Testable<ExpressionFactor<T> > {};
219 
225 template <typename T, typename A1, typename A2>
227  public:
229  virtual ~ExpressionFactor2() {}
230 
232  Vector evaluateError(const A1& a1, const A2& a2,
233  boost::optional<Matrix&> H1 = boost::none,
234  boost::optional<Matrix&> H2 = boost::none) const {
235  Values values;
236  values.insert(this->keys_[0], a1);
237  values.insert(this->keys_[1], a2);
238  std::vector<Matrix> H(2);
239  Vector error = this->unwhitenedError(values, H);
240  if (H1) (*H1) = H[0];
241  if (H2) (*H2) = H[1];
242  return error;
243  }
244 
247  virtual Expression<T> expression(Key key1, Key key2) const {
248  throw std::runtime_error("ExpressionFactor2::expression not provided: cannot deserialize.");
249  }
250 
251  protected:
254 
258  const T& measurement)
259  : ExpressionFactor<T>(noiseModel, measurement) {
260  this->keys_.push_back(key1);
261  this->keys_.push_back(key2);
262  }
263 
264  private:
266  virtual Expression<T> expression() const {
267  return expression(this->keys_[0], this->keys_[1]);
268  }
269 
270  friend class boost::serialization::access;
271  template <class ARCHIVE>
272  void serialize(ARCHIVE& ar, const unsigned int /*version*/) {
273  ar& boost::serialization::make_nvp(
274  "ExpressionFactor", boost::serialization::base_object<ExpressionFactor<T> >(*this));
275  }
276 };
277 // ExpressionFactor2
278 
279 }// \ namespace gtsam
void insert(Key j, const Value &val)
Add a variable with the given j, throws KeyAlreadyExists<J> if j is already present.
Definition: Values.cpp:133
This is the base class for all factor types.
Definition: Factor.h:54
A non-templated config holding any types of Manifold-group elements.
Definition: Values.h:70
FastVector< int > dims_
dimensions of the Jacobian matrices
Definition: ExpressionFactor.h:44
ExpressionFactor2()
Default constructor, for serialization.
Definition: ExpressionFactor.h:253
const T & measured() const
return the measurement
Definition: ExpressionFactor.h:67
virtual void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const
Print.
Definition: NonlinearFactor.cpp:63
virtual Expression< T > expression() const
Recreate expression from keys_ and measured_, used in load below.
Definition: ExpressionFactor.h:183
ExpressionFactor(const SharedNoiseModel &noiseModel, const T &measurement)
Default constructor, for serialization.
Definition: ExpressionFactor.h:151
ExpressionFactor(const SharedNoiseModel &noiseModel, const T &measurement, const Expression< T > &expression)
Constructor: creates a factor from a measurement and measurement function.
Definition: ExpressionFactor.h:57
std::uint64_t Key
Integer nonlinear key type.
Definition: types.h:57
virtual ~ExpressionFactor()
Destructor.
Definition: ExpressionFactor.h:64
bool equals(const NonlinearFactor &f, double tol) const
equals relies on Testable traits being defined for T
Definition: ExpressionFactor.h:77
virtual Expression< T > expression(Key key1, Key key2) const
Recreate expression from given keys_ and measured_, used in load Needed to deserialize a derived fact...
Definition: ExpressionFactor.h:247
virtual gtsam::NonlinearFactor::shared_ptr clone() const
Definition: ExpressionFactor.h:141
virtual boost::shared_ptr< GaussianFactor > linearize(const Values &x) const
linearize to a GaussianFactor
Definition: ExpressionFactor.h:102
A helper that implements the traits interface for GTSAM types.
Definition: Testable.h:150
ExpressionFactor2(Key key1, Key key2, const SharedNoiseModel &noiseModel, const T &measurement)
Constructor takes care of keys, but still need to call initialize.
Definition: ExpressionFactor.h:256
Binary specialization of ExpressionFactor meant as a base class for binary factors.
Definition: ExpressionFactor.h:226
Definition: VerticalBlockMatrix.h:41
boost::function< std::string(Key)> KeyFormatter
Typedef for a function to format a key, i.e. to convert it to a string.
Definition: Key.h:33
Nonlinear factor base class.
Definition: NonlinearFactor.h:50
const SharedNoiseModel & noiseModel() const
access to the noise model
Definition: NonlinearFactor.h:210
Vector evaluateError(const A1 &a1, const A2 &a2, boost::optional< Matrix & > H1=boost::none, boost::optional< Matrix & > H2=boost::none) const
Backwards compatible evaluateError, to make existing tests compile.
Definition: ExpressionFactor.h:232
size_t size() const
Definition: Factor.h:129
void initialize(const Expression< T > &expression)
Initialize with constructor arguments.
Definition: ExpressionFactor.h:157
virtual ~ExpressionFactor2()
Destructor.
Definition: ExpressionFactor.h:229
virtual Vector unwhitenedError(const Values &x, boost::optional< std::vector< Matrix > & > H=boost::none) const
Error function without the NoiseModel, .
Definition: ExpressionFactor.h:89
A nonlinear sum-of-squares factor with a zero-mean noise model implementing the density Templated on...
Definition: NonlinearFactor.h:161
A manifold defines a space in which there is a notion of a linear tangent space that can be centered ...
Definition: concepts.h:30
Non-linear factor base classes.
Expression class that supports automatic differentiation.
Definition: Expression.h:49
A Gaussian factor in the squared-error form.
Definition: JacobianFactor.h:87
Factor that supports arbitrary expressions via AD.
Definition: Expression.h:38
virtual bool active(const Values &) const
Checks whether a factor should be used based on a set of values.
Definition: NonlinearFactor.h:113
void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const
print relies on Testable traits being defined for T
Definition: ExpressionFactor.h:70
const Matrix & matrix() const
Access to full matrix (including any portions excluded by rowStart(), rowEnd(), and firstBlock())
Definition: VerticalBlockMatrix.h:187
Global functions in a separate testing namespace.
Definition: chartTesting.h:28
Concept check for values that can be used in unit tests.
noiseModel::Base::shared_ptr SharedNoiseModel
Note, deliberately not in noiseModel namespace.
Definition: NoiseModel.h:1072
KeyVector keys_
The keys involved in this factor.
Definition: Factor.h:72
Expression< T > expression_
the expression that is AD enabled
Definition: ExpressionFactor.h:43
T measured_
the measurement to be compared with the expression
Definition: ExpressionFactor.h:42
virtual bool equals(const NonlinearFactor &f, double tol=1e-9) const
Check if two factors are equal.
Definition: NonlinearFactor.cpp:71
virtual double error(const Values &c) const
Calculate the error of the factor.
Definition: NonlinearFactor.cpp:97
NoiseModelFactor()
Default constructor for I/O only.
Definition: NonlinearFactor.h:176
Expressions for Block Automatic Differentiation.