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