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