Teuchos - Trilinos Tools Package Version of the Day
Loading...
Searching...
No Matches
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
12namespace Teuchos {
13
14namespace MathExpr {
15
16Language 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
88LanguagePtr 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
96ReaderTablesPtr 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
105SymbolSetReader::SymbolSetReader():
106 Reader(ask_reader_tables())
107{
108}
109
110SymbolSetReader::~SymbolSetReader()
111{
112}
113
114void SymbolSetReader::at_shift(any& result, int token, std::string& text) {
115 if (token == TOK_NAME) result = text;
116}
117
118void 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
128std::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
135std::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
144class 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
319Reader* new_calc_reader() {
320 return new CalcReader();
321}
322
323} // end namespace MathExpr
324
325} // end namespace Teuchos
void reset()
Reset to null.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos,...
RCP< const ReaderTables > ReaderTablesPtr
an RCP to a const ReaderTables
RCP< const Language > LanguagePtr
an RCP to a const Language
ReaderTablesPtr make_reader_tables(Language const &language)
constructs ReaderTables for the given Language.
Productions productions
vector of productions