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