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