NDEVR
API Documentation
optimization_algorithm_levenberg.h
1#pragma once
2#include "optimization_algorithm_with_hessian.h"
3
4namespace NDEVR
5{
6 constexpr g_type gs_epsilon = g_type(1e-6);
9 template<class t_type>
11 {
12 public:
18 {
19 _currentLambda = g_type(-1.);
20 _tau = g_type(1e-5); // Carlos: originally 1e-5
21 _goodStepUpperScale = g_type(2. / 3.);
22 _goodStepLowerScale = g_type(1. / 3.);
23 _ni = 2.;
25 _nBad = 0;
26 }
27
28 void clear()
29 {
30 _currentLambda = g_type(-1.);
31 _tau = g_type(1e-5); // Carlos: originally 1e-5
32 _goodStepUpperScale = g_type(2. / 3.);
33 _goodStepLowerScale = g_type(1. / 3.);
34 _ni = 2.;
36 _nBad = 0;
38 }
40
46 OptimizationAlgorithm::SolverResult solve(int iteration, bool online, IndexScratch& scratch)
47 {
48
49 if (iteration == 0 && !online)
50 { // built up the CCS structure, here due to easy time measure
51 bool ok = OptimizationAlgorithmWithHessian<t_type>::solver.buildStructure(false, scratch);
52 if (!ok)
54 }
55
57
58
60 g_type tempChi = currentChi;
61
62 g_type iniChi = currentChi;
63
65
66 // core part of the Levenbarg algorithm
67 if (iteration == 0)
68 {
70 _ni = 2;
71 _nBad = 0;
72 }
73
74 g_type rho = 0;
75 int& qmax = _levenbergIterations;
76 qmax = 0;
77 do
78 {
80 // update the diagonal of the system matrix
83 //lib_assert(ok2, "bad solve?");
84 if (ok2)
85 {
87 // restore the diagonal
89
92 }
93 else
94 {
95 tempChi = std::numeric_limits<g_type>::max();
96 }
97 rho = (currentChi - tempChi);
98 g_type scale = computeScale();
99 scale += g_type(1e-3); // make sure it's non-zero :)
100 rho /= scale;
101
102 if (rho > gs_epsilon && std::isfinite(tempChi))
103 { // last step was good
104 g_type alpha = g_type(1. - pow((2 * rho - 1), 3));
105 // crop lambda between minimum and maximum factors
106 alpha = getMin(alpha, _goodStepUpperScale);
107 g_type scaleFactor = getMax(_goodStepLowerScale, alpha);
108 _currentLambda *= scaleFactor;
109 _ni = 2;
110 currentChi = tempChi;
112 }
113 else {
115 _ni *= 2;
116 OptimizationAlgorithmWithHessian<t_type>::optimizer().pop(); // restore the last state before trying to optimize
117 }
118 qmax++;
119 } while (rho < gs_epsilon && qmax < 10 && !OptimizationAlgorithmWithHessian<t_type>::optimizer().terminate());
120
121 if (qmax == 10 || rho <= gs_epsilon)
123
124 //Stop criterium (Raul)
125 if ((iniChi - currentChi) * 1e3 < iniChi)
126 _nBad++;
127 else
128 _nBad = 0;
129
130 if (_nBad >= 3)
133 }
134
138 void optimize(uint04 iterations, bool online, IndexScratch& scratch)
139 {
140 //WLock lock(blockPoseIndices);
142 return;
144 return;
145 for (uint04 i = 0; i < iterations; i++)
146 {
148 return;
149 OptimizationAlgorithm::SolverResult result = solve(i, online, scratch);
150 if (result != OptimizationAlgorithm::OK)
151 return;
152 }
153 }
154
156 g_type currentLambda() const { return _currentLambda; }
157
160 void setUserLambdaInit(g_type lambda)
161 {
162 _lambdaInit = lambda;
163 }
164
167
168 protected:
169 // Levenberg parameters
170 g_type _lambdaInit = 0.0;
172 g_type _tau;
175 g_type _ni;
177 int _nBad;
178
183 g_type computeLambdaInit() const
184 {
185 if (_lambdaInit > 0.0)
186 return _lambdaInit;
187 g_type maxDiagonal = 0.;
188 for (uint04 k = 0; k < OptimizationAlgorithmWithHessian<t_type>::optimizer().indexMapping().size(); k++) {
190 assert(v);
191 int dim = v->dimension();
192 for (int j = 0; j < dim; ++j) {
193 maxDiagonal = std::max(fabs(v->hessian(j, j)), maxDiagonal);
194 }
195 }
196 return _tau * maxDiagonal;
197 }
198
200 g_type computeScale() const
201 {
202 g_type scale = 0.;
203 for (size_t j = 0; j < OptimizationAlgorithmWithHessian<t_type>::solver.vectorSize(); j++) {
205 }
206 return scale;
207 }
208 public:
209 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
210 };
211
212}
A general case Vertex for optimization.
virtual sint04 dimension() const =0
dimension of the estimated state belonging to this node
virtual const g_type & hessian(int i, int j) const =0
get the element from the hessian matrix
Implementation of the Levenberg-Marquardt optimization algorithm.
OptimizationAlgorithmLevenberg()
construct the Levenberg algorithm, which will use the given Solver for solving the linearized system.
void setUserLambdaInit(g_type lambda)
Sets a user-specified initial damping factor.
g_type currentLambda() const
return the currently used damping factor
int _nBad
Counter for consecutive bad (non-improving) iterations.
g_type _tau
Scaling factor for initial lambda computation.
void clear()
Resets all Levenberg-Marquardt state to initial values.
void optimize(uint04 iterations, bool online, IndexScratch &scratch)
Runs Levenberg-Marquardt optimization for the given number of iterations.
int levenbergIteration()
return the number of levenberg iterations performed in the last round
g_type _ni
Multiplicative increase factor for lambda on bad steps.
OptimizationAlgorithm::SolverResult solve(int iteration, bool online, IndexScratch &scratch)
Performs a single Levenberg-Marquardt iteration with adaptive damping.
g_type _lambdaInit
User-specified initial lambda (0 = auto-compute).
g_type computeLambdaInit() const
helper for Levenberg, this function computes the initial damping factor, if the user did not specify ...
g_type computeScale() const
Computes the predicted reduction scale for the trust-region ratio.
g_type _goodStepLowerScale
Lower bound for lambda decrease if a good LM step.
int _levenbergIterations
The number of Levenberg iterations performed to accept the last step.
g_type _goodStepUpperScale
Upper bound for lambda decrease if a good LM step.
bool init(bool online=false)
Initializes the solver, detecting whether Schur complement should be used.
t_solver solver
The underlying solver instance.
SparseOptimizer & optimizer()
Returns a mutable reference to the underlying sparse optimizer.
SolverResult
Result codes returned by the solver after each iteration.
@ Fail
Iteration failed (e.g., singular matrix).
@ OK
Iteration succeeded, continue.
@ Terminate
Optimization should stop (converged or no improvement).
const VertexContainer & indexMapping() const
the index mapping of the vertices
void update(const g_type *update)
update the estimate of the active vertices
void computeActiveErrors()
computes the error vectors of all edges in the activeSet, and caches them
g_type activeRobustChi2() const
Returns the total robustified chi-squared error of all active edges.
The primary namespace for the NDEVR SDK.
constexpr t_type getMin(const t_type &left, const t_type &right)
Finds the minimum of the given arguments based on the < operator Author: Tyler Parke Date: 2017-11-05...
constexpr t_type getMax(const t_type &left, const t_type &right)
Finds the max of the given arguments using the > operator The only requirement is that t_type have > ...
uint32_t uint04
-Defines an alias representing a 4 byte, unsigned integer -Can represent exact integer values 0 throu...
constexpr g_type gs_epsilon
Convergence threshold for Levenberg-Marquardt.
Scratch buffers for block index assignments during structure building.