/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * -------------------------------------------------------------------------- * * 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-2016 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. * * -------------------------------------------------------------------------- * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ #ifndef __PLUMED_lepton_Operation_h #define __PLUMED_lepton_Operation_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-2015 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 "CustomFunction.h" #include "Exception.h" #include #include #include #include #include #include #include namespace PLMD { namespace lepton { class ExpressionTreeNode; /** * An Operation represents a single step in the evaluation of an expression, such as a function, * an operator, or a constant value. Each Operation takes some number of values as arguments * and produces a single value. * * This is an abstract class with subclasses for specific operations. */ class LEPTON_EXPORT Operation { public: virtual ~Operation() { } /** * This enumeration lists all Operation subclasses. This is provided so that switch statements * can be used when processing or analyzing parsed expressions. */ enum Id {CONSTANT, VARIABLE, CUSTOM, ADD, SUBTRACT, MULTIPLY, DIVIDE, POWER, NEGATE, SQRT, EXP, LOG, SIN, COS, SEC, CSC, TAN, COT, ASIN, ACOS, ATAN, SINH, COSH, TANH, ERF, ERFC, STEP, DELTA, NANDELTA, SQUARE, CUBE, RECIPROCAL, ADD_CONSTANT, MULTIPLY_CONSTANT, POWER_CONSTANT, MIN, MAX, ABS, FLOOR, CEIL, SELECT, ACOT, ASEC, ACSC, COTH, SECH, CSCH, ASINH, ACOSH, ATANH, ACOTH, ASECH, ACSCH, ATAN2}; /** * Get the name of this Operation. */ virtual std::string getName() const = 0; /** * Get this Operation's ID. */ virtual Id getId() const = 0; /** * Get the number of arguments this operation expects. */ virtual int getNumArguments() const = 0; /** * Create a clone of this Operation. */ virtual Operation* clone() const = 0; /** * Perform the computation represented by this operation. * * @param args the array of arguments * @param variables a map containing the values of all variables * @return the result of performing the computation. */ virtual double evaluate(double* args, const std::map& variables) const = 0; /** * Return an ExpressionTreeNode which represents the analytic derivative of this Operation with respect to a variable. * * @param children the child nodes * @param childDerivs the derivatives of the child nodes with respect to the variable * @param variable the variable with respect to which the derivate should be taken */ virtual ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const = 0; /** * Get whether this operation should be displayed with infix notation. */ virtual bool isInfixOperator() const { return false; } /** * Get whether this is a symmetric binary operation, such that exchanging its arguments * does not affect the result. */ virtual bool isSymmetric() const { return false; } virtual bool operator!=(const Operation& op) const { return op.getId() != getId(); } virtual bool operator==(const Operation& op) const { return !(*this != op); } class Constant; class Variable; class Custom; class Add; class Subtract; class Multiply; class Divide; class Power; class Negate; class Sqrt; class Exp; class Log; class Sin; class Cos; class Sec; class Csc; class Tan; class Cot; class Asin; class Acos; class Atan; class Sinh; class Cosh; class Tanh; class Erf; class Erfc; class Step; class Delta; class Nandelta; class Square; class Cube; class Reciprocal; class AddConstant; class MultiplyConstant; class PowerConstant; class Min; class Max; class Abs; class Floor; class Ceil; class Select; class Acot; class Asec; class Acsc; class Coth; class Sech; class Csch; class Asinh; class Acosh; class Atanh; class Acoth; class Asech; class Acsch; class Atan2; }; class LEPTON_EXPORT Operation::Constant : public Operation { public: Constant(double value) : value(value) { } std::string getName() const { std::stringstream name; name << value; return name.str(); } Id getId() const { return CONSTANT; } int getNumArguments() const { return 0; } Operation* clone() const { return new Constant(value); } double evaluate(double* args, const std::map& variables) const { return value; } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; double getValue() const { return value; } bool operator!=(const Operation& op) const { const Constant* o = dynamic_cast(&op); return (o == NULL || o->value != value); } private: double value; }; class LEPTON_EXPORT Operation::Variable : public Operation { public: Variable(const std::string& name) : name(name) { } std::string getName() const { return name; } Id getId() const { return VARIABLE; } int getNumArguments() const { return 0; } Operation* clone() const { return new Variable(name); } double evaluate(double* args, const std::map& variables) const { std::map::const_iterator iter = variables.find(name); if (iter == variables.end()) throw Exception("No value specified for variable "+name); return iter->second; } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; bool operator!=(const Operation& op) const { const Variable* o = dynamic_cast(&op); return (o == NULL || o->name != name); } private: std::string name; }; class LEPTON_EXPORT Operation::Custom : public Operation { public: Custom(const std::string& name, CustomFunction* function) : name(name), function(function), isDerivative(false), derivOrder(function->getNumArguments(), 0) { } Custom(const Custom& base, int derivIndex) : name(base.name), function(base.function->clone()), isDerivative(true), derivOrder(base.derivOrder) { derivOrder[derivIndex]++; } ~Custom() { delete function; } std::string getName() const { return name; } Id getId() const { return CUSTOM; } int getNumArguments() const { return function->getNumArguments(); } Operation* clone() const { Custom* clone = new Custom(name, function->clone()); clone->isDerivative = isDerivative; clone->derivOrder = derivOrder; return clone; } double evaluate(double* args, const std::map& variables) const { if (isDerivative) return function->evaluateDerivative(args, &derivOrder[0]); return function->evaluate(args); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; const std::vector& getDerivOrder() const { return derivOrder; } bool operator!=(const Operation& op) const { const Custom* o = dynamic_cast(&op); return (o == NULL || o->name != name || o->isDerivative != isDerivative || o->derivOrder != derivOrder); } private: std::string name; CustomFunction* function; bool isDerivative; std::vector derivOrder; }; class LEPTON_EXPORT Operation::Add : public Operation { public: Add() { } std::string getName() const { return "+"; } Id getId() const { return ADD; } int getNumArguments() const { return 2; } Operation* clone() const { return new Add(); } double evaluate(double* args, const std::map& variables) const { return args[0]+args[1]; } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; bool isInfixOperator() const { return true; } bool isSymmetric() const { return true; } }; class LEPTON_EXPORT Operation::Subtract : public Operation { public: Subtract() { } std::string getName() const { return "-"; } Id getId() const { return SUBTRACT; } int getNumArguments() const { return 2; } Operation* clone() const { return new Subtract(); } double evaluate(double* args, const std::map& variables) const { return args[0]-args[1]; } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; bool isInfixOperator() const { return true; } }; class LEPTON_EXPORT Operation::Multiply : public Operation { public: Multiply() { } std::string getName() const { return "*"; } Id getId() const { return MULTIPLY; } int getNumArguments() const { return 2; } Operation* clone() const { return new Multiply(); } double evaluate(double* args, const std::map& variables) const { return args[0]*args[1]; } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; bool isInfixOperator() const { return true; } bool isSymmetric() const { return true; } }; class LEPTON_EXPORT Operation::Divide : public Operation { public: Divide() { } std::string getName() const { return "/"; } Id getId() const { return DIVIDE; } int getNumArguments() const { return 2; } Operation* clone() const { return new Divide(); } double evaluate(double* args, const std::map& variables) const { return args[0]/args[1]; } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; bool isInfixOperator() const { return true; } }; class LEPTON_EXPORT Operation::Power : public Operation { public: Power() { } std::string getName() const { return "^"; } Id getId() const { return POWER; } int getNumArguments() const { return 2; } Operation* clone() const { return new Power(); } double evaluate(double* args, const std::map& variables) const { return std::pow(args[0], args[1]); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; bool isInfixOperator() const { return true; } }; class LEPTON_EXPORT Operation::Negate : public Operation { public: Negate() { } std::string getName() const { return "-"; } Id getId() const { return NEGATE; } int getNumArguments() const { return 1; } Operation* clone() const { return new Negate(); } double evaluate(double* args, const std::map& variables) const { return -args[0]; } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Sqrt : public Operation { public: Sqrt() { } std::string getName() const { return "sqrt"; } Id getId() const { return SQRT; } int getNumArguments() const { return 1; } Operation* clone() const { return new Sqrt(); } double evaluate(double* args, const std::map& variables) const { return std::sqrt(args[0]); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Exp : public Operation { public: Exp() { } std::string getName() const { return "exp"; } Id getId() const { return EXP; } int getNumArguments() const { return 1; } Operation* clone() const { return new Exp(); } double evaluate(double* args, const std::map& variables) const { return std::exp(args[0]); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Log : public Operation { public: Log() { } std::string getName() const { return "log"; } Id getId() const { return LOG; } int getNumArguments() const { return 1; } Operation* clone() const { return new Log(); } double evaluate(double* args, const std::map& variables) const { return std::log(args[0]); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Sin : public Operation { public: Sin() { } std::string getName() const { return "sin"; } Id getId() const { return SIN; } int getNumArguments() const { return 1; } Operation* clone() const { return new Sin(); } double evaluate(double* args, const std::map& variables) const { return std::sin(args[0]); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Cos : public Operation { public: Cos() { } std::string getName() const { return "cos"; } Id getId() const { return COS; } int getNumArguments() const { return 1; } Operation* clone() const { return new Cos(); } double evaluate(double* args, const std::map& variables) const { return std::cos(args[0]); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Sec : public Operation { public: Sec() { } std::string getName() const { return "sec"; } Id getId() const { return SEC; } int getNumArguments() const { return 1; } Operation* clone() const { return new Sec(); } double evaluate(double* args, const std::map& variables) const { return 1.0/std::cos(args[0]); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Csc : public Operation { public: Csc() { } std::string getName() const { return "csc"; } Id getId() const { return CSC; } int getNumArguments() const { return 1; } Operation* clone() const { return new Csc(); } double evaluate(double* args, const std::map& variables) const { return 1.0/std::sin(args[0]); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Tan : public Operation { public: Tan() { } std::string getName() const { return "tan"; } Id getId() const { return TAN; } int getNumArguments() const { return 1; } Operation* clone() const { return new Tan(); } double evaluate(double* args, const std::map& variables) const { return std::tan(args[0]); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Cot : public Operation { public: Cot() { } std::string getName() const { return "cot"; } Id getId() const { return COT; } int getNumArguments() const { return 1; } Operation* clone() const { return new Cot(); } double evaluate(double* args, const std::map& variables) const { return 1.0/std::tan(args[0]); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Asin : public Operation { public: Asin() { } std::string getName() const { return "asin"; } Id getId() const { return ASIN; } int getNumArguments() const { return 1; } Operation* clone() const { return new Asin(); } double evaluate(double* args, const std::map& variables) const { return std::asin(args[0]); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Acos : public Operation { public: Acos() { } std::string getName() const { return "acos"; } Id getId() const { return ACOS; } int getNumArguments() const { return 1; } Operation* clone() const { return new Acos(); } double evaluate(double* args, const std::map& variables) const { return std::acos(args[0]); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Atan : public Operation { public: Atan() { } std::string getName() const { return "atan"; } Id getId() const { return ATAN; } int getNumArguments() const { return 1; } Operation* clone() const { return new Atan(); } double evaluate(double* args, const std::map& variables) const { return std::atan(args[0]); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Sinh : public Operation { public: Sinh() { } std::string getName() const { return "sinh"; } Id getId() const { return SINH; } int getNumArguments() const { return 1; } Operation* clone() const { return new Sinh(); } double evaluate(double* args, const std::map& variables) const { return std::sinh(args[0]); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Cosh : public Operation { public: Cosh() { } std::string getName() const { return "cosh"; } Id getId() const { return COSH; } int getNumArguments() const { return 1; } Operation* clone() const { return new Cosh(); } double evaluate(double* args, const std::map& variables) const { return std::cosh(args[0]); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Tanh : public Operation { public: Tanh() { } std::string getName() const { return "tanh"; } Id getId() const { return TANH; } int getNumArguments() const { return 1; } Operation* clone() const { return new Tanh(); } double evaluate(double* args, const std::map& variables) const { return std::tanh(args[0]); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Erf : public Operation { public: Erf() { } std::string getName() const { return "erf"; } Id getId() const { return ERF; } int getNumArguments() const { return 1; } Operation* clone() const { return new Erf(); } double evaluate(double* args, const std::map& variables) const; ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Erfc : public Operation { public: Erfc() { } std::string getName() const { return "erfc"; } Id getId() const { return ERFC; } int getNumArguments() const { return 1; } Operation* clone() const { return new Erfc(); } double evaluate(double* args, const std::map& variables) const; ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Step : public Operation { public: Step() { } std::string getName() const { return "step"; } Id getId() const { return STEP; } int getNumArguments() const { return 1; } Operation* clone() const { return new Step(); } double evaluate(double* args, const std::map& variables) const { return (args[0] >= 0.0 ? 1.0 : 0.0); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Delta : public Operation { public: Delta() { } std::string getName() const { return "delta"; } Id getId() const { return DELTA; } int getNumArguments() const { return 1; } Operation* clone() const { return new Delta(); } double evaluate(double* args, const std::map& variables) const { return (args[0] == 0.0 ? 1.0/0.0 : 0.0); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Nandelta : public Operation { public: Nandelta() { } std::string getName() const { return "nandelta"; } Id getId() const { return NANDELTA; } int getNumArguments() const { return 1; } Operation* clone() const { return new Nandelta(); } double evaluate(double* args, const std::map& variables) const { return (args[0] == 0.0 ? std::numeric_limits::quiet_NaN() : 0.0); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Square : public Operation { public: Square() { } std::string getName() const { return "square"; } Id getId() const { return SQUARE; } int getNumArguments() const { return 1; } Operation* clone() const { return new Square(); } double evaluate(double* args, const std::map& variables) const { return args[0]*args[0]; } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Cube : public Operation { public: Cube() { } std::string getName() const { return "cube"; } Id getId() const { return CUBE; } int getNumArguments() const { return 1; } Operation* clone() const { return new Cube(); } double evaluate(double* args, const std::map& variables) const { return args[0]*args[0]*args[0]; } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Reciprocal : public Operation { public: Reciprocal() { } std::string getName() const { return "recip"; } Id getId() const { return RECIPROCAL; } int getNumArguments() const { return 1; } Operation* clone() const { return new Reciprocal(); } double evaluate(double* args, const std::map& variables) const { return 1.0/args[0]; } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::AddConstant : public Operation { public: AddConstant(double value) : value(value) { } std::string getName() const { std::stringstream name; name << value << "+"; return name.str(); } Id getId() const { return ADD_CONSTANT; } int getNumArguments() const { return 1; } Operation* clone() const { return new AddConstant(value); } double evaluate(double* args, const std::map& variables) const { return args[0]+value; } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; double getValue() const { return value; } bool operator!=(const Operation& op) const { const AddConstant* o = dynamic_cast(&op); return (o == NULL || o->value != value); } private: double value; }; class LEPTON_EXPORT Operation::MultiplyConstant : public Operation { public: MultiplyConstant(double value) : value(value) { } std::string getName() const { std::stringstream name; name << value << "*"; return name.str(); } Id getId() const { return MULTIPLY_CONSTANT; } int getNumArguments() const { return 1; } Operation* clone() const { return new MultiplyConstant(value); } double evaluate(double* args, const std::map& variables) const { return args[0]*value; } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; double getValue() const { return value; } bool operator!=(const Operation& op) const { const MultiplyConstant* o = dynamic_cast(&op); return (o == NULL || o->value != value); } private: double value; }; class LEPTON_EXPORT Operation::PowerConstant : public Operation { public: PowerConstant(double value) : value(value) { intValue = (int) value; isIntPower = (intValue == value); } std::string getName() const { std::stringstream name; name << "^" << value; return name.str(); } Id getId() const { return POWER_CONSTANT; } int getNumArguments() const { return 1; } Operation* clone() const { return new PowerConstant(value); } double evaluate(double* args, const std::map& variables) const { if (isIntPower) { // Integer powers can be computed much more quickly by repeated multiplication. int exponent = intValue; double base = args[0]; if (exponent < 0) { exponent = -exponent; base = 1.0/base; } double result = 1.0; while (exponent != 0) { if ((exponent&1) == 1) result *= base; base *= base; exponent = exponent>>1; } return result; } else return std::pow(args[0], value); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; double getValue() const { return value; } bool operator!=(const Operation& op) const { const PowerConstant* o = dynamic_cast(&op); return (o == NULL || o->value != value); } bool isInfixOperator() const { return true; } private: double value; int intValue; bool isIntPower; }; class LEPTON_EXPORT Operation::Min : public Operation { public: Min() { } std::string getName() const { return "min"; } Id getId() const { return MIN; } int getNumArguments() const { return 2; } Operation* clone() const { return new Min(); } double evaluate(double* args, const std::map& variables) const { // parens around (std::min) are workaround for horrible microsoft max/min macro trouble return (std::min)(args[0], args[1]); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Max : public Operation { public: Max() { } std::string getName() const { return "max"; } Id getId() const { return MAX; } int getNumArguments() const { return 2; } Operation* clone() const { return new Max(); } double evaluate(double* args, const std::map& variables) const { // parens around (std::min) are workaround for horrible microsoft max/min macro trouble return (std::max)(args[0], args[1]); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Abs : public Operation { public: Abs() { } std::string getName() const { return "abs"; } Id getId() const { return ABS; } int getNumArguments() const { return 1; } Operation* clone() const { return new Abs(); } double evaluate(double* args, const std::map& variables) const { return std::abs(args[0]); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Floor : public Operation { public: Floor() { } std::string getName() const { return "floor"; } Id getId() const { return FLOOR; } int getNumArguments() const { return 1; } Operation* clone() const { return new Floor(); } double evaluate(double* args, const std::map& variables) const { return std::floor(args[0]); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Ceil : public Operation { public: Ceil() { } std::string getName() const { return "ceil"; } Id getId() const { return CEIL; } int getNumArguments() const { return 1; } Operation* clone() const { return new Ceil(); } double evaluate(double* args, const std::map& variables) const { return std::ceil(args[0]); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; class LEPTON_EXPORT Operation::Select : public Operation { public: Select() { } std::string getName() const { return "select"; } Id getId() const { return SELECT; } int getNumArguments() const { return 3; } Operation* clone() const { return new Select(); } double evaluate(double* args, const std::map& variables) const { return (args[0] != 0.0 ? args[1] : args[2]); } ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; }; #define LEPTON_CLASS_OPERATION(Name,name,NAME,nargs,impl) \ class LEPTON_EXPORT Operation::Name : public Operation { \ public: \ Name() { \ } \ std::string getName() const { \ return #name; \ } \ Id getId() const { \ return NAME; \ } \ int getNumArguments() const { \ return nargs; \ } \ Operation* clone() const { \ return new Name(); \ } \ double evaluate(double* args, const std::map& variables) const { \ return impl; \ } \ ExpressionTreeNode differentiate(const std::vector& children, const std::vector& childDerivs, const std::string& variable) const; \ } LEPTON_CLASS_OPERATION(Acot,acot,ACOT,1,std::atan(1.0/args[0])); LEPTON_CLASS_OPERATION(Asec,asec,ASEC,1,std::acos(1.0/args[0])); LEPTON_CLASS_OPERATION(Acsc,acsc,ACSC,1,std::asin(1.0/args[0])); LEPTON_CLASS_OPERATION(Coth,coth,ACOT,1,1.0/std::tanh(args[0])); LEPTON_CLASS_OPERATION(Sech,sech,SECH,1,1.0/std::cosh(args[0])); LEPTON_CLASS_OPERATION(Csch,csch,CSCH,1,1.0/std::sinh(args[0])); LEPTON_CLASS_OPERATION(Asinh,asinh,ASINH,1,std::asinh(args[0])); LEPTON_CLASS_OPERATION(Acosh,acosh,ACOSH,1,std::acosh(args[0])); LEPTON_CLASS_OPERATION(Atanh,atanh,ATANH,1,std::atanh(args[0])); LEPTON_CLASS_OPERATION(Acoth,acoth,ACOTH,1,0.5*std::log((args[0]+1.0)/(args[0]-1.0))); LEPTON_CLASS_OPERATION(Asech,asech,ASECH,1,std::log(std::sqrt(1.0/args[0]-1.0)*std::sqrt(1.0/args[0]+1.0)+1.0/args[0])); LEPTON_CLASS_OPERATION(Acsch,acsch,ACSCH,1,std::log(1.0/args[0]+std::sqrt(1.0/(args[0]*args[0])+1.0))); LEPTON_CLASS_OPERATION(Atan2,atan2,ATAN2,2,std::atan2(args[0],args[1])); } // namespace lepton } // namespace PLMD #endif /*LEPTON_OPERATION_H_*/