init
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
/* -------------------------------------------------------------------------- *
|
||||
* 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) 2013 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. *
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
#include "CompiledExpression.h"
|
||||
#include "Operation.h"
|
||||
#include "ParsedExpression.h"
|
||||
#include <utility>
|
||||
#include <cstdint>
|
||||
|
||||
using namespace Lepton;
|
||||
|
||||
CompiledExpression::CompiledExpression(const ParsedExpression& expression)
|
||||
{
|
||||
ParsedExpression expr = expression.optimize(); // Just in case it wasn't already optimized.
|
||||
std::vector<std::pair<ExpressionTreeNode, int>> temps;
|
||||
compileExpression(expr.getRootNode(), temps);
|
||||
}
|
||||
|
||||
CompiledExpression& CompiledExpression::operator=(const CompiledExpression& expression)
|
||||
{
|
||||
arguments = expression.arguments;
|
||||
target = expression.target;
|
||||
variableIndices = expression.variableIndices;
|
||||
variableNames = expression.variableNames;
|
||||
workspace.resize(expression.workspace.size());
|
||||
argValues.resize(expression.argValues.size());
|
||||
operation.resize(expression.operation.size());
|
||||
for (size_t i = 0; i < operation.size(); ++i) { operation[i] = expression.operation[i]->clone(); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
void CompiledExpression::compileExpression(const ExpressionTreeNode& node, std::vector<std::pair<ExpressionTreeNode, int>>& temps)
|
||||
{
|
||||
if (findTempIndex(node, temps) != -1) { return; } // We have already processed a node identical to this one.
|
||||
|
||||
// Process the child nodes.
|
||||
|
||||
std::vector<int> args;
|
||||
for (size_t i = 0; i < node.getChildren().size(); ++i)
|
||||
{
|
||||
compileExpression(node.getChildren()[i], temps);
|
||||
args.push_back(findTempIndex(node.getChildren()[i], temps));
|
||||
}
|
||||
|
||||
// Process this node.
|
||||
|
||||
if (node.getOperation().getId() == Operation::VARIABLE)
|
||||
{
|
||||
variableIndices[node.getOperation().getName()] = int(workspace.size());
|
||||
variableNames.insert(node.getOperation().getName());
|
||||
}
|
||||
else
|
||||
{
|
||||
int stepIndex = int(arguments.size());
|
||||
arguments.push_back(std::vector<int>());
|
||||
target.push_back(int(workspace.size()));
|
||||
operation.push_back(node.getOperation().clone());
|
||||
if (args.size() == 0) arguments[stepIndex].push_back(0); // The value won't actually be used. We just need something there.
|
||||
else
|
||||
{
|
||||
// If the arguments are sequential, we can just pass a pointer to the first one.
|
||||
|
||||
bool sequential = true;
|
||||
for (size_t i = 1; i < args.size(); ++i) if (args[i] != args[i - 1] + 1) sequential = false;
|
||||
if (sequential) arguments[stepIndex].push_back(args[0]);
|
||||
else
|
||||
{
|
||||
arguments[stepIndex] = args;
|
||||
if (args.size() > argValues.size()) argValues.resize(args.size(), 0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
temps.push_back(std::make_pair(node, workspace.size()));
|
||||
workspace.push_back(0.0);
|
||||
}
|
||||
|
||||
int CompiledExpression::findTempIndex(const ExpressionTreeNode& node, std::vector<std::pair<ExpressionTreeNode, int>>& temps)
|
||||
{
|
||||
for (size_t i = 0; i < temps.size(); ++i) { if (temps[i].first == node) { return int(i); } }
|
||||
return -1;
|
||||
}
|
||||
|
||||
double& CompiledExpression::getVariableReference(const std::string& name)
|
||||
{
|
||||
auto index = variableIndices.find(name);
|
||||
if (index == variableIndices.end()) throw Exception("getVariableReference: Unknown variable '" + name + "'");
|
||||
return workspace[index->second];
|
||||
}
|
||||
|
||||
double CompiledExpression::evaluate() const
|
||||
{
|
||||
// Loop over the operations and evaluate each one.
|
||||
|
||||
for (size_t step = 0; step < operation.size(); ++step)
|
||||
{
|
||||
const std::vector<int>& args = arguments[step];
|
||||
if (args.size() == 1) workspace[target[step]] = operation[step]->evaluate(&workspace[args[0]], dummyVariables);
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < args.size(); ++i) argValues[i] = workspace[args[i]];
|
||||
workspace[target[step]] = operation[step]->evaluate(&argValues[0], dummyVariables);
|
||||
}
|
||||
}
|
||||
return workspace[workspace.size() - 1];
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
#pragma once
|
||||
|
||||
/* -------------------------------------------------------------------------- *
|
||||
* 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) 2013 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. *
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
#include "ExpressionTreeNode.h"
|
||||
#include "windowsIncludes.h"
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Lepton
|
||||
{
|
||||
class Operation;
|
||||
class ParsedExpression;
|
||||
|
||||
/**
|
||||
* A CompiledExpression is a highly optimized representation of an expression for cases when you want to evaluate
|
||||
* it many times as quickly as possible. You should treat it as an opaque object; none of the internal representation
|
||||
* is visible.
|
||||
*
|
||||
* A CompiledExpression is created by calling createCompiledExpression() on a ParsedExpression.
|
||||
*
|
||||
* WARNING: CompiledExpression is NOT thread safe. You should never access a CompiledExpression from two threads at
|
||||
* the same time.
|
||||
*/
|
||||
|
||||
class LEPTON_EXPORT CompiledExpression
|
||||
{
|
||||
public:
|
||||
CompiledExpression() {}
|
||||
CompiledExpression(const CompiledExpression& expression) { *this = expression; }
|
||||
~CompiledExpression() { for (size_t i = 0; i < operation.size(); ++i) if (operation[i] != nullptr) delete operation[i]; }
|
||||
CompiledExpression& operator=(const CompiledExpression& expression);
|
||||
/**
|
||||
* Get the names of all variables used by this expression.
|
||||
*/
|
||||
const std::set<std::string>& getVariables() const { return variableNames; }
|
||||
/**
|
||||
* Get a reference to the memory location where the value of a particular variable is stored. This can be used
|
||||
* to set the value of the variable before calling evaluate().
|
||||
*/
|
||||
double& getVariableReference(const std::string& name);
|
||||
/**
|
||||
* Evaluate the expression. The values of all variables should have been set before calling this.
|
||||
*/
|
||||
double evaluate() const;
|
||||
private:
|
||||
friend class ParsedExpression;
|
||||
CompiledExpression(const ParsedExpression& expression);
|
||||
void compileExpression(const ExpressionTreeNode& node, std::vector<std::pair<ExpressionTreeNode, int>>& temps);
|
||||
int findTempIndex(const ExpressionTreeNode& node, std::vector<std::pair<ExpressionTreeNode, int>>& temps);
|
||||
std::vector<std::vector<int>> arguments;
|
||||
std::vector<int> target;
|
||||
std::vector<Operation*> operation;
|
||||
std::map<std::string, int> variableIndices;
|
||||
std::set<std::string> variableNames;
|
||||
mutable std::vector<double> workspace;
|
||||
mutable std::vector<double> argValues;
|
||||
std::map<std::string, double> dummyVariables;
|
||||
};
|
||||
} // namespace Lepton
|
||||
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
/* -------------------------------------------------------------------------- *
|
||||
* 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. *
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
#include "windowsIncludes.h"
|
||||
|
||||
namespace Lepton
|
||||
{
|
||||
|
||||
/**
|
||||
* This class is the interface for defining your own function that may be included in expressions.
|
||||
* To use it, create a concrete subclass that implements all of the virtual methods for each new function
|
||||
* you want to define. Then when you call Parser::parse() to parse an expression, pass a map of
|
||||
* function names to CustomFunction objects.
|
||||
*/
|
||||
|
||||
class LEPTON_EXPORT CustomFunction
|
||||
{
|
||||
public:
|
||||
virtual ~CustomFunction() { }
|
||||
/**
|
||||
* Get the number of arguments this function exprects.
|
||||
*/
|
||||
virtual int getNumArguments() const = 0;
|
||||
/**
|
||||
* Evaluate the function.
|
||||
*
|
||||
* @param arguments the array of argument values
|
||||
*/
|
||||
virtual double evaluate(const double* arguments) const = 0;
|
||||
/**
|
||||
* Evaluate a derivative of the function.
|
||||
*
|
||||
* @param arguments the array of argument values
|
||||
* @param derivOrder an array specifying the number of times the function has been differentiated
|
||||
* with respect to each of its arguments. For example, the array {0, 2} indicates
|
||||
* a second derivative with respect to the second argument.
|
||||
*/
|
||||
virtual double evaluateDerivative(const double* arguments, const int* derivOrder) const = 0;
|
||||
/**
|
||||
* Create a new duplicate of this object on the heap using the "new" operator.
|
||||
*/
|
||||
virtual CustomFunction* clone() const = 0;
|
||||
};
|
||||
} // namespace Lepton
|
||||
@@ -0,0 +1,58 @@
|
||||
#ifndef LEPTON_EXCEPTION_H_
|
||||
#define LEPTON_EXCEPTION_H_
|
||||
|
||||
/* -------------------------------------------------------------------------- *
|
||||
* 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. *
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
namespace Lepton
|
||||
{
|
||||
|
||||
/**
|
||||
* This class is used for all exceptions thrown by Lepton.
|
||||
*/
|
||||
|
||||
class Exception final : public std::exception
|
||||
{
|
||||
public:
|
||||
Exception(const std::string& message) : message(message) { }
|
||||
~Exception() throw() override { }
|
||||
|
||||
const char* what() const throw() override { return message.c_str(); }
|
||||
|
||||
private:
|
||||
std::string message;
|
||||
};
|
||||
} // namespace Lepton
|
||||
|
||||
#endif /*LEPTON_EXCEPTION_H_*/
|
||||
@@ -0,0 +1,92 @@
|
||||
/* -------------------------------------------------------------------------- *
|
||||
* 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-2013 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. *
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
#include "ExpressionProgram.h"
|
||||
#include "Operation.h"
|
||||
#include "ParsedExpression.h"
|
||||
|
||||
using namespace Lepton;
|
||||
|
||||
ExpressionProgram::ExpressionProgram() : maxArgs(0), stackSize(0) {}
|
||||
|
||||
ExpressionProgram::ExpressionProgram(const ParsedExpression& expression) : maxArgs(0), stackSize(0)
|
||||
{
|
||||
buildProgram(expression.getRootNode());
|
||||
int currentStackSize = 0;
|
||||
for (size_t i = 0; i < operations.size(); ++i)
|
||||
{
|
||||
int args = operations[i]->getNumArguments();
|
||||
if (args > maxArgs) { maxArgs = args; }
|
||||
currentStackSize += 1 - args;
|
||||
if (currentStackSize > stackSize) { stackSize = currentStackSize; }
|
||||
}
|
||||
}
|
||||
|
||||
ExpressionProgram::~ExpressionProgram() { for (size_t i = 0; i < operations.size(); ++i) { delete operations[i]; } }
|
||||
|
||||
ExpressionProgram::ExpressionProgram(const ExpressionProgram& program) { *this = program; }
|
||||
|
||||
ExpressionProgram& ExpressionProgram::operator=(const ExpressionProgram& program)
|
||||
{
|
||||
maxArgs = program.maxArgs;
|
||||
stackSize = program.stackSize;
|
||||
operations.resize(program.operations.size());
|
||||
for (size_t i = 0; i < operations.size(); ++i) { operations[i] = program.operations[i]->clone(); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ExpressionProgram::buildProgram(const ExpressionTreeNode& node)
|
||||
{
|
||||
for (size_t i = node.getChildren().size() - 1; i >= 0; i--) { buildProgram(node.getChildren()[i]); }
|
||||
operations.push_back(node.getOperation().clone());
|
||||
}
|
||||
|
||||
int ExpressionProgram::getNumOperations() const { return int(operations.size()); }
|
||||
|
||||
const Operation& ExpressionProgram::getOperation(int index) const { return *operations[index]; }
|
||||
|
||||
int ExpressionProgram::getStackSize() const { return stackSize; }
|
||||
|
||||
double ExpressionProgram::evaluate() const { return evaluate(std::map<std::string, double>()); }
|
||||
|
||||
double ExpressionProgram::evaluate(const std::map<std::string, double>& variables) const
|
||||
{
|
||||
std::vector<double> stack(stackSize + 1);
|
||||
int stackPointer = stackSize;
|
||||
for (size_t i = 0; i < operations.size(); ++i)
|
||||
{
|
||||
int numArgs = operations[i]->getNumArguments();
|
||||
double result = operations[i]->evaluate(&stack[stackPointer], variables);
|
||||
stackPointer += numArgs - 1;
|
||||
stack[stackPointer] = result;
|
||||
}
|
||||
return stack[stackSize - 1];
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
#ifndef LEPTON_EXPRESSION_PROGRAM_H_
|
||||
#define LEPTON_EXPRESSION_PROGRAM_H_
|
||||
|
||||
/* -------------------------------------------------------------------------- *
|
||||
* 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. *
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
#include "ExpressionTreeNode.h"
|
||||
#include "windowsIncludes.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Lepton
|
||||
{
|
||||
class ParsedExpression;
|
||||
|
||||
/**
|
||||
* An ExpressionProgram is a linear sequence of Operations for evaluating an expression. The evaluation
|
||||
* is done with a stack. The arguments to each Operation are first taken off the stack in order, then it is
|
||||
* evaluated and the result is pushed back onto the stack. At the end, the stack contains a single value,
|
||||
* which is the value of the expression.
|
||||
*
|
||||
* An ExpressionProgram is created by calling createProgram() on a ParsedExpression.
|
||||
*/
|
||||
|
||||
class LEPTON_EXPORT ExpressionProgram
|
||||
{
|
||||
public:
|
||||
ExpressionProgram();
|
||||
ExpressionProgram(const ExpressionProgram& program);
|
||||
~ExpressionProgram();
|
||||
ExpressionProgram& operator=(const ExpressionProgram& program);
|
||||
/**
|
||||
* Get the number of Operations that make up this program.
|
||||
*/
|
||||
int getNumOperations() const;
|
||||
/**
|
||||
* Get an Operation in this program.
|
||||
*/
|
||||
const Operation& getOperation(int index) const;
|
||||
/**
|
||||
* Get the size of the stack needed to execute this program. This is the largest number of elements present
|
||||
* on the stack at any point during evaluation.
|
||||
*/
|
||||
int getStackSize() const;
|
||||
/**
|
||||
* Evaluate the expression. If the expression involves any variables, this method will throw an exception.
|
||||
*/
|
||||
double evaluate() const;
|
||||
/**
|
||||
* Evaluate the expression.
|
||||
*
|
||||
* @param variables a map specifying the values of all variables that appear in the expression. If any
|
||||
* variable appears in the expression but is not included in this map, an exception
|
||||
* will be thrown.
|
||||
*/
|
||||
double evaluate(const std::map<std::string, double>& variables) const;
|
||||
private:
|
||||
friend class ParsedExpression;
|
||||
ExpressionProgram(const ParsedExpression& expression);
|
||||
void buildProgram(const ExpressionTreeNode& node);
|
||||
std::vector<Operation*> operations;
|
||||
int maxArgs, stackSize;
|
||||
};
|
||||
} // namespace Lepton
|
||||
|
||||
#endif /*LEPTON_EXPRESSION_PROGRAM_H_*/
|
||||
@@ -0,0 +1,103 @@
|
||||
/* -------------------------------------------------------------------------- *
|
||||
* 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. *
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
#include "ExpressionTreeNode.h"
|
||||
#include "Exception.h"
|
||||
#include "Operation.h"
|
||||
|
||||
using namespace Lepton;
|
||||
|
||||
ExpressionTreeNode::ExpressionTreeNode(Operation* operation, const std::vector<ExpressionTreeNode>& children) : operation(operation), children(children)
|
||||
{
|
||||
if (size_t(operation->getNumArguments()) != children.size())
|
||||
{
|
||||
throw Exception("Parse error: wrong number of arguments to function: " + operation->getName());
|
||||
}
|
||||
}
|
||||
|
||||
ExpressionTreeNode::ExpressionTreeNode(Operation* operation, const ExpressionTreeNode& child1, const ExpressionTreeNode& child2) : operation(operation)
|
||||
{
|
||||
children.push_back(child1);
|
||||
children.push_back(child2);
|
||||
if (size_t(operation->getNumArguments()) != children.size())
|
||||
{
|
||||
throw Exception("Parse error: wrong number of arguments to function: " + operation->getName());
|
||||
}
|
||||
}
|
||||
|
||||
ExpressionTreeNode::ExpressionTreeNode(Operation* operation, const ExpressionTreeNode& child) : operation(operation)
|
||||
{
|
||||
children.push_back(child);
|
||||
if (size_t(operation->getNumArguments()) != children.size())
|
||||
{
|
||||
throw Exception("Parse error: wrong number of arguments to function: " + operation->getName());
|
||||
}
|
||||
}
|
||||
|
||||
ExpressionTreeNode::ExpressionTreeNode(Operation* operation) : operation(operation)
|
||||
{
|
||||
if (size_t(operation->getNumArguments()) != children.size())
|
||||
{
|
||||
throw Exception("Parse error: wrong number of arguments to function: " + operation->getName());
|
||||
}
|
||||
}
|
||||
|
||||
ExpressionTreeNode::ExpressionTreeNode(const ExpressionTreeNode& node) : operation(node.getOperation().clone()), children(node.getChildren()) {}
|
||||
|
||||
ExpressionTreeNode::ExpressionTreeNode() {}
|
||||
|
||||
ExpressionTreeNode::~ExpressionTreeNode() { delete operation; }
|
||||
|
||||
bool ExpressionTreeNode::operator!=(const ExpressionTreeNode& node) const
|
||||
{
|
||||
if (node.getOperation() != getOperation()) { return true; }
|
||||
if (getOperation().isSymmetric() && getChildren().size() == 2)
|
||||
{
|
||||
if (getChildren()[0] == node.getChildren()[0] && getChildren()[1] == node.getChildren()[1]) { return false; }
|
||||
if (getChildren()[0] == node.getChildren()[1] && getChildren()[1] == node.getChildren()[0]) { return false; }
|
||||
return true;
|
||||
}
|
||||
for (size_t i = 0; i < getChildren().size(); ++i) { if (getChildren()[i] != node.getChildren()[i]) { return true; } }
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ExpressionTreeNode::operator==(const ExpressionTreeNode& node) const { return !(*this != node); }
|
||||
|
||||
ExpressionTreeNode& ExpressionTreeNode::operator=(const ExpressionTreeNode& node)
|
||||
{
|
||||
delete operation;
|
||||
operation = node.getOperation().clone();
|
||||
children = node.getChildren();
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Operation& ExpressionTreeNode::getOperation() const { return *operation; }
|
||||
const std::vector<ExpressionTreeNode>& ExpressionTreeNode::getChildren() const { return children; }
|
||||
@@ -0,0 +1,105 @@
|
||||
#ifndef LEPTON_EXPRESSION_TREE_NODE_H_
|
||||
#define LEPTON_EXPRESSION_TREE_NODE_H_
|
||||
|
||||
/* -------------------------------------------------------------------------- *
|
||||
* 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. *
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
#include "windowsIncludes.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Lepton
|
||||
{
|
||||
class Operation;
|
||||
|
||||
/**
|
||||
* This class represents a node in the abstract syntax tree representation of an expression.
|
||||
* Each node is defined by an Operation and a set of children. When the expression is
|
||||
* evaluated, each child is first evaluated in order, then the resulting values are passed
|
||||
* as the arguments to the Operation's evaluate() method.
|
||||
*/
|
||||
|
||||
class LEPTON_EXPORT ExpressionTreeNode
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create a new ExpressionTreeNode.
|
||||
*
|
||||
* @param operation the operation for this node. The ExpressionTreeNode takes over ownership
|
||||
* of this object, and deletes it when the node is itself deleted.
|
||||
* @param children the children of this node
|
||||
*/
|
||||
ExpressionTreeNode(Operation* operation, const std::vector<ExpressionTreeNode>& children);
|
||||
/**
|
||||
* Create a new ExpressionTreeNode with two children.
|
||||
*
|
||||
* @param operation the operation for this node. The ExpressionTreeNode takes over ownership
|
||||
* of this object, and deletes it when the node is itself deleted.
|
||||
* @param child1 the first child of this node
|
||||
* @param child2 the second child of this node
|
||||
*/
|
||||
ExpressionTreeNode(Operation* operation, const ExpressionTreeNode& child1, const ExpressionTreeNode& child2);
|
||||
/**
|
||||
* Create a new ExpressionTreeNode with one child.
|
||||
*
|
||||
* @param operation the operation for this node. The ExpressionTreeNode takes over ownership
|
||||
* of this object, and deletes it when the node is itself deleted.
|
||||
* @param child the child of this node
|
||||
*/
|
||||
ExpressionTreeNode(Operation* operation, const ExpressionTreeNode& child);
|
||||
/**
|
||||
* Create a new ExpressionTreeNode with no children.
|
||||
*
|
||||
* @param operation the operation for this node. The ExpressionTreeNode takes over ownership
|
||||
* of this object, and deletes it when the node is itself deleted.
|
||||
*/
|
||||
ExpressionTreeNode(Operation* operation);
|
||||
ExpressionTreeNode(const ExpressionTreeNode& node);
|
||||
ExpressionTreeNode();
|
||||
~ExpressionTreeNode();
|
||||
bool operator==(const ExpressionTreeNode& node) const;
|
||||
bool operator!=(const ExpressionTreeNode& node) const;
|
||||
ExpressionTreeNode& operator=(const ExpressionTreeNode& node);
|
||||
/**
|
||||
* Get the Operation performed by this node.
|
||||
*/
|
||||
const Operation& getOperation() const;
|
||||
/**
|
||||
* Get this node's child nodes.
|
||||
*/
|
||||
const std::vector<ExpressionTreeNode>& getChildren() const;
|
||||
private:
|
||||
Operation* operation = nullptr;
|
||||
std::vector<ExpressionTreeNode> children;
|
||||
};
|
||||
} // namespace Lepton
|
||||
|
||||
#endif /*LEPTON_EXPRESSION_TREE_NODE_H_*/
|
||||
@@ -0,0 +1,43 @@
|
||||
#ifndef LEPTON_H_
|
||||
#define LEPTON_H_
|
||||
|
||||
/* -------------------------------------------------------------------------- *
|
||||
* 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. *
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
#include "CompiledExpression.h"
|
||||
#include "CustomFunction.h"
|
||||
#include "ExpressionProgram.h"
|
||||
#include "ExpressionTreeNode.h"
|
||||
#include "Operation.h"
|
||||
#include "ParsedExpression.h"
|
||||
#include "Parser.h"
|
||||
|
||||
#endif /*LEPTON_H_*/
|
||||
@@ -0,0 +1,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. *
|
||||
* -------------------------------------------------------------------------- */
|
||||
@@ -0,0 +1,87 @@
|
||||
#ifndef LEPTON_MSVC_ERFC_H_
|
||||
#define LEPTON_MSVC_ERFC_H_
|
||||
|
||||
/*
|
||||
* Up to version 11 (VC++ 2012), Microsoft does not support the
|
||||
* standard C99 erf() and erfc() functions so we have to fake them here.
|
||||
* These were added in version 12 (VC++ 2013), which sets _MSC_VER=1800
|
||||
* (VC11 has _MSC_VER=1700).
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define M_PI 3.14159265358979323846264338327950288
|
||||
|
||||
#if _MSC_VER <= 1700 // 1700 is VC11, 1800 is VC12
|
||||
/***************************
|
||||
* erf.cpp
|
||||
* author: Steve Strand
|
||||
* written: 29-Jan-04
|
||||
***************************/
|
||||
|
||||
#include <cmath>
|
||||
|
||||
static const double rel_error= 1E-12; //calculate 12 significant figures
|
||||
//you can adjust rel_error to trade off between accuracy and speed
|
||||
//but don't ask for > 15 figures (assuming usual 52 bit mantissa in a double)
|
||||
|
||||
static double erfc(double x);
|
||||
|
||||
static double erf(double x)
|
||||
//erf(x) = 2/sqrt(pi)*integral(exp(-t^2),t,0,x)
|
||||
// = 2/sqrt(pi)*[x - x^3/3 + x^5/5*2! - x^7/7*3! + ...]
|
||||
// = 1-erfc(x)
|
||||
{
|
||||
static const double two_sqrtpi= 1.128379167095512574; // 2/sqrt(pi)
|
||||
if (fabs(x) > 2.2) {
|
||||
return 1.0 - erfc(x); //use continued fraction when fabs(x) > 2.2
|
||||
}
|
||||
double sum= x, term= x, xsqr= x*x;
|
||||
int j= 1;
|
||||
do {
|
||||
term*= xsqr/j;
|
||||
sum-= term/(2*j+1);
|
||||
++j;
|
||||
term*= xsqr/j;
|
||||
sum+= term/(2*j+1);
|
||||
++j;
|
||||
} while (fabs(term)/sum > rel_error);
|
||||
return two_sqrtpi*sum;
|
||||
}
|
||||
|
||||
|
||||
static double erfc(double x)
|
||||
//erfc(x) = 2/sqrt(pi)*integral(exp(-t^2),t,x,inf)
|
||||
// = exp(-x^2)/sqrt(pi) * [1/x+ (1/2)/x+ (2/2)/x+ (3/2)/x+ (4/2)/x+ ...]
|
||||
// = 1-erf(x)
|
||||
//expression inside [] is a continued fraction so '+' means add to denominator only
|
||||
{
|
||||
static const double one_sqrtpi= 0.564189583547756287; // 1/sqrt(pi)
|
||||
if (fabs(x) < 2.2) {
|
||||
return 1.0 - erf(x); //use series when fabs(x) < 2.2
|
||||
}
|
||||
// Don't look for x==0 here!
|
||||
if (x < 0) { //continued fraction only valid for x>0
|
||||
return 2.0 - erfc(-x);
|
||||
}
|
||||
double a=1, b=x; //last two convergent numerators
|
||||
double c=x, d=x*x+0.5; //last two convergent denominators
|
||||
double q1, q2= b/d; //last two convergents (a/c and b/d)
|
||||
double n= 1.0, t;
|
||||
do {
|
||||
t= a*n+b*x;
|
||||
a= b;
|
||||
b= t;
|
||||
t= c*n+d*x;
|
||||
c= d;
|
||||
d= t;
|
||||
n+= 0.5;
|
||||
q1= q2;
|
||||
q2= b/d;
|
||||
} while (fabs(q1-q2)/q2 > rel_error);
|
||||
return one_sqrtpi*exp(-x*x)*q2;
|
||||
}
|
||||
|
||||
#endif // _MSC_VER <= 1700
|
||||
#endif // _MSC_VER
|
||||
|
||||
#endif // LEPTON_MSVC_ERFC_H_
|
||||
@@ -0,0 +1,355 @@
|
||||
/* -------------------------------------------------------------------------- *
|
||||
* 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. *
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
#include "Operation.h"
|
||||
#include "ExpressionTreeNode.h"
|
||||
#include "MSVC_erfc.h"
|
||||
|
||||
using namespace Lepton;
|
||||
|
||||
double Operation::Erf::evaluate(double* args, const std::map<std::string, double>& /*variable*/) const { return erf(args[0]); }
|
||||
|
||||
double Operation::Erfc::evaluate(double* args, const std::map<std::string, double>& /*variable*/) const { return erfc(args[0]); }
|
||||
|
||||
ExpressionTreeNode Operation::Constant::differentiate(const std::vector<ExpressionTreeNode>& /*children*/,
|
||||
const std::vector<ExpressionTreeNode>& /*childDerivs*/, const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Constant(0.0));
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Variable::differentiate(const std::vector<ExpressionTreeNode>& /*children*/,
|
||||
const std::vector<ExpressionTreeNode>& /*childDerivs*/, const std::string& variable) const
|
||||
{
|
||||
if (variable == name) { return ExpressionTreeNode(new Constant(1.0)); }
|
||||
return ExpressionTreeNode(new Constant(0.0));
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Custom::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
if (function->getNumArguments() == 0) { return ExpressionTreeNode(new Constant(0.0)); }
|
||||
ExpressionTreeNode result = ExpressionTreeNode(new Multiply(), ExpressionTreeNode(new Custom(*this, 0), children), childDerivs[0]);
|
||||
for (int i = 1; i < getNumArguments(); ++i)
|
||||
{
|
||||
result = ExpressionTreeNode(new Add(),
|
||||
result,
|
||||
ExpressionTreeNode(new Multiply(), ExpressionTreeNode(new Custom(*this, i), children), childDerivs[i]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Add::differentiate(const std::vector<ExpressionTreeNode>& /*children*/, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Add(), childDerivs[0], childDerivs[1]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Subtract::differentiate(const std::vector<ExpressionTreeNode>& /*children*/, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Subtract(), childDerivs[0], childDerivs[1]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Multiply::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Add(),
|
||||
ExpressionTreeNode(new Multiply(), children[0], childDerivs[1]),
|
||||
ExpressionTreeNode(new Multiply(), children[1], childDerivs[0]));
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Divide::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Divide(),
|
||||
ExpressionTreeNode(new Subtract(),
|
||||
ExpressionTreeNode(new Multiply(), children[1], childDerivs[0]),
|
||||
ExpressionTreeNode(new Multiply(), children[0], childDerivs[1])),
|
||||
ExpressionTreeNode(new Square(), children[1]));
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Power::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Add(),
|
||||
ExpressionTreeNode(new Multiply(),
|
||||
ExpressionTreeNode(new Multiply(),
|
||||
children[1],
|
||||
ExpressionTreeNode(new Power(),
|
||||
children[0], ExpressionTreeNode(new AddConstant(-1.0), children[1]))),
|
||||
childDerivs[0]),
|
||||
ExpressionTreeNode(new Multiply(),
|
||||
ExpressionTreeNode(new Multiply(),
|
||||
ExpressionTreeNode(new Log(), children[0]),
|
||||
ExpressionTreeNode(new Power(), children[0], children[1])),
|
||||
childDerivs[1]));
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Negate::differentiate(const std::vector<ExpressionTreeNode>& /*children*/, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const { return ExpressionTreeNode(new Negate(), childDerivs[0]); }
|
||||
|
||||
ExpressionTreeNode Operation::Sqrt::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Multiply(), ExpressionTreeNode(new MultiplyConstant(0.5),
|
||||
ExpressionTreeNode(new Reciprocal(),
|
||||
ExpressionTreeNode(new Sqrt(), children[0]))),
|
||||
childDerivs[0]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Exp::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Multiply(), ExpressionTreeNode(new Exp(), children[0]), childDerivs[0]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Log::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Multiply(), ExpressionTreeNode(new Reciprocal(), children[0]), childDerivs[0]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Sin::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Multiply(), ExpressionTreeNode(new Cos(), children[0]), childDerivs[0]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Cos::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Multiply(),
|
||||
ExpressionTreeNode(new Negate(),
|
||||
ExpressionTreeNode(new Sin(), children[0])),
|
||||
childDerivs[0]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Sec::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Multiply(),
|
||||
ExpressionTreeNode(new Multiply(),
|
||||
ExpressionTreeNode(new Sec(), children[0]),
|
||||
ExpressionTreeNode(new Tan(), children[0])),
|
||||
childDerivs[0]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Csc::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Multiply(),
|
||||
ExpressionTreeNode(new Negate(),
|
||||
ExpressionTreeNode(new Multiply(),
|
||||
ExpressionTreeNode(new Csc(), children[0]),
|
||||
ExpressionTreeNode(new Cot(), children[0]))),
|
||||
childDerivs[0]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Tan::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Multiply(),
|
||||
ExpressionTreeNode(new Square(),
|
||||
ExpressionTreeNode(new Sec(), children[0])),
|
||||
childDerivs[0]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Cot::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Multiply(),
|
||||
ExpressionTreeNode(new Negate(),
|
||||
ExpressionTreeNode(new Square(),
|
||||
ExpressionTreeNode(new Csc(), children[0]))),
|
||||
childDerivs[0]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Asin::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Multiply(),
|
||||
ExpressionTreeNode(new Reciprocal(),
|
||||
ExpressionTreeNode(new Sqrt(),
|
||||
ExpressionTreeNode(new Subtract(),
|
||||
ExpressionTreeNode(new Constant(1.0)),
|
||||
ExpressionTreeNode(new Square(), children[0])))),
|
||||
childDerivs[0]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Acos::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Multiply(),
|
||||
ExpressionTreeNode(new Negate(),
|
||||
ExpressionTreeNode(new Reciprocal(),
|
||||
ExpressionTreeNode(new Sqrt(),
|
||||
ExpressionTreeNode(new Subtract(),
|
||||
ExpressionTreeNode(new Constant(1.0)),
|
||||
ExpressionTreeNode(new Square(), children[0]))))),
|
||||
childDerivs[0]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Atan::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Multiply(),
|
||||
ExpressionTreeNode(new Reciprocal(),
|
||||
ExpressionTreeNode(new AddConstant(1.0),
|
||||
ExpressionTreeNode(new Square(), children[0]))),
|
||||
childDerivs[0]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Sinh::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Multiply(), ExpressionTreeNode(new Cosh(), children[0]), childDerivs[0]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Cosh::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Multiply(), ExpressionTreeNode(new Sinh(), children[0]), childDerivs[0]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Tanh::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Multiply(),
|
||||
ExpressionTreeNode(new Subtract(),
|
||||
ExpressionTreeNode(new Constant(1.0)),
|
||||
ExpressionTreeNode(new Square(),
|
||||
ExpressionTreeNode(new Tanh(), children[0]))),
|
||||
childDerivs[0]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Erf::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Multiply(),
|
||||
ExpressionTreeNode(new Multiply(),
|
||||
ExpressionTreeNode(new Constant(2.0 / sqrt(M_PI))),
|
||||
ExpressionTreeNode(new Exp(),
|
||||
ExpressionTreeNode(new Negate(),
|
||||
ExpressionTreeNode(new Square(), children[0])))),
|
||||
childDerivs[0]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Erfc::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Multiply(),
|
||||
ExpressionTreeNode(new Multiply(),
|
||||
ExpressionTreeNode(new Constant(-2.0 / sqrt(M_PI))),
|
||||
ExpressionTreeNode(new Exp(),
|
||||
ExpressionTreeNode(new Negate(),
|
||||
ExpressionTreeNode(new Square(), children[0])))),
|
||||
childDerivs[0]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Step::differentiate(const std::vector<ExpressionTreeNode>& /*children*/, const std::vector<ExpressionTreeNode>& /*childDerivs*/,
|
||||
const std::string& /*variable*/) const { return ExpressionTreeNode(new Constant(0.0)); }
|
||||
|
||||
ExpressionTreeNode Operation::Delta::differentiate(const std::vector<ExpressionTreeNode>& /*children*/, const std::vector<ExpressionTreeNode>& /*childDerivs*/,
|
||||
const std::string& /*variable*/) const { return ExpressionTreeNode(new Constant(0.0)); }
|
||||
|
||||
ExpressionTreeNode Operation::Square::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Multiply(),
|
||||
ExpressionTreeNode(new MultiplyConstant(2.0),
|
||||
children[0]),
|
||||
childDerivs[0]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Cube::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Multiply(),
|
||||
ExpressionTreeNode(new MultiplyConstant(3.0),
|
||||
ExpressionTreeNode(new Square(), children[0])),
|
||||
childDerivs[0]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Reciprocal::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Multiply(),
|
||||
ExpressionTreeNode(new Negate(),
|
||||
ExpressionTreeNode(new Reciprocal(),
|
||||
ExpressionTreeNode(new Square(), children[0]))),
|
||||
childDerivs[0]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::AddConstant::differentiate(const std::vector<ExpressionTreeNode>& /*children*/,
|
||||
const std::vector<ExpressionTreeNode>& childDerivs, const std::string& /*variable*/) const
|
||||
{
|
||||
return childDerivs[0];
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::MultiplyConstant::differentiate(const std::vector<ExpressionTreeNode>& /*children*/,
|
||||
const std::vector<ExpressionTreeNode>& childDerivs, const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new MultiplyConstant(value), childDerivs[0]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::PowerConstant::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
return ExpressionTreeNode(new Multiply(), ExpressionTreeNode(new MultiplyConstant(value), ExpressionTreeNode(new PowerConstant(value - 1), children[0])),
|
||||
childDerivs[0]);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Min::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
const ExpressionTreeNode step(new Step(), ExpressionTreeNode(new Subtract(), children[0], children[1]));
|
||||
return ExpressionTreeNode(new Subtract(),
|
||||
ExpressionTreeNode(new Multiply(), childDerivs[1], step),
|
||||
ExpressionTreeNode(new Multiply(), childDerivs[0],
|
||||
ExpressionTreeNode(new AddConstant(-1), step)));
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Max::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
const ExpressionTreeNode step(new Step(), ExpressionTreeNode(new Subtract(), children[0], children[1]));
|
||||
return ExpressionTreeNode(new Subtract(),
|
||||
ExpressionTreeNode(new Multiply(), childDerivs[0], step),
|
||||
ExpressionTreeNode(new Multiply(), childDerivs[1],
|
||||
ExpressionTreeNode(new AddConstant(-1), step)));
|
||||
}
|
||||
|
||||
ExpressionTreeNode Operation::Abs::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs,
|
||||
const std::string& /*variable*/) const
|
||||
{
|
||||
const ExpressionTreeNode step(new Step(), children[0]);
|
||||
return ExpressionTreeNode(new Multiply(), childDerivs[0], ExpressionTreeNode(new AddConstant(-1), ExpressionTreeNode(new MultiplyConstant(2), step)));
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,370 @@
|
||||
/* -------------------------------------------------------------------------- *
|
||||
* 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. *
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
#include "ParsedExpression.h"
|
||||
#include "CompiledExpression.h"
|
||||
#include "ExpressionProgram.h"
|
||||
#include "Operation.h"
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
using namespace Lepton;
|
||||
|
||||
ParsedExpression::ParsedExpression() : rootNode(ExpressionTreeNode()) {}
|
||||
|
||||
ParsedExpression::ParsedExpression(const ExpressionTreeNode& rootNode) : rootNode(rootNode) {}
|
||||
|
||||
const ExpressionTreeNode& ParsedExpression::getRootNode() const { return rootNode; }
|
||||
|
||||
double ParsedExpression::evaluate() const { return evaluate(getRootNode(), std::map<std::string, double>()); }
|
||||
|
||||
double ParsedExpression::evaluate(const std::map<std::string, double>& variables) const { return evaluate(getRootNode(), variables); }
|
||||
|
||||
double ParsedExpression::evaluate(const ExpressionTreeNode& node, const std::map<std::string, double>& variables)
|
||||
{
|
||||
size_t numArgs = node.getChildren().size();
|
||||
std::vector<double> args(std::max(numArgs, size_t(1)));
|
||||
for (size_t i = 0; i < numArgs; ++i) { args[i] = evaluate(node.getChildren()[i], variables); }
|
||||
return node.getOperation().evaluate(&args[0], variables);
|
||||
}
|
||||
|
||||
ParsedExpression ParsedExpression::optimize() const
|
||||
{
|
||||
ExpressionTreeNode result = precalculateConstantSubexpressions(getRootNode());
|
||||
while (true)
|
||||
{
|
||||
ExpressionTreeNode simplified = substituteSimplerExpression(result);
|
||||
if (simplified == result) { break; }
|
||||
result = simplified;
|
||||
}
|
||||
return ParsedExpression(result);
|
||||
}
|
||||
|
||||
ParsedExpression ParsedExpression::optimize(const std::map<std::string, double>& variables) const
|
||||
{
|
||||
ExpressionTreeNode result = preevaluateVariables(getRootNode(), variables);
|
||||
result = precalculateConstantSubexpressions(result);
|
||||
while (true)
|
||||
{
|
||||
ExpressionTreeNode simplified = substituteSimplerExpression(result);
|
||||
if (simplified == result) { break; }
|
||||
result = simplified;
|
||||
}
|
||||
return ParsedExpression(result);
|
||||
}
|
||||
|
||||
ExpressionTreeNode ParsedExpression::preevaluateVariables(const ExpressionTreeNode& node, const std::map<std::string, double>& variables)
|
||||
{
|
||||
if (node.getOperation().getId() == Operation::VARIABLE)
|
||||
{
|
||||
const Operation::Variable& var = dynamic_cast<const Operation::Variable&>(node.getOperation());
|
||||
auto iter = variables.find(var.getName());
|
||||
if (iter == variables.end()) { return node; }
|
||||
return ExpressionTreeNode(new Operation::Constant(iter->second));
|
||||
}
|
||||
std::vector<ExpressionTreeNode> children(node.getChildren().size());
|
||||
for (size_t i = 0; i < children.size(); ++i) { children[i] = preevaluateVariables(node.getChildren()[i], variables); }
|
||||
return ExpressionTreeNode(node.getOperation().clone(), children);
|
||||
}
|
||||
|
||||
ExpressionTreeNode ParsedExpression::precalculateConstantSubexpressions(const ExpressionTreeNode& node)
|
||||
{
|
||||
std::vector<ExpressionTreeNode> children(node.getChildren().size());
|
||||
for (size_t i = 0; i < children.size(); ++i) { children[i] = precalculateConstantSubexpressions(node.getChildren()[i]); }
|
||||
ExpressionTreeNode result = ExpressionTreeNode(node.getOperation().clone(), children);
|
||||
if (node.getOperation().getId() == Operation::VARIABLE) { return result; }
|
||||
for (size_t i = 0; i < children.size(); ++i) { if (children[i].getOperation().getId() != Operation::CONSTANT) { return result; } }
|
||||
return ExpressionTreeNode(new Operation::Constant(evaluate(result, std::map<std::string, double>())));
|
||||
}
|
||||
|
||||
ExpressionTreeNode ParsedExpression::substituteSimplerExpression(const ExpressionTreeNode& node)
|
||||
{
|
||||
std::vector<ExpressionTreeNode> childs(node.getChildren().size());
|
||||
for (size_t i = 0; i < childs.size(); ++i) { childs[i] = substituteSimplerExpression(node.getChildren()[i]); }
|
||||
Operation::Id op1 = childs[0].getOperation().getId();
|
||||
Operation::Id op2 = childs[1].getOperation().getId();
|
||||
switch (node.getOperation().getId())
|
||||
{
|
||||
case Operation::ADD:
|
||||
{
|
||||
const double first = getConstantValue(childs[0]);
|
||||
const double second = getConstantValue(childs[1]);
|
||||
if (first == 0.0) { return childs[1]; } // Add 0
|
||||
if (second == 0.0) { return childs[0]; } // Add 0
|
||||
if (first == first) { return ExpressionTreeNode(new Operation::AddConstant(first), childs[1]); } // Add a constant
|
||||
if (second == second) { return ExpressionTreeNode(new Operation::AddConstant(second), childs[0]); } // Add a constant
|
||||
if (op2 == Operation::NEGATE) { return ExpressionTreeNode(new Operation::Subtract(), childs[0], childs[1].getChildren()[0]); } // a+(-b) = a-b
|
||||
if (op1 == Operation::NEGATE) { return ExpressionTreeNode(new Operation::Subtract(), childs[1], childs[0].getChildren()[0]); } // (-a)+b = b-a
|
||||
break;
|
||||
}
|
||||
case Operation::SUBTRACT:
|
||||
{
|
||||
if (childs[0] == childs[1]) { return ExpressionTreeNode(new Operation::Constant(0.0)); } // Subtracting anything from itself is 0
|
||||
const double first = getConstantValue(childs[0]);
|
||||
if (first == 0.0) { return ExpressionTreeNode(new Operation::Negate(), childs[1]); } // Subtract from 0
|
||||
const double second = getConstantValue(childs[1]);
|
||||
if (second == 0.0) { return childs[0]; } // Subtract 0
|
||||
if (second == second) { return ExpressionTreeNode(new Operation::AddConstant(-second), childs[0]); } // Subtract a constant
|
||||
if (op2 == Operation::NEGATE) { return ExpressionTreeNode(new Operation::Add(), childs[0], childs[1].getChildren()[0]); } // a-(-b) = a+b
|
||||
break;
|
||||
}
|
||||
case Operation::MULTIPLY:
|
||||
{
|
||||
double first = getConstantValue(childs[0]);
|
||||
double second = getConstantValue(childs[1]);
|
||||
if (first == 0.0 || second == 0.0) { return ExpressionTreeNode(new Operation::Constant(0.0)); } // Multiply by 0
|
||||
if (first == 1.0) { return childs[1]; } // Multiply by 1
|
||||
if (second == 1.0) { return childs[0]; } // Multiply by 1
|
||||
if (op1 == Operation::CONSTANT)
|
||||
{ // Multiply by a constant
|
||||
if (op2 == Operation::MULTIPLY_CONSTANT)
|
||||
{ // Combine two multiplies into a single one
|
||||
return ExpressionTreeNode(
|
||||
new Operation::MultiplyConstant(first * dynamic_cast<const Operation::MultiplyConstant*>(&childs[1].getOperation())->getValue()),
|
||||
childs[1].getChildren()[0]);
|
||||
}
|
||||
return ExpressionTreeNode(new Operation::MultiplyConstant(first), childs[1]);
|
||||
}
|
||||
if (op2 == Operation::CONSTANT)
|
||||
{ // Multiply by a constant
|
||||
if (op1 == Operation::MULTIPLY_CONSTANT)
|
||||
{ // Combine two multiplies into a single one
|
||||
return ExpressionTreeNode(
|
||||
new Operation::MultiplyConstant(second * dynamic_cast<const Operation::MultiplyConstant*>(&childs[0].getOperation())->getValue()),
|
||||
childs[0].getChildren()[0]);
|
||||
}
|
||||
return ExpressionTreeNode(new Operation::MultiplyConstant(second), childs[0]);
|
||||
}
|
||||
if (op1 == Operation::NEGATE && op2 == Operation::NEGATE)
|
||||
{ // The two negations cancel
|
||||
return ExpressionTreeNode(new Operation::Multiply(), childs[0].getChildren()[0], childs[1].getChildren()[0]);
|
||||
}
|
||||
if (op1 == Operation::NEGATE && op2 == Operation::MULTIPLY_CONSTANT)
|
||||
{ // Negate the constant
|
||||
return ExpressionTreeNode(new Operation::Multiply(), childs[0].getChildren()[0],
|
||||
ExpressionTreeNode(
|
||||
new Operation::MultiplyConstant(
|
||||
-dynamic_cast<const Operation::MultiplyConstant*>(&childs[1].getOperation())->getValue()),
|
||||
childs[1].getChildren()[0]));
|
||||
}
|
||||
if (op2 == Operation::NEGATE && op1 == Operation::MULTIPLY_CONSTANT)
|
||||
{ // Negate the constant
|
||||
return ExpressionTreeNode(new Operation::Multiply(),
|
||||
ExpressionTreeNode(
|
||||
new Operation::MultiplyConstant(
|
||||
-dynamic_cast<const Operation::MultiplyConstant*>(&childs[0].getOperation())->getValue()),
|
||||
childs[0].getChildren()[0]), childs[1].getChildren()[0]);
|
||||
}
|
||||
if (op1 == Operation::NEGATE)
|
||||
{ // Pull the negation out so it can possibly be optimized further
|
||||
return ExpressionTreeNode(new Operation::Negate(), ExpressionTreeNode(new Operation::Multiply(), childs[0].getChildren()[0], childs[1]));
|
||||
}
|
||||
if (op2 == Operation::NEGATE)
|
||||
{ // Pull the negation out so it can possibly be optimized further
|
||||
return ExpressionTreeNode(new Operation::Negate(), ExpressionTreeNode(new Operation::Multiply(), childs[0], childs[1].getChildren()[0]));
|
||||
}
|
||||
if (op2 == Operation::RECIPROCAL) { return ExpressionTreeNode(new Operation::Divide(), childs[0], childs[1].getChildren()[0]); } // a*(1/b) = a/b
|
||||
if (op1 == Operation::RECIPROCAL) { return ExpressionTreeNode(new Operation::Divide(), childs[1], childs[0].getChildren()[0]); } // (1/a)*b = b/a
|
||||
if (childs[0] == childs[1]) { return ExpressionTreeNode(new Operation::Square(), childs[0]); } // x*x = square(x)
|
||||
if (op1 == Operation::SQUARE && childs[0].getChildren()[0] == childs[1]) { return ExpressionTreeNode(new Operation::Cube(), childs[1]); } // x^3
|
||||
if (op2 == Operation::SQUARE && childs[1].getChildren()[0] == childs[0]) { return ExpressionTreeNode(new Operation::Cube(), childs[0]); } // x^3
|
||||
break;
|
||||
}
|
||||
case Operation::DIVIDE:
|
||||
{
|
||||
if (childs[0] == childs[1]) { return ExpressionTreeNode(new Operation::Constant(1.0)); } // Dividing anything from itself is 0
|
||||
const double numerator = getConstantValue(childs[0]);
|
||||
if (numerator == 0.0) { return ExpressionTreeNode(new Operation::Constant(0.0)); } // 0 divided by something
|
||||
if (numerator == 1.0) { return ExpressionTreeNode(new Operation::Reciprocal(), childs[1]); } // 1 divided by something
|
||||
const double denominator = getConstantValue(childs[1]);
|
||||
if (denominator == 1.0) { return childs[0]; } // Divide by 1
|
||||
if (op2 == Operation::CONSTANT)
|
||||
{
|
||||
if (op1 == Operation::MULTIPLY_CONSTANT)
|
||||
{ // Combine a multiply and a divide into one multiply
|
||||
return ExpressionTreeNode(new Operation::MultiplyConstant
|
||||
(dynamic_cast<const Operation::MultiplyConstant*>(&childs[0].getOperation())->getValue() / denominator),
|
||||
childs[0].getChildren()[0]);
|
||||
}
|
||||
return ExpressionTreeNode(new Operation::MultiplyConstant(1.0 / denominator), childs[0]); // Replace a divide with a multiply
|
||||
}
|
||||
if (op1 == Operation::NEGATE && op2 == Operation::NEGATE)
|
||||
{ // The two negations cancel
|
||||
return ExpressionTreeNode(new Operation::Divide(), childs[0].getChildren()[0], childs[1].getChildren()[0]);
|
||||
}
|
||||
if (op2 == Operation::NEGATE && op1 == Operation::MULTIPLY_CONSTANT)
|
||||
{ // Negate the constant
|
||||
return ExpressionTreeNode(new Operation::Divide(), ExpressionTreeNode(
|
||||
new Operation::MultiplyConstant(
|
||||
-dynamic_cast<const Operation::MultiplyConstant*>(&childs[0].getOperation())->getValue()),
|
||||
childs[0].getChildren()[0]), childs[1].getChildren()[0]);
|
||||
}
|
||||
if (op1 == Operation::NEGATE)
|
||||
{ // Pull the negation out so it can possibly be optimized further
|
||||
return ExpressionTreeNode(new Operation::Negate(), ExpressionTreeNode(new Operation::Divide(), childs[0].getChildren()[0], childs[1]));
|
||||
}
|
||||
if (op2 == Operation::NEGATE)
|
||||
{ // Pull the negation out so it can possibly be optimized further
|
||||
return ExpressionTreeNode(new Operation::Negate(), ExpressionTreeNode(new Operation::Divide(), childs[0], childs[1].getChildren()[0]));
|
||||
}
|
||||
if (childs[1].getOperation().getId() == Operation::RECIPROCAL)
|
||||
{ // a/(1/b) = a*b
|
||||
return ExpressionTreeNode(new Operation::Multiply(), childs[0], childs[1].getChildren()[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Operation::POWER:
|
||||
{
|
||||
double base = getConstantValue(childs[0]);
|
||||
if (base == 0.0) { return ExpressionTreeNode(new Operation::Constant(0.0)); } // 0 to any power is 0
|
||||
if (base == 1.0) { return ExpressionTreeNode(new Operation::Constant(1.0)); } // 1 to any power is 1
|
||||
double exponent = getConstantValue(childs[1]);
|
||||
if (exponent == 0.0) { return ExpressionTreeNode(new Operation::Constant(1.0)); } // x^0 = 1
|
||||
if (exponent == 1.0) { return childs[0]; } // x^1 = x
|
||||
if (exponent == -1.0) { return ExpressionTreeNode(new Operation::Reciprocal(), childs[0]); } // x^-1 = recip(x)
|
||||
if (exponent == 2.0) { return ExpressionTreeNode(new Operation::Square(), childs[0]); } // x^2 = square(x)
|
||||
if (exponent == 3.0) { return ExpressionTreeNode(new Operation::Cube(), childs[0]); } // x^3 = cube(x)
|
||||
if (exponent == 0.5) { return ExpressionTreeNode(new Operation::Sqrt(), childs[0]); } // x^0.5 = sqrt(x)
|
||||
if (exponent == exponent) { return ExpressionTreeNode(new Operation::PowerConstant(exponent), childs[0]); } // Constant power
|
||||
break;
|
||||
}
|
||||
case Operation::NEGATE:
|
||||
{
|
||||
if (op1 == Operation::MULTIPLY_CONSTANT)
|
||||
{ // Combine a multiply and a negate into a single multiply
|
||||
return ExpressionTreeNode(
|
||||
new Operation::MultiplyConstant(-dynamic_cast<const Operation::MultiplyConstant*>(&childs[0].getOperation())->getValue()),
|
||||
childs[0].getChildren()[0]);
|
||||
}
|
||||
if (op1 == Operation::CONSTANT) { return ExpressionTreeNode(new Operation::Constant(-getConstantValue(childs[0]))); } // Negate a constant
|
||||
if (op1 == Operation::NEGATE) { return childs[0].getChildren()[0]; } // The two negations cancel
|
||||
break;
|
||||
}
|
||||
case Operation::MULTIPLY_CONSTANT:
|
||||
{
|
||||
if (op1 == 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*>(&
|
||||
childs[0].getOperation())->getValue()), childs[0].getChildren()[0]);
|
||||
}
|
||||
if (op1 == Operation::CONSTANT)
|
||||
{ // Multiply two constants
|
||||
return ExpressionTreeNode(
|
||||
new Operation::Constant(
|
||||
dynamic_cast<const Operation::MultiplyConstant*>(&node.getOperation())->getValue() * getConstantValue(childs[0])));
|
||||
}
|
||||
if (op1 == 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()),
|
||||
childs[0].getChildren()[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// If operation ID is not one of the above,
|
||||
// we don't substitute a simpler expression.
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ExpressionTreeNode(node.getOperation().clone(), childs);
|
||||
}
|
||||
|
||||
ParsedExpression ParsedExpression::differentiate(const std::string& variable) const { return differentiate(getRootNode(), variable); }
|
||||
|
||||
ExpressionTreeNode ParsedExpression::differentiate(const ExpressionTreeNode& node, const std::string& variable)
|
||||
{
|
||||
std::vector<ExpressionTreeNode> childDerivs(node.getChildren().size());
|
||||
for (size_t i = 0; i < childDerivs.size(); ++i) { 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 std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
|
||||
ExpressionProgram ParsedExpression::createProgram() const { return ExpressionProgram(*this); }
|
||||
|
||||
CompiledExpression ParsedExpression::createCompiledExpression() const { return CompiledExpression(*this); }
|
||||
|
||||
ParsedExpression ParsedExpression::renameVariables(const std::map<std::string, std::string>& replacements) const
|
||||
{
|
||||
return ParsedExpression(renameNodeVariables(getRootNode(), replacements));
|
||||
}
|
||||
|
||||
ExpressionTreeNode ParsedExpression::renameNodeVariables(const ExpressionTreeNode& node, const std::map<std::string, std::string>& replacements)
|
||||
{
|
||||
if (node.getOperation().getId() == Operation::VARIABLE)
|
||||
{
|
||||
auto replace = replacements.find(node.getOperation().getName());
|
||||
if (replace != replacements.end()) { return ExpressionTreeNode(new Operation::Variable(replace->second)); }
|
||||
}
|
||||
std::vector<ExpressionTreeNode> children;
|
||||
for (size_t i = 0; i < node.getChildren().size(); ++i) { children.push_back(renameNodeVariables(node.getChildren()[i], replacements)); }
|
||||
return ExpressionTreeNode(node.getOperation().clone(), children);
|
||||
}
|
||||
|
||||
std::ostream& Lepton::operator<<(std::ostream& out, const ExpressionTreeNode& node)
|
||||
{
|
||||
if (node.getOperation().isInfixOperator() && node.getChildren().size() == 2)
|
||||
{
|
||||
out << "(" << node.getChildren()[0] << ")" << node.getOperation().getName() << "(" << node.getChildren()[1] << ")";
|
||||
}
|
||||
else if (node.getOperation().isInfixOperator() && node.getChildren().size() == 1)
|
||||
{
|
||||
out << "(" << node.getChildren()[0] << ")" << node.getOperation().getName();
|
||||
}
|
||||
else
|
||||
{
|
||||
out << node.getOperation().getName();
|
||||
if (!node.getChildren().empty())
|
||||
{
|
||||
out << "(";
|
||||
for (size_t i = 0; i < node.getChildren().size(); ++i)
|
||||
{
|
||||
if (i > 0) { out << ", "; }
|
||||
out << node.getChildren()[i];
|
||||
}
|
||||
out << ")";
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& Lepton::operator<<(std::ostream& out, const ParsedExpression& exp)
|
||||
{
|
||||
out << exp.getRootNode();
|
||||
return out;
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
#ifndef LEPTON_PARSED_EXPRESSION_H_
|
||||
#define LEPTON_PARSED_EXPRESSION_H_
|
||||
|
||||
/* -------------------------------------------------------------------------- *
|
||||
* 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=2013 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. *
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
#include "ExpressionTreeNode.h"
|
||||
#include "windowsIncludes.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace Lepton
|
||||
{
|
||||
class CompiledExpression;
|
||||
class ExpressionProgram;
|
||||
|
||||
/**
|
||||
* This class represents the result of parsing an expression. It provides methods for working with the
|
||||
* expression in various ways, such as evaluating it, getting the tree representation of the expresson, etc.
|
||||
*/
|
||||
|
||||
class LEPTON_EXPORT ParsedExpression
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create an uninitialized ParsedExpression. This exists so that ParsedExpressions can be put in STL containers.
|
||||
* Doing anything with it will produce an exception.
|
||||
*/
|
||||
ParsedExpression();
|
||||
/**
|
||||
* Create a ParsedExpression. Normally you will not call this directly. Instead, use the Parser class
|
||||
* to parse expression.
|
||||
*/
|
||||
ParsedExpression(const ExpressionTreeNode& rootNode);
|
||||
/**
|
||||
* Get the root node of the expression's abstract syntax tree.
|
||||
*/
|
||||
const ExpressionTreeNode& getRootNode() const;
|
||||
/**
|
||||
* Evaluate the expression. If the expression involves any variables, this method will throw an exception.
|
||||
*/
|
||||
double evaluate() const;
|
||||
/**
|
||||
* Evaluate the expression.
|
||||
*
|
||||
* @param variables a map specifying the values of all variables that appear in the expression. If any
|
||||
* variable appears in the expression but is not included in this map, an exception
|
||||
* will be thrown.
|
||||
*/
|
||||
double evaluate(const std::map<std::string, double>& variables) const;
|
||||
/**
|
||||
* Create a new ParsedExpression which produces the same result as this one, but is faster to evaluate.
|
||||
*/
|
||||
ParsedExpression optimize() const;
|
||||
/**
|
||||
* Create a new ParsedExpression which produces the same result as this one, but is faster to evaluate.
|
||||
*
|
||||
* @param variables a map specifying values for a subset of variables that appear in the expression.
|
||||
* All occurrences of these variables in the expression are replaced with the values
|
||||
* specified.
|
||||
*/
|
||||
ParsedExpression optimize(const std::map<std::string, double>& variables) const;
|
||||
/**
|
||||
* Create a new ParsedExpression which is the analytic derivative of this expression with respect to a
|
||||
* particular variable.
|
||||
*
|
||||
* @param variable the variable with respect to which the derivate should be taken
|
||||
*/
|
||||
ParsedExpression differentiate(const std::string& variable) const;
|
||||
/**
|
||||
* Create an ExpressionProgram that represents the same calculation as this expression.
|
||||
*/
|
||||
ExpressionProgram createProgram() const;
|
||||
/**
|
||||
* Create a CompiledExpression that represents the same calculation as this expression.
|
||||
*/
|
||||
CompiledExpression createCompiledExpression() const;
|
||||
/**
|
||||
* Create a new ParsedExpression which is identical to this one, except that the names of some
|
||||
* variables have been changed.
|
||||
*
|
||||
* @param replacements a map whose keys are the names of variables, and whose values are the
|
||||
* new names to replace them with
|
||||
*/
|
||||
ParsedExpression renameVariables(const std::map<std::string, std::string>& replacements) const;
|
||||
private:
|
||||
static double evaluate(const ExpressionTreeNode& node, const std::map<std::string, double>& variables);
|
||||
static ExpressionTreeNode preevaluateVariables(const ExpressionTreeNode& node, const std::map<std::string, double>& variables);
|
||||
static ExpressionTreeNode precalculateConstantSubexpressions(const ExpressionTreeNode& node);
|
||||
static ExpressionTreeNode substituteSimplerExpression(const ExpressionTreeNode& node);
|
||||
static ExpressionTreeNode differentiate(const ExpressionTreeNode& node, const std::string& variable);
|
||||
static double getConstantValue(const ExpressionTreeNode& node);
|
||||
static ExpressionTreeNode renameNodeVariables(const ExpressionTreeNode& node, const std::map<std::string, std::string>& replacements);
|
||||
ExpressionTreeNode rootNode;
|
||||
};
|
||||
|
||||
LEPTON_EXPORT std::ostream& operator<<(std::ostream& out, const ExpressionTreeNode& node);
|
||||
|
||||
LEPTON_EXPORT std::ostream& operator<<(std::ostream& out, const ParsedExpression& exp);
|
||||
} // namespace Lepton
|
||||
|
||||
#endif /*LEPTON_PARSED_EXPRESSION_H_*/
|
||||
@@ -0,0 +1,388 @@
|
||||
/* -------------------------------------------------------------------------- *
|
||||
* 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-2013 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. *
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
#include "Parser.h"
|
||||
#include "CustomFunction.h"
|
||||
#include "ExpressionTreeNode.h"
|
||||
#include "Operation.h"
|
||||
#include "ParsedExpression.h"
|
||||
#include <exception>
|
||||
#include <cctype>
|
||||
#include <iostream>
|
||||
|
||||
using namespace Lepton;
|
||||
|
||||
static const std::string Digits = "0123456789";
|
||||
static const std::string Operators = "+-*/^";
|
||||
static const bool LeftAssociative[] = { true, true, true, true, false };
|
||||
static const int Precedence[] = { 0, 0, 1, 1, 3 };
|
||||
static const Operation::Id OperationId[] = { Operation::ADD, Operation::SUBTRACT, Operation::MULTIPLY, Operation::DIVIDE, Operation::POWER };
|
||||
|
||||
class Lepton::ParseToken
|
||||
{
|
||||
public:
|
||||
enum Type { Number, Operator, Variable, Function, LeftParen, RightParen, Comma, Whitespace };
|
||||
|
||||
ParseToken(std::string text, Type type) : text(text), type(type) { }
|
||||
|
||||
const std::string& getText() const { return text; }
|
||||
|
||||
Type getType() const { return type; }
|
||||
|
||||
private:
|
||||
std::string text;
|
||||
Type type;
|
||||
};
|
||||
|
||||
std::string Parser::trim(const std::string& expression)
|
||||
{
|
||||
// Remove leading and trailing spaces.
|
||||
|
||||
size_t start, end;
|
||||
for (start = 0; start < expression.size() && isspace(expression[start]); ++start) { }
|
||||
for (end = expression.size() - 1; end > start && isspace(expression[end]); end--) { }
|
||||
if (start == end && isspace(expression[end])) { return ""; }
|
||||
return expression.substr(start, end - start + 1);
|
||||
}
|
||||
|
||||
ParseToken Parser::getNextToken(const std::string& expression, size_t start)
|
||||
{
|
||||
char c = expression[start];
|
||||
if (c == '(') { return ParseToken("(", ParseToken::LeftParen); }
|
||||
if (c == ')') { return ParseToken(")", ParseToken::RightParen); }
|
||||
if (c == ',') { return ParseToken(",", ParseToken::Comma); }
|
||||
if (Operators.find(c) != std::string::npos) { return ParseToken(std::string(1, c), ParseToken::Operator); }
|
||||
if (isspace(c))
|
||||
{
|
||||
// White space
|
||||
|
||||
for (size_t pos = start + 1; pos < expression.size(); ++pos)
|
||||
{
|
||||
if (!isspace(expression[pos])) { return ParseToken(expression.substr(start, pos - start), ParseToken::Whitespace); }
|
||||
}
|
||||
return ParseToken(expression.substr(start, std::string::npos), ParseToken::Whitespace);
|
||||
}
|
||||
if (c == '.' || Digits.find(c) != std::string::npos)
|
||||
{
|
||||
// A number
|
||||
|
||||
bool foundDecimal = (c == '.');
|
||||
bool foundExp = false;
|
||||
size_t pos = start + 1;
|
||||
for (; pos < expression.size(); ++pos)
|
||||
{
|
||||
c = expression[pos];
|
||||
if (Digits.find(c) != std::string::npos) { continue; }
|
||||
if (c == '.' && !foundDecimal)
|
||||
{
|
||||
foundDecimal = true;
|
||||
continue;
|
||||
}
|
||||
if ((c == 'e' || c == 'E') && !foundExp)
|
||||
{
|
||||
foundExp = true;
|
||||
if (pos < expression.size() - 1 && (expression[pos + 1] == '-' || expression[pos + 1] == '+')) { pos++; }
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ParseToken(expression.substr(start, pos - start), ParseToken::Number);
|
||||
}
|
||||
|
||||
// A variable, function, or left parenthesis
|
||||
|
||||
for (size_t pos = start; pos < expression.size(); ++pos)
|
||||
{
|
||||
c = expression[pos];
|
||||
if (c == '(') { return ParseToken(expression.substr(start, pos - start + 1), ParseToken::Function); }
|
||||
if (Operators.find(c) != std::string::npos || c == ',' || c == ')' || isspace(c))
|
||||
{
|
||||
return ParseToken(expression.substr(start, pos - start), ParseToken::Variable);
|
||||
}
|
||||
}
|
||||
return ParseToken(expression.substr(start, std::string::npos), ParseToken::Variable);
|
||||
}
|
||||
|
||||
std::vector<ParseToken> Parser::tokenize(const std::string& expression)
|
||||
{
|
||||
std::vector<ParseToken> tokens;
|
||||
size_t pos = 0;
|
||||
while (pos < expression.size())
|
||||
{
|
||||
ParseToken token = getNextToken(expression, pos);
|
||||
if (token.getType() != ParseToken::Whitespace) { tokens.push_back(token); }
|
||||
pos += token.getText().size();
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
ParsedExpression Parser::parse(const std::string& expression) { return parse(expression, std::map<std::string, CustomFunction*>()); }
|
||||
|
||||
ParsedExpression Parser::parse(const std::string& expression, const std::map<std::string, CustomFunction*>& customFunctions)
|
||||
{
|
||||
// First split the expression into subexpressions.
|
||||
|
||||
std::string primaryExpression = expression;
|
||||
std::vector<std::string> subexpressions;
|
||||
while (true)
|
||||
{
|
||||
std::string::size_type pos = primaryExpression.find_last_of(';');
|
||||
if (pos == std::string::npos) { break; }
|
||||
std::string sub = trim(primaryExpression.substr(pos + 1));
|
||||
if (!sub.empty()) { subexpressions.push_back(sub); }
|
||||
primaryExpression = primaryExpression.substr(0, pos);
|
||||
}
|
||||
|
||||
// Parse the subexpressions.
|
||||
|
||||
std::map<std::string, ExpressionTreeNode> subexpDefs;
|
||||
for (size_t i = 0; i < subexpressions.size(); ++i)
|
||||
{
|
||||
size_t equalsPos = subexpressions[i].find('=');
|
||||
if (equalsPos == std::string::npos) { throw Exception("Parse error: subexpression does not specify a name"); }
|
||||
std::string name = trim(subexpressions[i].substr(0, equalsPos));
|
||||
if (name.empty()) { throw Exception("Parse error: subexpression does not specify a name"); }
|
||||
std::vector<ParseToken> tokens = tokenize(subexpressions[i].substr(equalsPos + 1));
|
||||
size_t pos = 0;
|
||||
subexpDefs[name] = parsePrecedence(tokens, pos, customFunctions, subexpDefs, 0);
|
||||
if (pos != tokens.size()) { throw Exception("Parse error: unexpected text at end of subexpression: " + tokens[pos].getText()); }
|
||||
}
|
||||
|
||||
// Now parse the primary expression.
|
||||
|
||||
std::vector<ParseToken> tokens = tokenize(primaryExpression);
|
||||
size_t pos = 0;
|
||||
ExpressionTreeNode result = parsePrecedence(tokens, pos, customFunctions, subexpDefs, 0);
|
||||
if (pos != tokens.size()) { throw Exception("Parse error: unexpected text at end of expression: " + tokens[pos].getText()); }
|
||||
return ParsedExpression(result);
|
||||
}
|
||||
|
||||
ExpressionTreeNode Parser::parsePrecedence(const std::vector<ParseToken>& tokens, size_t& pos, const std::map<std::string, CustomFunction*>& customFunctions,
|
||||
const std::map<std::string, ExpressionTreeNode>& subexpressionDefs, int precedence)
|
||||
{
|
||||
if (pos == tokens.size()) { throw Exception("Parse error: unexpected end of expression"); }
|
||||
|
||||
// Parse the next value (number, variable, function, parenthesized expression)
|
||||
|
||||
ParseToken token = tokens[pos];
|
||||
ExpressionTreeNode result;
|
||||
if (token.getType() == ParseToken::Number)
|
||||
{
|
||||
double value;
|
||||
std::stringstream(token.getText()) >> value;
|
||||
result = ExpressionTreeNode(new Operation::Constant(value));
|
||||
pos++;
|
||||
}
|
||||
else if (token.getType() == ParseToken::Variable)
|
||||
{
|
||||
const auto subexp = subexpressionDefs.find(token.getText());
|
||||
if (subexp == subexpressionDefs.end())
|
||||
{
|
||||
Operation* op = new Operation::Variable(token.getText());
|
||||
result = ExpressionTreeNode(op);
|
||||
}
|
||||
else { result = subexp->second; }
|
||||
pos++;
|
||||
}
|
||||
else if (token.getType() == ParseToken::LeftParen)
|
||||
{
|
||||
pos++;
|
||||
result = parsePrecedence(tokens, pos, customFunctions, subexpressionDefs, 0);
|
||||
if (pos == tokens.size() || tokens[pos].getType() != ParseToken::RightParen) { throw Exception("Parse error: unbalanced parentheses"); }
|
||||
pos++;
|
||||
}
|
||||
else if (token.getType() == ParseToken::Function)
|
||||
{
|
||||
pos++;
|
||||
std::vector<ExpressionTreeNode> args;
|
||||
bool moreArgs;
|
||||
do
|
||||
{
|
||||
args.push_back(parsePrecedence(tokens, pos, customFunctions, subexpressionDefs, 0));
|
||||
moreArgs = (pos < tokens.size() && tokens[pos].getType() == ParseToken::Comma);
|
||||
if (moreArgs) { pos++; }
|
||||
} while (moreArgs);
|
||||
if (pos == tokens.size() || tokens[pos].getType() != ParseToken::RightParen) { throw Exception("Parse error: unbalanced parentheses"); }
|
||||
pos++;
|
||||
Operation* op = getFunctionOperation(token.getText(), customFunctions);
|
||||
try { result = ExpressionTreeNode(op, args); }
|
||||
catch (...)
|
||||
{
|
||||
delete op;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
else if (token.getType() == ParseToken::Operator && token.getText() == "-")
|
||||
{
|
||||
pos++;
|
||||
const ExpressionTreeNode toNegate = parsePrecedence(tokens, pos, customFunctions, subexpressionDefs, 2);
|
||||
result = ExpressionTreeNode(new Operation::Negate(), toNegate);
|
||||
}
|
||||
else { throw Exception("Parse error: unexpected token: " + token.getText()); }
|
||||
|
||||
// Now deal with the next binary operator.
|
||||
|
||||
while (pos < tokens.size() && tokens[pos].getType() == ParseToken::Operator)
|
||||
{
|
||||
token = tokens[pos];
|
||||
int opIndex = int(Operators.find(token.getText()));
|
||||
int opPrecedence = Precedence[opIndex];
|
||||
if (opPrecedence < precedence) { return result; }
|
||||
pos++;
|
||||
ExpressionTreeNode arg = parsePrecedence(tokens, pos, customFunctions, subexpressionDefs, LeftAssociative[opIndex] ? opPrecedence + 1 : opPrecedence);
|
||||
Operation* op = getOperatorOperation(token.getText());
|
||||
try { result = ExpressionTreeNode(op, result, arg); }
|
||||
catch (...)
|
||||
{
|
||||
delete op;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Operation* Parser::getOperatorOperation(const std::string& name)
|
||||
{
|
||||
switch (OperationId[Operators.find(name)])
|
||||
{
|
||||
case Operation::ADD:
|
||||
return new Operation::Add();
|
||||
case Operation::SUBTRACT:
|
||||
return new Operation::Subtract();
|
||||
case Operation::MULTIPLY:
|
||||
return new Operation::Multiply();
|
||||
case Operation::DIVIDE:
|
||||
return new Operation::Divide();
|
||||
case Operation::POWER:
|
||||
return new Operation::Power();
|
||||
default:
|
||||
throw Exception("Parse error: unknown operator");
|
||||
}
|
||||
}
|
||||
|
||||
Operation* Parser::getFunctionOperation(const std::string& name, const std::map<std::string, CustomFunction*>& customFunctions)
|
||||
{
|
||||
static std::map<std::string, Operation::Id> opMap;
|
||||
if (opMap.empty())
|
||||
{
|
||||
opMap["sqrt"] = Operation::SQRT;
|
||||
opMap["exp"] = Operation::EXP;
|
||||
opMap["log"] = Operation::LOG;
|
||||
opMap["sin"] = Operation::SIN;
|
||||
opMap["cos"] = Operation::COS;
|
||||
opMap["sec"] = Operation::SEC;
|
||||
opMap["csc"] = Operation::CSC;
|
||||
opMap["tan"] = Operation::TAN;
|
||||
opMap["cot"] = Operation::COT;
|
||||
opMap["asin"] = Operation::ASIN;
|
||||
opMap["acos"] = Operation::ACOS;
|
||||
opMap["atan"] = Operation::ATAN;
|
||||
opMap["sinh"] = Operation::SINH;
|
||||
opMap["cosh"] = Operation::COSH;
|
||||
opMap["tanh"] = Operation::TANH;
|
||||
opMap["erf"] = Operation::ERF;
|
||||
opMap["erfc"] = Operation::ERFC;
|
||||
opMap["step"] = Operation::STEP;
|
||||
opMap["delta"] = Operation::DELTA;
|
||||
opMap["square"] = Operation::SQUARE;
|
||||
opMap["cube"] = Operation::CUBE;
|
||||
opMap["recip"] = Operation::RECIPROCAL;
|
||||
opMap["min"] = Operation::MIN;
|
||||
opMap["max"] = Operation::MAX;
|
||||
opMap["abs"] = Operation::ABS;
|
||||
}
|
||||
const std::string trimmed = name.substr(0, name.size() - 1);
|
||||
|
||||
// First check custom functions.
|
||||
|
||||
const auto custom = customFunctions.find(trimmed);
|
||||
if (custom != customFunctions.end()) { return new Operation::Custom(trimmed, custom->second->clone()); }
|
||||
|
||||
// Now try standard functions.
|
||||
|
||||
const auto iter = opMap.find(trimmed);
|
||||
if (iter == opMap.end()) { throw Exception("Parse error: unknown function: " + trimmed); }
|
||||
switch (iter->second)
|
||||
{
|
||||
case Operation::SQRT:
|
||||
return new Operation::Sqrt();
|
||||
case Operation::EXP:
|
||||
return new Operation::Exp();
|
||||
case Operation::LOG:
|
||||
return new Operation::Log();
|
||||
case Operation::SIN:
|
||||
return new Operation::Sin();
|
||||
case Operation::COS:
|
||||
return new Operation::Cos();
|
||||
case Operation::SEC:
|
||||
return new Operation::Sec();
|
||||
case Operation::CSC:
|
||||
return new Operation::Csc();
|
||||
case Operation::TAN:
|
||||
return new Operation::Tan();
|
||||
case Operation::COT:
|
||||
return new Operation::Cot();
|
||||
case Operation::ASIN:
|
||||
return new Operation::Asin();
|
||||
case Operation::ACOS:
|
||||
return new Operation::Acos();
|
||||
case Operation::ATAN:
|
||||
return new Operation::Atan();
|
||||
case Operation::SINH:
|
||||
return new Operation::Sinh();
|
||||
case Operation::COSH:
|
||||
return new Operation::Cosh();
|
||||
case Operation::TANH:
|
||||
return new Operation::Tanh();
|
||||
case Operation::ERF:
|
||||
return new Operation::Erf();
|
||||
case Operation::ERFC:
|
||||
return new Operation::Erfc();
|
||||
case Operation::STEP:
|
||||
return new Operation::Step();
|
||||
case Operation::DELTA:
|
||||
return new Operation::Delta();
|
||||
case Operation::SQUARE:
|
||||
return new Operation::Square();
|
||||
case Operation::CUBE:
|
||||
return new Operation::Cube();
|
||||
case Operation::RECIPROCAL:
|
||||
return new Operation::Reciprocal();
|
||||
case Operation::MIN:
|
||||
return new Operation::Min();
|
||||
case Operation::MAX:
|
||||
return new Operation::Max();
|
||||
case Operation::ABS:
|
||||
return new Operation::Abs();
|
||||
default:
|
||||
throw Exception("Parse error: unknown function");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
#ifndef LEPTON_PARSER_H_
|
||||
#define LEPTON_PARSER_H_
|
||||
|
||||
/* -------------------------------------------------------------------------- *
|
||||
* 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. *
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
#include "windowsIncludes.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Lepton
|
||||
{
|
||||
class CustomFunction;
|
||||
class ExpressionTreeNode;
|
||||
class Operation;
|
||||
class ParsedExpression;
|
||||
class ParseToken;
|
||||
|
||||
/**
|
||||
* This class provides the main interface for parsing expressions.
|
||||
*/
|
||||
|
||||
class LEPTON_EXPORT Parser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Parse a mathematical expression and return a representation of it as an abstract syntax tree.
|
||||
*/
|
||||
static ParsedExpression parse(const std::string& expression);
|
||||
/**
|
||||
* Parse a mathematical expression and return a representation of it as an abstract syntax tree.
|
||||
*
|
||||
* @param expression
|
||||
* @param customFunctions a map specifying user defined functions that may appear in the expression.
|
||||
* The key are function names, and the values are corresponding CustomFunction objects.
|
||||
*/
|
||||
static ParsedExpression parse(const std::string& expression, const std::map<std::string, CustomFunction*>& customFunctions);
|
||||
private:
|
||||
static std::string trim(const std::string& expression);
|
||||
static std::vector<ParseToken> tokenize(const std::string& expression);
|
||||
static ParseToken getNextToken(const std::string& expression, size_t start);
|
||||
static ExpressionTreeNode parsePrecedence(const std::vector<ParseToken>& tokens, size_t& pos,
|
||||
const std::map<std::string, CustomFunction*>& customFunctions,
|
||||
const std::map<std::string, ExpressionTreeNode>& subexpressionDefs, int precedence);
|
||||
static Operation* getOperatorOperation(const std::string& name);
|
||||
static Operation* getFunctionOperation(const std::string& name, const std::map<std::string, CustomFunction*>& customFunctions);
|
||||
};
|
||||
} // namespace Lepton
|
||||
|
||||
#endif /*LEPTON_PARSER_H_*/
|
||||
@@ -0,0 +1,41 @@
|
||||
#ifndef LEPTON_WINDOW_INCLUDE_H_
|
||||
#define LEPTON_WINDOW_INCLUDE_H_
|
||||
|
||||
/*
|
||||
* Shared libraries are messy in Visual Studio. We have to distinguish three
|
||||
* cases:
|
||||
* (1) this header is being used to build the Lepton shared library
|
||||
* (dllexport)
|
||||
* (2) this header is being used by a *client* of the Lepton shared
|
||||
* library (dllimport)
|
||||
* (3) we are building the Lepton static library, or the client is
|
||||
* being compiled with the expectation of linking with the
|
||||
* Lepton static library (nothing special needed)
|
||||
* In the CMake script for building this library, we define one of the symbols
|
||||
* Lepton_BUILDING_{SHARED|STATIC}_LIBRARY
|
||||
* Client code normally has no special symbol defined, in which case we'll
|
||||
* assume it wants to use the shared library. However, if the client defines
|
||||
* the symbol LEPTON_USE_STATIC_LIBRARIES we'll suppress the dllimport so
|
||||
* that the client code can be linked with static libraries. Note that
|
||||
* the client symbol is not library dependent, while the library symbols
|
||||
* affect only the Lepton library, meaning that other libraries can
|
||||
* be clients of this one. However, we are assuming all-static or all-shared.
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// We don't want to hear about how sprintf is "unsafe".
|
||||
#pragma warning(disable:4996)
|
||||
#if defined(LEPTON_BUILDING_SHARED_LIBRARY)
|
||||
#define LEPTON_EXPORT __declspec(dllexport)
|
||||
// Keep MS VC++ quiet about lack of dll export of private members.
|
||||
#pragma warning(disable:4251)
|
||||
#elif defined(LEPTON_BUILDING_STATIC_LIBRARY) || defined(LEPTON_USE_STATIC_LIBRARIES)
|
||||
#define LEPTON_EXPORT __declspec(dllimport) // i.e., a client of a shared library
|
||||
#else
|
||||
#define LEPTON_EXPORT
|
||||
#endif
|
||||
#else
|
||||
#define LEPTON_EXPORT // Linux, Mac
|
||||
#endif
|
||||
|
||||
#endif // LEPTON_WINDOW_INCLUDE_H_
|
||||
Reference in New Issue
Block a user