generator_test.cpp
Go to the documentation of this file.
1 #include <iostream>
2 #include <sstream>
3 #include <boost/random/additive_combine.hpp>
4 #include <stan/lang/ast_def.cpp>
6 #include <stan/io/dump.hpp>
7 #include <test/test-models/good/lang/test_lp.hpp>
9 #include <gtest/gtest.h>
10 
12  const std::string& quoted_s) {
13  std::stringstream ss;
15  EXPECT_EQ(quoted_s, ss.str());
16 }
17 
19  const std::string& expected_output_content) {
20  std::stringstream ss;
22  std::string s_rendered = ss.str();
23  EXPECT_EQ("\"" + expected_output_content + "\"", ss.str());
24 }
25 
26 TEST(langGenerator, quotedString) {
29  test_generate_quoted_string_quote("abc'def", "abc\\'def");
30  test_generate_quoted_string_quote("\"abc", "\\\"abc");
31  test_generate_quoted_string_quote("abc\"", "abc\\\"");
32  test_generate_quoted_string_quote("abc\"def", "abc\\\"def");
33  test_generate_quoted_string_quote("abc\"def\"ghi", "abc\\\"def\\\"ghi");
34 }
35 
37  const std::string& e_exp) {
38  std::stringstream ss;
40  EXPECT_EQ(e_exp, ss.str());
41 }
42 
43 TEST(lang,printStringLiteral) {
44  test_generate_quoted_string("", "\"\"");
45  test_generate_quoted_string("\\d\\", "\"\\\\d\\\\\"");
46  test_generate_quoted_string("ab\"c", "\"ab\\\"c\"");
47  test_generate_quoted_string("'hey,' he said.","\"\\'hey,\\' he said.\"");
48 }
49 
50 TEST(lang,printQuotedExpression) {
55  using std::vector;
56  test_generate_quoted_expression(int_literal(1), "\"1\"");
57  vector<expression> args;
58 
59  expression expr(variable("foo"));
60  vector<vector<expression> > dimss;
61  vector<expression> dim;
62  dim.push_back(int_literal(1));
63  dimss.push_back(dim);
64  std::string s_exp = "\"get_base1(foo,1,\\\"foo\\\",1)\"";
65  test_generate_quoted_expression(index_op(expr,dimss), s_exp);
66 }
67 
68 
69 TEST(lang, logProbPolymorphismDouble) {
70  using std::vector;
71  using Eigen::Matrix;
72  using Eigen::Dynamic;
73 
74  std::string txt = "foo <- 3\nbar <- 4";
75  std::stringstream in(txt);
76  stan::io::dump dump(in);
77 
78  test_lp_model_namespace::test_lp_model model(dump);
79 
80  std::vector<double> params_r(2);
81  params_r[0] = 1.0;
82  params_r[1] = -3.2;
83 
84  std::vector<int> params_i;
85 
86  Matrix<double, Dynamic, 1> params_r_vec(2);
87  for (int i = 0; i < 2; ++i)
88  params_r_vec(i) = params_r[i];
89 
90  double lp1 = model.log_prob<true,true>(params_r, params_i, 0);
91  double lp2 = model.log_prob<true,true>(params_r_vec, 0);
92  EXPECT_FLOAT_EQ(lp1, lp2);
93 
94  lp1 = model.log_prob<true,false>(params_r, params_i, 0);
95  lp2 = model.log_prob<true,false>(params_r_vec, 0);
96  EXPECT_FLOAT_EQ(lp1, lp2);
97 
98  lp1 = model.log_prob<false,true>(params_r, params_i, 0);
99  lp2 = model.log_prob<false,true>(params_r_vec, 0);
100  EXPECT_FLOAT_EQ(lp1, lp2);
101 
102  lp1 = model.log_prob<false,false>(params_r, params_i, 0);
103  lp2 = model.log_prob<false,false>(params_r_vec, 0);
104  EXPECT_FLOAT_EQ(lp1, lp2);
105 
106  // only test generate_inits for doubles -- no var allowed
107  std::string init_txt = "y <- c(-2.9,1.2)";
108  std::stringstream init_in(init_txt);
109  stan::io::dump init_dump(init_in);
110  std::vector<int> params_i_init;
111  std::vector<double> params_r_init;
112  std::stringstream pstream;
113  model.transform_inits(init_dump, params_i_init, params_r_init, &pstream);
114  EXPECT_EQ(0U, params_i_init.size());
115  EXPECT_EQ(2U, params_r_init.size());
116 
117  Matrix<double,Dynamic,1> params_r_vec_init;
118  model.transform_inits(init_dump, params_r_vec_init, &pstream);
119  EXPECT_EQ(int(params_r.size()), params_r_vec_init.size());
120  for (int i = 0; i < params_r_vec_init.size(); ++i)
121  EXPECT_FLOAT_EQ(params_r_init[i], params_r_vec_init(i));
122 
123  // only test write_array for doubles --- no var allowed
124  std::vector<double> params_r_write(2);
125  params_r_write[0] = -3.2;
126  params_r_write[1] = 1.79;
127  std::vector<int> params_i_write;
128 
129  Matrix<double,Dynamic,1> params_r_vec_write(2);
130  params_r_vec_write << -3.2, 1.79;
131 
132  boost::ecuyer1988 rng(123);
133  for (int incl_tp = 0; incl_tp < 2; ++incl_tp) {
134  for (int incl_gq = 0; incl_gq < 2; ++incl_gq) {
135  std::vector<double> vars_write;
136  Matrix<double,Dynamic,1> vars_vec_write(17);
137  model.write_array(rng, params_r_write, params_i_write, vars_write, incl_tp, incl_gq, 0);
138  model.write_array(rng, params_r_vec_write, vars_vec_write, incl_tp, incl_gq, 0);
139  EXPECT_EQ(int(vars_write.size()), vars_vec_write.size());
140  for (int i = 0; i < vars_vec_write.size(); ++i)
141  EXPECT_FLOAT_EQ(vars_write[i], vars_vec_write(i));
142  }
143  }
144 
145 }
146 TEST(lang, logProbPolymorphismVar) {
147  using std::vector;
148  using Eigen::Matrix;
149  using Eigen::Dynamic;
150  using stan::math::var;
151 
152  std::string txt = "foo <- 3\nbar <- 4";
153  std::stringstream in(txt);
154  stan::io::dump dump(in);
155 
156  test_lp_model_namespace::test_lp_model model(dump);
157 
158  std::vector<var> params_r(2);
159  params_r[0] = 1.0;
160  params_r[1] = -3.2;
161 
162  std::vector<int> params_i;
163 
164  Matrix<var, Dynamic, 1> params_r_vec(2);
165  for (int i = 0; i < 2; ++i)
166  params_r_vec(i) = params_r[i];
167 
168  var lp1 = model.log_prob<true,true>(params_r, params_i, 0);
169  var lp2 = model.log_prob<true,true>(params_r_vec, 0);
170  EXPECT_FLOAT_EQ(lp1.val(), lp2.val());
171 
172  lp1 = model.log_prob<true,false>(params_r, params_i, 0);
173  lp2 = model.log_prob<true,false>(params_r_vec, 0);
174  EXPECT_FLOAT_EQ(lp1.val(), lp2.val());
175 
176  lp1 = model.log_prob<false,true>(params_r, params_i, 0);
177  lp2 = model.log_prob<false,true>(params_r_vec, 0);
178  EXPECT_FLOAT_EQ(lp1.val(), lp2.val());
179 
180  lp1 = model.log_prob<false,false>(params_r, params_i, 0);
181  lp2 = model.log_prob<false,false>(params_r_vec, 0);
182  EXPECT_FLOAT_EQ(lp1.val(), lp2.val());
183 }
184 
186  std::string model_name = "name";
187  std::stringstream ss;
188  stan::lang::generate_model_typedef(model_name,ss);
189 
190  EXPECT_EQ(1, count_matches("typedef name_namespace::name stan_model;",
191  ss.str()));
192 }
193 
194 // * transform_inits
195 
198  std::string model_name = "m";
199  std::stringstream output;
201  // fake reader history - no stan program, just AST
202  reader.add_event(0, 0, "start", "generator-test");
203  reader.add_event(500, 500, "end", "generator-test");
204  stan::lang::generate_cpp(prog, model_name, reader.history(), output);
205  std::string output_str = output.str();
206 
207  EXPECT_EQ(1, count_matches("// Code generated by Stan version ", output_str))
208  << "generate_version_comment()";
209  EXPECT_EQ(1, count_matches("#include", output_str))
210  << "generate_includes()";
211  EXPECT_EQ(1, count_matches("namespace " + model_name + "_namespace {", output_str))
212  << "generate_start_namespace()";
213  EXPECT_LT(1, count_matches("using", output_str))
214  << "generate_usings()";
215 
216  EXPECT_EQ(1, count_matches("class " + model_name, output_str))
217  << "generate_class_decl()";
218  EXPECT_EQ(1, count_matches("private:", output_str))
219  << "generate_private_decl()";
220 
221  EXPECT_EQ(1, count_matches("public:", output_str))
222  << "generate_public_decl()";
223 
224  // FIXME(carpenter): change this again when the second ctor eliminated
225  EXPECT_EQ(2, count_matches(" " + model_name + "(", output_str))
226  << "generate_constructor()";
227 
228  EXPECT_EQ(1, count_matches("~" + model_name + "(", output_str))
229  << "generate_destructor()";
230  EXPECT_EQ(2, count_matches("void transform_inits(", output_str))
231  << "generate_init_method()";
232  EXPECT_EQ(1, count_matches("T__ log_prob(", output_str))
233  << "generate_log_prob()";
234  EXPECT_EQ(1, count_matches("T_ log_prob(", output_str))
235  << "generate_log_prob()";
236  EXPECT_EQ(1, count_matches("void get_param_names(", output_str))
237  << "generate_param_names_method()";
238  EXPECT_EQ(1, count_matches("void get_dims(", output_str))
239  << "generate_dims_method()";
240  EXPECT_EQ(2, count_matches("void write_array(", output_str))
241  << "generate_write_array_method()";
242  EXPECT_EQ(1, count_matches("static std::string model_name()", output_str))
243  << "generate_model_name_method()";
244  EXPECT_EQ(1, count_matches("void constrained_param_names(", output_str))
245  << "generate_constrained_param_names_method()";
246  EXPECT_EQ(1, count_matches("void unconstrained_param_names(", output_str))
247  << "generate_unconstrained_param_names_method()";
248  EXPECT_EQ(1, count_matches("}; // model", output_str))
249  << "generate_end_class_decl()";
250  EXPECT_EQ(1, count_matches("typedef " + model_name + "_namespace::"
251  + model_name + " stan_model;",
252  output_str))
253  << "generate_model_typedef()";
254 
255  EXPECT_EQ(0, count_matches("int main", output_str));
256 }
257 
258 // These next tests depend on the parser to build up a prog instance,
259 // which is too onerous to do directly from the ast.
260 // Very brittle because getting exact match of expected output.
261 
262 TEST(langGenerator,funArgsInt0) {
263  expect_matches(1,
264  "functions { int foo() { return 3; } } model { }",
265  "int\n"
266  "foo(");
267 }
268 TEST(langGenerator,funArgsInt1Real) {
269  expect_matches(1,
270  "functions { int foo(real x) { return 3; } } model { }",
271  "int\n"
272  "foo(");
273 }
274 TEST(langGenerator,funArgsInt1Int) {
275  expect_matches(1,
276  "functions { int foo(int x) { return x; } } model { }",
277  "int\n"
278  "foo(");
279 }
280 TEST(langGenerator,funArgs0) {
281  expect_matches(1,
282  "functions { real foo() { return 1.7; } } model { }",
283  "double\n"
284  "foo(");
285 }
286 TEST(langGenerator,funArgs1) {
287  expect_matches(1,
288  "functions { real foo(real x) { return x; } } model { }",
289  "typename boost::math::tools::promote_args<T0__>::type\n"
290  "foo(");
291 }
292 TEST(langGenerator,funArgs4) {
293  expect_matches(1,
294  "functions { real foo(real x1, real x2, real x3, real x4) { return x1; } } model { }",
295  "typename boost::math::tools::promote_args<T0__, T1__, T2__, T3__>::type\n"
296  "foo(");
297 }
298 TEST(langGenerator,funArgs5) {
299  expect_matches(1,
300  "functions { real foo(real x1, real x2, real x3, real x4, real x5) { return x1; } } model { }",
301  "typename boost::math::tools::promote_args<T0__, T1__, T2__, T3__, typename boost::math::tools::promote_args<T4__>::type>::type\n"
302  "foo(");
303 }
304 TEST(langGenerator,funArgs0lp) {
305  expect_matches(1,
306  "functions { real foo_lp() { return 1.0; } } model { }",
307  "typename boost::math::tools::promote_args<T_lp__>::type\n"
308  "foo_lp(");
309 }
310 TEST(langGenerator,funArgs4lp) {
311  expect_matches(1,
312  "functions { real foo_lp(real x1, real x2, real x3, real x4) { return x1; } } model { }",
313  "typename boost::math::tools::promote_args<T0__, T1__, T2__, T3__, T_lp__>::type\n"
314  "foo_lp(");
315 }
316 TEST(langGenerator,funArgs5lp) {
317  expect_matches(1,
318  "functions { real foo_lp(real x1, real x2, real x3, real x4, real x5) { return x1; } } model { }",
319  "typename boost::math::tools::promote_args<T0__, T1__, T2__, T3__, typename boost::math::tools::promote_args<T4__, T_lp__>::type>::type\n"
320  "foo_lp(");
321 }
322 
323 TEST(langGenerator,shortCircuit1) {
324  expect_matches(1,
325  "transformed data { int a; a <- 1 || 2; }"
326  "model { }",
327  "(primitive_value(1) || primitive_value(2))");
328  expect_matches(1,
329  "transformed data { int a; a <- 1 && 2; }"
330  "model { }",
331  "(primitive_value(1) && primitive_value(2))");
332 }
333 
334 
335 TEST(langGenerator, sliceIndexes) {
336  // boundary condition of no indices
337  std::vector<stan::lang::idx> is2;
338  std::stringstream o2;
339  stan::lang::generate_idxs(is2, o2);
340  EXPECT_EQ("stan::model::nil_index_list()", o2.str());
341 
342  // two indexes
344  stan::lang::uni_idx ui3(e_int3);
345  stan::lang::idx idx0(ui3);
346 
348  stan::lang::ub_idx ub5(e_int5);
349  stan::lang::idx idx1(ub5);
350 
351  std::vector<stan::lang::idx> is;
352  is.push_back(idx0);
353  is.push_back(idx1);
354 
355  std::stringstream o;
357  EXPECT_EQ("stan::model::cons_list(stan::model::index_uni(3), stan::model::cons_list(stan::model::index_max(5), stan::model::nil_index_list()))",
358  o.str());
359 }
360 
361 TEST(langGenerator, slicedAssigns) {
364 
365  stan::lang::variable v("foo");
366  v.set_type(base_expr_type(double_type()), 0);
367 
369  stan::lang::uni_idx ui3(e_int3);
370  stan::lang::idx idx0(ui3);
371 
373  stan::lang::ub_idx ub5(e_int5);
374  stan::lang::idx idx1(ub5);
375 
376  std::vector<stan::lang::idx> is;
377  is.push_back(idx0);
378  is.push_back(idx1);
379  std::string op("=");
381  stan::lang::assgn a(v, is, op, e);
383  s.begin_line_ = 12U;
384  s.end_line_ = 14U;
385 
386  std::stringstream o;
387  generate_statement(s, 2, o);
388  EXPECT_TRUE(0U < o.str().find(
389  "stan::model::cons_list(stan::model::index_uni(3), stan::model::cons_list(stan::model::index_max(5), stan::model::nil_index_list()))"));
390 }
391 TEST(langGenerator, fills) {
392  expect_matches(1,
393  "transformed data { int a[3]; }"
394  " model { }",
395  "stan::math::fill(a, std::numeric_limits<int>::min());\n");
396 }
397 
398 
399 TEST(langGenerator, genRealVars) {
400  using stan::lang::scope;
403  scope td_origin = transformed_data_origin;
404  scope fun_origin = function_argument_origin;
405  std::stringstream o;
406 
407  o.str(std::string());
408  stan::lang::generate_real_var_type(td_origin, true, o);
409  EXPECT_EQ(1, count_matches("local_scalar_t__", o.str()));
410 
411  o.str(std::string());
412  stan::lang::generate_real_var_type(td_origin, false, o);
413  EXPECT_EQ(1, count_matches("double", o.str()));
414 
415  o.str(std::string());
416  stan::lang::generate_real_var_type(fun_origin, true, o);
417  EXPECT_EQ(1, count_matches("local_scalar_t__", o.str()));
418 
419  o.str(std::string());
420  stan::lang::generate_real_var_type(fun_origin, false, o);
421  EXPECT_EQ(1, count_matches("local_scalar_t__", o.str()));
422 }
423 
424 TEST(langGenerator, genArrayVars) {
426  using stan::lang::int_type;
431  using stan::lang::scope;
434  scope td_origin = transformed_data_origin;
435  scope fun_origin = function_argument_origin;
436  std::stringstream ssReal;
437  std::stringstream o;
438 
439  ssReal.str(std::string());
440  stan::lang::generate_real_var_type(td_origin, true, ssReal);
441  o.str(std::string());
442  stan::lang::generate_array_var_type(base_expr_type(double_type()),ssReal.str(),o);
443  EXPECT_EQ(1, count_matches("local_scalar_t__", o.str()));
444 
445  ssReal.str(std::string());
446  stan::lang::generate_real_var_type(td_origin, false, ssReal);
447  o.str(std::string());
448  stan::lang::generate_array_var_type(base_expr_type(double_type()),ssReal.str(),o);
449  EXPECT_EQ(1, count_matches("double", o.str()));
450 
451  ssReal.str(std::string());
452  stan::lang::generate_real_var_type(fun_origin, true, ssReal);
453  o.str(std::string());
454  stan::lang::generate_array_var_type(base_expr_type(double_type()),ssReal.str(),o);
455  EXPECT_EQ(1, count_matches("local_scalar_t__", o.str()));
456 
457  ssReal.str(std::string());
458  o.str(std::string());
459  stan::lang::generate_real_var_type(fun_origin, false, ssReal);
460  stan::lang::generate_array_var_type(base_expr_type(double_type()),ssReal.str(),o);
461  EXPECT_EQ(1, count_matches("local_scalar_t__", o.str()));
462 
463  ssReal.str(std::string());
464  o.str(std::string());
465  stan::lang::generate_array_var_type(base_expr_type(int_type()), ssReal.str(), o);
466  EXPECT_EQ(1, count_matches("int", o.str()));
467 
468  ssReal.str(std::string());
469  stan::lang::generate_real_var_type(td_origin, false, ssReal);
470  o.str(std::string());
471  stan::lang::generate_array_var_type(base_expr_type(vector_type()),ssReal.str(),o);
472  EXPECT_EQ(1, count_matches("Eigen::Matrix<double,Eigen::Dynamic,1> ", o.str()));
473 
474  ssReal.str(std::string());
475  stan::lang::generate_real_var_type(td_origin, true, ssReal);
476  o.str(std::string());
477  stan::lang::generate_array_var_type(base_expr_type(vector_type()), ssReal.str(), o);
478  EXPECT_EQ(1, count_matches("Eigen::Matrix<local_scalar_t__,Eigen::Dynamic,1> ", o.str()));
479 
480  ssReal.str(std::string());
481  stan::lang::generate_real_var_type(td_origin, false, ssReal);
482  o.str(std::string());
483  stan::lang::generate_array_var_type(base_expr_type(row_vector_type()), ssReal.str(), o);
484  EXPECT_EQ(1, count_matches("Eigen::Matrix<double,1,Eigen::Dynamic> ", o.str()));
485 
486  ssReal.str(std::string());
487  stan::lang::generate_real_var_type(td_origin, true, ssReal);
488  o.str(std::string());
489  stan::lang::generate_array_var_type(base_expr_type(row_vector_type()), ssReal.str(), o);
490  EXPECT_EQ(1, count_matches("Eigen::Matrix<local_scalar_t__,1,Eigen::Dynamic> ", o.str()));
491 
492  ssReal.str(std::string());
493  stan::lang::generate_real_var_type(td_origin, false, ssReal);
494  o.str(std::string());
495  stan::lang::generate_array_var_type(base_expr_type(matrix_type()), ssReal.str(), o);
496  EXPECT_EQ(1, count_matches("Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> ", o.str()));
497 
498  ssReal.str(std::string());
499  stan::lang::generate_real_var_type(td_origin, true, ssReal);
500  o.str(std::string());
501  stan::lang::generate_array_var_type(base_expr_type(matrix_type()), ssReal.str(), o);
502  EXPECT_EQ(1, count_matches("Eigen::Matrix<local_scalar_t__,Eigen::Dynamic,Eigen::Dynamic> ", o.str()));
503 }
504 
505 TEST(genArrayBuilderAdds, addScalars) {
507  std::vector<stan::lang::expression> elts;
508  elts.push_back(e_d3);
509  elts.push_back(e_d3);
510  elts.push_back(e_d3);
511  std::stringstream o2;
513  EXPECT_EQ(3, count_matches(".add(", o2.str()));
514 }
515 
516 
517 TEST(genExpression, mapRect) {
518  std::string model_code
519  = "functions {"
520  " vector foo(vector shared_params, vector job_params,"
521  " real[] data_r, int[] data_i) {"
522  " return [1, 2, 3]';"
523  " }"
524  "}"
525  "data {"
526  " vector[3] shared_params_d;"
527  " vector[3] job_params_d[3];"
528  " real data_r[3, 3];"
529  " int data_i[3, 3];"
530  "}"
531  "generated quantities {"
532  " vector[3] y_hat_gq"
533  " = map_rect(foo, shared_params_d, job_params_d, data_r, data_i);"
534  "}";
535  expect_matches(1, model_code, "map_rect<");
536  // can't predict number in between
537  expect_matches(1, model_code,
538  ", foo_functor__>(shared_params_d,"
539  " job_params_d, data_r, data_i, pstream__)");
540 }
void generate_model_typedef(const std::string &model_name, std::ostream &o)
void generate_array_builder_adds(const std::vector< expression > &elements, bool user_facing, std::ostream &o)
ofstream output
const int function_argument_origin
int count_matches(const std::string &target, const std::string &s)
Definition: util.hpp:19
void test_generate_quoted_expression(const stan::lang::expression &e, const std::string &e_exp)
void add_event(int concat_line_num, int line_num, const std::string &action, const std::string &path)
void generate_statement(const statement &s, int indent, std::ostream &o)
Float_t ss
Definition: plot.C:24
void generate_real_var_type(const scope &var_scope, bool has_var, std::ostream &o)
void generate_array_var_type(const base_expr_type &base_type, const std::string &real_var_type, std::ostream &o)
void expect_matches(int n, const std::string &stan_code, const std::string &target)
Definition: utility.hpp:214
const XML_Char * s
Definition: expat.h:262
double lang
Definition: runWimpSim.h:113
const double a
void generate_cpp(const program &prog, const std::string &model_name, const std::vector< io::preproc_event > &history, std::ostream &o)
void generate_quoted_string(const std::string &s, std::ostream &o)
std::size_t begin_line_
Definition: statement.hpp:209
TEST(langGenerator, quotedString)
const std::vector< preproc_event > & history() const
void test_generate_quoted_string(const std::string &s, const std::string &quoted_s)
::xsd::cxx::tree::string< char, simple_type > string
Definition: Database.h:154
ifstream in
Definition: comparison.C:7
void generate_idxs(const std::vector< idx > &idxs, std::ostream &o)
void test_generate_quoted_string_quote(const std::string &s, const std::string &expected_output_content)
std::size_t end_line_
Definition: statement.hpp:214
void set_type(const base_expr_type &base_type, std::size_t num_dims)
Float_t e
Definition: plot.C:35
const XML_Char XML_Content * model
Definition: expat.h:151
const int transformed_data_origin
void generate_quoted_expression(const expression &e, std::ostream &o)