Stan  1.0
probability, sampling & optimization
 All Classes Namespaces Files Functions Variables Typedefs Enumerator Friends Macros Pages
statement_grammar_def.hpp
Go to the documentation of this file.
1 #ifndef __STAN__GM__PARSER__STATEMENT_GRAMMAR_DEF__HPP__
2 #define __STAN__GM__PARSER__STATEMENT_GRAMMAR_DEF__HPP__
3 
4 #include <cstddef>
5 #include <iomanip>
6 #include <iostream>
7 #include <istream>
8 #include <map>
9 #include <set>
10 #include <sstream>
11 #include <string>
12 #include <utility>
13 #include <vector>
14 #include <stdexcept>
15 
16 #include <boost/spirit/include/qi.hpp>
17 // FIXME: get rid of unused include
18 #include <boost/spirit/include/phoenix_core.hpp>
19 #include <boost/spirit/include/phoenix_function.hpp>
20 #include <boost/spirit/include/phoenix_fusion.hpp>
21 #include <boost/spirit/include/phoenix_object.hpp>
22 #include <boost/spirit/include/phoenix_operator.hpp>
23 #include <boost/spirit/include/phoenix_stl.hpp>
24 
25 #include <boost/lexical_cast.hpp>
26 #include <boost/fusion/include/adapt_struct.hpp>
27 #include <boost/fusion/include/std_pair.hpp>
28 #include <boost/config/warning_disable.hpp>
29 #include <boost/spirit/include/qi.hpp>
30 #include <boost/spirit/include/qi_numeric.hpp>
31 #include <boost/spirit/include/classic_position_iterator.hpp>
32 #include <boost/spirit/include/phoenix_core.hpp>
33 #include <boost/spirit/include/phoenix_function.hpp>
34 #include <boost/spirit/include/phoenix_fusion.hpp>
35 #include <boost/spirit/include/phoenix_object.hpp>
36 #include <boost/spirit/include/phoenix_operator.hpp>
37 #include <boost/spirit/include/phoenix_stl.hpp>
38 #include <boost/spirit/include/support_multi_pass.hpp>
39 #include <boost/tuple/tuple.hpp>
40 #include <boost/variant/apply_visitor.hpp>
41 #include <boost/variant/recursive_variant.hpp>
42 
43 #include <stan/gm/ast.hpp>
49 
51  (stan::gm::variable_dims, var_dims_)
52  (stan::gm::expression, expr_) )
53 
54 BOOST_FUSION_ADAPT_STRUCT(stan::gm::variable_dims,
55  (std::string, name_)
56  (std::vector<stan::gm::expression>, dims_) )
57 
58 BOOST_FUSION_ADAPT_STRUCT(stan::gm::distribution,
59  (std::string, family_)
60  (std::vector<stan::gm::expression>, args_) )
61 
62 BOOST_FUSION_ADAPT_STRUCT(stan::gm::for_statement,
63  (std::string, variable_)
64  (stan::gm::range, range_)
65  (stan::gm::statement, statement_) )
66 
67 BOOST_FUSION_ADAPT_STRUCT(stan::gm::print_statement,
68  (std::vector<stan::gm::printable>, printables_) )
69 
70 BOOST_FUSION_ADAPT_STRUCT(stan::gm::sample,
71  (stan::gm::expression, expr_)
72  (stan::gm::distribution, dist_)
73  (stan::gm::range, truncation_) )
74 
75 BOOST_FUSION_ADAPT_STRUCT(stan::gm::statements,
76  (std::vector<stan::gm::var_decl>, local_decl_)
77  (std::vector<stan::gm::statement>, statements_) )
78 
79 namespace stan {
80 
81  namespace gm {
82 
83  struct validate_assignment {
84  template <typename T1, typename T2, typename T3, typename T4>
85  struct result { typedef bool type; };
86 
87  bool operator()(assignment& a,
88  const var_origin& origin_allowed,
89  variable_map& vm,
90  std::stringstream& error_msgs) const {
91 
92  // validate existence
93  std::string name = a.var_dims_.name_;
94  if (!vm.exists(name)) {
95  error_msgs << "unknown variable in assignment"
96  << "; lhs variable=" << a.var_dims_.name_
97  << std::endl;
98  return false;
99  }
100 
101  // validate origin
102  var_origin lhs_origin = vm.get_origin(name);
103  if (lhs_origin != local_origin
104  && lhs_origin != origin_allowed) {
105  error_msgs << "attempt to assign variable in wrong block."
106  << " left-hand-side variable origin=";
107  print_var_origin(error_msgs,lhs_origin);
108  error_msgs << std::endl;
109  return false;
110  }
111 
112  // validate types
113  a.var_type_ = vm.get(name);
114  size_t lhs_var_num_dims = a.var_type_.dims_.size();
115  size_t num_index_dims = a.var_dims_.dims_.size();
116 
117  expr_type lhs_type = infer_type_indexing(a.var_type_.base_type_,
118  lhs_var_num_dims,
119  num_index_dims);
120 
121  if (lhs_type.is_ill_formed()) {
122  error_msgs << "too many indexes for variable "
123  << "; variable name = " << name
124  << "; num dimensions given = " << num_index_dims
125  << "; variable array dimensions = " << lhs_var_num_dims;
126  return false;
127  }
128  if (lhs_type.num_dims_ != a.expr_.expression_type().num_dims_) {
129  error_msgs << "mismatched dimensions on left- and right-hand side of assignment"
130  << "; left dims=" << lhs_type.num_dims_
131  << "; right dims=" << a.expr_.expression_type().num_dims_
132  << std::endl;
133  return false;
134  }
135 
136  base_expr_type lhs_base_type = lhs_type.base_type_;
137  base_expr_type rhs_base_type = a.expr_.expression_type().base_type_;
138  // int -> double promotion
139  bool types_compatible
140  = lhs_base_type == rhs_base_type
141  || ( lhs_base_type == DOUBLE_T && rhs_base_type == INT_T );
142  if (!types_compatible) {
143  error_msgs << "base type mismatch in assignment"
144  << "; left variable=" << a.var_dims_.name_
145  << "; left base type=";
146  write_base_expr_type(error_msgs,lhs_base_type);
147  error_msgs << "; right base type=";
148  write_base_expr_type(error_msgs,rhs_base_type);
149  error_msgs << std::endl;
150  return false;
151  }
152  return true;
153  }
154  };
155  boost::phoenix::function<validate_assignment> validate_assignment_f;
156 
157  struct validate_sample {
158  template <typename T1, typename T2>
159  struct result { typedef bool type; };
160 
161  bool is_double_return(const std::string& function_name,
162  const std::vector<expr_type>& arg_types,
163  std::ostream& error_msgs) const {
164  return function_signatures::instance()
165  .get_result_type(function_name,arg_types,error_msgs)
166  .is_primitive_double();
167  }
168  bool operator()(const sample& s,
169  std::ostream& error_msgs) const {
170  std::vector<expr_type> arg_types;
171  arg_types.push_back(s.expr_.expression_type());
172  for (size_t i = 0; i < s.dist_.args_.size(); ++i)
173  arg_types.push_back(s.dist_.args_[i].expression_type());
174  std::string function_name(s.dist_.family_);
175  function_name += "_log";
176  // expr_type result_type
177  // = function_signatures::instance()
178  // .get_result_type(function_name,arg_types,error_msgs);
179  // if (!result_type.is_primitive_double()) {
180  if (!is_double_return(function_name,arg_types,error_msgs)) {
181  error_msgs << "unknown distribution=" << s.dist_.family_ << std::endl;
182  return false;
183  }
184  if (s.truncation_.has_low()) {
185  std::vector<expr_type> arg_types_trunc(arg_types);
186  arg_types_trunc[0] = s.truncation_.low_.expression_type();
187  std::string function_name_cdf(s.dist_.family_);
188  function_name_cdf += "_cdf";
189  if (!is_double_return(function_name_cdf,arg_types_trunc,error_msgs)) {
190  error_msgs << "lower truncation not defined for specified arguments to "
191  << s.dist_.family_ << std::endl;
192  return false;
193  }
194  if (!is_double_return(function_name_cdf,arg_types,error_msgs)) {
195  error_msgs << "lower bound in truncation type does not match"
196  << " sampled variate in distribution's type"
197  << std::endl;
198  return false;
199  }
200  }
201  if (s.truncation_.has_high()) {
202  std::vector<expr_type> arg_types_trunc(arg_types);
203  arg_types_trunc[0] = s.truncation_.high_.expression_type();
204  std::string function_name_cdf(s.dist_.family_);
205  function_name_cdf += "_cdf";
206  if (!is_double_return(function_name_cdf,arg_types_trunc,error_msgs)) {
207  error_msgs << "upper truncation not defined for specified arguments to "
208  << s.dist_.family_ << std::endl;
209  return false;
210  }
211  if (!is_double_return(function_name_cdf,arg_types,error_msgs)) {
212  error_msgs << "upper bound in truncation type does not match"
213  << " sampled variate in distribution's type"
214  << std::endl;
215  return false;
216  }
217  }
218  return true;
219 
220  }
221  };
222  boost::phoenix::function<validate_sample> validate_sample_f;
223 
224  struct unscope_locals {
225  template <typename T1, typename T2>
226  struct result { typedef void type; };
227  void operator()(const std::vector<var_decl>& var_decls,
228  variable_map& vm) const {
229  for (size_t i = 0; i < var_decls.size(); ++i)
230  vm.remove(var_decls[i].name());
231  }
232  };
233  boost::phoenix::function<unscope_locals> unscope_locals_f;
234 
235  struct add_loop_identifier {
236  template <typename T1, typename T2, typename T3, typename T4>
237  struct result { typedef bool type; };
238  bool operator()(const std::string& name,
239  std::string& name_local,
240  variable_map& vm,
241  std::stringstream& error_msgs) const {
242  name_local = name;
243  if (vm.exists(name)) {
244  error_msgs << "ERROR: loop variable already declared."
245  << " variable name=\"" << name << "\"" << std::endl;
246  return false; // variable exists
247  }
248  vm.add(name,
249  base_var_decl(name,std::vector<expression>(),
250  INT_T),
251  local_origin); // loop var acts like local
252  return true;
253  }
254  };
255  boost::phoenix::function<add_loop_identifier> add_loop_identifier_f;
256 
257  struct remove_loop_identifier {
258  template <typename T1, typename T2>
259  struct result { typedef void type; };
260  void operator()(const std::string& name,
261  variable_map& vm) const {
262  vm.remove(name);
263  }
264  };
265  boost::phoenix::function<remove_loop_identifier> remove_loop_identifier_f;
266 
267  struct validate_int_expr2 {
268  template <typename T1, typename T2>
269  struct result { typedef bool type; };
270 
271  bool operator()(const expression& expr,
272  std::stringstream& error_msgs) const {
273  if (!expr.expression_type().is_primitive_int()) {
274  error_msgs << "expression denoting integer required; found type="
275  << expr.expression_type() << std::endl;
276  return false;
277  }
278  return true;
279  }
280  };
281  boost::phoenix::function<validate_int_expr2> validate_int_expr2_f;
282 
283  struct validate_allow_sample {
284  template <typename T1, typename T2>
285  struct result { typedef bool type; };
286 
287  bool operator()(const bool& allow_sample,
288  std::stringstream& error_msgs) const {
289  if (!allow_sample) {
290  error_msgs << "ERROR: sampling only allowed in model."
291  << std::endl;
292  return false;
293  }
294  return true;
295  }
296  };
297  boost::phoenix::function<validate_allow_sample> validate_allow_sample_f;
298 
299 
300 
301  template <typename Iterator>
302  statement_grammar<Iterator>::statement_grammar(variable_map& var_map,
303  std::stringstream& error_msgs)
304  : statement_grammar::base_type(statement_r),
305  var_map_(var_map),
306  error_msgs_(error_msgs),
307  expression_g(var_map,error_msgs),
308  var_decls_g(var_map,error_msgs)
309  {
310  using boost::spirit::qi::_1;
311  using boost::spirit::qi::char_;
312  using boost::spirit::qi::eps;
313  using boost::spirit::qi::lexeme;
314  using boost::spirit::qi::lit;
315  using boost::spirit::qi::_pass;
316  using boost::spirit::qi::_val;
317 
318  using boost::spirit::qi::labels::_a;
319  using boost::spirit::qi::labels::_r1;
320  using boost::spirit::qi::labels::_r2;
321 
322  // _r1 true if sample_r allowed (inherited)
323  // _r2 source of variables allowed for assignments
324  // set to true if sample_r are allowed
325  statement_r.name("statement");
326  statement_r
327  %= statement_seq_r(_r1,_r2)
328  | for_statement_r(_r1,_r2)
329  | print_statement_r
330  | assignment_r
331  [_pass
332  = validate_assignment_f(_1,_r2,boost::phoenix::ref(var_map_),
333  boost::phoenix::ref(error_msgs_))]
334  | sample_r(_r1) [_pass = validate_sample_f(_1,
335  boost::phoenix::ref(error_msgs_))]
336  | no_op_statement_r
337  ;
338 
339  // _r1, _r2 same as statement_r
340  statement_seq_r.name("sequence of statements");
341  statement_seq_r
342  %= lit('{')
343  > local_var_decls_r[_a = _1]
344  > *statement_r(_r1,_r2)
345  > lit('}')
346  > eps[unscope_locals_f(_a,boost::phoenix::ref(var_map_))]
347  ;
348 
349  local_var_decls_r
350  %= var_decls_g(false,local_origin); // - constants
351 
352 
353  // _r1, _r2 same as statement_r
354  for_statement_r.name("for statement");
355  for_statement_r
356  %= lit("for")
357  > lit('(')
358  > identifier_r [_pass
359  = add_loop_identifier_f(_1,_a,
360  boost::phoenix::ref(var_map_),
361  boost::phoenix::ref(error_msgs_))]
362  > lit("in")
363  > range_r
364  > lit(')')
365  > statement_r(_r1,_r2)
366  > eps
367  [remove_loop_identifier_f(_a,boost::phoenix::ref(var_map_))];
368  ;
369 
370  print_statement_r.name("print statement");
371  print_statement_r
372  %= lit("print")
373  > lit('(')
374  > (printable_r % ',')
375  // > (expression_g % ',')
376  > lit(')');
377 
378  printable_r.name("printable");
379  printable_r
380  %= printable_string_r
381  | expression_g;
382 
383  printable_string_r.name("printable quoted string");
384  printable_string_r
385  %= lit('"')
386  > lexeme[*char_("a-zA-Z0-9/~!@#$%^&*()_+`-={}|[]:;'<>?,./ ")]
387  > lit('"');
388 
389  identifier_r.name("identifier");
390  identifier_r
391  %= (lexeme[char_("a-zA-Z")
392  >> *char_("a-zA-Z0-9_.")]);
393 
394  range_r.name("range expression pair, colon");
395  range_r
396  %= expression_g
397  [_pass = validate_int_expr2_f(_1,boost::phoenix::ref(error_msgs_))]
398  >> lit(':')
399  >> expression_g
400  [_pass = validate_int_expr2_f(_1,boost::phoenix::ref(error_msgs_))];
401 
402  assignment_r.name("variable assignment by expression");
403  assignment_r
404  %= var_lhs_r
405  >> lit("<-")
406  > expression_g
407  > lit(';')
408  ;
409 
410  var_lhs_r.name("variable and array dimensions");
411  var_lhs_r
412  %= identifier_r
413  >> opt_dims_r;
414 
415  opt_dims_r.name("array dimensions (optional)");
416  opt_dims_r
417  %= - dims_r;
418 
419  dims_r.name("array dimensions");
420  dims_r
421  %= lit('[')
422  > (expression_g
423  [_pass = validate_int_expr2_f(_1,boost::phoenix::ref(error_msgs_))]
424  % ',')
425  > lit(']')
426  ;
427 
428  // inherited _r1 = true if samples allowed as statements
429  sample_r.name("distribution of expression");
430  sample_r
431  %= expression_g
432  >> lit('~')
433  > eps
434  [_pass
435  = validate_allow_sample_f(_r1,boost::phoenix::ref(error_msgs_))]
436  > distribution_r
437  > -truncation_range_r
438  > lit(';');
439 
440  distribution_r.name("distribution and parameters");
441  distribution_r
442  %= identifier_r
443  >> lit('(')
444  >> -(expression_g % ',')
445  > lit(')');
446 
447  truncation_range_r.name("range pair");
448  truncation_range_r
449  %= lit('T')
450  > lit('[')
451  > -expression_g
452  > lit(',')
453  > -expression_g
454  > lit(']');
455 
456  no_op_statement_r.name("no op statement");
457  no_op_statement_r
458  %= lit(';') [_val = no_op_statement()]; // ok to re-use instance
459 
460  }
461 
462  }
463 }
464 #endif

     [ Stan Home Page ] © 2011–2012, Stan Development Team.