LCOV - code coverage report
Current view: top level - lepton - ParsedExpression.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 239 266 89.8 %
Date: 2026-11-05 10:19:06 Functions: 16 21 76.2 %

          Line data    Source code
       1             : /* -------------------------------------------------------------------------- *
       2             :  *                                   lepton                                   *
       3             :  * -------------------------------------------------------------------------- *
       4             :  * This is part of the lepton expression parser.                              *
       5             :  * See https://openmm.org/development.                                        *
       6             :  *                                                                            *
       7             :  * Portions copyright (c) 2009-2022 Stanford University and the Authors.      *
       8             :  * Authors: Peter Eastman                                                     *
       9             :  * Contributors:                                                              *
      10             :  *                                                                            *
      11             :  * Permission is hereby granted, free of charge, to any person obtaining a    *
      12             :  * copy of this software and associated documentation files (the "Software"), *
      13             :  * to deal in the Software without restriction, including without limitation  *
      14             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
      15             :  * and/or sell copies of the Software, and to permit persons to whom the      *
      16             :  * Software is furnished to do so, subject to the following conditions:       *
      17             :  *                                                                            *
      18             :  * The above copyright notice and this permission notice shall be included in *
      19             :  * all copies or substantial portions of the Software.                        *
      20             :  *                                                                            *
      21             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
      22             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
      23             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
      24             :  * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,    *
      25             :  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR      *
      26             :  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  *
      27             :  * USE OR OTHER DEALINGS IN THE SOFTWARE.                                     *
      28             :  * -------------------------------------------------------------------------- */
      29             : 
      30             : #include "ParsedExpression.h"
      31             : #include "CompiledExpression.h"
      32             : #include "ExpressionProgram.h"
      33             : #include "Operation.h"
      34             : #include <limits>
      35             : #include <vector>
      36             : 
      37             : namespace PLMD {
      38             : using namespace lepton;
      39             : using namespace std;
      40             : 
      41           0 : ParsedExpression::ParsedExpression() : rootNode(ExpressionTreeNode()) {
      42           0 : }
      43             : 
      44     2048198 : ParsedExpression::ParsedExpression(const ExpressionTreeNode& rootNode) : rootNode(rootNode) {
      45     2048198 : }
      46             : 
      47     2062917 : const ExpressionTreeNode& ParsedExpression::getRootNode() const {
      48     2062917 :     if (&rootNode.getOperation() == NULL)
      49           0 :         throw Exception("Illegal call to an initialized ParsedExpression");
      50     2062917 :     return rootNode;
      51             : }
      52             : 
      53           0 : double ParsedExpression::evaluate() const {
      54           0 :     return evaluate(getRootNode(), map<string, double>());
      55             : }
      56             : 
      57     2008322 : double ParsedExpression::evaluate(const map<string, double>& variables) const {
      58     2008322 :     return evaluate(getRootNode(), variables);
      59             : }
      60             : 
      61     2054845 : double ParsedExpression::evaluate(const ExpressionTreeNode& node, const map<string, double>& variables) {
      62     2054845 :     int numArgs = (int) node.getChildren().size();
      63     4099642 :     vector<double> args(max(numArgs, 1));
      64     2070221 :     for (int i = 0; i < numArgs; i++)
      65       15381 :         args[i] = evaluate(node.getChildren()[i], variables);
      66     4109643 :     return node.getOperation().evaluate(&args[0], variables);
      67             : }
      68             : 
      69        9316 : ParsedExpression ParsedExpression::optimize() const {
      70        9316 :     ExpressionTreeNode result = getRootNode();
      71        9316 :     vector<const ExpressionTreeNode*> examples;
      72        9316 :     result.assignTags(examples);
      73             :     map<int, ExpressionTreeNode> nodeCache;
      74        9316 :     result = precalculateConstantSubexpressions(result, nodeCache);
      75             :     while (true) {
      76        9387 :         examples.clear();
      77        9387 :         result.assignTags(examples);
      78             :         nodeCache.clear();
      79        9387 :         ExpressionTreeNode simplified = substituteSimplerExpression(result, nodeCache);
      80        9387 :         if (simplified == result)
      81             :             break;
      82          71 :         result = simplified;
      83        9387 :     }
      84       18632 :     return ParsedExpression(result);
      85        9316 : }
      86             : 
      87       12553 : ParsedExpression ParsedExpression::optimize(const map<string, double>& variables) const {
      88       12553 :     ExpressionTreeNode result = preevaluateVariables(getRootNode(), variables);
      89       12553 :     vector<const ExpressionTreeNode*> examples;
      90       12553 :     result.assignTags(examples);
      91             :     map<int, ExpressionTreeNode> nodeCache;
      92       12553 :     result = precalculateConstantSubexpressions(result, nodeCache);
      93             :     while (true) {
      94       22163 :         examples.clear();
      95       22163 :         result.assignTags(examples);
      96             :         nodeCache.clear();
      97       22163 :         ExpressionTreeNode simplified = substituteSimplerExpression(result, nodeCache);
      98       22163 :         if (simplified == result)
      99             :             break;
     100        9610 :         result = simplified;
     101       22163 :     }
     102       25106 :     return ParsedExpression(result);
     103       12553 : }
     104             : 
     105      229336 : ExpressionTreeNode ParsedExpression::preevaluateVariables(const ExpressionTreeNode& node, const map<string, double>& variables) {
     106      229336 :     if (node.getOperation().getId() == Operation::VARIABLE) {
     107       43573 :         const Operation::Variable& var = dynamic_cast<const Operation::Variable&>(node.getOperation());
     108       87146 :         map<string, double>::const_iterator iter = variables.find(var.getName());
     109       43573 :         if (iter == variables.end())
     110       41202 :             return node;
     111        2371 :         return ExpressionTreeNode(new Operation::Constant(iter->second));
     112             :     }
     113      185763 :     vector<ExpressionTreeNode> children(node.getChildren().size());
     114      402546 :     for (int i = 0; i < (int) children.size(); i++)
     115      216783 :         children[i] = preevaluateVariables(node.getChildren()[i], variables);
     116      185763 :     return ExpressionTreeNode(node.getOperation().clone(), children);
     117      185763 : }
     118             : 
     119      209210 : ExpressionTreeNode ParsedExpression::precalculateConstantSubexpressions(const ExpressionTreeNode& node, map<int, ExpressionTreeNode>& nodeCache) {
     120      209210 :     auto cached = nodeCache.find(node.tag);
     121      209210 :     if (cached != nodeCache.end())
     122       44341 :         return cached->second;
     123      164869 :     vector<ExpressionTreeNode> children(node.getChildren().size());
     124      352210 :     for (int i = 0; i < (int) children.size(); i++)
     125      187341 :         children[i] = precalculateConstantSubexpressions(node.getChildren()[i], nodeCache);
     126      164869 :     ExpressionTreeNode result = ExpressionTreeNode(node.getOperation().clone(), children);
     127      164869 :     if (node.getOperation().getId() == Operation::VARIABLE || node.getOperation().getId() == Operation::CUSTOM) {
     128       30010 :         nodeCache[node.tag] = result;
     129       30010 :         return result;
     130             :     }
     131      160845 :     for (int i = 0; i < (int) children.size(); i++)
     132      129703 :         if (children[i].getOperation().getId() != Operation::CONSTANT) {
     133      103717 :             nodeCache[node.tag] = result;
     134      103717 :             return result;
     135             :         }
     136       31142 :     result = ExpressionTreeNode(new Operation::Constant(evaluate(result, map<string, double>())));
     137       31142 :     nodeCache[node.tag] = result;
     138       31142 :     return result;
     139      164869 : }
     140             : 
     141      229769 : ExpressionTreeNode ParsedExpression::substituteSimplerExpression(const ExpressionTreeNode& node, map<int, ExpressionTreeNode>& nodeCache) {
     142      229769 :     vector<ExpressionTreeNode> children(node.getChildren().size());
     143      486483 :     for (int i = 0; i < (int) children.size(); i++) {
     144      256714 :         const ExpressionTreeNode& child = node.getChildren()[i];
     145      256714 :         auto cached = nodeCache.find(child.tag);
     146      256714 :         if (cached == nodeCache.end()) {
     147      198219 :             children[i] = substituteSimplerExpression(child, nodeCache);
     148      198219 :             nodeCache[child.tag] = children[i];
     149             :         }
     150             :         else
     151       58495 :             children[i] = cached->second;
     152             :     }
     153             : 
     154             :     // Collect some info on constant expressions in children
     155      229769 :     bool first_const = children.size() > 0 && isConstant(children[0]); // is first child constant?
     156      229769 :     bool second_const = children.size() > 1 && isConstant(children[1]); // is second child constant?
     157             :     double first, second; // if yes, value of first and second child
     158      229769 :     if (first_const)
     159       14122 :         first = getConstantValue(children[0]);
     160      229769 :     if (second_const)
     161       23179 :         second = getConstantValue(children[1]);
     162             : 
     163      229769 :     switch (node.getOperation().getId()) {
     164       27020 :         case Operation::ADD:
     165             :         {
     166       27020 :             if (first_const) {
     167        2389 :                 if (first == 0.0) { // Add 0
     168        1694 :                     return children[1];
     169             :                 } else { // Add a constant
     170         695 :                     return ExpressionTreeNode(new Operation::AddConstant(first), children[1]);
     171             :                 }
     172             :             }
     173       24631 :             if (second_const) {
     174        1787 :                 if (second == 0.0) { // Add 0
     175        1249 :                     return children[0];
     176             :                 } else { // Add a constant
     177         538 :                     return ExpressionTreeNode(new Operation::AddConstant(second), children[0]);
     178             :                 }
     179             :             }
     180       22844 :             if (children[1].getOperation().getId() == Operation::NEGATE) // a+(-b) = a-b
     181           4 :                 return ExpressionTreeNode(new Operation::Subtract(), children[0], children[1].getChildren()[0]);
     182       22840 :             if (children[0].getOperation().getId() == Operation::NEGATE) // (-a)+b = b-a
     183         115 :                 return ExpressionTreeNode(new Operation::Subtract(), children[1], children[0].getChildren()[0]);
     184             :             break;
     185             :         }
     186             :         case Operation::SUBTRACT:
     187             :         {
     188        7370 :             if (children[0] == children[1])
     189           2 :                 return ExpressionTreeNode(new Operation::Constant(0.0)); // Subtracting anything from itself is 0
     190        7368 :             if (first_const) {
     191        1267 :                 if (first == 0.0) // Subtract from 0
     192          28 :                     return ExpressionTreeNode(new Operation::Negate(), children[1]);
     193             :             }
     194        7340 :             if (second_const) {
     195        2278 :                 if (second == 0.0) { // Subtract 0
     196         356 :                     return children[0];
     197             :                 } else { // Subtract a constant
     198        1922 :                     return ExpressionTreeNode(new Operation::AddConstant(-second), children[0]);
     199             :                 }
     200             :             }
     201        5062 :             if (children[1].getOperation().getId() == Operation::NEGATE) // a-(-b) = a+b
     202           5 :                 return ExpressionTreeNode(new Operation::Add(), children[0], children[1].getChildren()[0]);
     203             :             break;
     204             :         }
     205       40953 :         case Operation::MULTIPLY:
     206             :         {
     207       40953 :             if ((first_const && first == 0.0) || (second_const && second == 0.0)) // Multiply by 0
     208        3622 :                 return ExpressionTreeNode(new Operation::Constant(0.0));
     209       37331 :             if (first_const && first == 1.0) // Multiply by 1
     210          77 :                 return children[1];
     211       37254 :             if (second_const && second == 1.0) // Multiply by 1
     212        5053 :                 return children[0];
     213       32201 :             if (first_const) { // Multiply by a constant
     214        9029 :                 if (children[1].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine two multiplies into a single one
     215         728 :                     return ExpressionTreeNode(new Operation::MultiplyConstant(first*dynamic_cast<const Operation::MultiplyConstant*>(&children[1].getOperation())->getValue()), children[1].getChildren()[0]);
     216        8301 :                 return ExpressionTreeNode(new Operation::MultiplyConstant(first), children[1]);
     217             :             }
     218       23172 :             if (second_const) { // Multiply by a constant
     219        1830 :                 if (children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine two multiplies into a single one
     220         342 :                     return ExpressionTreeNode(new Operation::MultiplyConstant(second*dynamic_cast<const Operation::MultiplyConstant*>(&children[0].getOperation())->getValue()), children[0].getChildren()[0]);
     221        1488 :                 return ExpressionTreeNode(new Operation::MultiplyConstant(second), children[0]);
     222             :             }
     223       21342 :             if (children[0].getOperation().getId() == Operation::NEGATE && children[1].getOperation().getId() == Operation::NEGATE) // The two negations cancel
     224           3 :                 return ExpressionTreeNode(new Operation::Multiply(), children[0].getChildren()[0], children[1].getChildren()[0]);
     225       21339 :             if (children[0].getOperation().getId() == Operation::NEGATE && children[1].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Negate the constant
     226           4 :                 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]));
     227       21335 :             if (children[1].getOperation().getId() == Operation::NEGATE && children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Negate the constant
     228         216 :                 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]);
     229       21119 :             if (children[0].getOperation().getId() == Operation::NEGATE) // Pull the negation out so it can possibly be optimized further
     230         399 :                 return ExpressionTreeNode(new Operation::Negate(), ExpressionTreeNode(new Operation::Multiply(), children[0].getChildren()[0], children[1]));
     231       20720 :             if (children[1].getOperation().getId() == Operation::NEGATE) // Pull the negation out so it can possibly be optimized further
     232          12 :                 return ExpressionTreeNode(new Operation::Negate(), ExpressionTreeNode(new Operation::Multiply(), children[0], children[1].getChildren()[0]));
     233       20708 :             if (children[1].getOperation().getId() == Operation::RECIPROCAL) // a*(1/b) = a/b
     234          53 :                 return ExpressionTreeNode(new Operation::Divide(), children[0], children[1].getChildren()[0]);
     235       20655 :             if (children[0].getOperation().getId() == Operation::RECIPROCAL) // (1/a)*b = b/a
     236          34 :                 return ExpressionTreeNode(new Operation::Divide(), children[1], children[0].getChildren()[0]);
     237       20621 :             if (children[0] == children[1])
     238        1152 :                 return ExpressionTreeNode(new Operation::Square(), children[0]); // x*x = square(x)
     239       19469 :             if (children[0].getOperation().getId() == Operation::SQUARE && children[0].getChildren()[0] == children[1])
     240           4 :                 return ExpressionTreeNode(new Operation::Cube(), children[1]); // x*x*x = cube(x)
     241       19465 :             if (children[1].getOperation().getId() == Operation::SQUARE && children[1].getChildren()[0] == children[0])
     242           0 :                 return ExpressionTreeNode(new Operation::Cube(), children[0]); // x*x*x = cube(x)
     243             :             break;
     244             :         }
     245             :         case Operation::DIVIDE:
     246             :         {
     247       11841 :             if (children[0] == children[1])
     248           4 :                 return ExpressionTreeNode(new Operation::Constant(1.0)); // Dividing anything by itself is 1
     249       11837 :             if (first_const && first == 0.0) // 0 divided by something
     250         214 :                 return ExpressionTreeNode(new Operation::Constant(0.0));
     251       11623 :             if (first_const && first == 1.0) // 1 divided by something
     252         124 :                 return ExpressionTreeNode(new Operation::Reciprocal(), children[1]);
     253       11499 :             if (second_const && second == 1.0) // Divide by 1
     254          67 :                 return children[0];
     255       11432 :             if (second_const) {
     256        2868 :                 if (children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine a multiply and a divide into one multiply
     257         767 :                     return ExpressionTreeNode(new Operation::MultiplyConstant(dynamic_cast<const Operation::MultiplyConstant*>(&children[0].getOperation())->getValue()/second), children[0].getChildren()[0]);
     258        2101 :                 return ExpressionTreeNode(new Operation::MultiplyConstant(1.0/second), children[0]); // Replace a divide with a multiply
     259             :             }
     260        8564 :             if (children[0].getOperation().getId() == Operation::NEGATE && children[1].getOperation().getId() == Operation::NEGATE) // The two negations cancel
     261           0 :                 return ExpressionTreeNode(new Operation::Divide(), children[0].getChildren()[0], children[1].getChildren()[0]);
     262        8564 :             if (children[1].getOperation().getId() == Operation::NEGATE && children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Negate the constant
     263           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]);
     264        8564 :             if (children[0].getOperation().getId() == Operation::NEGATE) // Pull the negation out so it can possibly be optimized further
     265         806 :                 return ExpressionTreeNode(new Operation::Negate(), ExpressionTreeNode(new Operation::Divide(), children[0].getChildren()[0], children[1]));
     266        7758 :             if (children[1].getOperation().getId() == Operation::NEGATE) // Pull the negation out so it can possibly be optimized further
     267           0 :                 return ExpressionTreeNode(new Operation::Negate(), ExpressionTreeNode(new Operation::Divide(), children[0], children[1].getChildren()[0]));
     268        7758 :             if (children[1].getOperation().getId() == Operation::RECIPROCAL) // a/(1/b) = a*b
     269           4 :                 return ExpressionTreeNode(new Operation::Multiply(), children[0], children[1].getChildren()[0]);
     270             :             break;
     271             :         }
     272        3899 :         case Operation::POWER:
     273             :         {
     274        3899 :             if (first_const && first == 0.0) // 0 to any power is 0
     275           8 :                 return ExpressionTreeNode(new Operation::Constant(0.0));
     276        3891 :             if (first_const && first == 1.0) // 1 to any power is 1
     277           8 :                 return ExpressionTreeNode(new Operation::Constant(1.0));
     278        3883 :             if (second_const) { // Constant exponent
     279        3869 :                 if (second == 0.0) // x^0 = 1
     280           4 :                     return ExpressionTreeNode(new Operation::Constant(1.0));
     281        3865 :                 if (second == 1.0) // x^1 = x
     282        1311 :                     return children[0];
     283        2554 :                 if (second == -1.0) // x^-1 = recip(x)
     284           0 :                     return ExpressionTreeNode(new Operation::Reciprocal(), children[0]);
     285        2554 :                 if (second == 2.0) // x^2 = square(x)
     286        2149 :                     return ExpressionTreeNode(new Operation::Square(), children[0]);
     287         405 :                 if (second == 3.0) // x^3 = cube(x)
     288         180 :                     return ExpressionTreeNode(new Operation::Cube(), children[0]);
     289         225 :                 if (second == 0.5) // x^0.5 = sqrt(x)
     290           9 :                     return ExpressionTreeNode(new Operation::Sqrt(), children[0]);
     291             :                 // Constant power
     292         216 :                 return ExpressionTreeNode(new Operation::PowerConstant(second), children[0]);
     293             :             }
     294             :             break;
     295             :         }
     296             :         case Operation::NEGATE:
     297             :         {
     298        7886 :             if (children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine a multiply and a negate into a single multiply
     299         549 :                 return ExpressionTreeNode(new Operation::MultiplyConstant(-dynamic_cast<const Operation::MultiplyConstant*>(&children[0].getOperation())->getValue()), children[0].getChildren()[0]);
     300        7337 :             if (first_const) // Negate a constant
     301         208 :                 return ExpressionTreeNode(new Operation::Constant(-first));
     302        7129 :             if (children[0].getOperation().getId() == Operation::NEGATE) // The two negations cancel
     303           8 :                 return children[0].getChildren()[0];
     304             :             break;
     305             :         }
     306             :         case Operation::MULTIPLY_CONSTANT:
     307             :         {
     308       24318 :             if (children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine two multiplies into a single one
     309           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]);
     310       24318 :             if (first_const) // Multiply two constants
     311           0 :                 return ExpressionTreeNode(new Operation::Constant(dynamic_cast<const Operation::MultiplyConstant*>(&node.getOperation())->getValue()*getConstantValue(children[0])));
     312       24318 :             if (children[0].getOperation().getId() == Operation::NEGATE) // Combine a multiply and a negate into a single multiply
     313        2387 :                 return ExpressionTreeNode(new Operation::MultiplyConstant(-dynamic_cast<const Operation::MultiplyConstant*>(&node.getOperation())->getValue()), children[0].getChildren()[0]);
     314             :             break;
     315             :         }
     316             :         case Operation::SQRT:
     317             :         {
     318        1770 :             if (children[0].getOperation().getId() == Operation::SQUARE) // sqrt(square(x)) = abs(x)
     319           6 :                 return ExpressionTreeNode(new Operation::Abs(), children[0].getChildren()[0]);
     320             :             break;
     321             :         }
     322             :         case Operation::SQUARE:
     323             :         {
     324       12990 :             if (children[0].getOperation().getId() == Operation::SQRT) // square(sqrt(x)) = x
     325          49 :                 return children[0].getChildren()[0];
     326             :             break;
     327             :         }
     328             :         case Operation::SELECT:
     329             :         {
     330         232 :             if (children[1] == children[2]) // Select between two identical values
     331           5 :                 return children[1];
     332             :             break;
     333             :         }
     334             :         default:
     335             :         {
     336             :             // If operation ID is not one of the above,
     337             :             // we don't substitute a simpler expression.
     338             :             break;
     339             :         }
     340             : 
     341             :     }
     342      190489 :     return ExpressionTreeNode(node.getOperation().clone(), children);
     343      229769 : }
     344             : 
     345        5657 : ParsedExpression ParsedExpression::differentiate(const string& variable) const {
     346        5657 :     vector<const ExpressionTreeNode*> examples;
     347        5657 :     getRootNode().assignTags(examples);
     348             :     map<int, ExpressionTreeNode> nodeCache;
     349       11314 :     return differentiate(getRootNode(), variable, nodeCache);
     350        5657 : }
     351             : 
     352       49364 : ExpressionTreeNode ParsedExpression::differentiate(const ExpressionTreeNode& node, const string& variable, map<int, ExpressionTreeNode>& nodeCache) {
     353       49364 :     auto cached = nodeCache.find(node.tag);
     354       49364 :     if (cached != nodeCache.end())
     355        7326 :         return cached->second;
     356       42038 :     vector<ExpressionTreeNode> childDerivs(node.getChildren().size());
     357       85745 :     for (int i = 0; i < (int) childDerivs.size(); i++)
     358       43707 :         childDerivs[i] = differentiate(node.getChildren()[i], variable, nodeCache);
     359       42038 :     ExpressionTreeNode result = node.getOperation().differentiate(node.getChildren(), childDerivs, variable);
     360       42038 :     nodeCache[node.tag] = result;
     361       42038 :     return result;
     362       42038 : }
     363             : 
     364      256482 : bool ParsedExpression::isConstant(const ExpressionTreeNode& node) {
     365      256482 :     return (node.getOperation().getId() == Operation::CONSTANT);
     366             : }
     367             : 
     368       37301 : double ParsedExpression::getConstantValue(const ExpressionTreeNode& node) {
     369       37301 :     if (node.getOperation().getId() != Operation::CONSTANT) {
     370           0 :         throw Exception("getConstantValue called on a non-constant ExpressionNode");
     371             :     }
     372       37301 :     return dynamic_cast<const Operation::Constant&>(node.getOperation()).getValue();
     373             : }
     374             : 
     375           0 : ExpressionProgram ParsedExpression::createProgram() const {
     376           0 :     return ExpressionProgram(*this);
     377             : }
     378             : 
     379        9304 : CompiledExpression ParsedExpression::createCompiledExpression() const {
     380        9304 :     return CompiledExpression(*this);
     381             : }
     382             : 
     383           0 : ParsedExpression ParsedExpression::renameVariables(const map<string, string>& replacements) const {
     384           0 :     return ParsedExpression(renameNodeVariables(getRootNode(), replacements));
     385             : }
     386             : 
     387           0 : ExpressionTreeNode ParsedExpression::renameNodeVariables(const ExpressionTreeNode& node, const map<string, string>& replacements) {
     388           0 :     if (node.getOperation().getId() == Operation::VARIABLE) {
     389           0 :         map<string, string>::const_iterator replace = replacements.find(node.getOperation().getName());
     390           0 :         if (replace != replacements.end())
     391           0 :             return ExpressionTreeNode(new Operation::Variable(replace->second));
     392             :     }
     393           0 :     vector<ExpressionTreeNode> children;
     394           0 :     for (int i = 0; i < (int) node.getChildren().size(); i++)
     395           0 :         children.push_back(renameNodeVariables(node.getChildren()[i], replacements));
     396           0 :     return ExpressionTreeNode(node.getOperation().clone(), children);
     397           0 : }
     398             : 
     399       70146 : ostream& lepton::operator<<(ostream& out, const ExpressionTreeNode& node) {
     400       70146 :     if (node.getOperation().isInfixOperator() && node.getChildren().size() == 2) {
     401       47541 :         out << "(" << node.getChildren()[0] << ")" << node.getOperation().getName() << "(" << node.getChildren()[1] << ")";
     402             :     }
     403       54299 :     else if (node.getOperation().isInfixOperator() && node.getChildren().size() == 1) {
     404         166 :         out << "(" << node.getChildren()[0] << ")" << node.getOperation().getName();
     405             :     }
     406             :     else {
     407       54216 :         out << node.getOperation().getName();
     408       54216 :         if (node.getChildren().size() > 0) {
     409       29373 :             out << "(";
     410       58908 :             for (int i = 0; i < (int) node.getChildren().size(); i++) {
     411       29535 :                 if (i > 0)
     412         162 :                     out << ", ";
     413       29535 :                 out << node.getChildren()[i];
     414             :             }
     415       29373 :             out << ")";
     416             :         }
     417             :     }
     418       70146 :     return out;
     419             : }
     420             : 
     421        8834 : ostream& lepton::operator<<(ostream& out, const ParsedExpression& exp) {
     422        8834 :     out << exp.getRootNode();
     423        8834 :     return out;
     424             : }
     425             : }

Generated by: LCOV version 1.16