LCOV - code coverage report
Current view: top level - lepton - ParsedExpression.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 221 257 86.0 %
Date: 2024-10-11 08:09:49 Functions: 16 21 76.2 %

          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-2021 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     2012017 : ParsedExpression::ParsedExpression(const ExpressionTreeNode& rootNode) : rootNode(rootNode) {
      79     2012017 : }
      80             : 
      81     2013723 : const ExpressionTreeNode& ParsedExpression::getRootNode() const {
      82     2013723 :     if (&rootNode.getOperation() == NULL)
      83           0 :         throw Exception("Illegal call to an initialized ParsedExpression");
      84     2013723 :     return rootNode;
      85             : }
      86             : 
      87           0 : double ParsedExpression::evaluate() const {
      88           0 :     return evaluate(getRootNode(), map<string, double>());
      89             : }
      90             : 
      91     2008067 : double ParsedExpression::evaluate(const map<string, double>& variables) const {
      92     2008067 :     return evaluate(getRootNode(), variables);
      93             : }
      94             : 
      95     2012701 : double ParsedExpression::evaluate(const ExpressionTreeNode& node, const map<string, double>& variables) {
      96     2012701 :     int numArgs = (int) node.getChildren().size();
      97     4024777 :     vector<double> args(max(numArgs, 1));
      98     2013817 :     for (int i = 0; i < numArgs; i++)
      99        1116 :         args[i] = evaluate(node.getChildren()[i], variables);
     100     4025390 :     return node.getOperation().evaluate(&args[0], variables);
     101             : }
     102             : 
     103        1134 : ParsedExpression ParsedExpression::optimize() const {
     104        1134 :     ExpressionTreeNode result = getRootNode();
     105             :     vector<const ExpressionTreeNode*> examples;
     106        1134 :     result.assignTags(examples);
     107             :     map<int, ExpressionTreeNode> nodeCache;
     108        1134 :     result = precalculateConstantSubexpressions(result, nodeCache);
     109             :     while (true) {
     110             :         examples.clear();
     111        1134 :         result.assignTags(examples);
     112             :         nodeCache.clear();
     113        1134 :         ExpressionTreeNode simplified = substituteSimplerExpression(result, nodeCache);
     114        1134 :         if (simplified == result)
     115             :             break;
     116           0 :         result = simplified;
     117        1134 :     }
     118        2268 :     return ParsedExpression(result);
     119        1134 : }
     120             : 
     121        1110 : ParsedExpression ParsedExpression::optimize(const map<string, double>& variables) const {
     122        1110 :     ExpressionTreeNode result = preevaluateVariables(getRootNode(), variables);
     123             :     vector<const ExpressionTreeNode*> examples;
     124        1110 :     result.assignTags(examples);
     125             :     map<int, ExpressionTreeNode> nodeCache;
     126        1110 :     result = precalculateConstantSubexpressions(result, nodeCache);
     127             :     while (true) {
     128             :         examples.clear();
     129        2167 :         result.assignTags(examples);
     130             :         nodeCache.clear();
     131        2167 :         ExpressionTreeNode simplified = substituteSimplerExpression(result, nodeCache);
     132        2167 :         if (simplified == result)
     133             :             break;
     134        1057 :         result = simplified;
     135        2167 :     }
     136        2220 :     return ParsedExpression(result);
     137        1110 : }
     138             : 
     139       19862 : ExpressionTreeNode ParsedExpression::preevaluateVariables(const ExpressionTreeNode& node, const map<string, double>& variables) {
     140       19862 :     if (node.getOperation().getId() == Operation::VARIABLE) {
     141        3872 :         const Operation::Variable& var = dynamic_cast<const Operation::Variable&>(node.getOperation());
     142        7744 :         map<string, double>::const_iterator iter = variables.find(var.getName());
     143        3872 :         if (iter == variables.end())
     144        3466 :             return node;
     145         406 :         return ExpressionTreeNode(new Operation::Constant(iter->second));
     146             :     }
     147       15990 :     vector<ExpressionTreeNode> children(node.getChildren().size());
     148       34742 :     for (int i = 0; i < (int) children.size(); i++)
     149       18752 :         children[i] = preevaluateVariables(node.getChildren()[i], variables);
     150       15990 :     return ExpressionTreeNode(node.getOperation().clone(), children);
     151       15990 : }
     152             : 
     153       22795 : ExpressionTreeNode ParsedExpression::precalculateConstantSubexpressions(const ExpressionTreeNode& node, map<int, ExpressionTreeNode>& nodeCache) {
     154       22795 :     auto cached = nodeCache.find(node.tag);
     155       22795 :     if (cached != nodeCache.end())
     156        4736 :         return cached->second;
     157       18059 :     vector<ExpressionTreeNode> children(node.getChildren().size());
     158       38610 :     for (int i = 0; i < (int) children.size(); i++)
     159       20551 :         children[i] = precalculateConstantSubexpressions(node.getChildren()[i], nodeCache);
     160       18059 :     ExpressionTreeNode result = ExpressionTreeNode(node.getOperation().clone(), children);
     161       18059 :     if (node.getOperation().getId() == Operation::VARIABLE || node.getOperation().getId() == Operation::CUSTOM) {
     162        2322 :         nodeCache[node.tag] = result;
     163        2322 :         return result;
     164             :     }
     165       18388 :     for (int i = 0; i < (int) children.size(); i++)
     166       14870 :         if (children[i].getOperation().getId() != Operation::CONSTANT) {
     167       12219 :             nodeCache[node.tag] = result;
     168       12219 :             return result;
     169             :         }
     170        3518 :     result = ExpressionTreeNode(new Operation::Constant(evaluate(result, map<string, double>())));
     171        3518 :     nodeCache[node.tag] = result;
     172        3518 :     return result;
     173       18059 : }
     174             : 
     175       25885 : ExpressionTreeNode ParsedExpression::substituteSimplerExpression(const ExpressionTreeNode& node, map<int, ExpressionTreeNode>& nodeCache) {
     176       25885 :     vector<ExpressionTreeNode> children(node.getChildren().size());
     177       55734 :     for (int i = 0; i < (int) children.size(); i++) {
     178       29849 :         const ExpressionTreeNode& child = node.getChildren()[i];
     179       29849 :         auto cached = nodeCache.find(child.tag);
     180       29849 :         if (cached == nodeCache.end()) {
     181       22584 :             children[i] = substituteSimplerExpression(child, nodeCache);
     182       22584 :             nodeCache[child.tag] = children[i];
     183             :         }
     184             :         else
     185        7265 :             children[i] = cached->second;
     186             :     }
     187             :     
     188             :     // Collect some info on constant expressions in children
     189       25885 :     bool first_const = children.size() > 0 && isConstant(children[0]); // is first child constant?
     190       25885 :     bool second_const = children.size() > 1 && isConstant(children[1]); ; // is second child constant?   
     191             :     double first, second; // if yes, value of first and second child
     192       25885 :     if (first_const)
     193        1723 :         first = getConstantValue(children[0]);
     194       25885 :     if (second_const)
     195        1604 :         second = getConstantValue(children[1]);
     196             : 
     197       25885 :     switch (node.getOperation().getId()) {
     198        2410 :         case Operation::ADD:
     199             :         {
     200        2410 :             if (first_const) {
     201          74 :                 if (first == 0.0) { // Add 0
     202          54 :                     return children[1];
     203             :                 } else { // Add a constant
     204          20 :                     return ExpressionTreeNode(new Operation::AddConstant(first), children[1]);
     205             :                 }
     206             :             }
     207        2336 :             if (second_const) {
     208         354 :                 if (second == 0.0) { // Add 0
     209         104 :                     return children[0];
     210             :                 } else { // Add a constant
     211         250 :                     return ExpressionTreeNode(new Operation::AddConstant(second), children[0]);
     212             :                 }
     213             :             }
     214        1982 :             if (children[1].getOperation().getId() == Operation::NEGATE) // a+(-b) = a-b
     215           2 :                 return ExpressionTreeNode(new Operation::Subtract(), children[0], children[1].getChildren()[0]);
     216        1980 :             if (children[0].getOperation().getId() == Operation::NEGATE) // (-a)+b = b-a
     217           2 :                 return ExpressionTreeNode(new Operation::Subtract(), children[1], children[0].getChildren()[0]);
     218             :             break;
     219             :         }
     220             :         case Operation::SUBTRACT:
     221             :         {
     222        1661 :             if (children[0] == children[1])
     223           2 :                 return ExpressionTreeNode(new Operation::Constant(0.0)); // Subtracting anything from itself is 0
     224        1659 :             if (first_const) {
     225          92 :                 if (first == 0.0) // Subtract from 0
     226           8 :                     return ExpressionTreeNode(new Operation::Negate(), children[1]);
     227             :             }
     228        1651 :             if (second_const) {
     229         147 :                 if (second == 0.0) { // Subtract 0
     230           9 :                     return children[0];
     231             :                 } else { // Subtract a constant
     232         138 :                     return ExpressionTreeNode(new Operation::AddConstant(-second), children[0]);
     233             :                 }
     234             :             }
     235        1504 :             if (children[1].getOperation().getId() == Operation::NEGATE) // a-(-b) = a+b
     236           2 :                 return ExpressionTreeNode(new Operation::Add(), children[0], children[1].getChildren()[0]);
     237             :             break;
     238             :         }
     239        5436 :         case Operation::MULTIPLY:
     240             :         {   
     241        5436 :             if ((first_const && first == 0.0) || (second_const && second == 0.0)) // Multiply by 0
     242         190 :                 return ExpressionTreeNode(new Operation::Constant(0.0));
     243        5246 :             if (first_const && first == 1.0) // Multiply by 1
     244          26 :                 return children[1];
     245        5220 :             if (second_const && second == 1.0) // Multiply by 1
     246         488 :                 return children[0];
     247        4732 :             if (first_const) { // Multiply by a constant
     248        1388 :                 if (children[1].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine two multiplies into a single one
     249          24 :                     return ExpressionTreeNode(new Operation::MultiplyConstant(first*dynamic_cast<const Operation::MultiplyConstant*>(&children[1].getOperation())->getValue()), children[1].getChildren()[0]);
     250        1364 :                 return ExpressionTreeNode(new Operation::MultiplyConstant(first), children[1]);
     251             :             }
     252        3344 :             if (second_const) { // Multiply by a constant
     253          23 :                 if (children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine two multiplies into a single one
     254           1 :                     return ExpressionTreeNode(new Operation::MultiplyConstant(second*dynamic_cast<const Operation::MultiplyConstant*>(&children[0].getOperation())->getValue()), children[0].getChildren()[0]);
     255          22 :                 return ExpressionTreeNode(new Operation::MultiplyConstant(second), children[0]);
     256             :             }
     257        3321 :             if (children[0].getOperation().getId() == Operation::NEGATE && children[1].getOperation().getId() == Operation::NEGATE) // The two negations cancel
     258           0 :                 return ExpressionTreeNode(new Operation::Multiply(), children[0].getChildren()[0], children[1].getChildren()[0]);
     259        3321 :             if (children[0].getOperation().getId() == Operation::NEGATE && children[1].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Negate the constant
     260           0 :                 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]));
     261        3321 :             if (children[1].getOperation().getId() == Operation::NEGATE && children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Negate the constant
     262         192 :                 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]);
     263        3129 :             if (children[0].getOperation().getId() == Operation::NEGATE) // Pull the negation out so it can possibly be optimized further
     264           2 :                 return ExpressionTreeNode(new Operation::Negate(), ExpressionTreeNode(new Operation::Multiply(), children[0].getChildren()[0], children[1]));
     265        3127 :             if (children[1].getOperation().getId() == Operation::NEGATE) // Pull the negation out so it can possibly be optimized further
     266           0 :                 return ExpressionTreeNode(new Operation::Negate(), ExpressionTreeNode(new Operation::Multiply(), children[0], children[1].getChildren()[0]));
     267        3127 :             if (children[1].getOperation().getId() == Operation::RECIPROCAL) // a*(1/b) = a/b
     268           0 :                 return ExpressionTreeNode(new Operation::Divide(), children[0], children[1].getChildren()[0]);
     269        3127 :             if (children[0].getOperation().getId() == Operation::RECIPROCAL) // (1/a)*b = b/a
     270           2 :                 return ExpressionTreeNode(new Operation::Divide(), children[1], children[0].getChildren()[0]);
     271        3125 :             if (children[0] == children[1])
     272         134 :                 return ExpressionTreeNode(new Operation::Square(), children[0]); // x*x = square(x)
     273        2991 :             if (children[0].getOperation().getId() == Operation::SQUARE && children[0].getChildren()[0] == children[1])
     274           2 :                 return ExpressionTreeNode(new Operation::Cube(), children[1]); // x*x*x = cube(x)
     275        2989 :             if (children[1].getOperation().getId() == Operation::SQUARE && children[1].getChildren()[0] == children[0])
     276           0 :                 return ExpressionTreeNode(new Operation::Cube(), children[0]); // x*x*x = cube(x)
     277             :             break;
     278             :         }
     279             :         case Operation::DIVIDE:
     280             :         {
     281         243 :             if (children[0] == children[1])
     282           2 :                 return ExpressionTreeNode(new Operation::Constant(1.0)); // Dividing anything from itself is 0
     283         241 :             if (first_const && first == 0.0) // 0 divided by something
     284           6 :                 return ExpressionTreeNode(new Operation::Constant(0.0));
     285         235 :             if (first_const && first == 1.0) // 1 divided by something
     286          18 :                 return ExpressionTreeNode(new Operation::Reciprocal(), children[1]);
     287         217 :             if (second_const && second == 1.0) // Divide by 1
     288           0 :                 return children[0];
     289         217 :             if (second_const) {
     290          35 :                 if (children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine a multiply and a divide into one multiply
     291           0 :                     return ExpressionTreeNode(new Operation::MultiplyConstant(dynamic_cast<const Operation::MultiplyConstant*>(&children[0].getOperation())->getValue()/second), children[0].getChildren()[0]);
     292          35 :                 return ExpressionTreeNode(new Operation::MultiplyConstant(1.0/second), children[0]); // Replace a divide with a multiply
     293             :             }
     294         182 :             if (children[0].getOperation().getId() == Operation::NEGATE && children[1].getOperation().getId() == Operation::NEGATE) // The two negations cancel
     295           0 :                 return ExpressionTreeNode(new Operation::Divide(), children[0].getChildren()[0], children[1].getChildren()[0]);
     296         182 :             if (children[1].getOperation().getId() == Operation::NEGATE && children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Negate the constant
     297           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]);
     298         182 :             if (children[0].getOperation().getId() == Operation::NEGATE) // Pull the negation out so it can possibly be optimized further
     299          22 :                 return ExpressionTreeNode(new Operation::Negate(), ExpressionTreeNode(new Operation::Divide(), children[0].getChildren()[0], children[1]));
     300         160 :             if (children[1].getOperation().getId() == Operation::NEGATE) // Pull the negation out so it can possibly be optimized further
     301           0 :                 return ExpressionTreeNode(new Operation::Negate(), ExpressionTreeNode(new Operation::Divide(), children[0], children[1].getChildren()[0]));
     302         160 :             if (children[1].getOperation().getId() == Operation::RECIPROCAL) // a/(1/b) = a*b
     303           2 :                 return ExpressionTreeNode(new Operation::Multiply(), children[0], children[1].getChildren()[0]);
     304             :             break;
     305             :         }
     306         329 :         case Operation::POWER:
     307             :         {
     308         329 :             if (first_const && first == 0.0) // 0 to any power is 0
     309           6 :                 return ExpressionTreeNode(new Operation::Constant(0.0));
     310         323 :             if (first_const && first == 1.0) // 1 to any power is 1
     311           6 :                 return ExpressionTreeNode(new Operation::Constant(1.0));
     312         317 :             if (second_const) { // Constant exponent
     313         305 :                 if (second == 0.0) // x^0 = 1
     314           0 :                     return ExpressionTreeNode(new Operation::Constant(1.0));
     315         305 :                 if (second == 1.0) // x^1 = x
     316          59 :                     return children[0];
     317         246 :                 if (second == -1.0) // x^-1 = recip(x)
     318           0 :                     return ExpressionTreeNode(new Operation::Reciprocal(), children[0]);
     319         246 :                 if (second == 2.0) // x^2 = square(x)
     320         124 :                     return ExpressionTreeNode(new Operation::Square(), children[0]);
     321         122 :                 if (second == 3.0) // x^3 = cube(x)
     322          46 :                     return ExpressionTreeNode(new Operation::Cube(), children[0]);
     323          76 :                 if (second == 0.5) // x^0.5 = sqrt(x)
     324           7 :                     return ExpressionTreeNode(new Operation::Sqrt(), children[0]);
     325             :                 // Constant power
     326          69 :                 return ExpressionTreeNode(new Operation::PowerConstant(second), children[0]);
     327             :             }
     328             :             break;
     329             :         }
     330             :         case Operation::NEGATE:
     331             :         {
     332         648 :             if (children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine a multiply and a negate into a single multiply
     333          10 :                 return ExpressionTreeNode(new Operation::MultiplyConstant(-dynamic_cast<const Operation::MultiplyConstant*>(&children[0].getOperation())->getValue()), children[0].getChildren()[0]);
     334         638 :             if (first_const) // Negate a constant
     335           0 :                 return ExpressionTreeNode(new Operation::Constant(-first));
     336         638 :             if (children[0].getOperation().getId() == Operation::NEGATE) // The two negations cancel
     337           0 :                 return children[0].getChildren()[0];
     338             :             break;
     339             :         }
     340             :         case Operation::MULTIPLY_CONSTANT:
     341             :         {
     342        3644 :             if (children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine two multiplies into a single one
     343           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]);
     344        3644 :             if (first_const) // Multiply two constants
     345           0 :                 return ExpressionTreeNode(new Operation::Constant(dynamic_cast<const Operation::MultiplyConstant*>(&node.getOperation())->getValue()*getConstantValue(children[0])));
     346        3644 :             if (children[0].getOperation().getId() == Operation::NEGATE) // Combine a multiply and a negate into a single multiply
     347         439 :                 return ExpressionTreeNode(new Operation::MultiplyConstant(-dynamic_cast<const Operation::MultiplyConstant*>(&node.getOperation())->getValue()), children[0].getChildren()[0]);
     348             :             break;
     349             :         }
     350             :         case Operation::SQRT:
     351             :         {
     352         221 :             if (children[0].getOperation().getId() == Operation::SQUARE) // sqrt(square(x)) = abs(x)
     353           4 :                 return ExpressionTreeNode(new Operation::Abs(), children[0].getChildren()[0]);
     354             :         }
     355             :         case Operation::SQUARE:
     356             :         {
     357         875 :             if (children[0].getOperation().getId() == Operation::SQRT) // square(sqrt(x)) = x
     358          27 :                 return children[0].getChildren()[0];
     359             :         }
     360             :         default:
     361             :         {
     362             :             // If operation ID is not one of the above,
     363             :             // we don't substitute a simpler expression.
     364             :             break;
     365             :         }
     366             : 
     367             :     }
     368       21965 :     return ExpressionTreeNode(node.getOperation().clone(), children);
     369       25885 : }
     370             : 
     371         596 : ParsedExpression ParsedExpression::differentiate(const string& variable) const {
     372             :     vector<const ExpressionTreeNode*> examples;
     373         596 :     getRootNode().assignTags(examples);
     374             :     map<int, ExpressionTreeNode> nodeCache;
     375        1192 :     return differentiate(getRootNode(), variable, nodeCache);
     376             : }
     377             : 
     378        5816 : ExpressionTreeNode ParsedExpression::differentiate(const ExpressionTreeNode& node, const string& variable, map<int, ExpressionTreeNode>& nodeCache) {
     379        5816 :     auto cached = nodeCache.find(node.tag);
     380        5816 :     if (cached != nodeCache.end())
     381         785 :         return cached->second;
     382        5031 :     vector<ExpressionTreeNode> childDerivs(node.getChildren().size());
     383       10251 :     for (int i = 0; i < (int) childDerivs.size(); i++)
     384        5220 :         childDerivs[i] = differentiate(node.getChildren()[i], variable, nodeCache);
     385        5031 :     ExpressionTreeNode result = node.getOperation().differentiate(node.getChildren(), childDerivs, variable);
     386        5031 :     nodeCache[node.tag] = result;
     387        5031 :     return result;
     388        5031 : }
     389             : 
     390       29817 : bool ParsedExpression::isConstant(const ExpressionTreeNode& node) {
     391       29817 :     return (node.getOperation().getId() == Operation::CONSTANT);
     392             : }
     393             : 
     394        3327 : double ParsedExpression::getConstantValue(const ExpressionTreeNode& node) {
     395        3327 :     if (node.getOperation().getId() != Operation::CONSTANT) {
     396           0 :         throw Exception("getConstantValue called on a non-constant ExpressionNode");
     397             :     }
     398        3327 :     return dynamic_cast<const Operation::Constant&>(node.getOperation()).getValue();
     399             : }
     400             : 
     401           0 : ExpressionProgram ParsedExpression::createProgram() const {
     402           0 :     return ExpressionProgram(*this);
     403             : }
     404             : 
     405        1134 : CompiledExpression ParsedExpression::createCompiledExpression() const {
     406        1134 :     return CompiledExpression(*this);
     407             : }
     408             : 
     409           0 : ParsedExpression ParsedExpression::renameVariables(const map<string, string>& replacements) const {
     410           0 :     return ParsedExpression(renameNodeVariables(getRootNode(), replacements));
     411             : }
     412             : 
     413           0 : ExpressionTreeNode ParsedExpression::renameNodeVariables(const ExpressionTreeNode& node, const map<string, string>& replacements) {
     414           0 :     if (node.getOperation().getId() == Operation::VARIABLE) {
     415           0 :         map<string, string>::const_iterator replace = replacements.find(node.getOperation().getName());
     416           0 :         if (replace != replacements.end())
     417           0 :             return ExpressionTreeNode(new Operation::Variable(replace->second));
     418             :     }
     419             :     vector<ExpressionTreeNode> children;
     420           0 :     for (int i = 0; i < (int) node.getChildren().size(); i++)
     421           0 :         children.push_back(renameNodeVariables(node.getChildren()[i], replacements));
     422           0 :     return ExpressionTreeNode(node.getOperation().clone(), children);
     423           0 : }
     424             : 
     425        9929 : ostream& lepton::operator<<(ostream& out, const ExpressionTreeNode& node) {
     426        9929 :     if (node.getOperation().isInfixOperator() && node.getChildren().size() == 2) {
     427        5811 :         out << "(" << node.getChildren()[0] << ")" << node.getOperation().getName() << "(" << node.getChildren()[1] << ")";
     428             :     }
     429        7992 :     else if (node.getOperation().isInfixOperator() && node.getChildren().size() == 1) {
     430          74 :         out << "(" << node.getChildren()[0] << ")" << node.getOperation().getName();
     431             :     }
     432             :     else {
     433        7955 :         out << node.getOperation().getName();
     434        7955 :         if (node.getChildren().size() > 0) {
     435        4884 :             out << "(";
     436        9816 :             for (int i = 0; i < (int) node.getChildren().size(); i++) {
     437        4932 :                 if (i > 0)
     438          48 :                     out << ", ";
     439        4932 :                 out << node.getChildren()[i];
     440             :             }
     441        4884 :             out << ")";
     442             :         }
     443             :     }
     444        9929 :     return out;
     445             : }
     446             : 
     447        1086 : ostream& lepton::operator<<(ostream& out, const ParsedExpression& exp) {
     448        1086 :     out << exp.getRootNode();
     449        1086 :     return out;
     450             : }
     451             : }

Generated by: LCOV version 1.15