ParsedExpression.cpp 17.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/* -------------------------------------------------------------------------- *
 *                                   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.               *
 *                                                                            *
 * Portions copyright (c) 2009 Stanford University and the Authors.           *
 * 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
33
34
#include "lepton/ParsedExpression.h"
#include "lepton/ExpressionProgram.h"
#include "lepton/Operation.h"
35
#include <limits>
36
37
38
39
40
#include <vector>

using namespace Lepton;
using namespace std;

41
42
43
ParsedExpression::ParsedExpression() : rootNode(ExpressionTreeNode()) {
}

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

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

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

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

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

ParsedExpression ParsedExpression::optimize() const {
70
    ExpressionTreeNode result = precalculateConstantSubexpressions(getRootNode());
Peter Eastman's avatar
Peter Eastman committed
71
72
73
74
75
76
    while (true) {
        ExpressionTreeNode simplified = substituteSimplerExpression(result);
        if (simplified == result)
            break;
        result = simplified;
    }
77
    return ParsedExpression(result);
78
79
80
}

ParsedExpression ParsedExpression::optimize(const map<string, double>& variables) const {
81
82
    ExpressionTreeNode result = preevaluateVariables(getRootNode(), variables);
    result = precalculateConstantSubexpressions(result);
Peter Eastman's avatar
Peter Eastman committed
83
84
85
86
87
88
    while (true) {
        ExpressionTreeNode simplified = substituteSimplerExpression(result);
        if (simplified == result)
            break;
        result = simplified;
    }
89
    return ParsedExpression(result);
90
91
92
93
94
95
96
97
98
99
100
}

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());
101
    for (int i = 0; i < (int) children.size(); i++)
102
103
104
105
106
107
        children[i] = preevaluateVariables(node.getChildren()[i], variables);
    return ExpressionTreeNode(node.getOperation().clone(), children);
}

ExpressionTreeNode ParsedExpression::precalculateConstantSubexpressions(const ExpressionTreeNode& node) {
    vector<ExpressionTreeNode> children(node.getChildren().size());
108
    for (int i = 0; i < (int) children.size(); i++)
109
110
111
112
        children[i] = precalculateConstantSubexpressions(node.getChildren()[i]);
    ExpressionTreeNode result = ExpressionTreeNode(node.getOperation().clone(), children);
    if (node.getOperation().getId() == Operation::VARIABLE)
        return result;
113
    for (int i = 0; i < (int) children.size(); i++)
114
115
116
117
118
119
120
        if (children[i].getOperation().getId() != Operation::CONSTANT)
            return result;
    return ExpressionTreeNode(new Operation::Constant(evaluate(result, map<string, double>())));
}

ExpressionTreeNode ParsedExpression::substituteSimplerExpression(const ExpressionTreeNode& node) {
    vector<ExpressionTreeNode> children(node.getChildren().size());
121
    for (int i = 0; i < (int) children.size(); i++)
122
123
        children[i] = substituteSimplerExpression(node.getChildren()[i]);
    switch (node.getOperation().getId()) {
124
        case Operation::ADD:
Peter Eastman's avatar
Peter Eastman committed
125
        {
126
127
            double first = getConstantValue(children[0]);
            double second = getConstantValue(children[1]);
Peter Eastman's avatar
Peter Eastman committed
128
            if (first == 0.0) // Add 0
129
                return children[1];
Peter Eastman's avatar
Peter Eastman committed
130
            if (second == 0.0) // Add 0
131
                return children[0];
132
133
134
135
            if (first == first) // Add a constant
                return ExpressionTreeNode(new Operation::AddConstant(first), children[1]);
            if (second == second) // Add a constant
                return ExpressionTreeNode(new Operation::AddConstant(second), children[0]);
136
            break;
Peter Eastman's avatar
Peter Eastman committed
137
        }
138
        case Operation::SUBTRACT:
Peter Eastman's avatar
Peter Eastman committed
139
140
        {
            double first = getConstantValue(children[0]);
Peter Eastman's avatar
Peter Eastman committed
141
            if (first == 0.0) // Subtract from 0
142
                return ExpressionTreeNode(new Operation::Negate(), children[1]);
Peter Eastman's avatar
Peter Eastman committed
143
            double second = getConstantValue(children[1]);
Peter Eastman's avatar
Peter Eastman committed
144
            if (second == 0.0) // Subtract 0
145
                return children[0];
146
147
            if (second == second) // Subtract a constant
                return ExpressionTreeNode(new Operation::AddConstant(-second), children[0]);
148
            break;
Peter Eastman's avatar
Peter Eastman committed
149
        }
150
        case Operation::MULTIPLY:
Peter Eastman's avatar
Peter Eastman committed
151
152
153
        {
            double first = getConstantValue(children[0]);
            double second = getConstantValue(children[1]);
Peter Eastman's avatar
Peter Eastman committed
154
            if (first == 0.0 || second == 0.0) // Multiply by 0
155
                return ExpressionTreeNode(new Operation::Constant(0.0));
Peter Eastman's avatar
Peter Eastman committed
156
            if (first == 1.0) // Multiply by 1
157
                return children[1];
Peter Eastman's avatar
Peter Eastman committed
158
            if (second == 1.0) // Multiply by 1
159
                return children[0];
160
161
162
163
            if (children[0].getOperation().getId() == Operation::CONSTANT) { // Multiply by a constant
                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
164
            }
165
166
167
168
            if (children[1].getOperation().getId() == Operation::CONSTANT) { // Multiply by a constant
                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
169
            }
Peter Eastman's avatar
Peter Eastman committed
170
171
172
173
174
175
176
177
178
179
            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]));
180
            break;
Peter Eastman's avatar
Peter Eastman committed
181
        }
182
        case Operation::DIVIDE:
Peter Eastman's avatar
Peter Eastman committed
183
        {
184
            double numerator = getConstantValue(children[0]);
185
            if (numerator == 0.0) // 0 divided by something
186
                return ExpressionTreeNode(new Operation::Constant(0.0));
Peter Eastman's avatar
Peter Eastman committed
187
            if (numerator == 1.0) // 1 divided by something
188
189
                return ExpressionTreeNode(new Operation::Reciprocal(), children[1]);
            double denominator = getConstantValue(children[1]);
Peter Eastman's avatar
Peter Eastman committed
190
            if (denominator == 1.0) // Divide by 1
191
                return children[0];
Peter Eastman's avatar
Peter Eastman committed
192
            if (children[1].getOperation().getId() == Operation::CONSTANT) {
193
194
195
                if (children[0].getOperation().getId() == Operation::MULTIPLY_CONSTANT) // Combine a multiply and a divide into one multiply
                    return ExpressionTreeNode(new Operation::MultiplyConstant(dynamic_cast<const Operation::MultiplyConstant*>(&children[0].getOperation())->getValue()/denominator), children[0].getChildren()[0]);
                return ExpressionTreeNode(new Operation::MultiplyConstant(1.0/denominator), children[0]); // Replace a divide with a multiply
Peter Eastman's avatar
Peter Eastman committed
196
            }
Peter Eastman's avatar
Peter Eastman committed
197
198
199
200
201
202
203
204
            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]));
205
            break;
Peter Eastman's avatar
Peter Eastman committed
206
        }
207
        case Operation::POWER:
Peter Eastman's avatar
Peter Eastman committed
208
        {
209
            double base = getConstantValue(children[0]);
Peter Eastman's avatar
Peter Eastman committed
210
            if (base == 0.0) // 0 to any power is 0
211
                return ExpressionTreeNode(new Operation::Constant(0.0));
Peter Eastman's avatar
Peter Eastman committed
212
            if (base == 1.0) // 1 to any power is 1
213
214
                return ExpressionTreeNode(new Operation::Constant(1.0));
            double exponent = getConstantValue(children[1]);
215
216
            if (exponent == 0.0) // x^0 = 1
                return ExpressionTreeNode(new Operation::Constant(1.0));
Peter Eastman's avatar
Peter Eastman committed
217
            if (exponent == 1.0) // x^1 = x
218
                return children[0];
Peter Eastman's avatar
Peter Eastman committed
219
            if (exponent == -1.0) // x^-1 = recip(x)
220
                return ExpressionTreeNode(new Operation::Reciprocal(), children[0]);
Peter Eastman's avatar
Peter Eastman committed
221
            if (exponent == 2.0) // x^2 = square(x)
222
                return ExpressionTreeNode(new Operation::Square(), children[0]);
Peter Eastman's avatar
Peter Eastman committed
223
            if (exponent == 3.0) // x^3 = cube(x)
224
                return ExpressionTreeNode(new Operation::Cube(), children[0]);
Peter Eastman's avatar
Peter Eastman committed
225
            if (exponent == 0.5) // x^0.5 = sqrt(x)
226
                return ExpressionTreeNode(new Operation::Sqrt(), children[0]);
227
228
229
230
231
232
233
234
            if (exponent == exponent) // Constant power
                return ExpressionTreeNode(new Operation::PowerConstant(exponent), children[0]);
            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]);
Peter Eastman's avatar
Peter Eastman committed
235
236
            if (children[0].getOperation().getId() == Operation::CONSTANT) // Negate a constant
                return ExpressionTreeNode(new Operation::Constant(-getConstantValue(children[0])));
Peter Eastman's avatar
Peter Eastman committed
237
238
            if (children[0].getOperation().getId() == Operation::NEGATE) // The two negations cancel
                return children[0].getChildren()[0];
239
            break;
Peter Eastman's avatar
Peter Eastman committed
240
        }
Peter Eastman's avatar
Peter Eastman committed
241
242
243
244
        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]);
Peter Eastman's avatar
Peter Eastman committed
245
246
            if (children[0].getOperation().getId() == Operation::CONSTANT) // Multiply two constants
                return ExpressionTreeNode(new Operation::Constant(dynamic_cast<const Operation::MultiplyConstant*>(&node.getOperation())->getValue()*getConstantValue(children[0])));
Peter Eastman's avatar
Peter Eastman committed
247
248
            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]);
Peter Eastman's avatar
Peter Eastman committed
249
        }
250
251
252
    }
    return ExpressionTreeNode(node.getOperation().clone(), children);
}
253
254
255
256
257
258
259

ParsedExpression ParsedExpression::differentiate(const std::string& variable) const {
    return differentiate(getRootNode(), variable);
}

ExpressionTreeNode ParsedExpression::differentiate(const ExpressionTreeNode& node, const std::string& variable) {
    vector<ExpressionTreeNode> childDerivs(node.getChildren().size());
260
    for (int i = 0; i < (int) childDerivs.size(); i++)
261
262
263
264
265
266
267
268
269
270
        childDerivs[i] = differentiate(node.getChildren()[i], variable);
    return node.getOperation().differentiate(node.getChildren(),childDerivs, variable);
}

double ParsedExpression::getConstantValue(const ExpressionTreeNode& node) {
    if (node.getOperation().getId() == Operation::CONSTANT)
        return dynamic_cast<const Operation::Constant&>(node.getOperation()).getValue();
    return numeric_limits<double>::quiet_NaN();
}

Peter Eastman's avatar
Peter Eastman committed
271
272
273
274
ExpressionProgram ParsedExpression::createProgram() const {
    return ExpressionProgram(*this);
}

275
ostream& Lepton::operator<<(ostream& out, const ExpressionTreeNode& node) {
276
277
278
279
280
281
282
283
284
285
286
287
288
    if (node.getOperation().isInfixOperator() && node.getChildren().size() == 2) {
        out << "(" << node.getChildren()[0] << ")" << node.getOperation().getName() << "(" << node.getChildren()[1] << ")";
    }
    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 << ")";
289
290
291
292
293
294
295
296
297
        }
    }
    return out;
}

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