g2o
Loading...
Searching...
No Matches
auto_differentiation.h
Go to the documentation of this file.
1// g2o - General Graph Optimization
2// Copyright (C) 2011 R. Kuemmerle, G. Grisetti, W. Burgard
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright notice,
10// this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above copyright
12// notice, this list of conditions and the following disclaimer in the
13// documentation and/or other materials provided with the distribution.
14//
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
18// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27#ifndef G2O_AUTO_DIFFERENTIATION_H
28#define G2O_AUTO_DIFFERENTIATION_H
29
30#include <algorithm>
31#include <cassert>
32#include <type_traits>
33
34#include "eigen_types.h"
36#include "g2o/stuff/misc.h"
37#include "g2o_core_api.h"
38
39namespace g2o {
40
45template <typename Edge>
47 template <int k>
48 EIGEN_STRONG_INLINE double* data(Edge* that) {
49 return const_cast<double*>(that->template vertexXn<k>()->estimate().data());
50 }
51};
52
62template <typename Edge>
64 public:
65 template <int k>
66 EIGEN_STRONG_INLINE double* data(Edge* that) {
67 auto& buffer = std::get<k>(_estimateBuffer);
68 buffer.resize(that->template vertexDimension<k>());
69 double* rawBuffer = const_cast<double*>(buffer.data());
70 bool gotData = that->template vertexXn<k>()->getEstimateData(rawBuffer);
71 assert(gotData && "Called getEstimateData, but seems unimplmented");
72 return gotData ? rawBuffer : nullptr;
73 }
74
75 protected:
76 template <typename>
77 struct BufferType;
78 template <std::size_t... Ints>
79 struct BufferType<std::index_sequence<Ints...>> {
80 using type =
81 std::tuple<VectorN<Edge::template VertexXnType<Ints>::Dimension>...>;
82 };
83
84 using Buffer = typename BufferType<
85 std::make_index_sequence<Edge::_nr_of_vertices>>::type;
87};
88
154template <typename Edge, typename EstimateAccess = EstimateAccessor<Edge>>
156 public:
158 template <int EdgeDimension, int VertexDimension>
160 typename Eigen::Matrix<double, EdgeDimension, VertexDimension,
161 Eigen::RowMajor>;
162
164 static void computeError(Edge* that) {
165 static_assert(Edge::Dimension > 0,
166 "Dynamically sized edges are not supported");
167 computeErrorNs(that, std::make_index_sequence<Edge::_nr_of_vertices>());
168 }
169
177 static void linearize(Edge* that) {
178 static_assert(Edge::Dimension > 0,
179 "Dynamically sized edges are not supported");
180 linearizeOplusNs(that, std::make_index_sequence<Edge::_nr_of_vertices>());
181 }
182
183 protected:
185 template <std::size_t... Ints>
186 static void computeErrorNs(Edge* that, std::index_sequence<Ints...>) {
187 static_assert(
188 std::min({Edge::template VertexXnType<Ints>::Dimension...}) > 0,
189 "Dynamically sized vertices are not supported");
190 EstimateAccess estimateAccess;
191 (*that)(estimateAccess.template data<Ints>(that)..., that->errorData());
192 }
193
197 template <std::size_t... Ints>
198 static void linearizeOplusNs(Edge* that, std::index_sequence<Ints...>) {
199 static_assert(
200 std::min({Edge::template VertexXnType<Ints>::Dimension...}) > 0,
201 "Dynamically sized vertices are not supported");
202 // all vertices are fixed, no need to compute anything here
203 if (that->allVerticesFixed()) {
204 (void(that->template jacobianOplusXn<Ints>().setZero()), ...);
205 return;
206 }
207
208 // tuple containing the Jacobians
209 std::tuple<ADJacobianType<Edge::Dimension,
210 Edge::template VertexXnType<Ints>::Dimension>...>
211 ad_jacobians;
212
213 // setting up the pointer to the parameters and the Jacobians for calling
214 // AD.
215 EstimateAccess estimateAccess;
216 double* parameters[] = {estimateAccess.template data<Ints>(that)...};
217 // double* parameters[] = { /* trivial case would be */
218 // const_cast<double*>(that->template
219 // vertexXn<Ints>()->estimate().data())...};
220
221 // pointers to the Jacobians, set to NULL if vertex is fixed to skip
222 // computation
223 double* jacobians[] = {
224 that->template vertexXn<Ints>()->fixed()
225 ? nullptr
226 : const_cast<double*>(std::get<Ints>(ad_jacobians).data())...};
227 // Calls the automatic differentiation for evaluation of the Jacobians.
228 double errorValue[Edge::Dimension];
229 using AutoDiffDims = ceres::internal::StaticParameterDims<
230 Edge::template VertexXnType<Ints>::Dimension...>;
231 bool diffState =
232 ceres::internal::AutoDifferentiate<Edge::Dimension, AutoDiffDims, Edge,
233 double>(
234 *that, parameters, Edge::Dimension, errorValue, jacobians);
235
236 assert(diffState && "Error during Automatic Differentiation");
237 if (!diffState) { // something went wrong during AD
238 (void(std::get<Ints>(ad_jacobians).setZero()), ...);
239 return;
240 }
241 // copy over the Jacobians (convert row-major -> column-major) for non-fixed
242 // vertices
243 (void(that->template vertexXn<Ints>()->fixed()
244 ? (that->template jacobianOplusXn<Ints>().setZero(), 0)
245 : (assign(that->template jacobianOplusXn<Ints>(),
246 std::get<Ints>(ad_jacobians)),
247 0)),
248 ...);
249 }
250
252 template <typename A, typename B>
253 static EIGEN_STRONG_INLINE void assign(const Eigen::MatrixBase<A>& a,
254 const Eigen::MatrixBase<B>& b) {
255 Eigen::MatrixBase<A>& aux = const_cast<Eigen::MatrixBase<A>&>(a);
256 aux = b;
257 }
258};
259
260} // namespace g2o
261
262// helper macros for fine-grained integration into own types
263#define G2O_MAKE_AUTO_AD_COMPUTEERROR \
264 void computeError() override { \
265 g2o::AutoDifferentiation< \
266 std::remove_reference<decltype(*this)>::type>::computeError(this); \
267 }
268#define G2O_MAKE_AUTO_AD_LINEARIZEOPLUS \
269 void linearizeOplus() override { \
270 g2o::AutoDifferentiation< \
271 std::remove_reference<decltype(*this)>::type>::linearize(this); \
272 }
273
277#define G2O_MAKE_AUTO_AD_FUNCTIONS \
278 G2O_MAKE_AUTO_AD_COMPUTEERROR \
279 G2O_MAKE_AUTO_AD_LINEARIZEOPLUS
280
281// helper macros for fine-grained integration into own types using
282// EstimateAccessorGet
283#define G2O_MAKE_AUTO_AD_COMPUTEERROR_BY_GET \
284 void computeError() override { \
285 using EdgeType = std::remove_reference<decltype(*this)>::type; \
286 g2o::AutoDifferentiation< \
287 EdgeType, g2o::EstimateAccessorGet<EdgeType>>::computeError(this); \
288 }
289
290#define G2O_MAKE_AUTO_AD_LINEARIZEOPLUS_BY_GET \
291 void linearizeOplus() override { \
292 using EdgeType = std::remove_reference<decltype(*this)>::type; \
293 g2o::AutoDifferentiation< \
294 EdgeType, g2o::EstimateAccessorGet<EdgeType>>::linearize(this); \
295 }
296
300#define G2O_MAKE_AUTO_AD_FUNCTIONS_BY_GET \
301 G2O_MAKE_AUTO_AD_COMPUTEERROR_BY_GET \
302 G2O_MAKE_AUTO_AD_LINEARIZEOPLUS_BY_GET
303
304#endif
Implementation of Automatic Differentiation for edges in g2o.
static void linearize(Edge *that)
static void linearizeOplusNs(Edge *that, std::index_sequence< Ints... >)
static void computeError(Edge *that)
helper for computing the error based on the functor in the edge
static EIGEN_STRONG_INLINE void assign(const Eigen::MatrixBase< A > &a, const Eigen::MatrixBase< B > &b)
helper function to perform a = b
typename Eigen::Matrix< double, EdgeDimension, VertexDimension, Eigen::RowMajor > ADJacobianType
type for the Jacobians during AD
static void computeErrorNs(Edge *that, std::index_sequence< Ints... >)
packed version to call the functor that evaluates the error function
EIGEN_STRONG_INLINE double * data(Edge *that)
typename BufferType< std::make_index_sequence< Edge::_nr_of_vertices > >::type Buffer
some general case utility functions
bool AutoDifferentiate(const Functor &functor, T const *const *parameters, int dynamic_num_outputs, T *function_value, T **jacobians)
Definition autodiff.h:295
ParameterDims< false, Ns... > StaticParameterDims
Definition jet.h:876
std::tuple< VectorN< Edge::template VertexXnType< Ints >::Dimension >... > type
EIGEN_STRONG_INLINE double * data(Edge *that)