LCOV - code coverage report
Current view: top level - include/utils - ExpressionBuilder.h (source / functions) Hit Total Coverage
Test: idaholab/moose phase_field: #31405 (292dce) with base fef103 Lines: 87 93 93.5 %
Date: 2025-09-04 07:55:36 Functions: 56 68 82.4 %
Legend: Lines: hit not hit

          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             : }

Generated by: LCOV version 1.14