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