LCOV - code coverage report
Current view: top level - lepton - ParsedExpression.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 176 219 80.4 %
Date: 2021-11-18 15:22:59 Functions: 15 20 75.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :  * -------------------------------------------------------------------------- *
       3             :  *                                   Lepton                                   *
       4             :  * -------------------------------------------------------------------------- *
       5             :  * This is part of the Lepton expression parser originating from              *
       6             :  * Simbios, the NIH National Center for Physics-Based Simulation of           *
       7             :  * Biological Structures at Stanford, funded under the NIH Roadmap for        *
       8             :  * Medical Research, grant U54 GM072970. See https://simtk.org.               *
       9             :  *                                                                            *
      10             :  * Portions copyright (c) 2013-2016 Stanford University and the Authors.      *
      11             :  * Authors: Peter Eastman                                                     *
      12             :  * Contributors:                                                              *
      13             :  *                                                                            *
      14             :  * Permission is hereby granted, free of charge, to any person obtaining a    *
      15             :  * copy of this software and associated documentation files (the "Software"), *
      16             :  * to deal in the Software without restriction, including without limitation  *
      17             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
      18             :  * and/or sell copies of the Software, and to permit persons to whom the      *
      19             :  * Software is furnished to do so, subject to the following conditions:       *
      20             :  *                                                                            *
      21             :  * The above copyright notice and this permission notice shall be included in *
      22             :  * all copies or substantial portions of the Software.                        *
      23             :  *                                                                            *
      24             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
      25             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
      26             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
      27             :  * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,    *
      28             :  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR      *
      29             :  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  *
      30             :  * USE OR OTHER DEALINGS IN THE SOFTWARE.                                     *
      31             :  * -------------------------------------------------------------------------- *
      32             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      33             : /* -------------------------------------------------------------------------- *
      34             :  *                                   lepton                                   *
      35             :  * -------------------------------------------------------------------------- *
      36             :  * This is part of the lepton expression parser originating from              *
      37             :  * Simbios, the NIH National Center for Physics-Based Simulation of           *
      38             :  * Biological Structures at Stanford, funded under the NIH Roadmap for        *
      39             :  * Medical Research, grant U54 GM072970. See https://simtk.org.               *
      40             :  *                                                                            *
      41             :  * Portions copyright (c) 2009 Stanford University and the Authors.           *
      42             :  * Authors: Peter Eastman                                                     *
      43             :  * Contributors:                                                              *
      44             :  *                                                                            *
      45             :  * Permission is hereby granted, free of charge, to any person obtaining a    *
      46             :  * copy of this software and associated documentation files (the "Software"), *
      47             :  * to deal in the Software without restriction, including without limitation  *
      48             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
      49             :  * and/or sell copies of the Software, and to permit persons to whom the      *
      50             :  * Software is furnished to do so, subject to the following conditions:       *
      51             :  *                                                                            *
      52             :  * The above copyright notice and this permission notice shall be included in *
      53             :  * all copies or substantial portions of the Software.                        *
      54             :  *                                                                            *
      55             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
      56             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
      57             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
      58             :  * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,    *
      59             :  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR      *
      60             :  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  *
      61             :  * USE OR OTHER DEALINGS IN THE SOFTWARE.                                     *
      62             :  * -------------------------------------------------------------------------- */
      63             : 
      64             : #include "ParsedExpression.h"
      65             : #include "CompiledExpression.h"
      66             : #include "ExpressionProgram.h"
      67             : #include "Operation.h"
      68             : #include <limits>
      69             : #include <vector>
      70             : 
      71             : namespace PLMD {
      72             : using namespace lepton;
      73             : using namespace std;
      74             : 
      75           0 : ParsedExpression::ParsedExpression() : rootNode(ExpressionTreeNode()) {
      76           0 : }
      77             : 
      78        2859 : ParsedExpression::ParsedExpression(const ExpressionTreeNode& rootNode) : rootNode(rootNode) {
      79        2859 : }
      80             : 
      81        3657 : const ExpressionTreeNode& ParsedExpression::getRootNode() const {
      82        3657 :     if (&rootNode.getOperation() == NULL)
      83           0 :         throw Exception("Illegal call to an initialized ParsedExpression");
      84        3657 :     return rootNode;
      85             : }
      86             : 
      87           0 : double ParsedExpression::evaluate() const {
      88           0 :     return evaluate(getRootNode(), map<string, double>());
      89             : }
      90             : 
      91           4 : double ParsedExpression::evaluate(const map<string, double>& variables) const {
      92           4 :     return evaluate(getRootNode(), variables);
      93             : }
      94             : 
      95       17938 : double ParsedExpression::evaluate(const ExpressionTreeNode& node, const map<string, double>& variables) {
      96       35876 :     int numArgs = (int) node.getChildren().size();
      97       35876 :     vector<double> args(max(numArgs, 1));
      98       30660 :     for (int i = 0; i < numArgs; i++)
      99       12722 :         args[i] = evaluate(node.getChildren()[i], variables);
     100       53814 :     return node.getOperation().evaluate(&args[0], variables);
     101             : }
     102             : 
     103         818 : ParsedExpression ParsedExpression::optimize() const {
     104        1636 :     ExpressionTreeNode result = precalculateConstantSubexpressions(getRootNode());
     105             :     while (true) {
     106         818 :         ExpressionTreeNode simplified = substituteSimplerExpression(result);
     107         818 :         if (simplified == result)
     108             :             break;
     109           0 :         result = simplified;
     110             :     }
     111        1636 :     return ParsedExpression(result);
     112             : }
     113             : 
     114         798 : ParsedExpression ParsedExpression::optimize(const map<string, double>& variables) const {
     115        1596 :     ExpressionTreeNode result = preevaluateVariables(getRootNode(), variables);
     116         798 :     result = precalculateConstantSubexpressions(result);
     117             :     while (true) {
     118        2672 :         ExpressionTreeNode simplified = substituteSimplerExpression(result);
     119        1735 :         if (simplified == result)
     120             :             break;
     121         937 :         result = simplified;
     122             :     }
     123        1596 :     return ParsedExpression(result);
     124             : }
     125             : 
     126       27945 : ExpressionTreeNode ParsedExpression::preevaluateVariables(const ExpressionTreeNode& node, const map<string, double>& variables) {
     127       27945 :     if (node.getOperation().getId() == Operation::VARIABLE) {
     128        5137 :         const Operation::Variable& var = dynamic_cast<const Operation::Variable&>(node.getOperation());
     129       10274 :         map<string, double>::const_iterator iter = variables.find(var.getName());
     130        5137 :         if (iter == variables.end())
     131        4356 :             return node;
     132        1562 :         return ExpressionTreeNode(new Operation::Constant(iter->second));
     133             :     }
     134       68424 :     vector<ExpressionTreeNode> children(node.getChildren().size());
     135       77102 :     for (int i = 0; i < (int) children.size(); i++)
     136       81441 :         children[i] = preevaluateVariables(node.getChildren()[i], variables);
     137       22808 :     return ExpressionTreeNode(node.getOperation().clone(), children);
     138             : }
     139             : 
     140       37382 : ExpressionTreeNode ParsedExpression::precalculateConstantSubexpressions(const ExpressionTreeNode& node) {
     141      112146 :     vector<ExpressionTreeNode> children(node.getChildren().size());
     142      108914 :     for (int i = 0; i < (int) children.size(); i++)
     143      107298 :         children[i] = precalculateConstantSubexpressions(node.getChildren()[i]);
     144       74764 :     ExpressionTreeNode result = ExpressionTreeNode(node.getOperation().clone(), children);
     145       37382 :     if (node.getOperation().getId() == Operation::VARIABLE || node.getOperation().getId() == Operation::CUSTOM)
     146        7011 :         return result;
     147       46261 :     for (int i = 0; i < (int) children.size(); i++)
     148       53486 :         if (children[i].getOperation().getId() != Operation::CONSTANT)
     149       18798 :             return result;
     150       34719 :     return ExpressionTreeNode(new Operation::Constant(evaluate(result, map<string, double>())));
     151             : }
     152             : 
     153       44985 : ExpressionTreeNode ParsedExpression::substituteSimplerExpression(const ExpressionTreeNode& node) {
     154      134955 :     vector<ExpressionTreeNode> children(node.getChildren().size());
     155      129849 :     for (int i = 0; i < (int) children.size(); i++)
     156      127296 :         children[i] = substituteSimplerExpression(node.getChildren()[i]);
     157       44985 :     switch (node.getOperation().getId()) {
     158             :         case Operation::ADD:
     159             :         {
     160        4049 :             double first = getConstantValue(children[0]);
     161        4049 :             double second = getConstantValue(children[1]);
     162        4049 :             if (first == 0.0) // Add 0
     163         473 :                 return children[1];
     164        3576 :             if (second == 0.0) // Add 0
     165         858 :                 return children[0];
     166        2718 :             if (first == first) // Add a constant
     167          52 :                 return ExpressionTreeNode(new Operation::AddConstant(first), children[1]);
     168        2692 :             if (second == second) // Add a constant
     169         930 :                 return ExpressionTreeNode(new Operation::AddConstant(second), children[0]);
     170        2227 :             if (children[1].getOperation().getId() == Operation::NEGATE) // a+(-b) = a-b
     171           0 :                 return ExpressionTreeNode(new Operation::Subtract(), children[0], children[1].getChildren()[0]);
     172        2227 :             if (children[0].getOperation().getId() == Operation::NEGATE) // (-a)+b = b-a
     173           0 :                 return ExpressionTreeNode(new Operation::Subtract(), children[1], children[0].getChildren()[0]);
     174             :             break;
     175             :         }
     176             :         case Operation::SUBTRACT:
     177             :         {
     178        1972 :             if (children[0] == children[1])
     179          24 :                 return ExpressionTreeNode(new Operation::Constant(0.0)); // Subtracting anything from itself is 0
     180        1960 :             double first = getConstantValue(children[0]);
     181        1960 :             if (first == 0.0) // Subtract from 0
     182          80 :                 return ExpressionTreeNode(new Operation::Negate(), children[1]);
     183        1920 :             double second = getConstantValue(children[1]);
     184        1920 :             if (second == 0.0) // Subtract 0
     185          32 :                 return children[0];
     186        1888 :             if (second == second) // Subtract a constant
     187         922 :                 return ExpressionTreeNode(new Operation::AddConstant(-second), children[0]);
     188        1427 :             if (children[1].getOperation().getId() == Operation::NEGATE) // a-(-b) = a+b
     189           0 :                 return ExpressionTreeNode(new Operation::Add(), children[0], children[1].getChildren()[0]);
     190             :             break;
     191             :         }
     192             :         case Operation::MULTIPLY:
     193             :         {
     194        6867 :             double first = getConstantValue(children[0]);
     195        6867 :             double second = getConstantValue(children[1]);
     196        6867 :             if (first == 0.0 || second == 0.0) // Multiply by 0
     197        2382 :                 return ExpressionTreeNode(new Operation::Constant(0.0));
     198        5676 :             if (first == 1.0) // Multiply by 1
     199          17 :                 return children[1];
     200        5659 :             if (second == 1.0) // Multiply by 1
     201         908 :                 return children[0];
     202        4751 :             if (children[0].getOperation().getId() == Operation::CONSTANT) { // Multiply by a constant
     203        1336 :                 if (children[1].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine two multiplies into a single one
     204          80 :                     return ExpressionTreeNode(new Operation::MultiplyConstant(first*dynamic_cast<const Operation::MultiplyConstant*>(&children[1].getOperation())->getValue()), children[1].getChildren()[0]);
     205        2632 :                 return ExpressionTreeNode(new Operation::MultiplyConstant(first), children[1]);
     206             :             }
     207        3415 :             if (children[1].getOperation().getId() == Operation::CONSTANT) { // Multiply by a constant
     208          15 :                 if (children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine two multiplies into a single one
     209           0 :                     return ExpressionTreeNode(new Operation::MultiplyConstant(second*dynamic_cast<const Operation::MultiplyConstant*>(&children[0].getOperation())->getValue()), children[0].getChildren()[0]);
     210          30 :                 return ExpressionTreeNode(new Operation::MultiplyConstant(second), children[0]);
     211             :             }
     212        3403 :             if (children[0].getOperation().getId() == Operation::NEGATE && children[1].getOperation().getId() == Operation::NEGATE) // The two negations cancel
     213           0 :                 return ExpressionTreeNode(new Operation::Multiply(), children[0].getChildren()[0], children[1].getChildren()[0]);
     214        6803 :             if (children[0].getOperation().getId() == Operation::NEGATE && children[1].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Negate the constant
     215           7 :                 return ExpressionTreeNode(new Operation::Multiply(), children[0].getChildren()[0], ExpressionTreeNode(new Operation::MultiplyConstant(-dynamic_cast<const Operation::MultiplyConstant*>(&children[1].getOperation())->getValue()), children[1].getChildren()[0]));
     216        6990 :             if (children[1].getOperation().getId() == Operation::NEGATE && children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Negate the constant
     217        1152 :                 return ExpressionTreeNode(new Operation::Multiply(), ExpressionTreeNode(new Operation::MultiplyConstant(-dynamic_cast<const Operation::MultiplyConstant*>(&children[0].getOperation())->getValue()), children[0].getChildren()[0]), children[1].getChildren()[0]);
     218        6414 :             if (children[0].getOperation().getId() == Operation::NEGATE) // Pull the negation out so it can possibly be optimized further
     219           8 :                 return ExpressionTreeNode(new Operation::Negate(), ExpressionTreeNode(new Operation::Multiply(), children[0].getChildren()[0], children[1]));
     220        3205 :             if (children[1].getOperation().getId() == Operation::NEGATE) // Pull the negation out so it can possibly be optimized further
     221           0 :                 return ExpressionTreeNode(new Operation::Negate(), ExpressionTreeNode(new Operation::Multiply(), children[0], children[1].getChildren()[0]));
     222        3205 :             if (children[1].getOperation().getId() == Operation::RECIPROCAL) // a*(1/b) = a/b
     223           0 :                 return ExpressionTreeNode(new Operation::Divide(), children[0], children[1].getChildren()[0]);
     224        3205 :             if (children[0].getOperation().getId() == Operation::RECIPROCAL) // (1/a)*b = b/a
     225          12 :                 return ExpressionTreeNode(new Operation::Divide(), children[1], children[0].getChildren()[0]);
     226        3201 :             if (children[0] == children[1])
     227         684 :                 return ExpressionTreeNode(new Operation::Square(), children[0]); // x*x = square(x)
     228        2881 :             if (children[0].getOperation().getId() == Operation::SQUARE && children[0].getChildren()[0] == children[1])
     229           0 :                 return ExpressionTreeNode(new Operation::Cube(), children[1]); // x*x*x = cube(x)
     230        5816 :             if (children[1].getOperation().getId() == Operation::SQUARE && children[1].getChildren()[0] == children[0])
     231           0 :                 return ExpressionTreeNode(new Operation::Cube(), children[0]); // x*x*x = cube(x)
     232             :             break;
     233             :         }
     234             :         case Operation::DIVIDE:
     235             :         {
     236         214 :             if (children[0] == children[1])
     237           0 :                 return ExpressionTreeNode(new Operation::Constant(1.0)); // Dividing anything from itself is 0
     238         214 :             double numerator = getConstantValue(children[0]);
     239         214 :             if (numerator == 0.0) // 0 divided by something
     240           0 :                 return ExpressionTreeNode(new Operation::Constant(0.0));
     241         214 :             if (numerator == 1.0) // 1 divided by something
     242          24 :                 return ExpressionTreeNode(new Operation::Reciprocal(), children[1]);
     243         202 :             double denominator = getConstantValue(children[1]);
     244         202 :             if (denominator == 1.0) // Divide by 1
     245           0 :                 return children[0];
     246         202 :             if (children[1].getOperation().getId() == Operation::CONSTANT) {
     247          42 :                 if (children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine a multiply and a divide into one multiply
     248           0 :                     return ExpressionTreeNode(new Operation::MultiplyConstant(dynamic_cast<const Operation::MultiplyConstant*>(&children[0].getOperation())->getValue()/denominator), children[0].getChildren()[0]);
     249          84 :                 return ExpressionTreeNode(new Operation::MultiplyConstant(1.0/denominator), children[0]); // Replace a divide with a multiply
     250             :             }
     251         188 :             if (children[0].getOperation().getId() == Operation::NEGATE && children[1].getOperation().getId() == Operation::NEGATE) // The two negations cancel
     252           0 :                 return ExpressionTreeNode(new Operation::Divide(), children[0].getChildren()[0], children[1].getChildren()[0]);
     253         320 :             if (children[1].getOperation().getId() == Operation::NEGATE && children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Negate the constant
     254           0 :                 return ExpressionTreeNode(new Operation::Divide(), ExpressionTreeNode(new Operation::MultiplyConstant(-dynamic_cast<const Operation::MultiplyConstant*>(&children[0].getOperation())->getValue()), children[0].getChildren()[0]), children[1].getChildren()[0]);
     255         320 :             if (children[0].getOperation().getId() == Operation::NEGATE) // Pull the negation out so it can possibly be optimized further
     256         112 :                 return ExpressionTreeNode(new Operation::Negate(), ExpressionTreeNode(new Operation::Divide(), children[0].getChildren()[0], children[1]));
     257         132 :             if (children[1].getOperation().getId() == Operation::NEGATE) // Pull the negation out so it can possibly be optimized further
     258           0 :                 return ExpressionTreeNode(new Operation::Negate(), ExpressionTreeNode(new Operation::Divide(), children[0], children[1].getChildren()[0]));
     259         132 :             if (children[1].getOperation().getId() == Operation::RECIPROCAL) // a/(1/b) = a*b
     260           0 :                 return ExpressionTreeNode(new Operation::Multiply(), children[0], children[1].getChildren()[0]);
     261             :             break;
     262             :         }
     263             :         case Operation::POWER:
     264             :         {
     265         362 :             double base = getConstantValue(children[0]);
     266         362 :             if (base == 0.0) // 0 to any power is 0
     267           0 :                 return ExpressionTreeNode(new Operation::Constant(0.0));
     268         362 :             if (base == 1.0) // 1 to any power is 1
     269           0 :                 return ExpressionTreeNode(new Operation::Constant(1.0));
     270         362 :             double exponent = getConstantValue(children[1]);
     271         362 :             if (exponent == 0.0) // x^0 = 1
     272           0 :                 return ExpressionTreeNode(new Operation::Constant(1.0));
     273         362 :             if (exponent == 1.0) // x^1 = x
     274          49 :                 return children[0];
     275         313 :             if (exponent == -1.0) // x^-1 = recip(x)
     276           0 :                 return ExpressionTreeNode(new Operation::Reciprocal(), children[0]);
     277         313 :             if (exponent == 2.0) // x^2 = square(x)
     278         290 :                 return ExpressionTreeNode(new Operation::Square(), children[0]);
     279         168 :             if (exponent == 3.0) // x^3 = cube(x)
     280         138 :                 return ExpressionTreeNode(new Operation::Cube(), children[0]);
     281          99 :             if (exponent == 0.5) // x^0.5 = sqrt(x)
     282          10 :                 return ExpressionTreeNode(new Operation::Sqrt(), children[0]);
     283          94 :             if (exponent == exponent) // Constant power
     284         188 :                 return ExpressionTreeNode(new Operation::PowerConstant(exponent), children[0]);
     285             :             break;
     286             :         }
     287             :         case Operation::NEGATE:
     288             :         {
     289        1243 :             if (children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine a multiply and a negate into a single multiply
     290           8 :                 return ExpressionTreeNode(new Operation::MultiplyConstant(-dynamic_cast<const Operation::MultiplyConstant*>(&children[0].getOperation())->getValue()), children[0].getChildren()[0]);
     291        1241 :             if (children[0].getOperation().getId() == Operation::CONSTANT) // Negate a constant
     292           0 :                 return ExpressionTreeNode(new Operation::Constant(-getConstantValue(children[0])));
     293        1241 :             if (children[0].getOperation().getId() == Operation::NEGATE) // The two negations cancel
     294           0 :                 return children[0].getChildren()[0];
     295             :             break;
     296             :         }
     297             :         case Operation::MULTIPLY_CONSTANT:
     298             :         {
     299        3453 :             if (children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine two multiplies into a single one
     300           0 :                 return ExpressionTreeNode(new Operation::MultiplyConstant(dynamic_cast<const Operation::MultiplyConstant*>(&node.getOperation())->getValue()*dynamic_cast<const Operation::MultiplyConstant*>(&children[0].getOperation())->getValue()), children[0].getChildren()[0]);
     301        3453 :             if (children[0].getOperation().getId() == Operation::CONSTANT) // Multiply two constants
     302          36 :                 return ExpressionTreeNode(new Operation::Constant(dynamic_cast<const Operation::MultiplyConstant*>(&node.getOperation())->getValue()*getConstantValue(children[0])));
     303        3441 :             if (children[0].getOperation().getId() == Operation::NEGATE) // Combine a multiply and a negate into a single multiply
     304        1748 :                 return ExpressionTreeNode(new Operation::MultiplyConstant(-dynamic_cast<const Operation::MultiplyConstant*>(&node.getOperation())->getValue()), children[0].getChildren()[0]);
     305             :             break;
     306             :         }
     307             :         default:
     308             :         {
     309             :             // If operation ID is not one of the above,
     310             :             // we don't substitute a simpler expression.
     311             :             break;
     312             :         }
     313             : 
     314             :     }
     315       37715 :     return ExpressionTreeNode(node.getOperation().clone(), children);
     316             : }
     317             : 
     318         441 : ParsedExpression ParsedExpression::differentiate(const string& variable) const {
     319         441 :     return differentiate(getRootNode(), variable);
     320             : }
     321             : 
     322        6374 : ExpressionTreeNode ParsedExpression::differentiate(const ExpressionTreeNode& node, const string& variable) {
     323       19122 :     vector<ExpressionTreeNode> childDerivs(node.getChildren().size());
     324       18240 :     for (int i = 0; i < (int) childDerivs.size(); i++)
     325       17799 :         childDerivs[i] = differentiate(node.getChildren()[i], variable);
     326       12748 :     return node.getOperation().differentiate(node.getChildren(),childDerivs, variable);
     327             : }
     328             : 
     329       26864 : double ParsedExpression::getConstantValue(const ExpressionTreeNode& node) {
     330       26864 :     if (node.getOperation().getId() == Operation::CONSTANT)
     331       13496 :         return dynamic_cast<const Operation::Constant&>(node.getOperation()).getValue();
     332             :     return numeric_limits<double>::quiet_NaN();
     333             : }
     334             : 
     335           0 : ExpressionProgram ParsedExpression::createProgram() const {
     336           0 :     return ExpressionProgram(*this);
     337             : }
     338             : 
     339         818 : CompiledExpression ParsedExpression::createCompiledExpression() const {
     340         818 :     return CompiledExpression(*this);
     341             : }
     342             : 
     343           0 : ParsedExpression ParsedExpression::renameVariables(const map<string, string>& replacements) const {
     344           0 :     return ParsedExpression(renameNodeVariables(getRootNode(), replacements));
     345             : }
     346             : 
     347           0 : ExpressionTreeNode ParsedExpression::renameNodeVariables(const ExpressionTreeNode& node, const map<string, string>& replacements) {
     348           0 :     if (node.getOperation().getId() == Operation::VARIABLE) {
     349           0 :         map<string, string>::const_iterator replace = replacements.find(node.getOperation().getName());
     350           0 :         if (replace != replacements.end())
     351           0 :             return ExpressionTreeNode(new Operation::Variable(replace->second));
     352             :     }
     353           0 :     vector<ExpressionTreeNode> children;
     354           0 :     for (int i = 0; i < (int) node.getChildren().size(); i++)
     355           0 :         children.push_back(renameNodeVariables(node.getChildren()[i], replacements));
     356           0 :     return ExpressionTreeNode(node.getOperation().clone(), children);
     357             : }
     358             : 
     359        9149 : ostream& lepton::operator<<(ostream& out, const ExpressionTreeNode& node) {
     360       11067 :     if (node.getOperation().isInfixOperator() && node.getChildren().size() == 2) {
     361       11292 :         out << "(" << node.getChildren()[0] << ")" << node.getOperation().getName() << "(" << node.getChildren()[1] << ")";
     362             :     }
     363        7339 :     else if (node.getOperation().isInfixOperator() && node.getChildren().size() == 1) {
     364         144 :         out << "(" << node.getChildren()[0] << ")" << node.getOperation().getName();
     365             :     }
     366             :     else {
     367       14462 :         out << node.getOperation().getName();
     368       14462 :         if (node.getChildren().size() > 0) {
     369        4567 :             out << "(";
     370       22847 :             for (int i = 0; i < (int) node.getChildren().size(); i++) {
     371        4571 :                 if (i > 0)
     372           4 :                     out << ", ";
     373        9142 :                 out << node.getChildren()[i];
     374             :             }
     375        4567 :             out << ")";
     376             :         }
     377             :     }
     378        9149 :     return out;
     379             : }
     380             : 
     381         778 : ostream& lepton::operator<<(ostream& out, const ParsedExpression& exp) {
     382         778 :     out << exp.getRootNode();
     383         778 :     return out;
     384             : }
     385             : }

Generated by: LCOV version 1.14