SourceXtractorPlusPlus 0.21
SourceXtractor++, the next generation SExtractor
Loading...
Searching...
No Matches
LevmarEngine.cpp
Go to the documentation of this file.
1
23#include <array>
24#include <cmath>
25#include <mutex>
26
27#include <levmar.h>
28#include <ElementsKernel/Exception.h>
29#include <ElementsKernel/Logging.h>
32
33#ifndef LEVMAR_WORKAREA_MAX_SIZE
34#define LEVMAR_WORKAREA_MAX_SIZE size_t(2ul<<30) // 2 GiB
35#endif
36
37namespace {
38
39__attribute__((unused))
40void printLevmarInfo(std::array<double, 10> info) {
41 std::cerr << "\nMinimization info:\n";
42 std::cerr << " ||e||_2 at initial p: " << info[0] << '\n';
43 std::cerr << " ||e||_2: " << info[1] << '\n';
44 std::cerr << " ||J^T e||_inf: " << info[2] << '\n';
45 std::cerr << " ||Dp||_2: " << info[3] << '\n';
46 std::cerr << " mu/max[J^T J]_ii: " << info[4] << '\n';
47 std::cerr << " # iterations: " << info[5] << '\n';
48 switch ((int) info[6]) {
49 case 1:
50 std::cerr << " stopped by small gradient J^T e\n";
51 break;
52 case 2:
53 std::cerr << " stopped by small Dp\n";
54 break;
55 case 3:
56 std::cerr << " stopped by itmax\n";
57 break;
58 case 4:
59 std::cerr << " singular matrix. Restart from current p with increased mu\n";
60 break;
61 case 5:
62 std::cerr << " no further error reduction is possible. Restart with increased mu\n";
63 break;
64 case 6:
65 std::cerr << " stopped by small ||e||_2\n";
66 break;
67 case 7:
68 std::cerr << " stopped by invalid (i.e. NaN or Inf) func values; a user error\n";
69 break;
70 }
71 std::cerr << " # function evaluations: " << info[7] << '\n';
72 std::cerr << " # Jacobian evaluations: " << info[8] << '\n';
73 std::cerr << " # linear systems solved: " << info[9] << "\n\n";
74}
75
76}
77
78namespace ModelFitting {
79
81
85
87
89 if (res == -1) {
91 }
92 switch (static_cast<int>(info[6])) {
93 case 7:
94 case 4:
96 case 3:
98 default:
100 }
101}
102
104 double epsilon2, double epsilon3, double delta)
105 : m_itmax{itmax}, m_opts{tau, epsilon1, epsilon2, epsilon3, delta} {
106#ifdef LINSOLVERS_RETAIN_MEMORY
107 logger.warn() << "Using a non thread safe levmar! Parallelism will be reduced.";
108#endif
109}
110
112
113
114#ifdef LINSOLVERS_RETAIN_MEMORY
115// If the Levmar library is not configured for multithreading, this mutex is used to ensure only one thread
116// at a time can enter levmar
117namespace {
119}
120#endif
121
124 // Create a tuple which keeps the references to the given manager and estimator
126
127 // The function which is called by the levmar loop
128 auto levmar_res_func = [](double *p, double *hx, int, int, void *extra) {
129#ifdef LINSOLVERS_RETAIN_MEMORY
130 levmar_mutex.unlock();
131#endif
132
133 auto* extra_ptr = (decltype(adata)*)extra;
135 pm.updateEngineValues(p);
137 re.populateResiduals(hx);
138
139#ifdef LINSOLVERS_RETAIN_MEMORY
140 levmar_mutex.lock();
141#endif
142 };
143
144 // Create the vector which will be used for keeping the parameter values
145 // and initialize it to the current values of the parameters
147 parameter_manager.getEngineValues(param_values.begin());
148
149 // Create a vector for getting the information of the minimization
150 std::array<double, 10> info = {0};
151
152 std::vector<double> covariance_matrix (parameter_manager.numberOfParameters() * parameter_manager.numberOfParameters());
153
154#ifdef LINSOLVERS_RETAIN_MEMORY
155 levmar_mutex.lock();
156#endif
157
159 size_t workarea_size = LM_DIF_WORKSZ(parameter_manager.numberOfParameters(),
160 residual_estimator.numberOfResiduals());
161
162 if (workarea_size <= LEVMAR_WORKAREA_MAX_SIZE / sizeof(double)) {
163 try {
164 workarea.reset(new double[workarea_size]);
165 } catch (const std::bad_alloc&) {
166 }
167 }
168
169 // Didn't allocate
170 if (workarea == nullptr) {
173 summary.iteration_no = workarea_size;
174 summary.parameter_sigmas.resize(parameter_manager.numberOfParameters());
175 return summary;
176 }
177
178 // Call the levmar library
179 auto start = std::chrono::steady_clock::now();
180 auto res = dlevmar_dif(levmar_res_func, // The function called from the levmar algorithm
181 param_values.data(), // The pointer where the parameter values are
182 NULL, // We don't use any measurement vector
183 parameter_manager.numberOfParameters(), // The number of free parameters
184 residual_estimator.numberOfResiduals(), // The number of residuals
185 m_itmax, // The maximum number of iterations
186 m_opts.data(), // The minimization options
187 info.data(), // Where the information of the minimization is stored
188 workarea.get(), // Working memory is allocated internally
189 covariance_matrix.data(),
190 &adata // No additional data needed
191 );
194#ifdef LINSOLVERS_RETAIN_MEMORY
195 levmar_mutex.unlock();
196#endif
197
198 // Create and return the summary object
200
201 auto converted_covariance_matrix = parameter_manager.convertCovarianceMatrixToWorldSpace(covariance_matrix);
202 for (unsigned int i=0; i<parameter_manager.numberOfParameters(); i++) {
203 summary.parameter_sigmas.push_back(sqrt(converted_covariance_matrix[i*(parameter_manager.numberOfParameters()+1)]));
204 }
205
206 summary.status_flag = getStatusFlag(info, res);
207 summary.engine_stop_reason = static_cast<int>(info[6]);
208 summary.iteration_no = static_cast<int>(info[5]);
209 summary.underlying_framework_info = info;
210 summary.duration = elapsed.count();
211 return summary;
212}
213
214} // end of namespace ModelFitting
#define LEVMAR_WORKAREA_MAX_SIZE
static Logging getLogger(const std::string &name="")
Class responsible for managing the parameters the least square engine minimizes.
LeastSquareSummary solveProblem(EngineParameterManager &parameter_manager, ResidualEstimator &residual_estimator) override
virtual ~LevmarEngine()
Destructor.
std::vector< double > m_opts
LevmarEngine(size_t itmax=1000, double tau=1E-3, double epsilon1=1E-8, double epsilon2=1E-8, double epsilon3=1E-8, double delta=1E-4)
Constructs a new instance of the engine.
Provides to the LeastSquareEngine the residual values.
T data(T... args)
T end(T... args)
static LeastSquareSummary::StatusFlag getStatusFlag(int ret)
static std::shared_ptr< LeastSquareEngine > createLevmarEngine(unsigned max_iterations)
static LeastSquareEngineManager::StaticEngine levmar_engine
static Elements::Logging logger
T sqrt(T... args)
Class containing the summary information of solving a least square minimization problem.
T tie(T... args)