gtsam
Loading...
Searching...
No Matches
DoglegOptimizerImpl.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
17#pragma once
18
19#include <iomanip>
20#include <cassert>
21
23#include <gtsam/base/timing.h>
24
25namespace gtsam {
26
33struct GTSAM_EXPORT DoglegOptimizerImpl {
34
35 struct GTSAM_EXPORT IterationResult {
36 double delta;
37 VectorValues dx_d;
38 double f_error;
39 };
40
55 SEARCH_EACH_ITERATION,
56 SEARCH_REDUCE_ONLY,
57 ONE_STEP_PER_ITERATION
58 };
59
95 template<class M, class F, class VALUES>
96 static IterationResult Iterate(
97 double delta, TrustRegionAdaptationMode mode, const VectorValues& dx_u, const VectorValues& dx_n,
98 const M& Rd, const F& f, const VALUES& x0, const double f_error, const bool verbose=false);
99
122 static VectorValues ComputeDoglegPoint(double delta, const VectorValues& dx_u, const VectorValues& dx_n, const bool verbose=false);
123
133 static VectorValues ComputeBlend(double delta, const VectorValues& x_u, const VectorValues& x_n, const bool verbose=false);
134};
135
136
137/* ************************************************************************* */
138template<class M, class F, class VALUES>
140 double delta, TrustRegionAdaptationMode mode, const VectorValues& dx_u, const VectorValues& dx_n,
141 const M& Rd, const F& f, const VALUES& x0, const double f_error, const bool verbose)
142{
143 gttic(M_error);
144 const double M_error = Rd.error(VectorValues::Zero(dx_u));
145 gttoc(M_error);
146
147 // Result to return
148 IterationResult result;
149
150 bool stay = true;
151 enum { NONE, INCREASED_DELTA, DECREASED_DELTA } lastAction = NONE; // Used to prevent alternating between increasing and decreasing in one iteration
152 while(stay) {
153 gttic(Dog_leg_point);
154 // Compute dog leg point
155 result.dx_d = ComputeDoglegPoint(delta, dx_u, dx_n, verbose);
156 gttoc(Dog_leg_point);
157
158 if(verbose) std::cout << "delta = " << delta << ", dx_d_norm = " << result.dx_d.norm() << std::endl;
159
160 gttic(retract);
161 // Compute expmapped solution
162 const VALUES x_d(x0.retract(result.dx_d));
163 gttoc(retract);
164
165 gttic(decrease_in_f);
166 // Compute decrease in f
167 result.f_error = f.error(x_d);
168 gttoc(decrease_in_f);
169
170 gttic(new_M_error);
171 // Compute decrease in M
172 const double new_M_error = Rd.error(result.dx_d);
173 gttoc(new_M_error);
174
175 if(verbose) std::cout << std::setprecision(15) << "f error: " << f_error << " -> " << result.f_error << std::endl;
176 if(verbose) std::cout << std::setprecision(15) << "M error: " << M_error << " -> " << new_M_error << std::endl;
177
178 gttic(adjust_delta);
179 // Compute gain ratio. Here we take advantage of the invariant that the
180 // Bayes' net error at zero is equal to the nonlinear error
181 const double rho = std::abs(f_error - result.f_error) < 1e-15 || std::abs(M_error - new_M_error) < 1e-15 ?
182 0.5 :
183 (f_error - result.f_error) / (M_error - new_M_error);
184
185 if(verbose) std::cout << std::setprecision(15) << "rho = " << rho << std::endl;
186
187 if(rho >= 0.75) {
188 // M agrees very well with f, so try to increase lambda
189 const double dx_d_norm = result.dx_d.norm();
190 const double newDelta = std::max(delta, 3.0 * dx_d_norm); // Compute new delta
191
192 if(mode == ONE_STEP_PER_ITERATION || mode == SEARCH_REDUCE_ONLY)
193 stay = false; // If not searching, just return with the new delta
194 else if(mode == SEARCH_EACH_ITERATION) {
195 if(std::abs(newDelta - delta) < 1e-15 || lastAction == DECREASED_DELTA)
196 stay = false; // Searching, but Newton's solution is within trust region so keep the same trust region
197 else {
198 stay = true; // Searching and increased delta, so try again to increase delta
199 lastAction = INCREASED_DELTA;
200 }
201 } else {
202 assert(false); }
203
204 delta = newDelta; // Update delta from new delta
205
206 } else if(0.75 > rho && rho >= 0.25) {
207 // M agrees so-so with f, keep the same delta
208 stay = false;
209
210 } else if(0.25 > rho && rho >= 0.0) {
211 // M does not agree well with f, decrease delta until it does
212 double newDelta;
213 bool hitMinimumDelta;
214 if(delta > 1e-5) {
215 newDelta = 0.5 * delta;
216 hitMinimumDelta = false;
217 } else {
218 newDelta = delta;
219 hitMinimumDelta = true;
220 }
221 if(mode == ONE_STEP_PER_ITERATION || /* mode == SEARCH_EACH_ITERATION && */ lastAction == INCREASED_DELTA || hitMinimumDelta)
222 stay = false; // If not searching, just return with the new smaller delta
223 else if(mode == SEARCH_EACH_ITERATION || mode == SEARCH_REDUCE_ONLY) {
224 stay = true;
225 lastAction = DECREASED_DELTA;
226 } else {
227 assert(false); }
228
229 delta = newDelta; // Update delta from new delta
230
231 } else {
232 // f actually increased, so keep decreasing delta until f does not decrease.
233 // NOTE: NaN and Inf solutions also will fall into this case, so that we
234 // decrease delta if the solution becomes undetermined.
235 assert(0.0 > rho);
236 if(delta > 1e-5) {
237 delta *= 0.5;
238 stay = true;
239 lastAction = DECREASED_DELTA;
240 } else {
241 if(verbose) std::cout << "Warning: Dog leg stopping because cannot decrease error with minimum delta" << std::endl;
242 result.dx_d.setZero(); // Set delta to zero - don't allow error to increase
243 result.f_error = f_error;
244 stay = false;
245 }
246 }
247 gttoc(adjust_delta);
248 }
249
250 // dx_d and f_error have already been filled in during the loop
251 result.delta = delta;
252 return result;
253}
254
260struct GTSAM_EXPORT DoglegLineSearchImpl {
261 struct Params {
262 double minDelta;
263 double maxDelta;
264 double stepSize;
266 bool verbose;
267 };
268
294 template <class M, class F, class VALUES>
296 const VectorValues& dx_u,
297 const VectorValues& dx_n,
298 const M& Rd, const F& f,
299 const VALUES& x0);
300};
301
302/* ************************************************************************* */
303template <class M, class F, class VALUES>
305 const Params& params, const VectorValues& dx_u, const VectorValues& dx_n,
306 const M& Rd, const F& f, const VALUES& x0) {
307 if (params.verbose)
308 std::cout << "DoglegLineSearch | minDelta: " << params.minDelta
309 << " maxDelta: " << params.maxDelta
310 << " stepSize: " << params.stepSize << std::endl;
311 const double fInitError = f.error(x0);
312 const double gnStep = dx_n.norm();
313 const size_t numVars = dx_n.size();
314
315 double maxStep, step;
317 maxStep = std::min(params.maxDelta * numVars, gnStep);
318 step = std::min(params.minDelta * numVars, gnStep);
319 step = std::min(step, maxStep); // Edge case min_step > maxStep
320
321 if (params.verbose)
322 std::cout << "Search Region: [ " << step << " -> " << maxStep << "]"
323 << std::endl;
324
326 result.dx_d =
327 DoglegOptimizerImpl::ComputeDoglegPoint(step, dx_u, dx_n, params.verbose);
328 result.f_error = f.error(x0.retract(result.dx_d));
329 result.delta = step;
330 if (params.verbose)
331 std::cout << "Initial Step Error: " << result.f_error << std::endl;
332
333 // Validate Step size will terminate search
334 if (step < 1e-12 || params.stepSize < 1.0)
335 throw std::runtime_error(
336 "Invalid DoglegLineSearch configuration. Would cause infinite search.");
337
338 // Search Increase delta
339 double eps = std::numeric_limits<double>::epsilon();
340 while (step < maxStep - eps) {
341 // Compute the trust region for the evaluation point according to the
342 // Geometric Series
343 step = std::min(maxStep, step * params.stepSize);
344
345 // Compute the Evaluation Point and evaluate the error
347 step, dx_u, dx_n, params.verbose);
348 VALUES x_d(x0.retract(dx_d));
349 double fNewError = f.error(x_d);
350
351 if (params.verbose)
352 std::cout << "Step: " << step << " | Error: " << fNewError << std::endl;
353
354 // Check step acceptance conditions
355 bool updateDecreasedError = fNewError < result.f_error;
356 bool updateHasSufficientDecrease =
357 fNewError < (fInitError - params.sufficientDecreaseCoeff * step);
358
359 if (params.verbose)
360 std::cout << "Decrease Error: " << updateDecreasedError
361 << " | Suff. Dec.: " << updateHasSufficientDecrease
362 << std::endl;
363
364 if (updateDecreasedError && updateHasSufficientDecrease) {
365 result.f_error = fNewError;
366 result.dx_d = dx_d;
367 result.delta = step;
368
369 if (params.verbose) std::cout << "Step Accepted" << std::endl;
370 }
371 }
372
373 return result;
374}
375}
Timing utilities.
Factor Graph Values.
Global functions in a separate testing namespace.
Definition chartTesting.h:28
VectorValues represents a collection of vector-valued variables associated each with a unique integer...
Definition VectorValues.h:73
double norm() const
Vector L2 norm.
Definition VectorValues.cpp:286
static VectorValues Zero(const VectorValues &other)
Create a VectorValues with the same structure as other, but filled with zeros.
Definition VectorValues.cpp:77
size_t size() const
Number of variables stored.
Definition VectorValues.h:129
void setZero()
Set all values to zero vectors.
Definition VectorValues.cpp:143
This class contains the implementation of the Dogleg algorithm.
Definition DoglegOptimizerImpl.h:33
TrustRegionAdaptationMode
Specifies how the trust region is adapted at each Dogleg iteration.
Definition DoglegOptimizerImpl.h:54
static IterationResult Iterate(double delta, TrustRegionAdaptationMode mode, const VectorValues &dx_u, const VectorValues &dx_n, const M &Rd, const F &f, const VALUES &x0, const double f_error, const bool verbose=false)
Compute the update point for one iteration of the Dogleg algorithm, given an initial trust region rad...
Definition DoglegOptimizerImpl.h:139
static VectorValues ComputeDoglegPoint(double delta, const VectorValues &dx_u, const VectorValues &dx_n, const bool verbose=false)
Compute the dogleg point given a trust region radius .
Definition DoglegOptimizerImpl.cpp:26
Definition DoglegOptimizerImpl.h:35
This class contains an extension of the Dogleg Algorithm where a line search is performed across the ...
Definition DoglegOptimizerImpl.h:260
static DoglegOptimizerImpl::IterationResult Iterate(const Params &params, const VectorValues &dx_u, const VectorValues &dx_n, const M &Rd, const F &f, const VALUES &x0)
Compute the update point for one iteration of the Dogleg Line Search algorithm, starting with a trust...
Definition DoglegOptimizerImpl.h:304
Definition DoglegOptimizerImpl.h:261
bool verbose
Whether to print debug information.
Definition DoglegOptimizerImpl.h:266
double minDelta
Minimum allowed small delta.
Definition DoglegOptimizerImpl.h:262
double stepSize
Increase of trust region for outward steps.
Definition DoglegOptimizerImpl.h:264
double maxDelta
Maximum allowed delta.
Definition DoglegOptimizerImpl.h:263
double sufficientDecreaseCoeff
Coefficient for suff. decrease check.
Definition DoglegOptimizerImpl.h:265