gtsam  4.0.0
gtsam
NonlinearConjugateGradientOptimizer.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 
19 #pragma once
20 
21 #include <gtsam/base/Manifold.h>
23 #include <boost/tuple/tuple.hpp>
24 
25 namespace gtsam {
26 
29 
30  /* a class for the nonlinearConjugateGradient template */
31  class System {
32  public:
33  typedef Values State;
34  typedef VectorValues Gradient;
36 
37  protected:
38  const NonlinearFactorGraph &graph_;
39 
40  public:
41  System(const NonlinearFactorGraph &graph) :
42  graph_(graph) {
43  }
44  double error(const State &state) const;
45  Gradient gradient(const State &state) const;
46  State advance(const State &current, const double alpha,
47  const Gradient &g) const;
48  };
49 
50 public:
51 
52  typedef NonlinearOptimizer Base;
54  typedef boost::shared_ptr<NonlinearConjugateGradientOptimizer> shared_ptr;
55 
56 protected:
57  Parameters params_;
58 
59  const NonlinearOptimizerParams& _params() const override {
60  return params_;
61  }
62 
63 public:
64 
67  const Values& initialValues, const Parameters& params = Parameters());
68 
71  }
72 
73  GaussianFactorGraph::shared_ptr iterate() override;
74  const Values& optimize() override;
75 };
76 
78 template<class S, class V, class W>
79 double lineSearch(const S &system, const V currentValues, const W &gradient) {
80 
81  /* normalize it such that it becomes a unit vector */
82  const double g = gradient.norm();
83 
84  // perform the golden section search algorithm to decide the the optimal step size
85  // detail refer to http://en.wikipedia.org/wiki/Golden_section_search
86  const double phi = 0.5 * (1.0 + std::sqrt(5.0)), resphi = 2.0 - phi, tau =
87  1e-5;
88  double minStep = -1.0 / g, maxStep = 0, newStep = minStep
89  + (maxStep - minStep) / (phi + 1.0);
90 
91  V newValues = system.advance(currentValues, newStep, gradient);
92  double newError = system.error(newValues);
93 
94  while (true) {
95  const bool flag = (maxStep - newStep > newStep - minStep) ? true : false;
96  const double testStep =
97  flag ? newStep + resphi * (maxStep - newStep) :
98  newStep - resphi * (newStep - minStep);
99 
100  if ((maxStep - minStep)
101  < tau * (std::fabs(testStep) + std::fabs(newStep))) {
102  return 0.5 * (minStep + maxStep);
103  }
104 
105  const V testValues = system.advance(currentValues, testStep, gradient);
106  const double testError = system.error(testValues);
107 
108  // update the working range
109  if (testError >= newError) {
110  if (flag)
111  maxStep = testStep;
112  else
113  minStep = testStep;
114  } else {
115  if (flag) {
116  minStep = newStep;
117  newStep = testStep;
118  newError = testError;
119  } else {
120  maxStep = newStep;
121  newStep = testStep;
122  newError = testError;
123  }
124  }
125  }
126  return 0.0;
127 }
128 
138 template<class S, class V>
139 boost::tuple<V, int> nonlinearConjugateGradient(const S &system,
140  const V &initial, const NonlinearOptimizerParams &params,
141  const bool singleIteration, const bool gradientDescent = false) {
142 
143  // GTSAM_CONCEPT_MANIFOLD_TYPE(V);
144 
145  size_t iteration = 0;
146 
147  // check if we're already close enough
148  double currentError = system.error(initial);
149  if (currentError <= params.errorTol) {
150  if (params.verbosity >= NonlinearOptimizerParams::ERROR) {
151  std::cout << "Exiting, as error = " << currentError << " < "
152  << params.errorTol << std::endl;
153  }
154  return boost::tie(initial, iteration);
155  }
156 
157  V currentValues = initial;
158  typename S::Gradient currentGradient = system.gradient(currentValues),
159  prevGradient, direction = currentGradient;
160 
161  /* do one step of gradient descent */
162  V prevValues = currentValues;
163  double prevError = currentError;
164  double alpha = lineSearch(system, currentValues, direction);
165  currentValues = system.advance(prevValues, alpha, direction);
166  currentError = system.error(currentValues);
167 
168  // Maybe show output
169  if (params.verbosity >= NonlinearOptimizerParams::ERROR)
170  std::cout << "Initial error: " << currentError << std::endl;
171 
172  // Iterative loop
173  do {
174  if (gradientDescent == true) {
175  direction = system.gradient(currentValues);
176  } else {
177  prevGradient = currentGradient;
178  currentGradient = system.gradient(currentValues);
179  // Polak-Ribiere: beta = g'*(g_n-g_n-1)/g_n-1'*g_n-1
180  const double beta = std::max(0.0,
181  currentGradient.dot(currentGradient - prevGradient)
182  / prevGradient.dot(prevGradient));
183  direction = currentGradient + (beta * direction);
184  }
185 
186  alpha = lineSearch(system, currentValues, direction);
187 
188  prevValues = currentValues;
189  prevError = currentError;
190 
191  currentValues = system.advance(prevValues, alpha, direction);
192  currentError = system.error(currentValues);
193 
194  // Maybe show output
195  if (params.verbosity >= NonlinearOptimizerParams::ERROR)
196  std::cout << "iteration: " << iteration << ", currentError: " << currentError << std::endl;
197  } while (++iteration < params.maxIterations && !singleIteration
199  params.errorTol, prevError, currentError, params.verbosity));
200 
201  // Printing if verbose
202  if (params.verbosity >= NonlinearOptimizerParams::ERROR
203  && iteration >= params.maxIterations)
204  std::cout
205  << "nonlinearConjugateGradient: Terminating because reached maximum iterations"
206  << std::endl;
207 
208  return boost::tie(currentValues, iteration);
209 }
210 
211 } // \ namespace gtsam
212 
Verbosity verbosity
The printing verbosity during optimization (default SILENT)
Definition: NonlinearOptimizerParams.h:45
boost::tuple< V, int > nonlinearConjugateGradient(const S &system, const V &initial, const NonlinearOptimizerParams &params, const bool singleIteration, const bool gradientDescent=false)
Implement the nonlinear conjugate gradient method using the Polak-Ribiere formula suggested in http:/...
Definition: NonlinearConjugateGradientOptimizer.h:139
This is the abstract interface for classes that can optimize for the maximum-likelihood estimate of a...
Definition: NonlinearOptimizer.h:75
size_t maxIterations
The maximum iterations to stop iterating (default 100)
Definition: NonlinearOptimizerParams.h:41
A non-templated config holding any types of Manifold-group elements.
Definition: Values.h:70
bool checkConvergence(double relativeErrorTreshold, double absoluteErrorTreshold, double errorThreshold, double currentError, double newError, NonlinearOptimizerParams::Verbosity verbosity)
Check whether the relative error decrease is less than relativeErrorTreshold, the absolute error decr...
Definition: NonlinearOptimizer.cpp:169
Base class and basic functions for Manifold types.
double absoluteErrorTol
The maximum absolute error decrease to stop iterating (default 1e-5)
Definition: NonlinearOptimizerParams.h:43
double lineSearch(const S &system, const V currentValues, const W &gradient)
Implement the golden-section line search algorithm.
Definition: NonlinearConjugateGradientOptimizer.h:79
boost::shared_ptr< This > shared_ptr
shared_ptr to this class
Definition: GaussianFactorGraph.h:74
This class represents a collection of vector-valued variables associated each with a unique integer i...
Definition: VectorValues.h:90
Base class and parameters for nonlinear optimization algorithms.
Point3 optimize(const NonlinearFactorGraph &graph, const Values &values, Key landmarkKey)
Optimize for triangulation.
Definition: triangulation.cpp:73
An implementation of the nonlinear CG method using the template below.
Definition: NonlinearConjugateGradientOptimizer.h:28
A non-linear factor graph is a graph of non-Gaussian, i.e.
Definition: NonlinearFactorGraph.h:77
double relativeErrorTol
The maximum relative error decrease to stop iterating (default 1e-5)
Definition: NonlinearOptimizerParams.h:42
The common parameters for Nonlinear optimizers.
Definition: NonlinearOptimizerParams.h:34
double errorTol
The maximum total error to stop iterating (default 0.0)
Definition: NonlinearOptimizerParams.h:44
virtual ~NonlinearConjugateGradientOptimizer()
Destructor.
Definition: NonlinearConjugateGradientOptimizer.h:70
Global functions in a separate testing namespace.
Definition: chartTesting.h:28