LCOV - code coverage report
Current view: top level - lepton - ParsedExpression.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 230 257 89.5 %
Date: 2024-10-18 14:00:27 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     2045990 : ParsedExpression::ParsedExpression(const ExpressionTreeNode& rootNode) : rootNode(rootNode) {
      79     2045990 : }
      80             : 
      81     2067359 : const ExpressionTreeNode& ParsedExpression::getRootNode() const {
      82     2067359 :     if (&rootNode.getOperation() == NULL)
      83           0 :         throw Exception("Illegal call to an initialized ParsedExpression");
      84     2067359 :     return rootNode;
      85             : }
      86             : 
      87           0 : double ParsedExpression::evaluate() const {
      88           0 :     return evaluate(getRootNode(), map<string, double>());
      89             : }
      90             : 
      91     2008077 : double ParsedExpression::evaluate(const map<string, double>& variables) const {
      92     2008077 :     return evaluate(getRootNode(), variables);
      93             : }
      94             : 
      95     2036880 : double ParsedExpression::evaluate(const ExpressionTreeNode& node, const map<string, double>& variables) {
      96     2036880 :     int numArgs = (int) node.getChildren().size();
      97     4068833 :     vector<double> args(max(numArgs, 1));
      98     2044496 :     for (int i = 0; i < numArgs; i++)
      99        7621 :         args[i] = evaluate(node.getChildren()[i], variables);
     100     4073728 :     return node.getOperation().evaluate(&args[0], variables);
     101             : }
     102             : 
     103       16338 : ParsedExpression ParsedExpression::optimize() const {
     104       16338 :     ExpressionTreeNode result = getRootNode();
     105             :     vector<const ExpressionTreeNode*> examples;
     106       16338 :     result.assignTags(examples);
     107             :     map<int, ExpressionTreeNode> nodeCache;
     108       16338 :     result = precalculateConstantSubexpressions(result, nodeCache);
     109             :     while (true) {
     110             :         examples.clear();
     111       16338 :         result.assignTags(examples);
     112             :         nodeCache.clear();
     113       16338 :         ExpressionTreeNode simplified = substituteSimplerExpression(result, nodeCache);
     114       16338 :         if (simplified == result)
     115             :             break;
     116           0 :         result = simplified;
     117       16338 :     }
     118       32676 :     return ParsedExpression(result);
     119       16338 : }
     120             : 
     121        8253 : ParsedExpression ParsedExpression::optimize(const map<string, double>& variables) const {
     122        8253 :     ExpressionTreeNode result = preevaluateVariables(getRootNode(), variables);
     123             :     vector<const ExpressionTreeNode*> examples;
     124        8253 :     result.assignTags(examples);
     125             :     map<int, ExpressionTreeNode> nodeCache;
     126        8253 :     result = precalculateConstantSubexpressions(result, nodeCache);
     127             :     while (true) {
     128             :         examples.clear();
     129       14693 :         result.assignTags(examples);
     130             :         nodeCache.clear();
     131       14693 :         ExpressionTreeNode simplified = substituteSimplerExpression(result, nodeCache);
     132       14693 :         if (simplified == result)
     133             :             break;
     134        6440 :         result = simplified;
     135       14693 :     }
     136       16506 :     return ParsedExpression(result);
     137        8253 : }
     138             : 
     139      179165 : ExpressionTreeNode ParsedExpression::preevaluateVariables(const ExpressionTreeNode& node, const map<string, double>& variables) {
     140      179165 :     if (node.getOperation().getId() == Operation::VARIABLE) {
     141       31256 :         const Operation::Variable& var = dynamic_cast<const Operation::Variable&>(node.getOperation());
     142       62512 :         map<string, double>::const_iterator iter = variables.find(var.getName());
     143       31256 :         if (iter == variables.end())
     144       29828 :             return node;
     145        1428 :         return ExpressionTreeNode(new Operation::Constant(iter->second));
     146             :     }
     147      147909 :     vector<ExpressionTreeNode> children(node.getChildren().size());
     148      318821 :     for (int i = 0; i < (int) children.size(); i++)
     149      170912 :         children[i] = preevaluateVariables(node.getChildren()[i], variables);
     150      147909 :     return ExpressionTreeNode(node.getOperation().clone(), children);
     151      147909 : }
     152             : 
     153      211109 : ExpressionTreeNode ParsedExpression::precalculateConstantSubexpressions(const ExpressionTreeNode& node, map<int, ExpressionTreeNode>& nodeCache) {
     154      211109 :     auto cached = nodeCache.find(node.tag);
     155      211109 :     if (cached != nodeCache.end())
     156       40949 :         return cached->second;
     157      170160 :     vector<ExpressionTreeNode> children(node.getChildren().size());
     158      356678 :     for (int i = 0; i < (int) children.size(); i++)
     159      186518 :         children[i] = precalculateConstantSubexpressions(node.getChildren()[i], nodeCache);
     160      170160 :     ExpressionTreeNode result = ExpressionTreeNode(node.getOperation().clone(), children);
     161      170160 :     if (node.getOperation().getId() == Operation::VARIABLE || node.getOperation().getId() == Operation::CUSTOM) {
     162       34493 :         nodeCache[node.tag] = result;
     163       34493 :         return result;
     164             :     }
     165      152059 :     for (int i = 0; i < (int) children.size(); i++)
     166      130877 :         if (children[i].getOperation().getId() != Operation::CONSTANT) {
     167      114485 :             nodeCache[node.tag] = result;
     168      114485 :             return result;
     169             :         }
     170       21182 :     result = ExpressionTreeNode(new Operation::Constant(evaluate(result, map<string, double>())));
     171       21182 :     nodeCache[node.tag] = result;
     172       21182 :     return result;
     173      170160 : }
     174             : 
     175      219567 : ExpressionTreeNode ParsedExpression::substituteSimplerExpression(const ExpressionTreeNode& node, map<int, ExpressionTreeNode>& nodeCache) {
     176      219567 :     vector<ExpressionTreeNode> children(node.getChildren().size());
     177      460039 :     for (int i = 0; i < (int) children.size(); i++) {
     178      240472 :         const ExpressionTreeNode& child = node.getChildren()[i];
     179      240472 :         auto cached = nodeCache.find(child.tag);
     180      240472 :         if (cached == nodeCache.end()) {
     181      188536 :             children[i] = substituteSimplerExpression(child, nodeCache);
     182      188536 :             nodeCache[child.tag] = children[i];
     183             :         }
     184             :         else
     185       51936 :             children[i] = cached->second;
     186             :     }
     187             :     
     188             :     // Collect some info on constant expressions in children
     189      219567 :     bool first_const = children.size() > 0 && isConstant(children[0]); // is first child constant?
     190      219567 :     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      219567 :     if (first_const)
     193       11334 :         first = getConstantValue(children[0]);
     194      219567 :     if (second_const)
     195       18748 :         second = getConstantValue(children[1]);
     196             : 
     197      219567 :     switch (node.getOperation().getId()) {
     198       25454 :         case Operation::ADD:
     199             :         {
     200       25454 :             if (first_const) {
     201        1770 :                 if (first == 0.0) { // Add 0
     202        1673 :                     return children[1];
     203             :                 } else { // Add a constant
     204          97 :                     return ExpressionTreeNode(new Operation::AddConstant(first), children[1]);
     205             :                 }
     206             :             }
     207       23684 :             if (second_const) {
     208        1344 :                 if (second == 0.0) { // Add 0
     209        1067 :                     return children[0];
     210             :                 } else { // Add a constant
     211         277 :                     return ExpressionTreeNode(new Operation::AddConstant(second), children[0]);
     212             :                 }
     213             :             }
     214       22340 :             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       22338 :             if (children[0].getOperation().getId() == Operation::NEGATE) // (-a)+b = b-a
     217          23 :                 return ExpressionTreeNode(new Operation::Subtract(), children[1], children[0].getChildren()[0]);
     218             :             break;
     219             :         }
     220             :         case Operation::SUBTRACT:
     221             :         {
     222        6477 :             if (children[0] == children[1])
     223           2 :                 return ExpressionTreeNode(new Operation::Constant(0.0)); // Subtracting anything from itself is 0
     224        6475 :             if (first_const) {
     225        1673 :                 if (first == 0.0) // Subtract from 0
     226          28 :                     return ExpressionTreeNode(new Operation::Negate(), children[1]);
     227             :             }
     228        6447 :             if (second_const) {
     229        1687 :                 if (second == 0.0) { // Subtract 0
     230         243 :                     return children[0];
     231             :                 } else { // Subtract a constant
     232        1444 :                     return ExpressionTreeNode(new Operation::AddConstant(-second), children[0]);
     233             :                 }
     234             :             }
     235        4760 :             if (children[1].getOperation().getId() == Operation::NEGATE) // a-(-b) = a+b
     236           3 :                 return ExpressionTreeNode(new Operation::Add(), children[0], children[1].getChildren()[0]);
     237             :             break;
     238             :         }
     239       31793 :         case Operation::MULTIPLY:
     240             :         {   
     241       31793 :             if ((first_const && first == 0.0) || (second_const && second == 0.0)) // Multiply by 0
     242        3170 :                 return ExpressionTreeNode(new Operation::Constant(0.0));
     243       28623 :             if (first_const && first == 1.0) // Multiply by 1
     244          30 :                 return children[1];
     245       28593 :             if (second_const && second == 1.0) // Multiply by 1
     246        4295 :                 return children[0];
     247       24298 :             if (first_const) { // Multiply by a constant
     248        6061 :                 if (children[1].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine two multiplies into a single one
     249         791 :                     return ExpressionTreeNode(new Operation::MultiplyConstant(first*dynamic_cast<const Operation::MultiplyConstant*>(&children[1].getOperation())->getValue()), children[1].getChildren()[0]);
     250        5270 :                 return ExpressionTreeNode(new Operation::MultiplyConstant(first), children[1]);
     251             :             }
     252       18237 :             if (second_const) { // Multiply by a constant
     253        1397 :                 if (children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine two multiplies into a single one
     254         292 :                     return ExpressionTreeNode(new Operation::MultiplyConstant(second*dynamic_cast<const Operation::MultiplyConstant*>(&children[0].getOperation())->getValue()), children[0].getChildren()[0]);
     255        1105 :                 return ExpressionTreeNode(new Operation::MultiplyConstant(second), children[0]);
     256             :             }
     257       16840 :             if (children[0].getOperation().getId() == Operation::NEGATE && children[1].getOperation().getId() == Operation::NEGATE) // The two negations cancel
     258           2 :                 return ExpressionTreeNode(new Operation::Multiply(), children[0].getChildren()[0], children[1].getChildren()[0]);
     259       16838 :             if (children[0].getOperation().getId() == Operation::NEGATE && children[1].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Negate the constant
     260           2 :                 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       16836 :             if (children[1].getOperation().getId() == Operation::NEGATE && children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Negate the constant
     262         215 :                 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       16621 :             if (children[0].getOperation().getId() == Operation::NEGATE) // Pull the negation out so it can possibly be optimized further
     264         104 :                 return ExpressionTreeNode(new Operation::Negate(), ExpressionTreeNode(new Operation::Multiply(), children[0].getChildren()[0], children[1]));
     265       16517 :             if (children[1].getOperation().getId() == Operation::NEGATE) // Pull the negation out so it can possibly be optimized further
     266          10 :                 return ExpressionTreeNode(new Operation::Negate(), ExpressionTreeNode(new Operation::Multiply(), children[0], children[1].getChildren()[0]));
     267       16507 :             if (children[1].getOperation().getId() == Operation::RECIPROCAL) // a*(1/b) = a/b
     268          89 :                 return ExpressionTreeNode(new Operation::Divide(), children[0], children[1].getChildren()[0]);
     269       16418 :             if (children[0].getOperation().getId() == Operation::RECIPROCAL) // (1/a)*b = b/a
     270          32 :                 return ExpressionTreeNode(new Operation::Divide(), children[1], children[0].getChildren()[0]);
     271       16386 :             if (children[0] == children[1])
     272         589 :                 return ExpressionTreeNode(new Operation::Square(), children[0]); // x*x = square(x)
     273       15797 :             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       15795 :             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       13665 :             if (children[0] == children[1])
     282           2 :                 return ExpressionTreeNode(new Operation::Constant(1.0)); // Dividing anything from itself is 0
     283       13663 :             if (first_const && first == 0.0) // 0 divided by something
     284         212 :                 return ExpressionTreeNode(new Operation::Constant(0.0));
     285       13451 :             if (first_const && first == 1.0) // 1 divided by something
     286         232 :                 return ExpressionTreeNode(new Operation::Reciprocal(), children[1]);
     287       13219 :             if (second_const && second == 1.0) // Divide by 1
     288          11 :                 return children[0];
     289       13208 :             if (second_const) {
     290        2012 :                 if (children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine a multiply and a divide into one multiply
     291         769 :                     return ExpressionTreeNode(new Operation::MultiplyConstant(dynamic_cast<const Operation::MultiplyConstant*>(&children[0].getOperation())->getValue()/second), children[0].getChildren()[0]);
     292        1243 :                 return ExpressionTreeNode(new Operation::MultiplyConstant(1.0/second), children[0]); // Replace a divide with a multiply
     293             :             }
     294       11196 :             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       11196 :             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       11196 :             if (children[0].getOperation().getId() == Operation::NEGATE) // Pull the negation out so it can possibly be optimized further
     299         721 :                 return ExpressionTreeNode(new Operation::Negate(), ExpressionTreeNode(new Operation::Divide(), children[0].getChildren()[0], children[1]));
     300       10475 :             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       10475 :             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        3225 :         case Operation::POWER:
     307             :         {
     308        3225 :             if (first_const && first == 0.0) // 0 to any power is 0
     309           6 :                 return ExpressionTreeNode(new Operation::Constant(0.0));
     310        3219 :             if (first_const && first == 1.0) // 1 to any power is 1
     311           6 :                 return ExpressionTreeNode(new Operation::Constant(1.0));
     312        3213 :             if (second_const) { // Constant exponent
     313        3197 :                 if (second == 0.0) // x^0 = 1
     314           4 :                     return ExpressionTreeNode(new Operation::Constant(1.0));
     315        3193 :                 if (second == 1.0) // x^1 = x
     316        1258 :                     return children[0];
     317        1935 :                 if (second == -1.0) // x^-1 = recip(x)
     318           0 :                     return ExpressionTreeNode(new Operation::Reciprocal(), children[0]);
     319        1935 :                 if (second == 2.0) // x^2 = square(x)
     320        1674 :                     return ExpressionTreeNode(new Operation::Square(), children[0]);
     321         261 :                 if (second == 3.0) // x^3 = cube(x)
     322         139 :                     return ExpressionTreeNode(new Operation::Cube(), children[0]);
     323         122 :                 if (second == 0.5) // x^0.5 = sqrt(x)
     324           7 :                     return ExpressionTreeNode(new Operation::Sqrt(), children[0]);
     325             :                 // Constant power
     326         115 :                 return ExpressionTreeNode(new Operation::PowerConstant(second), children[0]);
     327             :             }
     328             :             break;
     329             :         }
     330             :         case Operation::NEGATE:
     331             :         {
     332        6886 :             if (children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine a multiply and a negate into a single multiply
     333         626 :                 return ExpressionTreeNode(new Operation::MultiplyConstant(-dynamic_cast<const Operation::MultiplyConstant*>(&children[0].getOperation())->getValue()), children[0].getChildren()[0]);
     334        6260 :             if (first_const) // Negate a constant
     335         208 :                 return ExpressionTreeNode(new Operation::Constant(-first));
     336        6052 :             if (children[0].getOperation().getId() == Operation::NEGATE) // The two negations cancel
     337           8 :                 return children[0].getChildren()[0];
     338             :             break;
     339             :         }
     340             :         case Operation::MULTIPLY_CONSTANT:
     341             :         {
     342       25217 :             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       25217 :             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       25217 :             if (children[0].getOperation().getId() == Operation::NEGATE) // Combine a multiply and a negate into a single multiply
     347        1745 :                 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        2629 :             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       18621 :             if (children[0].getOperation().getId() == Operation::SQRT) // square(sqrt(x)) = x
     358          45 :                 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      189673 :     return ExpressionTreeNode(node.getOperation().clone(), children);
     369      219567 : }
     370             : 
     371        5069 : ParsedExpression ParsedExpression::differentiate(const string& variable) const {
     372             :     vector<const ExpressionTreeNode*> examples;
     373        5069 :     getRootNode().assignTags(examples);
     374             :     map<int, ExpressionTreeNode> nodeCache;
     375       10138 :     return differentiate(getRootNode(), variable, nodeCache);
     376             : }
     377             : 
     378       43486 : ExpressionTreeNode ParsedExpression::differentiate(const ExpressionTreeNode& node, const string& variable, map<int, ExpressionTreeNode>& nodeCache) {
     379       43486 :     auto cached = nodeCache.find(node.tag);
     380       43486 :     if (cached != nodeCache.end())
     381        6206 :         return cached->second;
     382       37280 :     vector<ExpressionTreeNode> childDerivs(node.getChildren().size());
     383       75697 :     for (int i = 0; i < (int) childDerivs.size(); i++)
     384       38417 :         childDerivs[i] = differentiate(node.getChildren()[i], variable, nodeCache);
     385       37280 :     ExpressionTreeNode result = node.getOperation().differentiate(node.getChildren(), childDerivs, variable);
     386       37280 :     nodeCache[node.tag] = result;
     387       37280 :     return result;
     388       37280 : }
     389             : 
     390      240396 : bool ParsedExpression::isConstant(const ExpressionTreeNode& node) {
     391      240396 :     return (node.getOperation().getId() == Operation::CONSTANT);
     392             : }
     393             : 
     394       30082 : double ParsedExpression::getConstantValue(const ExpressionTreeNode& node) {
     395       30082 :     if (node.getOperation().getId() != Operation::CONSTANT) {
     396           0 :         throw Exception("getConstantValue called on a non-constant ExpressionNode");
     397             :     }
     398       30082 :     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       16338 : CompiledExpression ParsedExpression::createCompiledExpression() const {
     406       16338 :     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       63410 : ostream& lepton::operator<<(ostream& out, const ExpressionTreeNode& node) {
     426       63410 :     if (node.getOperation().isInfixOperator() && node.getChildren().size() == 2) {
     427       41592 :         out << "(" << node.getChildren()[0] << ")" << node.getOperation().getName() << "(" << node.getChildren()[1] << ")";
     428             :     }
     429       49546 :     else if (node.getOperation().isInfixOperator() && node.getChildren().size() == 1) {
     430         138 :         out << "(" << node.getChildren()[0] << ")" << node.getOperation().getName();
     431             :     }
     432             :     else {
     433       49477 :         out << node.getOperation().getName();
     434       49477 :         if (node.getChildren().size() > 0) {
     435       27312 :             out << "(";
     436       54710 :             for (int i = 0; i < (int) node.getChildren().size(); i++) {
     437       27398 :                 if (i > 0)
     438          86 :                     out << ", ";
     439       27398 :                 out << node.getChildren()[i];
     440             :             }
     441       27312 :             out << ")";
     442             :         }
     443             :     }
     444       63410 :     return out;
     445             : }
     446             : 
     447        8215 : ostream& lepton::operator<<(ostream& out, const ParsedExpression& exp) {
     448        8215 :     out << exp.getRootNode();
     449        8215 :     return out;
     450             : }
     451             : }

Generated by: LCOV version 1.16