1 #include <gtest/gtest.h>
2 #include <stan/optimization/bfgs.hpp>
3 #include <test/test-models/good/optimization/rosenbrock.hpp>
4
5 typedef rosenbrock_model_namespace::rosenbrock_model Model;
6 typedef stan::optimization::BFGSLineSearch<
7 Model, stan::optimization::BFGSUpdate_HInv<> >
8 Optimizer;
9
TEST(OptimizationBfgs,rosenbrock_bfgs_convergence)10 TEST(OptimizationBfgs, rosenbrock_bfgs_convergence) {
11 // -1,1 is the standard initialization for the Rosenbrock function
12 std::vector<double> cont_vector(2);
13 cont_vector[0] = -1;
14 cont_vector[1] = 1;
15 std::vector<int> disc_vector;
16
17 static const std::string DATA("");
18 std::stringstream data_stream(DATA);
19 stan::io::dump dummy_context(data_stream);
20
21 Model rb_model(dummy_context);
22 std::stringstream out;
23 Optimizer bfgs(rb_model, cont_vector, disc_vector, &out);
24 EXPECT_EQ("", out.str());
25
26 int ret = 0;
27 while (ret == 0) {
28 ret = bfgs.step();
29 }
30 bfgs.params_r(cont_vector);
31
32 // Check that the return code is normal
33 EXPECT_GE(ret, 0);
34
35 // Check the correct minimum was found
36 EXPECT_NEAR(cont_vector[0], 1.0, 1e-6);
37 EXPECT_NEAR(cont_vector[1], 1.0, 1e-6);
38
39 // Check that it didn't take too long to get there
40 EXPECT_LE(bfgs.iter_num(), 35);
41 EXPECT_LE(bfgs.grad_evals(), 70);
42 }
43
TEST(OptimizationBfgs,rosenbrock_bfgs_termconds)44 TEST(OptimizationBfgs, rosenbrock_bfgs_termconds) {
45 // -1,1 is the standard initialization for the Rosenbrock function
46 std::vector<double> cont_vector(2);
47 cont_vector[0] = -1;
48 cont_vector[1] = 1;
49 std::vector<int> disc_vector;
50
51 static const std::string DATA("");
52 std::stringstream data_stream(DATA);
53 stan::io::dump dummy_context(data_stream);
54
55 Model rb_model(dummy_context);
56
57 std::stringstream out;
58 Optimizer bfgs(rb_model, cont_vector, disc_vector, &out);
59 EXPECT_EQ("", out.str());
60 int ret;
61
62 bfgs._conv_opts.maxIts = 1e9;
63 bfgs._conv_opts.tolAbsX = 0;
64 bfgs._conv_opts.tolAbsF = 0;
65 bfgs._conv_opts.tolRelF = 0;
66 bfgs._conv_opts.tolAbsGrad = 0;
67 bfgs._conv_opts.tolRelGrad = 0;
68
69 bfgs._conv_opts.maxIts = 5;
70 bfgs.initialize(cont_vector);
71 while (0 == (ret = bfgs.step()))
72 ;
73 EXPECT_EQ(ret, stan::optimization::TERM_MAXIT);
74 EXPECT_EQ(bfgs.iter_num(), bfgs._conv_opts.maxIts);
75 bfgs._conv_opts.maxIts = 1e9;
76
77 bfgs._conv_opts.tolAbsX = 1e-8;
78 bfgs.initialize(cont_vector);
79 while (0 == (ret = bfgs.step()))
80 ;
81 EXPECT_EQ(ret, stan::optimization::TERM_ABSX);
82 bfgs._conv_opts.tolAbsX = 0;
83
84 bfgs._conv_opts.tolAbsF = 1e-12;
85 bfgs.initialize(cont_vector);
86 while (0 == (ret = bfgs.step()))
87 ;
88 EXPECT_EQ(ret, stan::optimization::TERM_ABSF);
89 bfgs._conv_opts.tolAbsF = 0;
90
91 bfgs._conv_opts.tolRelF = 1e+4;
92 bfgs.initialize(cont_vector);
93 while (0 == (ret = bfgs.step()))
94 ;
95 EXPECT_EQ(ret, stan::optimization::TERM_RELF);
96 bfgs._conv_opts.tolRelF = 0;
97
98 bfgs._conv_opts.tolAbsGrad = 1e-8;
99 bfgs.initialize(cont_vector);
100 while (0 == (ret = bfgs.step()))
101 ;
102 EXPECT_EQ(ret, stan::optimization::TERM_ABSGRAD);
103 bfgs._conv_opts.tolAbsGrad = 0;
104
105 bfgs._conv_opts.tolRelGrad = 1e+3;
106 bfgs.initialize(cont_vector);
107 while (0 == (ret = bfgs.step()))
108 ;
109 EXPECT_EQ(ret, stan::optimization::TERM_RELGRAD);
110 bfgs._conv_opts.tolRelGrad = 0;
111 }
112
TEST(OptimizationBfgs,rosenbrock_lbfgs_convergence)113 TEST(OptimizationBfgs, rosenbrock_lbfgs_convergence) {
114 // -1,1 is the standard initialization for the Rosenbrock function
115 std::vector<double> cont_vector(2);
116 cont_vector[0] = -1;
117 cont_vector[1] = 1;
118 std::vector<int> disc_vector;
119
120 static const std::string DATA("");
121 std::stringstream data_stream(DATA);
122 stan::io::dump dummy_context(data_stream);
123
124 Model rb_model(dummy_context);
125 std::stringstream out;
126 Optimizer bfgs(rb_model, cont_vector, disc_vector, &out);
127 EXPECT_EQ("", out.str());
128
129 int ret = 0;
130 while (ret == 0) {
131 ret = bfgs.step();
132 }
133 bfgs.params_r(cont_vector);
134
135 // Check that the return code is normal
136 EXPECT_GE(ret, 0);
137
138 // Check the correct minimum was found
139 EXPECT_NEAR(cont_vector[0], 1.0, 1e-6);
140 EXPECT_NEAR(cont_vector[1], 1.0, 1e-6);
141
142 // Check that it didn't take too long to get there
143 EXPECT_LE(bfgs.iter_num(), 35);
144 EXPECT_LE(bfgs.grad_evals(), 70);
145 }
146
TEST(OptimizationBfgs,rosenbrock_lbfgs_termconds)147 TEST(OptimizationBfgs, rosenbrock_lbfgs_termconds) {
148 // -1,1 is the standard initialization for the Rosenbrock function
149 std::vector<double> cont_vector(2);
150 cont_vector[0] = -1;
151 cont_vector[1] = 1;
152 std::vector<int> disc_vector;
153
154 static const std::string DATA("");
155 std::stringstream data_stream(DATA);
156 stan::io::dump dummy_context(data_stream);
157
158 Model rb_model(dummy_context);
159 std::stringstream out;
160 Optimizer bfgs(rb_model, cont_vector, disc_vector, &out);
161 EXPECT_EQ("", out.str());
162 int ret;
163
164 bfgs._conv_opts.maxIts = 1e9;
165 bfgs._conv_opts.tolAbsX = 0;
166 bfgs._conv_opts.tolAbsF = 0;
167 bfgs._conv_opts.tolRelF = 0;
168 bfgs._conv_opts.tolAbsGrad = 0;
169 bfgs._conv_opts.tolRelGrad = 0;
170
171 bfgs._conv_opts.maxIts = 5;
172 bfgs.initialize(cont_vector);
173 while (0 == (ret = bfgs.step()))
174 ;
175 EXPECT_EQ(ret, stan::optimization::TERM_MAXIT);
176 EXPECT_EQ(bfgs.iter_num(), bfgs._conv_opts.maxIts);
177 bfgs._conv_opts.maxIts = 1e9;
178
179 bfgs._conv_opts.tolAbsX = 1e-8;
180 bfgs.initialize(cont_vector);
181 while (0 == (ret = bfgs.step()))
182 ;
183 EXPECT_EQ(ret, stan::optimization::TERM_ABSX);
184 bfgs._conv_opts.tolAbsX = 0;
185
186 bfgs._conv_opts.tolAbsF = 1e-12;
187 bfgs.initialize(cont_vector);
188 while (0 == (ret = bfgs.step()))
189 ;
190 EXPECT_EQ(ret, stan::optimization::TERM_ABSF);
191 bfgs._conv_opts.tolAbsF = 0;
192
193 bfgs._conv_opts.tolRelF = 1e+4;
194 bfgs.initialize(cont_vector);
195 while (0 == (ret = bfgs.step()))
196 ;
197 EXPECT_EQ(ret, stan::optimization::TERM_RELF);
198 bfgs._conv_opts.tolRelF = 0;
199
200 bfgs._conv_opts.tolAbsGrad = 1e-8;
201 bfgs.initialize(cont_vector);
202 while (0 == (ret = bfgs.step()))
203 ;
204 EXPECT_EQ(ret, stan::optimization::TERM_ABSGRAD);
205 bfgs._conv_opts.tolAbsGrad = 0;
206
207 bfgs._conv_opts.tolRelGrad = 1e+3;
208 bfgs.initialize(cont_vector);
209 while (0 == (ret = bfgs.step()))
210 ;
211 EXPECT_EQ(ret, stan::optimization::TERM_RELGRAD);
212 bfgs._conv_opts.tolRelGrad = 0;
213 }
214
TEST(OptimizationBfgs,ConvergenceOptions)215 TEST(OptimizationBfgs, ConvergenceOptions) {
216 stan::optimization::ConvergenceOptions<> a;
217
218 EXPECT_FLOAT_EQ(a.maxIts, 10000);
219 EXPECT_FLOAT_EQ(a.fScale, 1);
220 EXPECT_FLOAT_EQ(a.tolAbsX, 1e-8);
221 EXPECT_FLOAT_EQ(a.tolAbsF, 1e-12);
222 EXPECT_FLOAT_EQ(a.tolAbsGrad, 1e-8);
223 EXPECT_FLOAT_EQ(a.tolRelF, 1e+4);
224 EXPECT_FLOAT_EQ(a.tolRelGrad, 1e+3);
225 }
226
TEST(OptimizationBfgs,LsOptions)227 TEST(OptimizationBfgs, LsOptions) {
228 stan::optimization::LSOptions<> a;
229
230 EXPECT_FLOAT_EQ(a.c1, 1e-4);
231 EXPECT_FLOAT_EQ(a.c2, 0.9);
232 EXPECT_FLOAT_EQ(a.minAlpha, 1e-12);
233 EXPECT_FLOAT_EQ(a.alpha0, 1e-3);
234 }
235
TEST(OptimizationBfgs,ModelAdaptor)236 TEST(OptimizationBfgs, ModelAdaptor) {
237 Eigen::Matrix<double, Eigen::Dynamic, 1> cont_vector(2);
238 cont_vector[0] = -1;
239 cont_vector[1] = 1;
240 std::vector<int> disc_vector;
241
242 static const std::string DATA("");
243 std::stringstream data_stream(DATA);
244 stan::io::dump dummy_context(data_stream);
245 Model rb_model(dummy_context);
246 std::stringstream out;
247 stan::optimization::ModelAdaptor<Model> mod(rb_model, disc_vector, &out);
248 EXPECT_EQ("", out.str());
249
250 // test streams
251 EXPECT_NO_THROW(
252 stan::optimization::ModelAdaptor<Model> mod(rb_model, disc_vector, 0));
253 EXPECT_NO_THROW(
254 stan::optimization::ModelAdaptor<Model> mod(rb_model, disc_vector, &out));
255 }
256
TEST(OptimizationBfgs,ModelAdaptor_fevals)257 TEST(OptimizationBfgs, ModelAdaptor_fevals) {
258 Eigen::Matrix<double, Eigen::Dynamic, 1> cont_vector(2);
259 cont_vector[0] = -1;
260 cont_vector[1] = 1;
261 std::vector<int> disc_vector;
262
263 static const std::string DATA("");
264 std::stringstream data_stream(DATA);
265 stan::io::dump dummy_context(data_stream);
266 Model rb_model(dummy_context);
267 std::stringstream out;
268 stan::optimization::ModelAdaptor<Model> mod(rb_model, disc_vector, &out);
269 EXPECT_EQ("", out.str());
270
271 EXPECT_FLOAT_EQ(mod.fevals(), 0);
272 }
273
TEST(OptimizationBfgs,ModelAdaptor_operator_parens__matrix_double)274 TEST(OptimizationBfgs, ModelAdaptor_operator_parens__matrix_double) {
275 Eigen::Matrix<double, Eigen::Dynamic, 1> cont_vector(2);
276 cont_vector[0] = -1;
277 cont_vector[1] = 1;
278 std::vector<int> disc_vector;
279
280 static const std::string DATA("");
281 std::stringstream data_stream(DATA);
282 stan::io::dump dummy_context(data_stream);
283 Model rb_model(dummy_context);
284 std::stringstream out;
285 stan::optimization::ModelAdaptor<Model> mod(rb_model, disc_vector, &out);
286 EXPECT_EQ("", out.str());
287
288 Eigen::Matrix<double, Eigen::Dynamic, 1> grad(2);
289 grad[0] = 4;
290 grad[1] = 0;
291 double f;
292
293 EXPECT_FLOAT_EQ(mod(cont_vector, f), 0);
294 }
295
TEST(OptimizationBfgs,ModelAdaptor_operator_parens__matrix_double_matrix)296 TEST(OptimizationBfgs, ModelAdaptor_operator_parens__matrix_double_matrix) {
297 Eigen::Matrix<double, Eigen::Dynamic, 1> cont_vector(2);
298 cont_vector[0] = -1;
299 cont_vector[1] = 1;
300 std::vector<int> disc_vector;
301
302 static const std::string DATA("");
303 std::stringstream data_stream(DATA);
304 stan::io::dump dummy_context(data_stream);
305 Model rb_model(dummy_context);
306 std::stringstream out;
307 stan::optimization::ModelAdaptor<Model> mod(rb_model, disc_vector, &out);
308 EXPECT_EQ("", out.str());
309
310 Eigen::Matrix<double, Eigen::Dynamic, 1> grad(2);
311 grad[0] = 4;
312 grad[1] = 0;
313 double f;
314
315 EXPECT_FLOAT_EQ(mod(cont_vector, f, grad), 0);
316 }
317
TEST(OptimizationBfgs,ModelAdaptor_df)318 TEST(OptimizationBfgs, ModelAdaptor_df) {
319 Eigen::Matrix<double, Eigen::Dynamic, 1> cont_vector(2);
320 cont_vector[0] = -1;
321 cont_vector[1] = 1;
322 std::vector<int> disc_vector;
323
324 static const std::string DATA("");
325 std::stringstream data_stream(DATA);
326 stan::io::dump dummy_context(data_stream);
327 Model rb_model(dummy_context);
328 std::stringstream out;
329 stan::optimization::ModelAdaptor<Model> mod(rb_model, disc_vector, &out);
330 EXPECT_EQ("", out.str());
331
332 Eigen::Matrix<double, Eigen::Dynamic, 1> grad(2);
333 grad[0] = 4;
334 grad[1] = 0;
335
336 EXPECT_FLOAT_EQ(mod.df(cont_vector, grad), 0);
337 }
338
TEST(OptimizationBfgs,BFGSLineSearch)339 TEST(OptimizationBfgs, BFGSLineSearch) {
340 std::vector<double> cont_vector(2);
341 cont_vector[0] = -1;
342 cont_vector[1] = 1;
343 std::vector<int> disc_vector;
344
345 static const std::string DATA("");
346 std::stringstream data_stream(DATA);
347 stan::io::dump dummy_context(data_stream);
348 Model rb_model(dummy_context);
349 std::stringstream out;
350 Optimizer bfgs(rb_model, cont_vector, disc_vector, &out);
351 EXPECT_EQ("", out.str());
352
353 // test streams
354 EXPECT_NO_THROW(Optimizer bfgs(rb_model, cont_vector, disc_vector, 0));
355 EXPECT_NO_THROW(Optimizer bfgs(rb_model, cont_vector, disc_vector, &out));
356 }
357
TEST(OptimizationBfgs,BFGSLineSearch_initialize)358 TEST(OptimizationBfgs, BFGSLineSearch_initialize) {
359 std::vector<double> cont_vector(2);
360 cont_vector[0] = -1;
361 cont_vector[1] = 1;
362 std::vector<int> disc_vector;
363
364 static const std::string DATA("");
365 std::stringstream data_stream(DATA);
366 stan::io::dump dummy_context(data_stream);
367 Model rb_model(dummy_context);
368 std::stringstream out;
369 Optimizer bfgs(rb_model, cont_vector, disc_vector, &out);
370 EXPECT_EQ("", out.str());
371
372 bfgs.initialize(cont_vector);
373 EXPECT_FLOAT_EQ(bfgs.curr_f(), 4);
374 EXPECT_FLOAT_EQ(bfgs.curr_x()[0], -1);
375 EXPECT_FLOAT_EQ(bfgs.curr_x()[1], 1);
376 EXPECT_FLOAT_EQ(bfgs.curr_g()[0], -4);
377 EXPECT_FLOAT_EQ(bfgs.curr_g()[1], 0);
378 EXPECT_FLOAT_EQ(bfgs.curr_p()[0], 4);
379 EXPECT_FLOAT_EQ(bfgs.curr_p()[1], 0);
380 }
381
TEST(OptimizationBfgs,BFGSLineSearch_grad_evals)382 TEST(OptimizationBfgs, BFGSLineSearch_grad_evals) {
383 std::vector<double> cont_vector(2);
384 cont_vector[0] = -1;
385 cont_vector[1] = 1;
386 std::vector<int> disc_vector;
387
388 static const std::string DATA("");
389 std::stringstream data_stream(DATA);
390 stan::io::dump dummy_context(data_stream);
391 Model rb_model(dummy_context);
392 std::stringstream out;
393 Optimizer bfgs(rb_model, cont_vector, disc_vector, &out);
394 EXPECT_EQ("", out.str());
395
396 EXPECT_FLOAT_EQ(bfgs.grad_evals(), 1);
397 }
398
TEST(OptimizationBfgs,BFGSLineSearch_logp)399 TEST(OptimizationBfgs, BFGSLineSearch_logp) {
400 std::vector<double> cont_vector(2);
401 cont_vector[0] = -1;
402 cont_vector[1] = 1;
403 std::vector<int> disc_vector;
404
405 static const std::string DATA("");
406 std::stringstream data_stream(DATA);
407 stan::io::dump dummy_context(data_stream);
408 Model rb_model(dummy_context);
409 std::stringstream out;
410 Optimizer bfgs(rb_model, cont_vector, disc_vector, &out);
411 EXPECT_EQ("", out.str());
412
413 EXPECT_FLOAT_EQ(bfgs.logp(), -4);
414 }
415
TEST(OptimizationBfgs,BFGSLineSearch_grad_norm)416 TEST(OptimizationBfgs, BFGSLineSearch_grad_norm) {
417 std::vector<double> cont_vector(2);
418 cont_vector[0] = -1;
419 cont_vector[1] = 1;
420 std::vector<int> disc_vector;
421
422 static const std::string DATA("");
423 std::stringstream data_stream(DATA);
424 stan::io::dump dummy_context(data_stream);
425 Model rb_model(dummy_context);
426 std::stringstream out;
427 Optimizer bfgs(rb_model, cont_vector, disc_vector, &out);
428 EXPECT_EQ("", out.str());
429
430 std::vector<double> grad;
431
432 bfgs.grad(grad);
433 EXPECT_FLOAT_EQ(bfgs.grad_norm(), 4);
434 }
435
TEST(OptimizationBfgs,BFGSLineSearch_grad)436 TEST(OptimizationBfgs, BFGSLineSearch_grad) {
437 std::vector<double> cont_vector(2);
438 cont_vector[0] = -1;
439 cont_vector[1] = 1;
440 std::vector<int> disc_vector;
441
442 static const std::string DATA("");
443 std::stringstream data_stream(DATA);
444 stan::io::dump dummy_context(data_stream);
445 Model rb_model(dummy_context);
446 std::stringstream out;
447 Optimizer bfgs(rb_model, cont_vector, disc_vector, &out);
448 EXPECT_EQ("", out.str());
449 std::vector<double> grad;
450
451 bfgs.grad(grad);
452 EXPECT_FLOAT_EQ(grad.size(), 2);
453 EXPECT_FLOAT_EQ(grad[0], 4);
454 EXPECT_FLOAT_EQ(grad[1], 0);
455 }
456
TEST(OptimizationBfgs,BFGSLineSearch_params_r)457 TEST(OptimizationBfgs, BFGSLineSearch_params_r) {
458 std::vector<double> cont_vector(2);
459 cont_vector[0] = -1;
460 cont_vector[1] = 1;
461 std::vector<int> disc_vector;
462
463 static const std::string DATA("");
464 std::stringstream data_stream(DATA);
465 stan::io::dump dummy_context(data_stream);
466 Model rb_model(dummy_context);
467 std::stringstream out;
468 Optimizer bfgs(rb_model, cont_vector, disc_vector, &out);
469 EXPECT_EQ("", out.str());
470 std::vector<double> x;
471
472 bfgs.params_r(x);
473 EXPECT_FLOAT_EQ(x.size(), 2);
474 EXPECT_FLOAT_EQ(x[0], -1);
475 EXPECT_FLOAT_EQ(x[1], 1);
476 }
477