Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://mooseframework.inl.gov
3 : //*
4 : //* All rights reserved, see COPYRIGHT for full restrictions
5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 : //*
7 : //* Licensed under LGPL 2.1, please see LICENSE for details
8 : //* https://www.gnu.org/licenses/lgpl-2.1.html
9 :
10 : #include "ExpressionBuilder.h"
11 :
12 : ExpressionBuilder::EBTermList
13 447 : operator, (const ExpressionBuilder::EBTerm & larg, const ExpressionBuilder::EBTerm & rarg)
14 : {
15 1341 : return {larg, rarg};
16 0 : }
17 :
18 : ExpressionBuilder::EBTermList
19 0 : operator, (const ExpressionBuilder::EBTerm & larg, const ExpressionBuilder::EBTermList & rargs)
20 : {
21 0 : ExpressionBuilder::EBTermList list = {larg};
22 0 : list.insert(list.end(), rargs.begin(), rargs.end());
23 0 : return list;
24 0 : }
25 :
26 : ExpressionBuilder::EBTermList
27 386 : operator, (const ExpressionBuilder::EBTermList & largs, const ExpressionBuilder::EBTerm & rarg)
28 : {
29 386 : ExpressionBuilder::EBTermList list = largs;
30 386 : list.push_back(rarg);
31 386 : return list;
32 0 : }
33 :
34 : std::ostream &
35 1449 : operator<<(std::ostream & os, const ExpressionBuilder::EBTerm & term)
36 : {
37 1449 : if (term._root != NULL)
38 1449 : return os << *term._root;
39 : else
40 0 : return os << "[NULL]";
41 : }
42 :
43 : std::string
44 36599 : ExpressionBuilder::EBSymbolNode::stringify() const
45 : {
46 36599 : return _symbol;
47 : }
48 :
49 : std::string
50 2 : ExpressionBuilder::EBTempIDNode::stringify() const
51 : {
52 2 : std::ostringstream s;
53 2 : s << '[' << _id << ']';
54 2 : return s.str();
55 2 : }
56 :
57 : std::string
58 864 : ExpressionBuilder::EBUnaryFuncTermNode::stringify() const
59 : {
60 864 : const char * name[] = {
61 : "sin", "cos", "tan", "abs", "log", "log2", "log10", "exp", "sinh", "cosh", "tanh"};
62 864 : std::ostringstream s;
63 864 : s << name[_type] << '(' << *_subnode << ')';
64 864 : return s.str();
65 864 : }
66 :
67 : std::string
68 74 : ExpressionBuilder::EBUnaryOpTermNode::stringify() const
69 : {
70 74 : const char * name[] = {"-", "!"};
71 74 : std::ostringstream s;
72 :
73 74 : s << name[_type];
74 :
75 74 : if (_subnode->precedence() > precedence())
76 73 : s << '(' << *_subnode << ')';
77 : else
78 1 : s << *_subnode;
79 :
80 74 : return s.str();
81 74 : }
82 :
83 : std::string
84 110 : ExpressionBuilder::EBBinaryFuncTermNode::stringify() const
85 : {
86 110 : const char * name[] = {"min", "max", "atan2", "hypot", "plog"};
87 110 : std::ostringstream s;
88 110 : s << name[_type] << '(' << *_left << ',' << *_right << ')';
89 110 : return s.str();
90 110 : }
91 :
92 : std::string
93 27096 : ExpressionBuilder::EBBinaryOpTermNode::stringify() const
94 : {
95 27096 : const char * name[] = {"+", "-", "*", "/", "%", "^", "<", ">", "<=", ">=", "=", "!="};
96 27096 : std::ostringstream s;
97 :
98 27096 : if (_left->precedence() > precedence())
99 2343 : s << '(' << *_left << ')';
100 : else
101 24753 : s << *_left;
102 :
103 27096 : s << name[_type];
104 :
105 : // these operators are left associative at equal precedence
106 : // (this matters for -,/,&,^ but not for + and *)
107 50301 : if (_right->precedence() > precedence() ||
108 23205 : (_right->precedence() == precedence() &&
109 110 : (_type == SUB || _type == DIV || _type == MOD || _type == POW)))
110 3964 : s << '(' << *_right << ')';
111 : else
112 23132 : s << *_right;
113 :
114 27096 : return s.str();
115 27096 : }
116 :
117 : int
118 108904 : ExpressionBuilder::EBBinaryOpTermNode::precedence() const
119 : {
120 108904 : switch (_type)
121 : {
122 : case ADD:
123 : case SUB:
124 : return 6;
125 : case MUL:
126 : case DIV:
127 : case MOD:
128 : return 5;
129 : case POW:
130 : return 2;
131 : case LESS:
132 : case GREATER:
133 : case LESSEQ:
134 : case GREATEREQ:
135 : return 8;
136 : case EQ:
137 : case NOTEQ:
138 : return 9;
139 : }
140 :
141 0 : mooseError("Unknown type.");
142 : }
143 :
144 : std::string
145 3 : ExpressionBuilder::EBTernaryFuncTermNode::stringify() const
146 : {
147 : const char * name[] = {"if"};
148 3 : std::ostringstream s;
149 3 : s << name[_type] << '(' << *_left << ',' << *_middle << ',' << *_right << ')';
150 3 : return s.str();
151 3 : }
152 :
153 : ExpressionBuilder::EBFunction &
154 1009 : ExpressionBuilder::EBFunction::operator()(const ExpressionBuilder::EBTerm & arg)
155 : {
156 3027 : this->_eval_arguments = {arg};
157 1009 : return *this;
158 : }
159 :
160 : ExpressionBuilder::EBFunction &
161 447 : ExpressionBuilder::EBFunction::operator()(const ExpressionBuilder::EBTermList & args)
162 : {
163 447 : this->_eval_arguments = EBTermList(args);
164 447 : return *this;
165 : }
166 :
167 : ExpressionBuilder::EBFunction &
168 1447 : ExpressionBuilder::EBFunction::operator=(const ExpressionBuilder::EBTerm & term)
169 : {
170 1447 : this->_arguments = this->_eval_arguments;
171 1447 : this->_term = term;
172 1447 : return *this;
173 : }
174 :
175 : ExpressionBuilder::EBFunction &
176 0 : ExpressionBuilder::EBFunction::operator=(const ExpressionBuilder::EBFunction & func)
177 : {
178 0 : this->_arguments = this->_eval_arguments;
179 0 : this->_term = EBTerm(func);
180 0 : return *this;
181 : }
182 :
183 1451 : ExpressionBuilder::EBFunction::operator ExpressionBuilder::EBTerm() const
184 : {
185 1451 : unsigned int narg = _arguments.size();
186 1451 : if (narg != _eval_arguments.size())
187 0 : mooseError("EBFunction is used wth a different number of arguments than it was defined with.");
188 :
189 : // prepare a copy of the function term to perform the substitution on
190 1451 : EBTerm result(_term);
191 :
192 : // prepare a rule list for the substitutions
193 : EBSubstitutionRuleList rules;
194 3720 : for (unsigned i = 0; i < narg; ++i)
195 2269 : rules.push_back(new EBTermSubstitution(_arguments[i], _eval_arguments[i]));
196 :
197 : // perform substitution
198 1451 : result.substitute(rules);
199 :
200 : // discard rule set
201 3720 : for (unsigned i = 0; i < narg; ++i)
202 2269 : delete rules[i];
203 :
204 1451 : return result;
205 1451 : }
206 :
207 1447 : ExpressionBuilder::EBFunction::operator std::string() const
208 : {
209 1447 : EBTerm eval;
210 1447 : eval = *this; // typecast EBFunction -> EBTerm performs a parameter substitution
211 1447 : std::ostringstream s;
212 1447 : s << eval;
213 1447 : return s.str();
214 1447 : }
215 :
216 : std::string
217 1 : ExpressionBuilder::EBFunction::args()
218 : {
219 1 : unsigned int narg = _arguments.size();
220 1 : if (narg < 1)
221 0 : return "";
222 :
223 1 : std::ostringstream s;
224 1 : s << _arguments[0];
225 2 : for (unsigned int i = 1; i < narg; ++i)
226 1 : s << ',' << _arguments[i];
227 :
228 : return s.str();
229 1 : }
230 :
231 : unsigned int
232 36 : ExpressionBuilder::EBFunction::substitute(const EBSubstitutionRule & rule)
233 : {
234 36 : return _term.substitute(rule);
235 : }
236 :
237 : unsigned int
238 0 : ExpressionBuilder::EBFunction::substitute(const EBSubstitutionRuleList & rules)
239 : {
240 0 : return _term.substitute(rules);
241 : }
242 :
243 : #define UNARY_FUNC_IMPLEMENT(op, OP) \
244 : ExpressionBuilder::EBTerm op(const ExpressionBuilder::EBTerm & term) \
245 : { \
246 : mooseAssert(term._root != NULL, "Empty term provided as argument of function " #op "()"); \
247 : return ExpressionBuilder::EBTerm(new ExpressionBuilder::EBUnaryFuncTermNode( \
248 : term.cloneRoot(), ExpressionBuilder::EBUnaryFuncTermNode::OP)); \
249 : }
250 0 : UNARY_FUNC_IMPLEMENT(sin, SIN)
251 0 : UNARY_FUNC_IMPLEMENT(cos, COS)
252 0 : UNARY_FUNC_IMPLEMENT(tan, TAN)
253 0 : UNARY_FUNC_IMPLEMENT(abs, ABS)
254 325 : UNARY_FUNC_IMPLEMENT(log, LOG)
255 0 : UNARY_FUNC_IMPLEMENT(log2, LOG2)
256 0 : UNARY_FUNC_IMPLEMENT(log10, LOG10)
257 0 : UNARY_FUNC_IMPLEMENT(exp, EXP)
258 0 : UNARY_FUNC_IMPLEMENT(sinh, SINH)
259 0 : UNARY_FUNC_IMPLEMENT(cosh, COSH)
260 612 : UNARY_FUNC_IMPLEMENT(tanh, TANH)
261 :
262 : #define BINARY_FUNC_IMPLEMENT(op, OP) \
263 : ExpressionBuilder::EBTerm op(const ExpressionBuilder::EBTerm & left, \
264 : const ExpressionBuilder::EBTerm & right) \
265 : { \
266 : mooseAssert(left._root != NULL, \
267 : "Empty term provided as first argument of function " #op "()"); \
268 : mooseAssert(right._root != NULL, \
269 : "Empty term provided as second argument of function " #op "()"); \
270 : return ExpressionBuilder::EBTerm(new ExpressionBuilder::EBBinaryFuncTermNode( \
271 : left.cloneRoot(), right.cloneRoot(), ExpressionBuilder::EBBinaryFuncTermNode::OP)); \
272 : }
273 0 : BINARY_FUNC_IMPLEMENT(min, MIN)
274 0 : BINARY_FUNC_IMPLEMENT(max, MAX)
275 1 : BINARY_FUNC_IMPLEMENT(atan2, ATAN2)
276 0 : BINARY_FUNC_IMPLEMENT(hypot, HYPOT)
277 36 : BINARY_FUNC_IMPLEMENT(plog, PLOG)
278 :
279 : // this is a function in ExpressionBuilder (pow) but an operator in FParser (^)
280 : ExpressionBuilder::EBTerm
281 2 : pow(const ExpressionBuilder::EBTerm & left, const ExpressionBuilder::EBTerm & right)
282 : {
283 : mooseAssert(left._root != NULL, "Empty term for base of pow()");
284 : mooseAssert(right._root != NULL, "Empty term for exponent of pow()");
285 : return ExpressionBuilder::EBTerm(new ExpressionBuilder::EBBinaryOpTermNode(
286 2 : left.cloneRoot(), right.cloneRoot(), ExpressionBuilder::EBBinaryOpTermNode::POW));
287 : }
288 :
289 : #define TERNARY_FUNC_IMPLEMENT(op, OP) \
290 : ExpressionBuilder::EBTerm op(const ExpressionBuilder::EBTerm & left, \
291 : const ExpressionBuilder::EBTerm & middle, \
292 : const ExpressionBuilder::EBTerm & right) \
293 : { \
294 : mooseAssert(left._root != NULL, \
295 : "Empty term provided as first argument of the ternary function " #op "()"); \
296 : mooseAssert(middle._root != NULL, \
297 : "Empty term provided as second argument of the ternary function " #op "()"); \
298 : mooseAssert(right._root != NULL, \
299 : "Empty term provided as third argument of the ternary function " #op "()"); \
300 : return ExpressionBuilder::EBTerm(new ExpressionBuilder::EBTernaryFuncTermNode( \
301 : left.cloneRoot(), \
302 : middle.cloneRoot(), \
303 : right.cloneRoot(), \
304 : ExpressionBuilder::EBTernaryFuncTermNode::OP)); \
305 : }
306 3 : TERNARY_FUNC_IMPLEMENT(conditional, CONDITIONAL)
307 :
308 : unsigned int
309 939 : ExpressionBuilder::EBUnaryTermNode::substitute(const EBSubstitutionRuleList & rules)
310 : {
311 939 : unsigned int nrule = rules.size();
312 :
313 1879 : for (unsigned int i = 0; i < nrule; ++i)
314 : {
315 1048 : EBTermNode * replace = rules[i]->apply(_subnode);
316 1048 : if (replace != NULL)
317 : {
318 108 : delete _subnode;
319 108 : _subnode = replace;
320 108 : return 1;
321 : }
322 : }
323 :
324 831 : return _subnode->substitute(rules);
325 : }
326 :
327 : unsigned int
328 21609 : ExpressionBuilder::EBBinaryTermNode::substitute(const EBSubstitutionRuleList & rules)
329 : {
330 21609 : unsigned int nrule = rules.size();
331 : unsigned int success = 0;
332 :
333 66599 : for (unsigned int i = 0; i < nrule; ++i)
334 : {
335 47961 : EBTermNode * replace = rules[i]->apply(_left);
336 47961 : if (replace != NULL)
337 : {
338 2971 : delete _left;
339 2971 : _left = replace;
340 : success = 1;
341 : break;
342 : }
343 : }
344 :
345 : if (success == 0)
346 18638 : success += _left->substitute(rules);
347 :
348 65145 : for (unsigned int i = 0; i < nrule; ++i)
349 : {
350 50980 : EBTermNode * replace = rules[i]->apply(_right);
351 50980 : if (replace != NULL)
352 : {
353 7444 : delete _right;
354 7444 : _right = replace;
355 7444 : return success + 1;
356 : }
357 : }
358 :
359 14165 : return success + _right->substitute(rules);
360 : }
361 :
362 : unsigned int
363 2 : ExpressionBuilder::EBTernaryTermNode::substitute(const EBSubstitutionRuleList & rules)
364 : {
365 2 : unsigned int nrule = rules.size();
366 : bool left_success = false, middle_success = false, right_success = false;
367 : EBTermNode * replace;
368 :
369 5 : for (unsigned int i = 0; i < nrule; ++i)
370 : {
371 3 : replace = rules[i]->apply(_left);
372 3 : if (replace)
373 : {
374 0 : delete _left;
375 0 : _left = replace;
376 : left_success = true;
377 0 : break;
378 : }
379 : }
380 :
381 5 : for (unsigned int i = 0; i < nrule; ++i)
382 : {
383 3 : replace = rules[i]->apply(_middle);
384 3 : if (replace)
385 : {
386 0 : delete _middle;
387 0 : _middle = replace;
388 : middle_success = true;
389 0 : break;
390 : }
391 : }
392 :
393 5 : for (unsigned int i = 0; i < nrule; ++i)
394 : {
395 3 : replace = rules[i]->apply(_right);
396 3 : if (replace)
397 : {
398 0 : delete _right;
399 0 : _right = replace;
400 : right_success = true;
401 0 : break;
402 : }
403 : }
404 :
405 2 : if (!left_success)
406 2 : left_success = _left->substitute(rules);
407 2 : if (!middle_success)
408 2 : middle_success = _middle->substitute(rules);
409 2 : if (!right_success)
410 2 : right_success = _right->substitute(rules);
411 :
412 2 : return left_success + middle_success + right_success;
413 : }
414 :
415 : unsigned int
416 38 : ExpressionBuilder::EBTerm::substitute(const EBSubstitutionRule & rule)
417 : {
418 38 : EBSubstitutionRuleList rules(1);
419 38 : rules[0] = &rule;
420 76 : return substitute(rules);
421 38 : }
422 :
423 : unsigned int
424 1490 : ExpressionBuilder::EBTerm::substitute(const EBSubstitutionRuleList & rules)
425 : {
426 1490 : unsigned int nrule = rules.size();
427 :
428 1490 : if (_root == NULL)
429 : return 0;
430 :
431 3798 : for (unsigned int i = 0; i < nrule; ++i)
432 : {
433 2309 : EBTermNode * replace = rules[i]->apply(_root);
434 2309 : if (replace != NULL)
435 : {
436 1 : delete _root;
437 1 : _root = replace;
438 1 : return 1;
439 : }
440 : }
441 :
442 1489 : return _root->substitute(rules);
443 : }
444 :
445 2272 : ExpressionBuilder::EBTermSubstitution::EBTermSubstitution(const EBTerm & find,
446 2272 : const EBTerm & replace)
447 : {
448 : // the expression we want to substitute (has to be a symbol node)
449 2272 : const EBSymbolNode * find_root = dynamic_cast<const EBSymbolNode *>(find.getRoot());
450 2272 : if (find_root == NULL)
451 0 : mooseError("Function arguments must be pure symbols.");
452 4544 : _find = find_root->stringify();
453 :
454 : // the term we want to substitute with
455 2272 : if (replace.getRoot() != NULL)
456 2272 : _replace = replace.cloneRoot();
457 : else
458 0 : mooseError("Trying to substitute in an empty term for ", _find);
459 2272 : }
460 :
461 : ExpressionBuilder::EBTermNode *
462 20956 : ExpressionBuilder::EBTermSubstitution::substitute(const EBSymbolNode & node) const
463 : {
464 20956 : if (node.stringify() == _find)
465 10451 : return _replace->clone();
466 : else
467 : return NULL;
468 : }
469 :
470 : ExpressionBuilder::EBTermNode *
471 73 : ExpressionBuilder::EBLogPlogSubstitution::substitute(const EBUnaryFuncTermNode & node) const
472 : {
473 73 : if (node._type == EBUnaryFuncTermNode::LOG)
474 : return new EBBinaryFuncTermNode(
475 73 : node.getSubnode()->clone(), _epsilon->clone(), EBBinaryFuncTermNode::PLOG);
476 : else
477 : return NULL;
478 : }
|