Teuchos - Trilinos Tools Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Teuchos_MathExpr.cpp
1 // @HEADER
2 // *****************************************************************************
3 // Teuchos: Common Tools Package
4 //
5 // Copyright 2004 NTESS and the Teuchos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #include <Teuchos_MathExpr.hpp>
11 
12 namespace Teuchos {
13 
14 namespace MathExpr {
15 
16 Language make_language() {
17  Language out;
18  Language::Productions& prods = out.productions;
19  prods.resize(NPRODS);
20  prods[PROD_PROGRAM]("program") >> "statements", "expr?";
21  prods[PROD_NO_STATEMENTS]("statements");
22  prods[PROD_NEXT_STATEMENT]("statements") >> "statements", "statement", ";", "S?";
23  prods[PROD_ASSIGN]("statement") >> "name", "S?", "=", "S?", "expr";
24  prods[PROD_NO_EXPR]("expr?");
25  prods[PROD_YES_EXPR]("expr?") >> "expr";
26  prods[PROD_EXPR]("expr") >> "ternary";
27  prods[PROD_TERNARY_DECAY]("ternary") >> "add_sub";
28  prods[PROD_OR_DECAY]("or") >> "and";
29  prods[PROD_AND_DECAY]("and") >> "comp";
30  prods[PROD_ADD_SUB_DECAY]("add_sub") >> "mul_div";
31  prods[PROD_MUL_DIV_DECAY]("mul_div") >> "neg";
32  prods[PROD_NEG_DECAY]("neg") >> "pow";
33  prods[PROD_POW_DECAY]("pow") >> "scalar";
34  prods[PROD_TERNARY]("ternary")
35  >> "or", "?", "S?", "add_sub", ":", "S?", "add_sub";
36  prods[PROD_OR]("or") >> "or", "||", "S?", "and";
37  prods[PROD_AND]("and") >> "and", "&&", "S?", "comp";
38  prods[PROD_GT]("comp") >> "add_sub", ">", "S?", "add_sub";
39  prods[PROD_LT]("comp") >> "add_sub", "<", "S?", "add_sub";
40  prods[PROD_GEQ]("comp") >> "add_sub", ">=", "S?", "add_sub";
41  prods[PROD_LEQ]("comp") >> "add_sub", "<=", "S?", "add_sub";
42  prods[PROD_EQ]("comp") >> "add_sub", "==", "S?", "add_sub";
43  prods[PROD_BOOL_PARENS]("comp") >> "(", "S?", "or", ")", "S?";
44  prods[PROD_ADD]("add_sub") >> "add_sub", "+", "S?", "mul_div";
45  prods[PROD_SUB]("add_sub") >> "add_sub", "-", "S?", "mul_div";
46  prods[PROD_MUL]("mul_div") >> "mul_div", "*", "S?", "pow";
47  prods[PROD_DIV]("mul_div") >> "mul_div", "/", "S?", "pow";
48  prods[PROD_POW]("pow") >> "scalar", "^", "S?", "pow";
49  prods[PROD_CALL]("scalar")
50  >> "name", "S?", "(", "S?", "args?", ")", "S?";
51  prods[PROD_NO_ARGS]("args?");
52  prods[PROD_SOME_ARGS]("args?") >> "args";
53  prods[PROD_FIRST_ARG]("args") >> "ternary";
54  prods[PROD_NEXT_ARG]("args") >> "args", ",", "S?", "ternary";
55  prods[PROD_NEG]("neg") >> "-", "S?", "neg";
56  prods[PROD_VAL_PARENS]("scalar") >> "(", "S?", "ternary", ")", "S?";
57  prods[PROD_CONST]("scalar") >> "constant", "S?";
58  prods[PROD_VAR]("scalar") >> "name", "S?";
59  prods[PROD_NO_SPACES]("S?");
60  prods[PROD_SPACES]("S?") >> "spaces";
61  out.tokens.resize(NTOKS);
62  out.tokens[TOK_SPACE]("spaces", "[ \t\n\r]+");
63  out.tokens[TOK_NAME]("name", "[_a-zA-Z][_a-zA-Z0-9]*");
64  out.tokens[TOK_ADD]("+", "\\+");
65  out.tokens[TOK_SUB]("-", "\\-");
66  out.tokens[TOK_MUL]("*", "\\*");
67  out.tokens[TOK_DIV]("/", "\\/");
68  out.tokens[TOK_POW]("^", "\\^");
69  out.tokens[TOK_LPAREN]("(", "\\(");
70  out.tokens[TOK_RPAREN](")", "\\)");
71  out.tokens[TOK_COMMA](",", ",");
72  out.tokens[TOK_CHECK]("?", "\\?");
73  out.tokens[TOK_CHOOSE](":", ":");
74  out.tokens[TOK_GT](">", ">");
75  out.tokens[TOK_LT]("<", "<");
76  out.tokens[TOK_GEQ](">=", ">=");
77  out.tokens[TOK_LEQ]("<=", "<=");
78  out.tokens[TOK_EQ]("==", "==");
79  out.tokens[TOK_AND]("&&", "&&");
80  out.tokens[TOK_OR]("||", "\\|\\|");
81  out.tokens[TOK_CONST]("constant",
82  "(0|([1-9][0-9]*))(\\.[0-9]*)?([eE]\\-?[1-9][0-9]*)?");
83  out.tokens[TOK_SEMICOLON](";", ";");
84  out.tokens[TOK_ASSIGN]("=", "=");
85  return out;
86 }
87 
88 LanguagePtr ask_language() {
89  static LanguagePtr ptr;
90  if (ptr.strong_count() == 0) {
91  ptr.reset(new Language(make_language()));
92  }
93  return ptr;
94 }
95 
96 ReaderTablesPtr ask_reader_tables() {
97  static ReaderTablesPtr ptr;
98  if (ptr.strong_count() == 0) {
99  LanguagePtr lang = ask_language();
100  ptr = make_reader_tables(*lang);
101  }
102  return ptr;
103 }
104 
105 SymbolSetReader::SymbolSetReader():
106  Reader(ask_reader_tables())
107 {
108 }
109 
110 SymbolSetReader::~SymbolSetReader()
111 {
112 }
113 
114 void SymbolSetReader::at_shift(any& result, int token, std::string& text) {
115  if (token == TOK_NAME) result = text;
116 }
117 
118 void SymbolSetReader::at_reduce(any& /* result */, int prod, std::vector<any>& rhs) {
119  if (prod == PROD_VAR) {
120  std::string& name = any_ref_cast<std::string>(rhs.at(0));
121  variable_names.insert(name);
122  } else if (prod == PROD_CALL) {
123  std::string& name = any_ref_cast<std::string>(rhs.at(0));
124  function_names.insert(name);
125  }
126 }
127 
128 std::set<std::string> get_variables_used(std::string const& expr) {
129  SymbolSetReader reader;
130  any result;
131  reader.read_string(result, expr, "get_variables_used");
132  return reader.variable_names;
133 }
134 
135 std::set<std::string> get_symbols_used(std::string const& expr) {
136  SymbolSetReader reader;
137  any result;
138  reader.read_string(result, expr, "get_symbols_used");
139  auto set = std::move(reader.variable_names);
140  set.insert(reader.function_names.begin(), reader.function_names.end());
141  return set;
142 }
143 
144 class CalcReader : public Reader {
145  public:
146  CalcReader():Reader(MathExpr::ask_reader_tables()) {
147  unary_function_map["sqrt"] = &std::sqrt;
148  unary_function_map["sin"] = &std::sin;
149  unary_function_map["cos"] = &std::cos;
150  unary_function_map["tan"] = &std::tan;
151  unary_function_map["asin"] = &std::asin;
152  unary_function_map["acos"] = &std::acos;
153  unary_function_map["atan"] = &std::atan;
154  unary_function_map["exp"] = &std::exp;
155  unary_function_map["log"] = &std::log;
156  unary_function_map["log10"] = &std::log10;
157  binary_function_map["atan2"] = &std::atan2;
158  }
159  virtual ~CalcReader() = default;
160  protected:
161  struct CallArgs {
162  double a0;
163  double a1;
164  int n;
165  };
166  virtual void at_shift(any& result_any, int token, std::string& text) {
167  using std::swap;
168  switch (token) {
169  case MathExpr::TOK_NAME: {
170  std::string& result = make_any_ref<std::string>(result_any);
171  swap(result, text);
172  return;
173  }
174  case MathExpr::TOK_CONST: {
175  result_any = std::atof(text.c_str());
176  return;
177  }
178  }
179  }
180  virtual void at_reduce(any& result, int prod, std::vector<any>& rhs) {
181  using std::swap;
182  switch (prod) {
183  case MathExpr::PROD_PROGRAM: {
184  TEUCHOS_TEST_FOR_EXCEPTION(!rhs.at(1).has_value(), ParserFail,
185  "Calculator needs an expression to evaluate!");
186  swap(result, rhs.at(1));
187  break;
188  }
189  case MathExpr::PROD_NO_STATEMENTS:
190  case MathExpr::PROD_NO_EXPR:
191  case MathExpr::PROD_NEXT_STATEMENT: {
192  break;
193  }
194  case MathExpr::PROD_ASSIGN: {
195  std::string const& name = any_ref_cast<std::string>(rhs.at(0));
196  double value = any_cast<double>(rhs.at(4));
197  variable_map[name] = value;
198  break;
199  }
200  case MathExpr::PROD_YES_EXPR:
201  case MathExpr::PROD_EXPR:
202  case MathExpr::PROD_TERNARY_DECAY:
203  case MathExpr::PROD_OR_DECAY:
204  case MathExpr::PROD_AND_DECAY:
205  case MathExpr::PROD_ADD_SUB_DECAY:
206  case MathExpr::PROD_MUL_DIV_DECAY:
207  case MathExpr::PROD_POW_DECAY:
208  case MathExpr::PROD_NEG_DECAY:
209  case MathExpr::PROD_SOME_ARGS:
210  swap(result, rhs.at(0));
211  break;
212  case MathExpr::PROD_TERNARY:
213  result = any_cast<bool>(rhs.at(0)) ?
214  any_cast<double>(rhs.at(3)) :
215  any_cast<double>(rhs.at(6));
216  break;
217  case MathExpr::PROD_OR:
218  result = any_cast<bool>(rhs.at(0)) || any_cast<bool>(rhs.at(3));
219  break;
220  case MathExpr::PROD_AND:
221  result = any_cast<bool>(rhs.at(0)) && any_cast<bool>(rhs.at(3));
222  break;
223  case MathExpr::PROD_GT:
224  result = any_cast<double>(rhs.at(0)) > any_cast<double>(rhs.at(3));
225  break;
226  case MathExpr::PROD_LT:
227  result = any_cast<double>(rhs.at(0)) < any_cast<double>(rhs.at(3));
228  break;
229  case MathExpr::PROD_GEQ:
230  result = any_cast<double>(rhs.at(0)) >= any_cast<double>(rhs.at(3));
231  break;
232  case MathExpr::PROD_LEQ:
233  result = any_cast<double>(rhs.at(0)) <= any_cast<double>(rhs.at(3));
234  break;
235  case MathExpr::PROD_EQ:
236  result = any_cast<double>(rhs.at(0)) == any_cast<double>(rhs.at(3));
237  break;
238  case MathExpr::PROD_BOOL_PARENS:
239  result = any_cast<bool>(rhs.at(2));
240  break;
241  case MathExpr::PROD_ADD:
242  result = any_cast<double>(rhs.at(0)) + any_cast<double>(rhs.at(3));
243  break;
244  case MathExpr::PROD_SUB:
245  result = any_cast<double>(rhs.at(0)) - any_cast<double>(rhs.at(3));
246  break;
247  case MathExpr::PROD_MUL:
248  result = any_cast<double>(rhs.at(0)) * any_cast<double>(rhs.at(3));
249  break;
250  case MathExpr::PROD_DIV:
251  result = any_cast<double>(rhs.at(0)) / any_cast<double>(rhs.at(3));
252  break;
253  case MathExpr::PROD_POW:
254  result = std::pow(any_cast<double>(rhs.at(0)), any_cast<double>(rhs.at(3)));
255  break;
256  case MathExpr::PROD_CALL: {
257  std::string& name = any_ref_cast<std::string>(rhs.at(0));
258  CallArgs& args = any_ref_cast<CallArgs>(rhs.at(4));
259  TEUCHOS_TEST_FOR_EXCEPTION(args.n < 1 || args.n > 2, ParserFail,
260  "Only unary and binary functions supported!\n");
261  if (args.n == 1) {
262  TEUCHOS_TEST_FOR_EXCEPTION(!unary_function_map.count(name), ParserFail,
263  "Unknown unary function name \"" << name << "\"\n");
264  Unary fptr = unary_function_map[name];
265  result = (*fptr)(args.a0);
266  } else {
267  TEUCHOS_TEST_FOR_EXCEPTION(!binary_function_map.count(name), ParserFail,
268  "Unknown binary function name \"" << name << "\"\n");
269  Binary fptr = binary_function_map[name];
270  result = (*fptr)(args.a0, args.a1);
271  }
272  break;
273  }
274  case MathExpr::PROD_NO_ARGS: {
275  CallArgs& args = make_any_ref<CallArgs>(result);
276  args.n = 0;
277  break;
278  }
279  case MathExpr::PROD_FIRST_ARG: {
280  CallArgs& args = make_any_ref<CallArgs>(result);
281  args.a0 = any_cast<double>(rhs.at(0));
282  args.n = 1;
283  break;
284  }
285  case MathExpr::PROD_NEXT_ARG: {
286  CallArgs& args = any_ref_cast<CallArgs>(rhs.at(0));
287  args.a1 = any_cast<double>(rhs.at(3));
288  args.n = 2;
289  swap(result, rhs.at(0));
290  break;
291  }
292  case MathExpr::PROD_NEG:
293  result = - any_cast<double>(rhs.at(2));
294  break;
295  case MathExpr::PROD_VAL_PARENS:
296  result = any_cast<double>(rhs.at(2));
297  break;
298  case MathExpr::PROD_CONST:
299  result = any_cast<double>(rhs.at(0));
300  break;
301  case MathExpr::PROD_VAR:
302  std::string const& name = any_ref_cast<std::string>(rhs.at(0));
303  auto it = variable_map.find(name);
304  TEUCHOS_TEST_FOR_EXCEPTION(it == variable_map.end(), ParserFail,
305  "variable " << name << " not defined!");
306  double value = it->second;
307  result = value;
308  break;
309  }
310  }
311  private:
312  typedef double (*Unary)(double);
313  typedef double (*Binary)(double, double);
314  std::map<std::string, Unary> unary_function_map;
315  std::map<std::string, Binary> binary_function_map;
316  std::map<std::string, double> variable_map;
317 };
318 
319 Reader* new_calc_reader() {
320  return new CalcReader();
321 }
322 
323 } // end namespace MathExpr
324 
325 } // end namespace Teuchos
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
Productions productions
vector of productions
ValueType & any_ref_cast(any &operand)
Keep the convenient behavior of Teuchos::any_cast w.r.t. references, but don&#39;t confuse it with the be...
RCP< const ReaderTables > ReaderTablesPtr
an RCP to a const ReaderTables
ReaderTablesPtr make_reader_tables(Language const &language)
constructs ReaderTables for the given Language.
RCP< const Language > LanguagePtr
an RCP to a const Language