www.mooseframework.org
ExpressionBuilder.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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 
14 {
15  return {larg, rarg};
16 }
17 
20 {
21  ExpressionBuilder::EBTermList list = {larg};
22  list.insert(list.end(), rargs.begin(), rargs.end());
23  return list;
24 }
25 
28 {
29  ExpressionBuilder::EBTermList list = largs;
30  list.push_back(rarg);
31  return list;
32 }
33 
34 std::ostream &
35 operator<<(std::ostream & os, const ExpressionBuilder::EBTerm & term)
36 {
37  if (term._root != NULL)
38  return os << *term._root;
39  else
40  return os << "[NULL]";
41 }
42 
43 std::string
45 {
46  return _symbol;
47 }
48 
49 std::string
51 {
52  std::ostringstream s;
53  s << '[' << _id << ']';
54  return s.str();
55 }
56 
57 std::string
59 {
60  const char * name[] = {
61  "sin", "cos", "tan", "abs", "log", "log2", "log10", "exp", "sinh", "cosh", "tanh"};
62  std::ostringstream s;
63  s << name[_type] << '(' << *_subnode << ')';
64  return s.str();
65 }
66 
67 std::string
69 {
70  const char * name[] = {"-", "!"};
71  std::ostringstream s;
72 
73  s << name[_type];
74 
75  if (_subnode->precedence() > precedence())
76  s << '(' << *_subnode << ')';
77  else
78  s << *_subnode;
79 
80  return s.str();
81 }
82 
83 std::string
85 {
86  const char * name[] = {"min", "max", "atan2", "hypot", "plog"};
87  std::ostringstream s;
88  s << name[_type] << '(' << *_left << ',' << *_right << ')';
89  return s.str();
90 }
91 
92 std::string
94 {
95  const char * name[] = {"+", "-", "*", "/", "%", "^", "<", ">", "<=", ">=", "=", "!="};
96  std::ostringstream s;
97 
98  if (_left->precedence() > precedence())
99  s << '(' << *_left << ')';
100  else
101  s << *_left;
102 
103  s << name[_type];
104 
105  // these operators are left associative at equal precedence
106  // (this matters for -,/,&,^ but not for + and *)
107  if (_right->precedence() > precedence() ||
108  (_right->precedence() == precedence() &&
109  (_type == SUB || _type == DIV || _type == MOD || _type == POW)))
110  s << '(' << *_right << ')';
111  else
112  s << *_right;
113 
114  return s.str();
115 }
116 
117 int
119 {
120  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  mooseError("Unknown type.");
142 }
143 
144 std::string
146 {
147  const char * name[] = {"if"};
148  std::ostringstream s;
149  s << name[_type] << '(' << *_left << ',' << *_middle << ',' << *_right << ')';
150  return s.str();
151 }
152 
155 {
156  this->_eval_arguments = {arg};
157  return *this;
158 }
159 
162 {
163  this->_eval_arguments = EBTermList(args);
164  return *this;
165 }
166 
169 {
170  this->_arguments = this->_eval_arguments;
171  this->_term = term;
172  return *this;
173 }
174 
177 {
178  this->_arguments = this->_eval_arguments;
179  this->_term = EBTerm(func);
180  return *this;
181 }
182 
183 ExpressionBuilder::EBFunction::operator ExpressionBuilder::EBTerm() const
184 {
185  unsigned int narg = _arguments.size();
186  if (narg != _eval_arguments.size())
187  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  EBTerm result(_term);
191 
192  // prepare a rule list for the substitutions
194  for (unsigned i = 0; i < narg; ++i)
195  rules.push_back(new EBTermSubstitution(_arguments[i], _eval_arguments[i]));
196 
197  // perform substitution
198  result.substitute(rules);
199 
200  // discard rule set
201  for (unsigned i = 0; i < narg; ++i)
202  delete rules[i];
203 
204  return result;
205 }
206 
207 ExpressionBuilder::EBFunction::operator std::string() const
208 {
209  EBTerm eval;
210  eval = *this; // typecast EBFunction -> EBTerm performs a parameter substitution
211  std::ostringstream s;
212  s << eval;
213  return s.str();
214 }
215 
216 std::string
218 {
219  unsigned int narg = _arguments.size();
220  if (narg < 1)
221  return "";
222 
223  std::ostringstream s;
224  s << _arguments[0];
225  for (unsigned int i = 1; i < narg; ++i)
226  s << ',' << _arguments[i];
227 
228  return s.str();
229 }
230 
231 unsigned int
233 {
234  return _term.substitute(rule);
235 }
236 
237 unsigned int
239 {
240  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  }
251 UNARY_FUNC_IMPLEMENT(cos, COS)
252 UNARY_FUNC_IMPLEMENT(tan, TAN)
253 UNARY_FUNC_IMPLEMENT(abs, ABS)
254 UNARY_FUNC_IMPLEMENT(log, LOG)
255 UNARY_FUNC_IMPLEMENT(log2, LOG2)
256 UNARY_FUNC_IMPLEMENT(log10, LOG10)
257 UNARY_FUNC_IMPLEMENT(exp, EXP)
258 UNARY_FUNC_IMPLEMENT(sinh, SINH)
259 UNARY_FUNC_IMPLEMENT(cosh, COSH)
260 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  }
274 BINARY_FUNC_IMPLEMENT(max, MAX)
275 BINARY_FUNC_IMPLEMENT(atan2, ATAN2)
276 BINARY_FUNC_IMPLEMENT(hypot, HYPOT)
277 BINARY_FUNC_IMPLEMENT(plog, PLOG)
278 
279 // this is a function in ExpressionBuilder (pow) but an operator in FParser (^)
281 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()");
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 TERNARY_FUNC_IMPLEMENT(conditional, CONDITIONAL)
307 
308 unsigned int
310 {
311  unsigned int nrule = rules.size();
312 
313  for (unsigned int i = 0; i < nrule; ++i)
314  {
315  EBTermNode * replace = rules[i]->apply(_subnode);
316  if (replace != NULL)
317  {
318  delete _subnode;
319  _subnode = replace;
320  return 1;
321  }
322  }
323 
324  return _subnode->substitute(rules);
325 }
326 
327 unsigned int
329 {
330  unsigned int nrule = rules.size();
331  unsigned int success = 0;
332 
333  for (unsigned int i = 0; i < nrule; ++i)
334  {
335  EBTermNode * replace = rules[i]->apply(_left);
336  if (replace != NULL)
337  {
338  delete _left;
339  _left = replace;
340  success = 1;
341  break;
342  }
343  }
344 
345  if (success == 0)
346  success += _left->substitute(rules);
347 
348  for (unsigned int i = 0; i < nrule; ++i)
349  {
350  EBTermNode * replace = rules[i]->apply(_right);
351  if (replace != NULL)
352  {
353  delete _right;
354  _right = replace;
355  return success + 1;
356  }
357  }
358 
359  return success + _right->substitute(rules);
360 }
361 
362 unsigned int
364 {
365  unsigned int nrule = rules.size();
366  bool left_success = false, middle_success = false, right_success = false;
367  EBTermNode * replace;
368 
369  for (unsigned int i = 0; i < nrule; ++i)
370  {
371  replace = rules[i]->apply(_left);
372  if (replace)
373  {
374  delete _left;
375  _left = replace;
376  left_success = true;
377  break;
378  }
379  }
380 
381  for (unsigned int i = 0; i < nrule; ++i)
382  {
383  replace = rules[i]->apply(_middle);
384  if (replace)
385  {
386  delete _middle;
387  _middle = replace;
388  middle_success = true;
389  break;
390  }
391  }
392 
393  for (unsigned int i = 0; i < nrule; ++i)
394  {
395  replace = rules[i]->apply(_right);
396  if (replace)
397  {
398  delete _right;
399  _right = replace;
400  right_success = true;
401  break;
402  }
403  }
404 
405  if (!left_success)
406  left_success = _left->substitute(rules);
407  if (!middle_success)
408  middle_success = _middle->substitute(rules);
409  if (!right_success)
410  right_success = _right->substitute(rules);
411 
412  return left_success + middle_success + right_success;
413 }
414 
415 unsigned int
417 {
418  EBSubstitutionRuleList rules(1);
419  rules[0] = &rule;
420  return substitute(rules);
421 }
422 
423 unsigned int
425 {
426  unsigned int nrule = rules.size();
427 
428  if (_root == NULL)
429  return 0;
430 
431  for (unsigned int i = 0; i < nrule; ++i)
432  {
433  EBTermNode * replace = rules[i]->apply(_root);
434  if (replace != NULL)
435  {
436  delete _root;
437  _root = replace;
438  return 1;
439  }
440  }
441 
442  return _root->substitute(rules);
443 }
444 
446  const EBTerm & replace)
447 {
448  // the expression we want to substitute (has to be a symbol node)
449  const EBSymbolNode * find_root = dynamic_cast<const EBSymbolNode *>(find.getRoot());
450  if (find_root == NULL)
451  mooseError("Function arguments must be pure symbols.");
452  _find = find_root->stringify();
453 
454  // the term we want to substitute with
455  if (replace.getRoot() != NULL)
456  _replace = replace.cloneRoot();
457  else
458  mooseError("Trying to substitute in an empty term for ", _find);
459 }
460 
463 {
464  if (node.stringify() == _find)
465  return _replace->clone();
466  else
467  return NULL;
468 }
469 
472 {
473  if (node._type == EBUnaryFuncTermNode::LOG)
474  return new EBBinaryFuncTermNode(
475  node.getSubnode()->clone(), _epsilon->clone(), EBBinaryFuncTermNode::PLOG);
476  else
477  return NULL;
478 }
User facing host object for an expression tree.
virtual std::string stringify() const
unsigned int substitute(const EBSubstitutionRule &rule)
void mooseError(Args &&... args)
virtual std::string stringify() const
BINARY_FUNC_IMPLEMENT(min, MIN)
virtual unsigned int substitute(const EBSubstitutionRuleList &rule)
Node representing a binary operator.
ExpressionBuilder::EBTermList operator,(const ExpressionBuilder::EBTerm &larg, const ExpressionBuilder::EBTerm &rarg)
const EBTermNode * getSubnode() const
Node representing a function with two arguments.
std::ostream & operator<<(std::ostream &os, const ExpressionBuilder::EBTerm &term)
virtual EBTermNode * clone() const =0
std::vector< EBTerm > EBTermList
std::basic_ostream< charT, traits > * os
EBFunction & operator()(const EBTerm &arg)
Base class for nodes in the expression tree.
Template class for leaf nodes holding symbols (i.e. variables) in the expression tree.
TERNARY_FUNC_IMPLEMENT(conditional, CONDITIONAL)
unsigned int substitute(const EBSubstitutionRule &rule)
virtual unsigned int substitute(const EBSubstitutionRuleList &rule)
virtual unsigned int substitute(const EBSubstitutionRuleList &)
Node representing a function with two arguments.
const std::string name
Definition: Setup.h:20
EBTermSubstitution(const EBTerm &find, const EBTerm &replace)
virtual EBTermNode * substitute(const EBUnaryFuncTermNode &) const
virtual unsigned int substitute(const EBSubstitutionRuleList &rule)
std::vector< const EBSubstitutionRule * > EBSubstitutionRuleList
UNARY_FUNC_IMPLEMENT(sin, SIN)
ExpressionBuilder::EBTerm pow(const ExpressionBuilder::EBTerm &left, T exponent)
const EBTermNode * getRoot() const
User facing host object for a function. This combines a term with an argument list.
virtual std::string stringify() const
virtual std::string stringify() const
std::string args()
get the list of arguments and check if they are all symbols
virtual std::string stringify() const
enum ExpressionBuilder::EBUnaryFuncTermNode::NodeType _type
virtual EBTermNode * substitute(const EBSymbolNode &) const
Generic Substitution rule to replace all occurences of a given symbol node term with a user defined t...
EBFunction & operator=(const EBTerm &)
Substitution rule functor base class to perform flexible term substitutions.
virtual std::string stringify() const
EBTermNode * cloneRoot() const