GCC Code Coverage Report


Directory: ./
File: lib/geogram/numerics/lbfgs_optimizers.cpp
Date: 2026-09-07 02:37:58
Exec Total Coverage
Lines: 40 74 54.1%
Functions: 6 14 42.9%
Branches: 12 74 16.2%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2000-2022 Inria
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 met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the ALICE Project-Team nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Contact: Bruno Levy
30 *
31 * https://www.inria.fr/fr/bruno-levy
32 *
33 * Inria,
34 * Domaine de Voluceau,
35 * 78150 Le Chesnay - Rocquencourt
36 * FRANCE
37 *
38 */
39
40 #ifdef GEOGRAM_WITH_HLBFGS
41
42 #include <geogram/numerics/lbfgs_optimizers.h>
43 #include <geogram/basic/command_line.h>
44 #include <geogram/basic/argused.h>
45 #include <geogram/third_party/HLBFGS/HLBFGS.h>
46 #include <geogram/bibliography/bibliography.h>
47
48 #include <setjmp.h>
49 #include <iostream>
50
51 namespace GEO {
52
53 /**
54 * \brief Optimizer configuration
55 * \details Manages global variables and callbacks for the
56 * communication between the Optimizer class and the HLBFGS
57 * library.
58 * \internal
59 * The current implementation is actually a bottleneck: optimizer
60 * execution config is stored in static variables which prevents multiple
61 * optimizers to execute in parallel.
62 */
63 namespace OptimizerConfig {
64
65 static Optimizer::newiteration_callback newiteration_callback_ = nullptr;
66 static Optimizer::funcgrad_callback funcgrad_callback_ = nullptr;
67 static Optimizer::evalhessian_callback evalhessian_callback_ = nullptr;
68 static index_t N_ = 0;
69
70 /**
71 * \brief Initializes Optimizer configuration
72 * \details Sets the problem dimension and the various optimizer
73 * callbacks for the optimizer execution
74 * \param[in] N dimension of the problem
75 * \param[in] funcgrad_callback callback that evaluates
76 * the function to be minimized and its gradient
77 * \param[in] newiteration_callback callback that will be
78 * called at each iteration
79 * \param[in] evalhessian_callback callback that evaluates
80 * the Hessian of function to be minimized (second
81 * order derivatives)
82 */
83 10 static void init(
84 index_t N,
85 Optimizer::funcgrad_callback funcgrad_callback,
86 Optimizer::newiteration_callback newiteration_callback,
87 Optimizer::evalhessian_callback evalhessian_callback
88 ) {
89 10 N_ = N;
90 10 funcgrad_callback_ = funcgrad_callback;
91 10 newiteration_callback_ = newiteration_callback;
92 10 evalhessian_callback_ = evalhessian_callback;
93 10 }
94
95 /**
96 * \brief HLBFGS callback called at each iteration.
97 * \param[in] iter current iteration
98 * \param[in] call_iter total number of evaluations
99 * \param[in] x value of the parameters at current iteration
100 * \param[in] f value of the function
101 * \param[in] g gradient of the function
102 * \param[in] gnorm norm of the gradient
103 */
104 310 static void HLBFGS_newiteration_callback(
105 int iter, int call_iter, double* x, double* f, double* g,
106 double* gnorm
107 ) {
108 310 GEO::geo_argused(iter);
109 310 GEO::geo_argused(call_iter);
110 310 (* newiteration_callback_)(N_, x, * f, g, * gnorm);
111 310 }
112
113 /**
114 * \brief HLBFGS callback that evaluates the function and its
115 * gradient.
116 * \param[in] N dimension of the problem
117 * \param[in] x value of the parameters at current iteration
118 * \param[in] prev_x value of the parameters at previous iteration
119 * \param[out] f value of the function
120 * \param[out] g gradient of the function
121 */
122 335 static void HLBFGS_funcgrad_callback(
123 int N, double* x, double* prev_x, double* f, double* g
124 ) {
125 335 GEO::geo_argused(prev_x);
126 335 (* funcgrad_callback_)((index_t) N, x, * f, g);
127 335 }
128
129 /**
130 * \brief HLBFGS callback that evaluates the function, its gradient
131 * and Hessian.
132 * \param[in] N dimension of the problem
133 * \param[in] x value of the parameters at current iteration
134 * \param[in] prev_x value of the parameters at previous iteration
135 * \param[out] f value of the function
136 * \param[out] g gradient of the function
137 * \param[out] m_hessian Hessian of the function
138 */
139 static void HLBFGS_evalhessian_callback(
140 int N, double* x, double* prev_x, double* f, double* g,
141 HESSIAN_MATRIX& m_hessian
142 ) {
143 GEO::geo_argused(prev_x);
144 (* evalhessian_callback_)((index_t) N, x, * f, g, m_hessian);
145 }
146 }
147
148 /************************************************************************/
149
150 10 HLBFGSOptimizer::HLBFGSOptimizer() :
151 10 b_m1qn3_(false),
152 10 b_cg_(false) {
153
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 geo_cite("WEB:HLBFGS");
154 10 }
155
156 40 HLBFGSOptimizer::~HLBFGSOptimizer() {
157 40 }
158
159 10 void HLBFGSOptimizer::optimize(double* x) {
160
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
10 geo_assert(newiteration_callback_ != nullptr);
161
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
10 geo_assert(funcgrad_callback_ != nullptr);
162
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
10 geo_assert(n_ > 0);
163
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
10 geo_assert(x != nullptr);
164
165 10 OptimizerConfig::init(
166 n_,
167 funcgrad_callback_,
168 newiteration_callback_,
169 nullptr
170 );
171
172 double parameter[20];
173 int hlbfgs_info[20];
174
175 // initialize parameters and infos
176
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 INIT_HLBFGS(parameter, hlbfgs_info);
177
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 hlbfgs_info[3] = b_m1qn3_ ? 1 : 0; // determines whether we use m1qn3
178 10 hlbfgs_info[4] = (int) max_iter_; // max iterations
179 10 hlbfgs_info[5] =
180
3/6
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 10 times.
10 GEO::CmdLine::get_arg_bool("debug") ? 1 : 0; // verbose
181
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 hlbfgs_info[10] = b_cg_ ? 1 : 0; // determines whether we use cg
182 10 parameter[5] = 0; // disabled
183 10 parameter[6] = epsg_;
184
185 10 HLBFGS(
186 10 (int) n_,
187
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 (int) m_,
188 x,
189 OptimizerConfig::HLBFGS_funcgrad_callback,
190 nullptr,
191 HLBFGS_UPDATE_Hessian,
192 OptimizerConfig::HLBFGS_newiteration_callback,
193 parameter,
194 hlbfgs_info
195 );
196 10 }
197
198 /************************************************************************/
199
200 HLBFGS_M1QN3Optimizer::HLBFGS_M1QN3Optimizer() {
201 set_m1qn3(true);
202 }
203
204 HLBFGS_M1QN3Optimizer::~HLBFGS_M1QN3Optimizer() {
205 }
206
207 /************************************************************************/
208
209 HLBFGS_CGOptimizer::HLBFGS_CGOptimizer() {
210 set_cg(true);
211 }
212
213 HLBFGS_CGOptimizer::~HLBFGS_CGOptimizer() {
214 }
215
216 /************************************************************************/
217
218 HLBFGS_HessOptimizer::HLBFGS_HessOptimizer() :
219 T_(0) {
220 }
221
222 HLBFGS_HessOptimizer::~HLBFGS_HessOptimizer() {
223 }
224
225 void HLBFGS_HessOptimizer::optimize(double* x) {
226 geo_assert(newiteration_callback_ != nullptr);
227 geo_assert(funcgrad_callback_ != nullptr);
228 geo_assert(evalhessian_callback_ != nullptr);
229 geo_assert(n_ > 0);
230 geo_assert(x != nullptr);
231
232 OptimizerConfig::init(
233 n_,
234 funcgrad_callback_,
235 newiteration_callback_,
236 evalhessian_callback_
237 );
238
239 double parameter[20];
240 int hlbfgs_info[20];
241
242 // initialize parameters and infos
243 INIT_HLBFGS(parameter, hlbfgs_info);
244 hlbfgs_info[4] = (int) max_iter_; // max iterations
245 hlbfgs_info[6] = (int) T_; // update interval of hessian
246 hlbfgs_info[7] = 1; // 0: without hessian, 1: with accurate hessian
247
248 HLBFGS(
249 (int) n_,
250 (int) m_,
251 x,
252 OptimizerConfig::HLBFGS_funcgrad_callback,
253 OptimizerConfig::HLBFGS_evalhessian_callback,
254 HLBFGS_UPDATE_Hessian,
255 OptimizerConfig::HLBFGS_newiteration_callback,
256 parameter,
257 hlbfgs_info
258 );
259 }
260 }
261
262 #endif
263