GTSAM  4.0.2
C++ library for smoothing and mapping (SAM)
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 
22 #include <array>
23 #include <gtsam/config.h>
24 #include <gtsam/base/Testable.h>
27 
28 #include <numeric>
29 #include <utility>
30 
31 namespace gtsam {
32 
45 template <typename T>
46 class ExpressionFactor : public NoiseModelFactor {
47  GTSAM_CONCEPT_ASSERT(IsTestable<T>);
48 
49 protected:
50 
51  typedef ExpressionFactor<T> This;
52  static const int Dim = traits<T>::dimension;
53 
57 
58 
59  public:
60 
61  // Provide access to the Matrix& version of unwhitenedError:
63  typedef std::shared_ptr<ExpressionFactor<T> > shared_ptr;
64 
73  const T& measurement, const Expression<T>& expression)
74  : NoiseModelFactor(noiseModel), measured_(measurement) {
75  initialize(expression);
76  }
77 
79  ~ExpressionFactor() override {}
80 
82  const T& measured() const { return measured_; }
83 
85  void print(const std::string& s = "",
86  const KeyFormatter& keyFormatter = DefaultKeyFormatter) const override {
87  NoiseModelFactor::print(s, keyFormatter);
88  traits<T>::Print(measured_, "ExpressionFactor with measurement: ");
89  }
90 
92  bool equals(const NonlinearFactor& f, double tol) const override {
93  const ExpressionFactor* p = dynamic_cast<const ExpressionFactor*>(&f);
94  return p && NoiseModelFactor::equals(f, tol) &&
95  traits<T>::Equals(measured_, p->measured_, tol) &&
96  dims_ == p->dims_;
97  }
98 
104  Vector unwhitenedError(const Values& x,
105  OptionalMatrixVecType H = nullptr) const override {
106  if (H) {
107  const T value = expression_.valueAndDerivatives(x, keys_, dims_, *H);
108  // NOTE(hayk): Doing the reverse, AKA Local(measured_, value) is not correct here
109  // because it would use the tangent space of the measurement instead of the value.
110  return -traits<T>::Local(value, measured_);
111  } else {
112  const T value = expression_.value(x);
113  return -traits<T>::Local(value, measured_);
114  }
115  }
116 
117  std::shared_ptr<GaussianFactor> linearize(const Values& x) const override {
118  // Only linearize if the factor is active
119  if (!active(x))
120  return std::shared_ptr<JacobianFactor>();
121 
122  // In case noise model is constrained, we need to provide a noise model
123  SharedDiagonal noiseModel;
124  if (noiseModel_ && noiseModel_->isConstrained()) {
125  noiseModel = std::static_pointer_cast<noiseModel::Constrained>(
126  noiseModel_)->unit();
127  }
128 
129  // Create a writeable JacobianFactor in advance
130  std::shared_ptr<JacobianFactor> factor(
131  new JacobianFactor(keys_, dims_, Dim, noiseModel));
132 
133  // Wrap keys and VerticalBlockMatrix into structure passed to expression_
134  VerticalBlockMatrix& Ab = factor->matrixObject();
135  internal::JacobianMap jacobianMap(keys_, Ab);
136 
137  // Zero out Jacobian so we can simply add to it
138  Ab.matrix().setZero();
139 
140  // Get value and Jacobians, writing directly into JacobianFactor
141  T value = expression_.valueAndJacobianMap(x, jacobianMap); // <<< Reverse AD happens here !
142 
143  // Evaluate error and set RHS vector b
144  Ab(size()).col(0) = traits<T>::Local(value, measured_);
145 
146  // Whiten the corresponding system, Ab already contains RHS
147  if (noiseModel_) {
148  Vector b = Ab(size()).col(0); // need b to be valid for Robust noise models
149  noiseModel_->WhitenSystem(Ab.matrix(), b);
150  }
151 
152  return std::move(factor);
153  }
154 
156  gtsam::NonlinearFactor::shared_ptr clone() const override {
157  return std::static_pointer_cast<gtsam::NonlinearFactor>(
158  gtsam::NonlinearFactor::shared_ptr(new This(*this)));
159  }
160 
161 protected:
162  ExpressionFactor() {}
164 
166  ExpressionFactor(const SharedNoiseModel& noiseModel, const T& measurement)
167  : NoiseModelFactor(noiseModel), measured_(measurement) {
168  // Not properly initialized yet, need to call initialize
169  }
170 
173  if (!noiseModel_)
174  throw std::invalid_argument("ExpressionFactor: no NoiseModel.");
175  if (noiseModel_->dim() != Dim)
176  throw std::invalid_argument(
177  "ExpressionFactor was created with a NoiseModel of incorrect dimension.");
178  expression_ = expression;
179 
180  // Get keys and dimensions for Jacobian matrices
181  // An Expression is assumed unmutable, so we do this now
182  if (keys_.empty()) {
183  // This is the case when called in ExpressionFactor Constructor.
184  // We then take the keys from the expression in sorted order.
185  std::tie(keys_, dims_) = expression_.keysAndDims();
186  } else {
187  // This happens with classes derived from BinaryExpressionFactor etc.
188  // In that case, the keys_ are already defined and we just need to grab
189  // the dimensions in the correct order.
190  std::map<Key, int> keyedDims;
191  expression_.dims(keyedDims);
192  for (Key key : keys_) dims_.push_back(keyedDims[key]);
193  }
194  }
195 
198  virtual Expression<T> expression() const {
199  throw std::runtime_error("ExpressionFactor::expression not provided: cannot deserialize.");
200  }
201 
202 private:
203 #ifdef GTSAM_ENABLE_BOOST_SERIALIZATION
204  template <class Archive>
206  void save(Archive& ar, const unsigned int /*version*/) const {
207  ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(NoiseModelFactor);
208  ar << boost::serialization::make_nvp("measured_", this->measured_);
209  }
210 
213  template <class Archive>
214  void load(Archive& ar, const unsigned int /*version*/) {
215  ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(NoiseModelFactor);
216  ar >> boost::serialization::make_nvp("measured_", this->measured_);
217  this->initialize(expression());
218  }
219 
220  // Indicate that we implement save/load separately, and be friendly to boost
221  BOOST_SERIALIZATION_SPLIT_MEMBER()
222 
223  friend class boost::serialization::access;
224 #endif
225 
226  // Alignment, see https://eigen.tuxfamily.org/dox/group__TopicStructHavingEigenMembers.html
227  enum { NeedsToAlign = (sizeof(T) % 16) == 0 };
228  public:
230 };
231 // ExpressionFactor
232 
234 template <typename T>
235 struct traits<ExpressionFactor<T> > : public Testable<ExpressionFactor<T> > {};
236 
248 template <typename T, typename... Args>
250 public:
251  static const std::size_t NARY_EXPRESSION_SIZE = sizeof...(Args);
252  using ArrayNKeys = std::array<Key, NARY_EXPRESSION_SIZE>;
253 
254  // Provide access to the Matrix& version of unwhitenedError:
256 
257  // Don't provide backward compatible evaluateVector(), due to its problematic
258  // variable length of optional Jacobian arguments. Vector evaluateError(const
259  // Args... args,...);
260 
263  virtual Expression<T> expression(const ArrayNKeys &keys) const {
264  throw std::runtime_error(
265  "ExpressionFactorN::expression not provided: cannot deserialize.");
266  }
267 
268 protected:
270  ExpressionFactorN() = default;
271 
274  const T &measurement)
275  : ExpressionFactor<T>(noiseModel, measurement) {
276  for (const auto &key : keys)
277  Factor::keys_.push_back(key);
278  }
279 
280 private:
282  Expression<T> expression() const override {
283  ArrayNKeys keys;
284  int idx = 0;
285  for (const auto &key : Factor::keys_)
286  keys[idx++] = key;
287  return expression(keys);
288  }
289 
290 #ifdef GTSAM_ENABLE_BOOST_SERIALIZATION
291  friend class boost::serialization::access;
292  template <class ARCHIVE>
293  void serialize(ARCHIVE &ar, const unsigned int /*version*/) {
294  ar &boost::serialization::make_nvp(
295  "ExpressionFactorN",
296  boost::serialization::base_object<ExpressionFactor<T>>(*this));
297  }
298 #endif
299 };
301 template <typename T, typename... Args>
302 struct traits<ExpressionFactorN<T, Args...>>
303  : public Testable<ExpressionFactorN<T, Args...>> {};
304 // ExpressionFactorN
305 
306 } // namespace gtsam
std::vector< Matrix > * OptionalMatrixVecType
Definition: NonlinearFactor.h:61
gtsam::NonlinearFactor::shared_ptr clone() const override
Definition: ExpressionFactor.h:156
bool equals(const NonlinearFactor &f, double tol=1e-9) const override
Concept check for values that can be used in unit tests.
std::string serialize(const T &input)
serializes to a string
Definition: serialization.h:113
virtual Expression< T > expression(const ArrayNKeys &keys) const
Definition: ExpressionFactor.h:263
void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const override
print relies on Testable traits being defined for T
Definition: ExpressionFactor.h:85
Definition: VerticalBlockMatrix.h:42
size_t size() const
Definition: Factor.h:159
Definition: Testable.h:152
std::vector< T, typename internal::FastDefaultVectorAllocator< T >::type > FastVector
Definition: FastVector.h:34
Definition: Group.h:43
Definition: NonlinearFactor.h:68
void initialize(const Expression< T > &expression)
Initialize with constructor arguments.
Definition: ExpressionFactor.h:172
Definition: Expression.h:47
const Matrix & matrix() const
Definition: VerticalBlockMatrix.h:188
KeyVector keys_
The keys involved in this factor.
Definition: Factor.h:87
T valueAndJacobianMap(const Values &values, internal::JacobianMap &jacobians) const
brief Return value and derivatives, reverse AD version
Definition: Expression-inl.h:204
virtual Expression< T > expression() const
Definition: ExpressionFactor.h:198
ExpressionFactor(const SharedNoiseModel &noiseModel, const T &measurement, const Expression< T > &expression)
Definition: ExpressionFactor.h:72
ExpressionFactor(const SharedNoiseModel &noiseModel, const T &measurement)
Default constructor, for serialization.
Definition: ExpressionFactor.h:166
Definition: JacobianMap.h:32
Expressions for Block Automatic Differentiation.
Definition: NonlinearFactor.h:197
#define GTSAM_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign)
Definition: types.h:293
const T & measured() const
Definition: ExpressionFactor.h:82
~ExpressionFactor() override
Destructor.
Definition: ExpressionFactor.h:79
const SharedNoiseModel & noiseModel() const
access to the noise model
Definition: NonlinearFactor.h:245
Vector unwhitenedError(const Values &x, OptionalMatrixVecType H=nullptr) const override
Definition: ExpressionFactor.h:104
GTSAM_EXPORT void save(const Matrix &A, const std::string &s, const std::string &filename)
Definition: Values.h:65
FastVector< int > dims_
dimensions of the Jacobian matrices
Definition: ExpressionFactor.h:56
T valueAndDerivatives(const Values &values, const KeyVector &keys, const FastVector< int > &dims, std::vector< Matrix > &H) const
private version that takes keys and dimensions, returns derivatives
Definition: Expression-inl.h:167
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
Definition: JacobianFactor.h:91
Definition: chartTesting.h:28
virtual Vector unwhitenedError(const Values &x, OptionalMatrixVecType H=nullptr) const =0
void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const override
Non-linear factor base classes.
virtual bool active(const Values &) const
Definition: NonlinearFactor.h:141
bool equals(const NonlinearFactor &f, double tol) const override
equals relies on Testable traits being defined for T
Definition: ExpressionFactor.h:92
T value(const Values &values, std::vector< Matrix > *H=nullptr) const
Return value and optional derivatives, reverse AD version Notes: this is not terribly efficient...
Definition: Expression-inl.h:142
Expression< T > expression_
the expression that is AD enabled
Definition: ExpressionFactor.h:55
ExpressionFactorN(const ArrayNKeys &keys, const SharedNoiseModel &noiseModel, const T &measurement)
Constructor takes care of keys, but still need to call initialize.
Definition: ExpressionFactor.h:273
const KeyVector & keys() const
Access the factor&#39;s involved variable keys.
Definition: Factor.h:142
T measured_
the measurement to be compared with the expression
Definition: ExpressionFactor.h:54
void dims(std::map< Key, int > &map) const
Return dimensions for each argument, as a map.
Definition: Expression-inl.h:132
Definition: ExpressionFactor.h:249
std::shared_ptr< GaussianFactor > linearize(const Values &x) const override
Definition: ExpressionFactor.h:117
Definition: Expression.h:36
std::uint64_t Key
Integer nonlinear key type.
Definition: types.h:102
Definition: NoiseModel.h:390
noiseModel::Base::shared_ptr SharedNoiseModel
Definition: NoiseModel.h:741