ParsedExpression.cpp 23.8 KB
Newer Older
1
2
3
4
5
6
7
8
/* -------------------------------------------------------------------------- *
 *                                   Lepton                                   *
 * -------------------------------------------------------------------------- *
 * This is part of the Lepton expression parser originating from              *
 * Simbios, the NIH National Center for Physics-Based Simulation of           *
 * Biological Structures at Stanford, funded under the NIH Roadmap for        *
 * Medical Research, grant U54 GM072970. See https://simtk.org.               *
 *                                                                            *
9
 * Portions copyright (c) 2009-2022 Stanford University and the Authors.      *
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 * Authors: Peter Eastman                                                     *
 * Contributors:                                                              *
 *                                                                            *
 * Permission is hereby granted, free of charge, to any person obtaining a    *
 * copy of this software and associated documentation files (the "Software"), *
 * to deal in the Software without restriction, including without limitation  *
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
 * and/or sell copies of the Software, and to permit persons to whom the      *
 * Software is furnished to do so, subject to the following conditions:       *
 *                                                                            *
 * The above copyright notice and this permission notice shall be included in *
 * all copies or substantial portions of the Software.                        *
 *                                                                            *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
 * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,    *
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR      *
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  *
 * USE OR OTHER DEALINGS IN THE SOFTWARE.                                     *
 * -------------------------------------------------------------------------- */

32
#include "lepton/ParsedExpression.h"
33
#include "lepton/CompiledExpression.h"
34
#include "lepton/CompiledVectorExpression.h"
35
36
#include "lepton/ExpressionProgram.h"
#include "lepton/Operation.h"
37
#include <limits>
38
39
40
41
42
#include <vector>

using namespace Lepton;
using namespace std;

43
44
45
ParsedExpression::ParsedExpression() : rootNode(ExpressionTreeNode()) {
}

Peter Eastman's avatar
Peter Eastman committed
46
ParsedExpression::ParsedExpression(const ExpressionTreeNode& rootNode) : rootNode(rootNode) {
47
48
49
}

const ExpressionTreeNode& ParsedExpression::getRootNode() const {
50
51
    if (&rootNode.getOperation() == NULL)
        throw Exception("Illegal call to an initialized ParsedExpression");
52
53
54
55
    return rootNode;
}

double ParsedExpression::evaluate() const {
56
    return evaluate(getRootNode(), map<string, double>());
57
58
}

59
double ParsedExpression::evaluate(const map<string, double>& variables) const {
60
    return evaluate(getRootNode(), variables);
61
62
}

63
double ParsedExpression::evaluate(const ExpressionTreeNode& node, const map<string, double>& variables) {
64
    int numArgs = (int) node.getChildren().size();
65
66
    vector<double> args(max(numArgs, 1));
    for (int i = 0; i < numArgs; i++)
67
68
69
        args[i] = evaluate(node.getChildren()[i], variables);
    return node.getOperation().evaluate(&args[0], variables);
}
70
71

ParsedExpression ParsedExpression::optimize() const {
72
73
74
75
76
    ExpressionTreeNode result = getRootNode();
    vector<const ExpressionTreeNode*> examples;
    result.assignTags(examples);
    map<int, ExpressionTreeNode> nodeCache;
    result = precalculateConstantSubexpressions(result, nodeCache);
Peter Eastman's avatar
Peter Eastman committed
77
    while (true) {
78
79
80
81
        examples.clear();
        result.assignTags(examples);
        nodeCache.clear();
        ExpressionTreeNode simplified = substituteSimplerExpression(result, nodeCache);
Peter Eastman's avatar
Peter Eastman committed
82
83
84
85
        if (simplified == result)
            break;
        result = simplified;
    }
86
    return ParsedExpression(result);
87
88
89
}

ParsedExpression ParsedExpression::optimize(const map<string, double>& variables) const {
90
    ExpressionTreeNode result = preevaluateVariables(getRootNode(), variables);
91
92
93
94
    vector<const ExpressionTreeNode*> examples;
    result.assignTags(examples);
    map<int, ExpressionTreeNode> nodeCache;
    result = precalculateConstantSubexpressions(result, nodeCache);
Peter Eastman's avatar
Peter Eastman committed
95
    while (true) {
96
97
98
99
        examples.clear();
        result.assignTags(examples);
        nodeCache.clear();
        ExpressionTreeNode simplified = substituteSimplerExpression(result, nodeCache);
Peter Eastman's avatar
Peter Eastman committed
100
101
102
103
        if (simplified == result)
            break;
        result = simplified;
    }
104
    return ParsedExpression(result);
105
106
107
108
109
110
111
112
113
114
115
}

ExpressionTreeNode ParsedExpression::preevaluateVariables(const ExpressionTreeNode& node, const map<string, double>& variables) {
    if (node.getOperation().getId() == Operation::VARIABLE) {
        const Operation::Variable& var = dynamic_cast<const Operation::Variable&>(node.getOperation());
        map<string, double>::const_iterator iter = variables.find(var.getName());
        if (iter == variables.end())
            return node;
        return ExpressionTreeNode(new Operation::Constant(iter->second));
    }
    vector<ExpressionTreeNode> children(node.getChildren().size());
116
    for (int i = 0; i < (int) children.size(); i++)
117
118
119
120
        children[i] = preevaluateVariables(node.getChildren()[i], variables);
    return ExpressionTreeNode(node.getOperation().clone(), children);
}

121
122
123
124
ExpressionTreeNode ParsedExpression::precalculateConstantSubexpressions(const ExpressionTreeNode& node, map<int, ExpressionTreeNode>& nodeCache) {
    auto cached = nodeCache.find(node.tag);
    if (cached != nodeCache.end())
        return cached->second;
125
    vector<ExpressionTreeNode> children(node.getChildren().size());
126
    for (int i = 0; i < (int) children.size(); i++)
127
        children[i] = precalculateConstantSubexpressions(node.getChildren()[i], nodeCache);
128
    ExpressionTreeNode result = ExpressionTreeNode(node.getOperation().clone(), children);
129
130
    if (node.getOperation().getId() == Operation::VARIABLE || node.getOperation().getId() == Operation::CUSTOM) {
        nodeCache[node.tag] = result;
131
        return result;
132
    }
133
    for (int i = 0; i < (int) children.size(); i++)
134
135
        if (children[i].getOperation().getId() != Operation::CONSTANT) {
            nodeCache[node.tag] = result;
136
            return result;
137
138
139
140
        }
    result = ExpressionTreeNode(new Operation::Constant(evaluate(result, map<string, double>())));
    nodeCache[node.tag] = result;
    return result;
141
142
}

143
ExpressionTreeNode ParsedExpression::substituteSimplerExpression(const ExpressionTreeNode& node, map<int, ExpressionTreeNode>& nodeCache) {
144
    vector<ExpressionTreeNode> children(node.getChildren().size());
145
146
147
148
149
150
151
152
153
154
    for (int i = 0; i < (int) children.size(); i++) {
        const ExpressionTreeNode& child = node.getChildren()[i];
        auto cached = nodeCache.find(child.tag);
        if (cached == nodeCache.end()) {
            children[i] = substituteSimplerExpression(child, nodeCache);
            nodeCache[child.tag] = children[i];
        }
        else
            children[i] = cached->second;
    }
155

156
157
    // Collect some info on constant expressions in children
    bool first_const = children.size() > 0 && isConstant(children[0]); // is first child constant?
158
    bool second_const = children.size() > 1 && isConstant(children[1]); // is second child constant?
159
160
161
162
163
164
    double first, second; // if yes, value of first and second child
    if (first_const)
        first = getConstantValue(children[0]);
    if (second_const)
        second = getConstantValue(children[1]);

165
    switch (node.getOperation().getId()) {
166
        case Operation::ADD:
Peter Eastman's avatar
Peter Eastman committed
167
        {
168
169
170
171
172
173
174
175
176
177
178
179
180
181
            if (first_const) {
                if (first == 0.0) { // Add 0
                    return children[1];
                } else { // Add a constant
                    return ExpressionTreeNode(new Operation::AddConstant(first), children[1]);
                }
            }
            if (second_const) {
                if (second == 0.0) { // Add 0
                    return children[0];
                } else { // Add a constant
                    return ExpressionTreeNode(new Operation::AddConstant(second), children[0]);
                }
            }
182
183
184
185
            if (children[1].getOperation().getId() == Operation::NEGATE) // a+(-b) = a-b
                return ExpressionTreeNode(new Operation::Subtract(), children[0], children[1].getChildren()[0]);
            if (children[0].getOperation().getId() == Operation::NEGATE) // (-a)+b = b-a
                return ExpressionTreeNode(new Operation::Subtract(), children[1], children[0].getChildren()[0]);
186
            break;
Peter Eastman's avatar
Peter Eastman committed
187
        }
188
        case Operation::SUBTRACT:
Peter Eastman's avatar
Peter Eastman committed
189
        {
190
191
            if (children[0] == children[1])
                return ExpressionTreeNode(new Operation::Constant(0.0)); // Subtracting anything from itself is 0
192
193
194
195
196
197
198
199
200
201
202
            if (first_const) {
                if (first == 0.0) // Subtract from 0
                    return ExpressionTreeNode(new Operation::Negate(), children[1]);
            }
            if (second_const) {
                if (second == 0.0) { // Subtract 0
                    return children[0];
                } else { // Subtract a constant
                    return ExpressionTreeNode(new Operation::AddConstant(-second), children[0]);
                }
            }
203
204
            if (children[1].getOperation().getId() == Operation::NEGATE) // a-(-b) = a+b
                return ExpressionTreeNode(new Operation::Add(), children[0], children[1].getChildren()[0]);
205
            break;
Peter Eastman's avatar
Peter Eastman committed
206
        }
207
        case Operation::MULTIPLY:
208
        {
209
            if ((first_const && first == 0.0) || (second_const && second == 0.0)) // Multiply by 0
210
                return ExpressionTreeNode(new Operation::Constant(0.0));
211
            if (first_const && first == 1.0) // Multiply by 1
212
                return children[1];
213
            if (second_const && second == 1.0) // Multiply by 1
214
                return children[0];
215
            if (first_const) { // Multiply by a constant
216
217
218
                if (children[1].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine two multiplies into a single one
                    return ExpressionTreeNode(new Operation::MultiplyConstant(first*dynamic_cast<const Operation::MultiplyConstant*>(&children[1].getOperation())->getValue()), children[1].getChildren()[0]);
                return ExpressionTreeNode(new Operation::MultiplyConstant(first), children[1]);
Peter Eastman's avatar
Peter Eastman committed
219
            }
220
            if (second_const) { // Multiply by a constant
221
222
223
                if (children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine two multiplies into a single one
                    return ExpressionTreeNode(new Operation::MultiplyConstant(second*dynamic_cast<const Operation::MultiplyConstant*>(&children[0].getOperation())->getValue()), children[0].getChildren()[0]);
                return ExpressionTreeNode(new Operation::MultiplyConstant(second), children[0]);
Peter Eastman's avatar
Peter Eastman committed
224
            }
Peter Eastman's avatar
Peter Eastman committed
225
226
227
228
229
230
231
232
233
234
            if (children[0].getOperation().getId() == Operation::NEGATE && children[1].getOperation().getId() == Operation::NEGATE) // The two negations cancel
                return ExpressionTreeNode(new Operation::Multiply(), children[0].getChildren()[0], children[1].getChildren()[0]);
            if (children[0].getOperation().getId() == Operation::NEGATE && children[1].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Negate the constant
                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]));
            if (children[1].getOperation().getId() == Operation::NEGATE && children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Negate the constant
                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]);
            if (children[0].getOperation().getId() == Operation::NEGATE) // Pull the negation out so it can possibly be optimized further
                return ExpressionTreeNode(new Operation::Negate(), ExpressionTreeNode(new Operation::Multiply(), children[0].getChildren()[0], children[1]));
            if (children[1].getOperation().getId() == Operation::NEGATE) // Pull the negation out so it can possibly be optimized further
                return ExpressionTreeNode(new Operation::Negate(), ExpressionTreeNode(new Operation::Multiply(), children[0], children[1].getChildren()[0]));
235
236
237
238
            if (children[1].getOperation().getId() == Operation::RECIPROCAL) // a*(1/b) = a/b
                return ExpressionTreeNode(new Operation::Divide(), children[0], children[1].getChildren()[0]);
            if (children[0].getOperation().getId() == Operation::RECIPROCAL) // (1/a)*b = b/a
                return ExpressionTreeNode(new Operation::Divide(), children[1], children[0].getChildren()[0]);
239
240
241
242
243
244
            if (children[0] == children[1])
                return ExpressionTreeNode(new Operation::Square(), children[0]); // x*x = square(x)
            if (children[0].getOperation().getId() == Operation::SQUARE && children[0].getChildren()[0] == children[1])
                return ExpressionTreeNode(new Operation::Cube(), children[1]); // x*x*x = cube(x)
            if (children[1].getOperation().getId() == Operation::SQUARE && children[1].getChildren()[0] == children[0])
                return ExpressionTreeNode(new Operation::Cube(), children[0]); // x*x*x = cube(x)
245
            break;
Peter Eastman's avatar
Peter Eastman committed
246
        }
247
        case Operation::DIVIDE:
Peter Eastman's avatar
Peter Eastman committed
248
        {
249
            if (children[0] == children[1])
250
                return ExpressionTreeNode(new Operation::Constant(1.0)); // Dividing anything by itself is 1
251
            if (first_const && first == 0.0) // 0 divided by something
252
                return ExpressionTreeNode(new Operation::Constant(0.0));
253
            if (first_const && first == 1.0) // 1 divided by something
254
                return ExpressionTreeNode(new Operation::Reciprocal(), children[1]);
255
            if (second_const && second == 1.0) // Divide by 1
256
                return children[0];
257
            if (second_const) {
258
                if (children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine a multiply and a divide into one multiply
259
260
                    return ExpressionTreeNode(new Operation::MultiplyConstant(dynamic_cast<const Operation::MultiplyConstant*>(&children[0].getOperation())->getValue()/second), children[0].getChildren()[0]);
                return ExpressionTreeNode(new Operation::MultiplyConstant(1.0/second), children[0]); // Replace a divide with a multiply
Peter Eastman's avatar
Peter Eastman committed
261
            }
Peter Eastman's avatar
Peter Eastman committed
262
263
264
265
266
267
268
269
            if (children[0].getOperation().getId() == Operation::NEGATE && children[1].getOperation().getId() == Operation::NEGATE) // The two negations cancel
                return ExpressionTreeNode(new Operation::Divide(), children[0].getChildren()[0], children[1].getChildren()[0]);
            if (children[1].getOperation().getId() == Operation::NEGATE && children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Negate the constant
                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]);
            if (children[0].getOperation().getId() == Operation::NEGATE) // Pull the negation out so it can possibly be optimized further
                return ExpressionTreeNode(new Operation::Negate(), ExpressionTreeNode(new Operation::Divide(), children[0].getChildren()[0], children[1]));
            if (children[1].getOperation().getId() == Operation::NEGATE) // Pull the negation out so it can possibly be optimized further
                return ExpressionTreeNode(new Operation::Negate(), ExpressionTreeNode(new Operation::Divide(), children[0], children[1].getChildren()[0]));
270
271
            if (children[1].getOperation().getId() == Operation::RECIPROCAL) // a/(1/b) = a*b
                return ExpressionTreeNode(new Operation::Multiply(), children[0], children[1].getChildren()[0]);
272
            break;
Peter Eastman's avatar
Peter Eastman committed
273
        }
274
        case Operation::POWER:
Peter Eastman's avatar
Peter Eastman committed
275
        {
276
            if (first_const && first == 0.0) // 0 to any power is 0
277
                return ExpressionTreeNode(new Operation::Constant(0.0));
278
            if (first_const && first == 1.0) // 1 to any power is 1
279
                return ExpressionTreeNode(new Operation::Constant(1.0));
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
            if (second_const) { // Constant exponent
                if (second == 0.0) // x^0 = 1
                    return ExpressionTreeNode(new Operation::Constant(1.0));
                if (second == 1.0) // x^1 = x
                    return children[0];
                if (second == -1.0) // x^-1 = recip(x)
                    return ExpressionTreeNode(new Operation::Reciprocal(), children[0]);
                if (second == 2.0) // x^2 = square(x)
                    return ExpressionTreeNode(new Operation::Square(), children[0]);
                if (second == 3.0) // x^3 = cube(x)
                    return ExpressionTreeNode(new Operation::Cube(), children[0]);
                if (second == 0.5) // x^0.5 = sqrt(x)
                    return ExpressionTreeNode(new Operation::Sqrt(), children[0]);
                // Constant power
                return ExpressionTreeNode(new Operation::PowerConstant(second), children[0]);
            }
296
297
298
299
300
301
            break;
        }
        case Operation::NEGATE:
        {
            if (children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine a multiply and a negate into a single multiply
                return ExpressionTreeNode(new Operation::MultiplyConstant(-dynamic_cast<const Operation::MultiplyConstant*>(&children[0].getOperation())->getValue()), children[0].getChildren()[0]);
302
303
            if (first_const) // Negate a constant
                return ExpressionTreeNode(new Operation::Constant(-first));
Peter Eastman's avatar
Peter Eastman committed
304
305
            if (children[0].getOperation().getId() == Operation::NEGATE) // The two negations cancel
                return children[0].getChildren()[0];
306
            break;
Peter Eastman's avatar
Peter Eastman committed
307
        }
Peter Eastman's avatar
Peter Eastman committed
308
309
310
311
        case Operation::MULTIPLY_CONSTANT:
        {
            if (children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine two multiplies into a single one
                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]);
312
            if (first_const) // Multiply two constants
Peter Eastman's avatar
Peter Eastman committed
313
                return ExpressionTreeNode(new Operation::Constant(dynamic_cast<const Operation::MultiplyConstant*>(&node.getOperation())->getValue()*getConstantValue(children[0])));
Peter Eastman's avatar
Peter Eastman committed
314
315
            if (children[0].getOperation().getId() == Operation::NEGATE) // Combine a multiply and a negate into a single multiply
                return ExpressionTreeNode(new Operation::MultiplyConstant(-dynamic_cast<const Operation::MultiplyConstant*>(&node.getOperation())->getValue()), children[0].getChildren()[0]);
316
            break;
Peter Eastman's avatar
Peter Eastman committed
317
        }
peastman's avatar
peastman committed
318
319
320
321
        case Operation::SQRT:
        {
            if (children[0].getOperation().getId() == Operation::SQUARE) // sqrt(square(x)) = abs(x)
                return ExpressionTreeNode(new Operation::Abs(), children[0].getChildren()[0]);
322
            break;
peastman's avatar
peastman committed
323
324
325
326
327
        }
        case Operation::SQUARE:
        {
            if (children[0].getOperation().getId() == Operation::SQRT) // square(sqrt(x)) = x
                return children[0].getChildren()[0];
328
329
330
331
332
333
334
            break;
        }
        case Operation::SELECT:
        {
            if (children[1] == children[2]) // Select between two identical values
                return children[1];
            break;
peastman's avatar
peastman committed
335
        }
336
337
338
339
340
341
342
        default:
        {
            // If operation ID is not one of the above,
            // we don't substitute a simpler expression.
            break;
        }

343
344
345
    }
    return ExpressionTreeNode(node.getOperation().clone(), children);
}
346

347
ParsedExpression ParsedExpression::differentiate(const string& variable) const {
348
349
350
351
    vector<const ExpressionTreeNode*> examples;
    getRootNode().assignTags(examples);
    map<int, ExpressionTreeNode> nodeCache;
    return differentiate(getRootNode(), variable, nodeCache);
352
353
}

354
355
356
357
ExpressionTreeNode ParsedExpression::differentiate(const ExpressionTreeNode& node, const string& variable, map<int, ExpressionTreeNode>& nodeCache) {
    auto cached = nodeCache.find(node.tag);
    if (cached != nodeCache.end())
        return cached->second;
358
    vector<ExpressionTreeNode> childDerivs(node.getChildren().size());
359
    for (int i = 0; i < (int) childDerivs.size(); i++)
360
361
362
363
        childDerivs[i] = differentiate(node.getChildren()[i], variable, nodeCache);
    ExpressionTreeNode result = node.getOperation().differentiate(node.getChildren(), childDerivs, variable);
    nodeCache[node.tag] = result;
    return result;
364
365
}

366
367
368
369
bool ParsedExpression::isConstant(const ExpressionTreeNode& node) {
    return (node.getOperation().getId() == Operation::CONSTANT);
}

370
double ParsedExpression::getConstantValue(const ExpressionTreeNode& node) {
371
372
373
374
    if (node.getOperation().getId() != Operation::CONSTANT) {
        throw Exception("getConstantValue called on a non-constant ExpressionNode");
    }
    return dynamic_cast<const Operation::Constant&>(node.getOperation()).getValue();
375
376
}

Peter Eastman's avatar
Peter Eastman committed
377
378
379
380
ExpressionProgram ParsedExpression::createProgram() const {
    return ExpressionProgram(*this);
}

381
382
383
384
CompiledExpression ParsedExpression::createCompiledExpression() const {
    return CompiledExpression(*this);
}

385
386
387
388
CompiledVectorExpression ParsedExpression::createCompiledVectorExpression(int width) const {
    return CompiledVectorExpression(*this, width);
}

389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
ParsedExpression ParsedExpression::renameVariables(const map<string, string>& replacements) const {
    return ParsedExpression(renameNodeVariables(getRootNode(), replacements));
}

ExpressionTreeNode ParsedExpression::renameNodeVariables(const ExpressionTreeNode& node, const map<string, string>& replacements) {
    if (node.getOperation().getId() == Operation::VARIABLE) {
        map<string, string>::const_iterator replace = replacements.find(node.getOperation().getName());
        if (replace != replacements.end())
            return ExpressionTreeNode(new Operation::Variable(replace->second));
    }
    vector<ExpressionTreeNode> children;
    for (int i = 0; i < (int) node.getChildren().size(); i++)
        children.push_back(renameNodeVariables(node.getChildren()[i], replacements));
    return ExpressionTreeNode(node.getOperation().clone(), children);
}

405
ostream& Lepton::operator<<(ostream& out, const ExpressionTreeNode& node) {
406
407
408
    if (node.getOperation().isInfixOperator() && node.getChildren().size() == 2) {
        out << "(" << node.getChildren()[0] << ")" << node.getOperation().getName() << "(" << node.getChildren()[1] << ")";
    }
409
410
411
    else if (node.getOperation().isInfixOperator() && node.getChildren().size() == 1) {
        out << "(" << node.getChildren()[0] << ")" << node.getOperation().getName();
    }
412
413
414
415
416
417
418
419
420
421
    else {
        out << node.getOperation().getName();
        if (node.getChildren().size() > 0) {
            out << "(";
            for (int i = 0; i < (int) node.getChildren().size(); i++) {
                if (i > 0)
                    out << ", ";
                out << node.getChildren()[i];
            }
            out << ")";
422
423
424
425
426
427
428
429
430
        }
    }
    return out;
}

ostream& Lepton::operator<<(ostream& out, const ParsedExpression& exp) {
    out << exp.getRootNode();
    return out;
}