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 : #pragma once
11 :
12 : #include <vector>
13 : #include <ostream>
14 : #include <sstream>
15 : #include <iomanip>
16 :
17 : #include "MooseError.h"
18 : #include "libmesh/libmesh_common.h"
19 :
20 : using namespace libMesh;
21 :
22 : /**
23 : * ExpressionBuilder adds an interface to derived classes that enables
24 : * convenient construction of FParser expressions through operator overloading.
25 : * It exposes the new types EBTerm and EBFunction
26 : * Variables used in your expressions are of type EBTerm. The following declares
27 : * three variables that can be used in an expression:
28 : *
29 : * EBTerm c1("c1"), c2("c3"), phi("phi");
30 : *
31 : * Declare a function 'G' and define it. Note the double bracket syntax '(())'':
32 : *
33 : * EBFunction G;
34 : * G((c1, c2, c3)) = c1 + 2 * c2 + 3 * pow(c3, 2);
35 : *
36 : * Performing a substitution is as easy as:
37 : * EBFunction H;
38 : * H((c1, c2)) = G((c1, c2, 1-c1-c2))
39 : *
40 : * Use the ```<<``` io operator to output functions or terms. Or use explicit or
41 : * implicit casts from EBFunction to std::string``` to pass a function to the
42 : * FParser Parse method. FParser variables are built using the ```args()``` method.
43 : *
44 : * FunctionParserADBase<Real> GParser;
45 : * GParser.Parse(G, G.args);
46 : */
47 : class ExpressionBuilder
48 : {
49 : public:
50 : ExpressionBuilder(){};
51 :
52 : // forward delcarations
53 : class EBTerm;
54 : class EBTermNode;
55 : class EBFunction;
56 : class EBSubstitutionRule;
57 : typedef std::vector<EBTerm> EBTermList;
58 : typedef std::vector<EBTermNode *> EBTermNodeList;
59 : typedef std::vector<const EBSubstitutionRule *> EBSubstitutionRuleList;
60 :
61 : /// Base class for nodes in the expression tree
62 : class EBTermNode
63 : {
64 : public:
65 : virtual ~EBTermNode(){};
66 : virtual EBTermNode * clone() const = 0;
67 :
68 : virtual std::string stringify() const = 0;
69 12579 : virtual unsigned int substitute(const EBSubstitutionRuleList & /*rule*/) { return 0; }
70 : virtual int precedence() const = 0;
71 56808 : friend std::ostream & operator<<(std::ostream & os, const EBTermNode & node)
72 : {
73 113616 : return os << node.stringify();
74 : }
75 : };
76 :
77 : /// Template class for leaf nodes holding numbers in the expression tree
78 : template <typename T>
79 : class EBNumberNode : public EBTermNode
80 : {
81 : T _value;
82 :
83 : public:
84 130894 : EBNumberNode(T value) : _value(value){};
85 115408 : virtual EBNumberNode<T> * clone() const { return new EBNumberNode(_value); }
86 :
87 : virtual std::string stringify() const;
88 22093 : virtual int precedence() const { return 0; }
89 : };
90 :
91 : /// Template class for leaf nodes holding symbols (i.e. variables) in the expression tree
92 : class EBSymbolNode : public EBTermNode
93 : {
94 : std::string _symbol;
95 :
96 : public:
97 141639 : EBSymbolNode(std::string symbol) : _symbol(symbol){};
98 276138 : virtual EBSymbolNode * clone() const { return new EBSymbolNode(_symbol); }
99 :
100 : virtual std::string stringify() const;
101 21924 : virtual int precedence() const { return 0; }
102 : };
103 :
104 : /**
105 : * Template class for leaf nodes holding anonymous IDs in the expression tree.
106 : * No such node must be left in the final expression that is serialized and passed to FParser
107 : */
108 : class EBTempIDNode : public EBTermNode
109 : {
110 : unsigned long _id;
111 :
112 : public:
113 3288 : EBTempIDNode(unsigned int id) : _id(id){};
114 0 : virtual EBTempIDNode * clone() const { return new EBTempIDNode(_id); }
115 :
116 : virtual std::string stringify() const; // returns "[idnumber]"
117 0 : virtual int precedence() const { return 0; }
118 : };
119 :
120 : /// Base class for nodes with a single sub node (i.e. functions or operators taking one argument)
121 : class EBUnaryTermNode : public EBTermNode
122 : {
123 : public:
124 6604 : EBUnaryTermNode(EBTermNode * subnode) : _subnode(subnode){};
125 6604 : virtual ~EBUnaryTermNode() { delete _subnode; };
126 :
127 : virtual unsigned int substitute(const EBSubstitutionRuleList & rule);
128 73 : const EBTermNode * getSubnode() const { return _subnode; }
129 :
130 : protected:
131 : EBTermNode * _subnode;
132 : };
133 :
134 : /// Node representing a function with two arguments
135 : class EBUnaryFuncTermNode : public EBUnaryTermNode
136 : {
137 : public:
138 : enum NodeType
139 : {
140 : SIN,
141 : COS,
142 : TAN,
143 : ABS,
144 : LOG,
145 : LOG2,
146 : LOG10,
147 : EXP,
148 : SINH,
149 : COSH,
150 : TANH
151 : } _type;
152 :
153 : EBUnaryFuncTermNode(EBTermNode * subnode, NodeType type)
154 6049 : : EBUnaryTermNode(subnode), _type(type){};
155 5112 : virtual EBUnaryFuncTermNode * clone() const
156 : {
157 5112 : return new EBUnaryFuncTermNode(_subnode->clone(), _type);
158 : };
159 :
160 : virtual std::string stringify() const;
161 1692 : virtual int precedence() const { return 2; }
162 : };
163 :
164 : /// Node representing a unary operator
165 : class EBUnaryOpTermNode : public EBUnaryTermNode
166 : {
167 : public:
168 : enum NodeType
169 : {
170 : NEG,
171 : LOGICNOT
172 : } _type;
173 :
174 : EBUnaryOpTermNode(EBTermNode * subnode, NodeType type)
175 555 : : EBUnaryTermNode(subnode), _type(type){};
176 481 : virtual EBUnaryOpTermNode * clone() const
177 : {
178 481 : return new EBUnaryOpTermNode(_subnode->clone(), _type);
179 : };
180 :
181 : virtual std::string stringify() const;
182 149 : virtual int precedence() const { return 3; }
183 : };
184 :
185 : /// Base class for nodes with two sub nodes (i.e. functions or operators taking two arguments)
186 : class EBBinaryTermNode : public EBTermNode
187 : {
188 : public:
189 210926 : EBBinaryTermNode(EBTermNode * left, EBTermNode * right) : _left(left), _right(right){};
190 210926 : virtual ~EBBinaryTermNode()
191 210926 : {
192 210926 : delete _left;
193 210926 : delete _right;
194 210926 : };
195 :
196 : virtual unsigned int substitute(const EBSubstitutionRuleList & rule);
197 :
198 : protected:
199 : EBTermNode * _left;
200 : EBTermNode * _right;
201 : };
202 :
203 : /// Node representing a binary operator
204 : class EBBinaryOpTermNode : public EBBinaryTermNode
205 : {
206 : public:
207 : enum NodeType
208 : {
209 : ADD,
210 : SUB,
211 : MUL,
212 : DIV,
213 : MOD,
214 : POW,
215 : LESS,
216 : GREATER,
217 : LESSEQ,
218 : GREATEREQ,
219 : EQ,
220 : NOTEQ
221 : };
222 :
223 : EBBinaryOpTermNode(EBTermNode * left, EBTermNode * right, NodeType type)
224 210453 : : EBBinaryTermNode(left, right), _type(type){};
225 183511 : virtual EBBinaryOpTermNode * clone() const
226 : {
227 183511 : return new EBBinaryOpTermNode(_left->clone(), _right->clone(), _type);
228 : };
229 :
230 : virtual std::string stringify() const;
231 : virtual int precedence() const;
232 :
233 : protected:
234 : NodeType _type;
235 : };
236 :
237 : /// Node representing a function with two arguments
238 : class EBBinaryFuncTermNode : public EBBinaryTermNode
239 : {
240 : public:
241 : enum NodeType
242 : {
243 : MIN,
244 : MAX,
245 : ATAN2,
246 : HYPOT,
247 : PLOG
248 : } _type;
249 :
250 : EBBinaryFuncTermNode(EBTermNode * left, EBTermNode * right, NodeType type)
251 73 : : EBBinaryTermNode(left, right), _type(type){};
252 360 : virtual EBBinaryFuncTermNode * clone() const
253 : {
254 360 : return new EBBinaryFuncTermNode(_left->clone(), _right->clone(), _type);
255 : };
256 :
257 : virtual std::string stringify() const;
258 180 : virtual int precedence() const { return 2; }
259 : };
260 :
261 : /// Base class for nodes with two sub nodes (i.e. functions or operators taking two arguments)
262 : class EBTernaryTermNode : public EBBinaryTermNode
263 : {
264 : public:
265 : EBTernaryTermNode(EBTermNode * left, EBTermNode * middle, EBTermNode * right)
266 3 : : EBBinaryTermNode(left, right), _middle(middle){};
267 3 : virtual ~EBTernaryTermNode() { delete _middle; };
268 :
269 : virtual unsigned int substitute(const EBSubstitutionRuleList & rule);
270 :
271 : protected:
272 : EBTermNode * _middle;
273 : };
274 :
275 : /// Node representing a function with three arguments
276 : class EBTernaryFuncTermNode : public EBTernaryTermNode
277 : {
278 : public:
279 : enum NodeType
280 : {
281 : CONDITIONAL
282 : } _type;
283 :
284 : EBTernaryFuncTermNode(EBTermNode * left, EBTermNode * middle, EBTermNode * right, NodeType type)
285 3 : : EBTernaryTermNode(left, middle, right), _type(type){};
286 0 : virtual EBTernaryFuncTermNode * clone() const
287 : {
288 0 : return new EBTernaryFuncTermNode(_left->clone(), _middle->clone(), _right->clone(), _type);
289 : };
290 :
291 : virtual std::string stringify() const;
292 0 : virtual int precedence() const { return 2; }
293 : };
294 :
295 : /**
296 : * Substitution rule functor base class to perform flexible term substitutions
297 : */
298 : class EBSubstitutionRule
299 : {
300 : public:
301 : virtual EBTermNode * apply(const EBTermNode *) const = 0;
302 : virtual ~EBSubstitutionRule() {}
303 : };
304 :
305 : /**
306 : * Substitution rule base class that applies to nodes of type Node_T
307 : */
308 : template <class Node_T>
309 : class EBSubstitutionRuleTyped : public EBSubstitutionRule
310 : {
311 : public:
312 : virtual EBTermNode * apply(const EBTermNode *) const;
313 :
314 : protected:
315 : // on successful substitution this returns a new node to replace the old one, otherwise it
316 : // returns NULL
317 : virtual EBTermNode * substitute(const Node_T &) const = 0;
318 : };
319 :
320 : /**
321 : * Generic Substitution rule to replace all occurences of a given symbol node
322 : * term with a user defined term. This is used by EBFunction.
323 : */
324 : class EBTermSubstitution : public EBSubstitutionRuleTyped<EBSymbolNode>
325 : {
326 : public:
327 : EBTermSubstitution(const EBTerm & find, const EBTerm & replace);
328 4541 : virtual ~EBTermSubstitution() { delete _replace; }
329 :
330 : protected:
331 : virtual EBTermNode * substitute(const EBSymbolNode &) const;
332 : std::string _find;
333 : EBTermNode * _replace;
334 : };
335 :
336 : /**
337 : * Substitution rule to replace all occurences of log(x) with plog(x, epsilon)
338 : * with a user defined term for epsilon.
339 : */
340 : class EBLogPlogSubstitution : public EBSubstitutionRuleTyped<EBUnaryFuncTermNode>
341 : {
342 : public:
343 37 : EBLogPlogSubstitution(const EBTerm & epsilon) : _epsilon(epsilon.cloneRoot())
344 : {
345 : mooseAssert(_epsilon != NULL, "Epsilon must not be an empty term in EBLogPlogSubstitution");
346 : }
347 37 : virtual ~EBLogPlogSubstitution() { delete _epsilon; }
348 :
349 : protected:
350 : virtual EBTermNode * substitute(const EBUnaryFuncTermNode &) const;
351 : EBTermNode * _epsilon;
352 : };
353 :
354 : /**
355 : * User facing host object for an expression tree. Each EBTerm contains a _root
356 : * node pointer to an EBTermNode object. The _root pointer should never be NULL,
357 : * but it should be safe if it ever is. The default constructor assigns a
358 : * EBTempIDNode to _root with a unique ID.
359 : */
360 : class EBTerm
361 : {
362 : public:
363 : // the default constructor assigns a temporary id node to root we use the address of the
364 : // current EBTerm object as the ID. This could be problematic if we create and destroy terms,
365 : // but then we should not expect the substitution to do sane things anyways.
366 3288 : EBTerm() : _root(new EBTempIDNode(reinterpret_cast<unsigned long long>(this))){};
367 :
368 10327 : EBTerm(const EBTerm & term) : _root(term.cloneRoot()){};
369 48760 : ~EBTerm() { delete _root; };
370 :
371 : private:
372 : // construct a term from a node
373 27993 : EBTerm(EBTermNode * root) : _root(root){};
374 :
375 : public:
376 : // construct from number or string
377 1 : EBTerm(int number) : _root(new EBNumberNode<int>(number)) {}
378 3061 : EBTerm(Real number) : _root(new EBNumberNode<Real>(number)) {}
379 7140 : EBTerm(const char * symbol) : _root(new EBSymbolNode(symbol)) {}
380 :
381 : // concatenate terms to form a parameter list with (()) syntax (those need to be out-of-class!)
382 : friend EBTermList operator,(const ExpressionBuilder::EBTerm & larg,
383 : const ExpressionBuilder::EBTerm & rarg);
384 : friend EBTermList operator,(const ExpressionBuilder::EBTerm & larg,
385 : const ExpressionBuilder::EBTermList & rargs);
386 : friend EBTermList operator,(const ExpressionBuilder::EBTermList & largs,
387 : const ExpressionBuilder::EBTerm & rarg);
388 :
389 : // dump term as FParser expression
390 : friend std::ostream & operator<<(std::ostream & os, const EBTerm & term);
391 : // cast into a string
392 409 : operator std::string() const { return _root->stringify(); }
393 :
394 : // assign a term
395 3299 : EBTerm & operator=(const EBTerm & term)
396 : {
397 3299 : delete _root;
398 3299 : _root = term.cloneRoot();
399 3299 : return *this;
400 : }
401 :
402 : // perform a substitution (returns substituton count)
403 : unsigned int substitute(const EBSubstitutionRule & rule);
404 : unsigned int substitute(const EBSubstitutionRuleList & rules);
405 :
406 4544 : const EBTermNode * getRoot() const { return _root; }
407 59009 : EBTermNode * cloneRoot() const { return _root == NULL ? NULL : _root->clone(); }
408 :
409 : protected:
410 : EBTermNode * _root;
411 :
412 : public:
413 : /**
414 : * Unary operators
415 : */
416 : #define UNARY_OP_IMPLEMENT(op, OP) \
417 : EBTerm operator op() const \
418 : { \
419 : mooseAssert(_root != NULL, "Empty term provided for unary operator " #op); \
420 : return EBTerm(new EBUnaryOpTermNode(cloneRoot(), EBUnaryOpTermNode::OP)); \
421 : }
422 74 : UNARY_OP_IMPLEMENT(-, NEG)
423 : UNARY_OP_IMPLEMENT(!, LOGICNOT)
424 :
425 : /**
426 : * Unary functions
427 : */
428 : friend EBTerm sin(const EBTerm &);
429 : friend EBTerm cos(const EBTerm &);
430 : friend EBTerm tan(const EBTerm &);
431 : friend EBTerm abs(const EBTerm &);
432 : friend EBTerm log(const EBTerm &);
433 : friend EBTerm log2(const EBTerm &);
434 : friend EBTerm log10(const EBTerm &);
435 : friend EBTerm exp(const EBTerm &);
436 : friend EBTerm sinh(const EBTerm &);
437 : friend EBTerm cosh(const EBTerm &);
438 : friend EBTerm tanh(const EBTerm &);
439 :
440 : /*
441 : * Binary operators (including number,term operations)
442 : */
443 : #define BINARY_OP_IMPLEMENT(op, OP) \
444 : EBTerm operator op(const EBTerm & term) const \
445 : { \
446 : mooseAssert(_root != NULL, "Empty term provided on left side of operator " #op); \
447 : mooseAssert(term._root != NULL, "Empty term provided on right side of operator " #op); \
448 : return EBTerm(new EBBinaryOpTermNode(cloneRoot(), term.cloneRoot(), EBBinaryOpTermNode::OP)); \
449 : } \
450 : friend EBTerm operator op(int left, const EBTerm & right) \
451 : { \
452 : mooseAssert(right._root != NULL, "Empty term provided on right side of operator " #op); \
453 : return EBTerm(new EBBinaryOpTermNode( \
454 : new EBNumberNode<int>(left), right.cloneRoot(), EBBinaryOpTermNode::OP)); \
455 : } \
456 : friend EBTerm operator op(Real left, const EBTerm & right) \
457 : { \
458 : mooseAssert(right._root != NULL, "Empty term provided on right side of operator " #op); \
459 : return EBTerm(new EBBinaryOpTermNode( \
460 : new EBNumberNode<Real>(left), right.cloneRoot(), EBBinaryOpTermNode::OP)); \
461 : } \
462 : friend EBTerm operator op(const EBFunction & left, const EBTerm & right) \
463 : { \
464 : mooseAssert(EBTerm(left)._root != NULL, "Empty term provided on left side of operator " #op); \
465 : mooseAssert(right._root != NULL, "Empty term provided on right side of operator " #op); \
466 : return EBTerm(new EBBinaryOpTermNode( \
467 : EBTerm(left).cloneRoot(), right.cloneRoot(), EBBinaryOpTermNode::OP)); \
468 : } \
469 : friend EBTerm operator op(const EBFunction & left, const EBFunction & right); \
470 : friend EBTerm operator op(int left, const EBFunction & right); \
471 : friend EBTerm operator op(Real left, const EBFunction & right);
472 5164 : BINARY_OP_IMPLEMENT(+, ADD)
473 4686 : BINARY_OP_IMPLEMENT(-, SUB)
474 12575 : BINARY_OP_IMPLEMENT(*, MUL)
475 1227 : BINARY_OP_IMPLEMENT(/, DIV)
476 1 : BINARY_OP_IMPLEMENT(%, MOD)
477 4 : BINARY_OP_IMPLEMENT(<, LESS)
478 1 : BINARY_OP_IMPLEMENT(>, GREATER)
479 1 : BINARY_OP_IMPLEMENT(<=, LESSEQ)
480 1 : BINARY_OP_IMPLEMENT(>=, GREATEREQ)
481 1 : BINARY_OP_IMPLEMENT(==, EQ)
482 1 : BINARY_OP_IMPLEMENT(!=, NOTEQ)
483 :
484 : /*
485 : * Compound assignment operators
486 : */
487 : #define BINARYCOMP_OP_IMPLEMENT(op, OP) \
488 : EBTerm & operator op(const EBTerm & term) \
489 : { \
490 : mooseAssert(_root != NULL, "Empty term provided on left side of operator " #op); \
491 : mooseAssert(term._root != NULL, "Empty term provided on right side of operator " #op); \
492 : if (dynamic_cast<EBTempIDNode *>(_root)) \
493 : mooseError("Using compound assignment operator on anonymous term. Set it to 0 first!"); \
494 : _root = new EBBinaryOpTermNode(_root, term.cloneRoot(), EBBinaryOpTermNode::OP); \
495 : return *this; \
496 : }
497 : BINARYCOMP_OP_IMPLEMENT(+=, ADD)
498 : BINARYCOMP_OP_IMPLEMENT(-=, SUB)
499 : BINARYCOMP_OP_IMPLEMENT(*=, MUL)
500 : BINARYCOMP_OP_IMPLEMENT(/=, DIV)
501 : BINARYCOMP_OP_IMPLEMENT(%=, MOD)
502 :
503 : /**
504 : * @{
505 : * Binary functions
506 : */
507 : friend EBTerm min(const EBTerm &, const EBTerm &);
508 : friend EBTerm max(const EBTerm &, const EBTerm &);
509 : friend EBTerm pow(const EBTerm &, const EBTerm &);
510 : template <typename T>
511 : friend EBTerm pow(const EBTerm &, T exponent);
512 : friend EBTerm atan2(const EBTerm &, const EBTerm &);
513 : friend EBTerm hypot(const EBTerm &, const EBTerm &);
514 : friend EBTerm plog(const EBTerm &, const EBTerm &);
515 : ///@}
516 :
517 : /**
518 : * Ternary functions
519 : */
520 : friend EBTerm conditional(const EBTerm &, const EBTerm &, const EBTerm &);
521 : };
522 :
523 : /// User facing host object for a function. This combines a term with an argument list.
524 : class EBFunction
525 : {
526 : public:
527 1442 : EBFunction(){};
528 :
529 : /// @{
530 : /// set the temporary argument list which is either used for evaluation
531 : /// or committed to the argument list upon function definition (assignment)
532 : EBFunction & operator()(const EBTerm & arg);
533 : EBFunction & operator()(const EBTermList & args);
534 : /// @}
535 :
536 : /// @{
537 : /// convenience operators to allow single bracket syntax
538 72 : EBFunction & operator()(const EBTerm & a1, const EBTerm & a2) { return (*this)((a1, a2)); }
539 364 : EBFunction & operator()(const EBTerm & a1, const EBTerm & a2, const EBTerm & a3)
540 : {
541 364 : return (*this)((a1, a2, a3));
542 : }
543 : EBFunction &
544 : operator()(const EBTerm & a1, const EBTerm & a2, const EBTerm & a3, const EBTerm & a4)
545 : {
546 : return (*this)((a1, a2, a3, a4));
547 : }
548 : EBFunction & operator()(const EBTerm & a1,
549 : const EBTerm & a2,
550 : const EBTerm & a3,
551 : const EBTerm & a4,
552 : const EBTerm & a5)
553 : {
554 : return (*this)((a1, a2, a3, a4, a5));
555 : }
556 5 : EBFunction & operator()(const EBTerm & a1,
557 : const EBTerm & a2,
558 : const EBTerm & a3,
559 : const EBTerm & a4,
560 : const EBTerm & a5,
561 : const EBTerm & a6)
562 : {
563 5 : return (*this)((a1, a2, a3, a4, a5, a6));
564 : }
565 : EBFunction & operator()(const EBTerm & a1,
566 : const EBTerm & a2,
567 : const EBTerm & a3,
568 : const EBTerm & a4,
569 : const EBTerm & a5,
570 : const EBTerm & a6,
571 : const EBTerm & a7)
572 : {
573 : return (*this)((a1, a2, a3, a4, a5, a6, a7));
574 : }
575 : EBFunction & operator()(const EBTerm & a1,
576 : const EBTerm & a2,
577 : const EBTerm & a3,
578 : const EBTerm & a4,
579 : const EBTerm & a5,
580 : const EBTerm & a6,
581 : const EBTerm & a7,
582 : const EBTerm & a8)
583 : {
584 : return (*this)((a1, a2, a3, a4, a5, a6, a7, a8));
585 : }
586 : EBFunction & operator()(const EBTerm & a1,
587 : const EBTerm & a2,
588 : const EBTerm & a3,
589 : const EBTerm & a4,
590 : const EBTerm & a5,
591 : const EBTerm & a6,
592 : const EBTerm & a7,
593 : const EBTerm & a8,
594 : const EBTerm & a9)
595 : {
596 : return (*this)((a1, a2, a3, a4, a5, a6, a7, a8, a9));
597 : }
598 : /// @}
599 :
600 : /// cast an EBFunction into an EBTerm
601 : operator EBTerm() const;
602 :
603 : /// cast into a string (via the cast into a term above)
604 : operator std::string() const;
605 :
606 : /// @{
607 : /// function definition (assignment)
608 : EBFunction & operator=(const EBTerm &);
609 : EBFunction & operator=(const EBFunction &);
610 : /// @}
611 :
612 : /// get the list of arguments and check if they are all symbols
613 : std::string args();
614 :
615 : /// @{
616 : /// Unary operators on functions
617 1 : EBTerm operator-() { return -EBTerm(*this); }
618 : EBTerm operator!() { return !EBTerm(*this); }
619 : /// @}
620 :
621 : // perform a substitution (returns substituton count)
622 : unsigned int substitute(const EBSubstitutionRule & rule);
623 : unsigned int substitute(const EBSubstitutionRuleList & rules);
624 :
625 : protected:
626 : /// argument list the function is declared with
627 : EBTermList _arguments;
628 : /// argument list passed in when evaluating the function
629 : EBTermList _eval_arguments;
630 :
631 : // underlying term that the _eval_arguments are substituted in
632 : EBTerm _term;
633 : };
634 :
635 : /*
636 : * Binary operators
637 : */
638 : #define BINARYFUNC_OP_IMPLEMENT(op, OP) \
639 : friend EBTerm operator op(const EBFunction & left, const EBFunction & right) \
640 : { \
641 : mooseAssert(EBTerm(left)._root != NULL, "Empty term provided on left side of operator " #op); \
642 : mooseAssert(EBTerm(right)._root != NULL, \
643 : "Empty term provided on right side of operator " #op); \
644 : return EBTerm(new EBBinaryOpTermNode( \
645 : EBTerm(left).cloneRoot(), EBTerm(right).cloneRoot(), EBBinaryOpTermNode::OP)); \
646 : } \
647 : friend EBTerm operator op(int left, const EBFunction & right) \
648 : { \
649 : mooseAssert(EBTerm(right)._root != NULL, \
650 : "Empty term provided on right side of operator " #op); \
651 : return EBTerm(new EBBinaryOpTermNode( \
652 : new EBNumberNode<int>(left), EBTerm(right).cloneRoot(), EBBinaryOpTermNode::OP)); \
653 : } \
654 : friend EBTerm operator op(Real left, const EBFunction & right) \
655 : { \
656 : mooseAssert(EBTerm(right)._root != NULL, \
657 : "Empty term provided on right side of operator " #op); \
658 : return EBTerm(new EBBinaryOpTermNode( \
659 : new EBNumberNode<Real>(left), EBTerm(right).cloneRoot(), EBBinaryOpTermNode::OP)); \
660 : }
661 1 : BINARYFUNC_OP_IMPLEMENT(+, ADD)
662 0 : BINARYFUNC_OP_IMPLEMENT(-, SUB)
663 : BINARYFUNC_OP_IMPLEMENT(*, MUL)
664 : BINARYFUNC_OP_IMPLEMENT(/, DIV)
665 : BINARYFUNC_OP_IMPLEMENT(%, MOD)
666 : BINARYFUNC_OP_IMPLEMENT(<, LESS)
667 : BINARYFUNC_OP_IMPLEMENT(>, GREATER)
668 : BINARYFUNC_OP_IMPLEMENT(<=, LESSEQ)
669 : BINARYFUNC_OP_IMPLEMENT(>=, GREATEREQ)
670 : BINARYFUNC_OP_IMPLEMENT(==, EQ)
671 : BINARYFUNC_OP_IMPLEMENT(!=, NOTEQ)
672 : };
673 :
674 : // convenience function for numeric exponent
675 : template <typename T>
676 : ExpressionBuilder::EBTerm
677 3277 : pow(const ExpressionBuilder::EBTerm & left, T exponent)
678 : {
679 : return ExpressionBuilder::EBTerm(
680 6554 : new ExpressionBuilder::EBBinaryOpTermNode(left.cloneRoot(),
681 3277 : new ExpressionBuilder::EBNumberNode<T>(exponent),
682 3277 : ExpressionBuilder::EBBinaryOpTermNode::POW));
683 : }
684 :
685 : // convert a number node into a string
686 : template <typename T>
687 : std::string
688 15698 : ExpressionBuilder::EBNumberNode<T>::stringify() const
689 : {
690 15698 : std::ostringstream s;
691 15698 : s << std::setprecision(12) << _value;
692 15698 : return s.str();
693 15698 : }
694 :
695 : template <class Node_T>
696 : ExpressionBuilder::EBTermNode *
697 102307 : ExpressionBuilder::EBSubstitutionRuleTyped<Node_T>::apply(
698 : const ExpressionBuilder::EBTermNode * node) const
699 : {
700 102307 : const Node_T * match_node = dynamic_cast<const Node_T *>(node);
701 102307 : if (match_node == NULL)
702 : return NULL;
703 : else
704 21029 : return substitute(*match_node);
705 : }
|