...

Package mathparser

import "bestcode/mathparser"
Overview
Index

Overview ▾

Math Parser

mathparser package provides a MathParser interface and the implementation to parse mathemtical expressions given as strings at runtime. User defined functions and variables are supported.

type Function

type Function interface {
    Run(params []Parameter) float64

    // This method returns the length of the parameters array that will be
    // passed to the Run(params []Parameter) method.
    //
    // For example, for a function like F(X, Y, Z), this function should return 3.
    // -1 means number of paramaters is unknown (can be anything)
    NumberOfParams() int
}

Function interface represents a user defined callback function that takes n parameters. During evaluation of an expression, MathParser calls

Function.Run(p []Parameter)

to request the value of the function when it takes len(p) number of parameters.

For example, a user could define a function like this:

type MyFunc struct {}
func (f *MyFunc) Run(p []Parameter) float64 {
  return do_something_with_params( p );
}
func (f *MyFunc) NumberOfParameters() int {
  return 2;
}

The implementation of the Function interface can use panic(error) to report errors. For example if you want to validate the input to the function during evaluation time, you can check the number of parameters and if incorrect, you can panic. MathParser's Value method will recover from panic and it will return the error.

User defined functions can be registered using CreateFunc method of MathParser. Example:

mathParser.CreateFunc("MYFUNC", new(MyFunc));

type MathParser

type MathParser interface {

    // Please see SetExpression() method to read about Expression property.
    Expression() string

    // Expression property represents the mathematical expression which is input to be evaluated by the user.
    //
    // The expression can contain variables such as X, Y, T, HEIGHT, WEIGHT and so on.
    // Expression can also contain functions that take any number of parameters.
    // Variable and Function names are not case sensitive.
    //
    // When Expression is assigned a value, it becomes 'dirty' and further attempt to
    // evaluate its value will require it to be parsed. But once it is parsed,
    // and a parse tree representing the expression is formed, it won't be parsed again,
    // until it is assigned a new string. Instead, the parse tree will be used to retrieve
    // current results as the values of variables change.
    //
    // X, Y and PI variables can be predefined using CreateDefaultVars method.
    // SetVariable method can be used to add user variables.
    //
    // CreateDefaultFuncs method can be used to define the default set of functions that
    // are described below. Functions that take one parameter are:
    //
    // SQR: Square function which can be used as SQR(X)
    //
    // SIN: Sinus function which can be used as SIN(X), X is a real-type expression.
    // Sin returns the sine of the angle X in radians.
    //
    // COS: Cosinus function which can be used as COS(X), X is a real-type expression.
    // COS returns the cosine of the angle X in radians.
    //
    // ATAN: ArcTangent function which can be used as ATAN(X)
    //
    // SINH: Sinus Hyperbolic function which can be used as SINH(X)
    //
    // COSH: Cosinus Hyperbolic function which can be used as COSH(X)
    //
    // COTAN: which can be used as COTAN(X)
    //
    // TAN: which can be used as TAN(X)
    //
    // EXP: which can be used as EXP(X)
    //
    // LN: natural log, which can be used as LN(X)
    //
    // LOG: 10 based log, which can be used as LOG(X)
    //
    // SQRT: which can be used as SQRT(X)
    //
    // ABS: absolute value, which can be used as ABS(X)
    //
    // SIGN: SIGN(X) returns -1 if X<0; +1 if X>0, 0 if X=0; it can be used as SQR(X)
    //
    // TRUNC: Discards the fractional part of a number. e.g. TRUNC(-3.2) is -3, TRUNC(3.2) is 3.
    //
    // CEIL: CEIL(-3.2) = -3, CEIL(3.2) = 4
    //
    // FLOOR: FLOOR(-3.2) = -4, FLOOR(3.2) = 3
    //
    // INTPOW: The INTPOW function raises Base to an integral power. INTPOW(2, 3) = 8.
    // Note that result of INTPOW(2, 3.4) = 8 as well.
    //
    // POW: The Power function raises Base to any power. For fractional exponents or
    // exponents greater than MaxInt, Base must be greater than 0.
    //
    // LOGN: The LogN function returns the log base N of X. Example: LOGN(10, 100) = 2
    //
    // MIN: MIN(2, 3) is 2. Takes any number of parameters.
    //
    // MAX: MAX(2, 3) is 3. Takes any number of parameters.
    //
    // SUM: SUM(2, 3) is 5. Takes any number of parameters.
    //
    // MOD: MOD(x,y) function implements the Go % (modulus) operator.
    //
    // INTDIV: INTDIV(x,y) function performs integer division.
    //
    // IF:  The IF(b, case1, case2) function provides branching capability.
    // If b is not 0, then it returns case1, else it returns case2.
    // Behavior is similar to: return b ? case1 : case2;
    // If b==0 then case1 will not be evaluated, and vice versa.
    // Example: IF(HEIGHT, 3/HEIGHT, 3) will make sure 3/HEIGHT does not cause division by zero.
    //
    // User functions can be added using CreateFunc method.
    // Functions and Variables can be deleted using DeleteVar, DeleteFunc,
    // DeleteAllVars, DeleteAllFuncs methods.
    //
    //  Supported operators are +,-,*,/,^,% (mod), =(equals),&(and),|(or),!(not), <>(not equals), <=(less than or equals), >=(greater than or equals)
    SetExpression(newVal string)

    // Returns the value of the expression. Parses the expression if it was not parsed before.
    Value() (float64, error)

    // Returns the currect value of the variable.
    // Returns error if the variable does not exist.
    // Variable name is not case sensitive.
    Variable(varName string) (float64, error)

    // Creates a new variable or sets the value of an existing variable.
    // Variable name is not case sensitive. Returns error if the variable needs
    // to be created and the name is not a valid variable name.
    SetVariable(varName string, newVal float64) error

    // Set OptimizationOn to let the MathParser evaluate constant expressions
    // at parse time. The optimized parse tree will enhance subsequant evaluation
    // operations, though initial parsing will be slower.
    //
    // Optimization is good if you are going to parse once and evaluate the same
    // expression many many times with different variable values and there happens
    // to be many constant branches in the expression.
    OptimizationOn() bool

    // Set OptimizationOn to let the MathParser evaluate constant expressions
    // at parse time. The optimized parse tree will enhance subsequant evaluation
    // operations, though initial parsing will be slower.
    //
    // Optimization is good if you are going to parse once and evaluate the same
    // expression many many times with different variable values and there happens
    // to be many constant branches in the expression.
    SetOptimizationOn(newVal bool)

    // Returns current VariableResolver function, nil if not set before.
    VariableResolver() VariableResolver

    // Set the VariableResolver for this MathParser instance.
    // VariableResolver function is used to resolve variable values at evaluation time
    // when they are not predefined.
    SetVariableResolver(variableResolver VariableResolver)

    // Parses the expression and forms a parse tree. Returns error if it cannot parse.
    // Upon successful completion of parsing, it will set the Dirty flag to false, so that
    // unless the expression is changed or variables and functions added or removed,
    // expression does not need to be re-parsed. Users may want to call the parse method
    // directly to check the validity of an input expression.
    //
    // If OptimizationOn property is true, Parse method will optimize the parse tree by
    // evaluating constant branches of the parse tree at that moment, so that Value
    // function may run faster.
    Parse() error

    // Creates a variable whose value is constant and cannot be changed.
    // Using constants where possible enables the optimizer recognize
    // constant branches and simplify them into single constant nodes to improve
    // evaluation performance.
    CreateConstant(constName string, constValue float64) error

    // CreateFunc method creates a new function that takes n number of parameters in
    // the parser's list of functions. If the function name already exists, then
    // CreateFunc returns error. Function name is not case sensitive.
    //
    // The second parameter is a reference to an implementation of the Function interface:
    //
    //  type Function interface {
    //     func Run(p []Parameter) float64;
    //     func NumberOfParams() int;
    //  }
    //
    // While evaluating the expression, if a registered function name is
    // encountered, the user supplied Function.Run(p []Parameter) will be called.
    //
    // This event handler ( Function.Run )
    // will need to return a result representing the value of the function
    // based on the parameters passed as an array if []Parameter.
    //
    // The number of parameters that this function will take is determined by
    // the Function.NumberOfParams() method.
    //
    // You can find examples of usage in the parser source code.
    CreateFunc(newFuncName string, function Function) error

    // CreateDefaultFuncs method creates some predefined functions in the parser's list of functions.
    //
    // Default functions that take one parameter are:
    //
    // SQR: Square function which can be used as SQR(X)
    //
    // SIN: Sinus function which can be used as SIN(X), X is a real-type expression. Sin returns the sine of the angle X in radians.
    //
    // COS: Cosinus function which can be used as COS(X), X is a real-type expression. COS returns the cosine of the angle X in radians.
    //
    // ATAN: ArcTangent function which can be used as ATAN(X)
    //
    // SINH: Sinus Hyperbolic function which can be used as SINH(X)
    //
    // COSH: Cosinus Hyperbolic function which can be used as COSH(X)
    //
    // COTAN: which can be used as COTAN(X)
    //
    // TAN: which can be used as TAN(X)
    //
    // EXP: which can be used as EXP(X)
    //
    // LN: natural log, which can be used as LN(X)
    //
    // LOG: 10 based log, which can be used as LOG(X)
    //
    // SQRT: which can be used as SQRT(X)
    //
    // ABS: absolute value, which can be used as ABS(X)
    //
    // SIGN: SIGN(X) returns -1 if X<0; +1 if X>0, 0 if X=0; it can be used as SQR(X)
    //
    // TRUNC: Discards the fractional part of a number. e.g. TRUNC(-3.2) is -3, TRUNC(3.2) is 3.
    //
    // CEIL: CEIL(-3.2) = 3, CEIL(3.2) = 4
    //
    // FLOOR: FLOOR(-3.2) = -4, FLOOR(3.2) = 3
    //
    //
    // INTPOW: The INTPOW function raises Base to an integral power. INTPOW(2, 3) = 8. Note that result of INTPOW(2, 3.4) = 8 as well.
    //
    // POW: The Power function raises Base to any power. For fractional exponents or exponents greater than MaxInt, Base must be greater than 0.
    //
    // LOGN: The LogN function returns the log base N of X. Example: LOGN(10, 100) = 2
    //
    // MIN: MIN(2, 3) is 2.
    //
    // MAX: MAX(2, 3) is 3.
    //
    // SUM: SUM(2, 3) is 5. Takes any number of parameters.
    //
    // MOD: MOD(x,y) function implements the Go % (modulus) operator.
    //
    // INTDIV: INTDIV(x,y) function performs integer division.
    //
    // IF:  The IF(b, case1, case2) function provides branching capability.
    // If b is not 0, then it returns case1, else it returns case2.
    // Behavior is similar to: return b ? case1 : case2;
    // If b==0 then case1 will not be evaluated, and vice versa.
    //  Example: IF(HEIGHT, 3/HEIGHT, 3) will make sure 3/HEIGHT does not cause division by zero.
    CreateDefaultFuncs() error

    // X, Y and PI variables can be predefined using CreateDefaultVars and can be immediately
    // used in the expression. Initial values of X and Y are 0. PI is 3.14159265358979
    CreateDefaultVars() error

    // DeleteVar method deletes an existing variable from the list of available variables.
    // If the variable does not exist, then DeleteVar does nothing.
    //
    // When a variable is deleted dirty flag is set to true so that next time
    // the Value function is called the expression will be reparsed.
    // Variable name is not case sensitive.
    DeleteVar(varName string)

    // DeleteFunc method deletes an existing function from the list of available functions.
    // If the function does not exist, DeleteFunc does nothing.
    //
    // When a function is deleted dirty flag is set to true so that next time the
    // Value function is called the expression will be reparsed.
    // Function name is not case sensitive.
    DeleteFunc(funcName string)

    // DeleteAllVars method deletes all variables from the list of available variables.
    //
    // This action may be useful when number of unused variables is too high that
    // causes performance to degrade.
    //
    // When a variable is deleted dirty flag is set to true so that next time the
    // Value function is called the expression will be reparsed.
    DeleteAllVars()

    // DeleteAllFuncs method deletes all variables from the list of available functions.
    //
    // This action may be useful when number of unused functions is too high that
    // causes performance to degrade.
    //
    // When a function is deleted Dirty flag is set to true so that next time the
    // Value function is called the expression will be reparsed.
    DeleteAllFuncs()

    // Returns the list of variable names as an array of strings.
    Variables() []string

    // Returns an array of functions declared for this parser.
    Functions() []string

    // FreeParseTree can be explicitly called to free the resources taken by the
    // allocated Parse tree when an expression is parsed. FreeParseTree sets the dirty
    // flag to true so that next time the Value function is called, expression will
    // be parsed forming a new, valid parse tree to be evaluated.
    FreeParseTree()

    // Returns true if a variable with the name 'varName' is used in the current expression.
    // Variable name is not case sensitive. Returns error if the expression cannot be parsed.
    IsVariableUsed(varName string) (bool, error)

    // Returns true if a function with the name 'funcName' is used in the current expression.
    // Function name is not case sensitive. Returns error if the expression cannot be parsed.
    IsFuncUsed(funcName string) (bool, error)

    // Returns the list of variables used in the current expression as an array of strings.
    // If variables are not defined ahead of time, then VariableResolver must have been set.
    // Otherwise, when an undefined variable is found in the expression, ParserException will be thrown.
    VariablesUsed() ([]string, error)

    // Returns true if a variable with the name 'varName' is present in the current
    // variables list as a variable or constant.
    IsVariable(varName string) bool

    // Returns true if a constant with the name 'constName' is defined.
    // If the given name is defined as a variable, but not a constant, this method
    // returns false.
    IsConstant(constName string) bool

    // Returns true if a function with the name 'funcName' is present in the current functions list.
    IsFunction(funcName string) bool

    // Optimizes the parse tree by finding branches that evaluate to a constant and
    // replacing them with a leaf representing the constant.
    // Until the expression is changed and reparsed, further evaluation requests will be
    // quicker if a lot of constant elimination was done.
    //
    // If the same expression will not be evaluated repeatedly with varying
    // values of parameters used in it, then optimization will not bring any gain,
    // but will slow performance.
    //
    // If OptimizationOn property is set to true, this method is called automatically when an
    // evaluation is requested by calling Value() method.
    Optimize()

    // Tells if expressions use locale specific decimal separator such as dot or comma.
    // For example, in the US expressions should use dot (.) as a decimal separator,
    // and in the Europe they would use comma (,) for decimal separator. If this property is set to
    // comma as the decimal separator, then function parameter separator is going to be colon (:).
    // If decimal separator is dot (.), then function parameter is comma (,). It is upto the
    // user of the parser to decide whether the current locale requires dot or comma.
    SetDecimalSeparator(separatorChar byte)

    // Returns the decimal separator character byte. Default is dot (.) as used in the US.
    DecimalSeparator() byte

    // Returns the character byte used to separate function parameters. If decimal separator is
    // dot (.) then the character for function parameter separator is comma (,). If comma is used
    // for decimal separator, then function parameter separator is colon (:).
    FunctionParamSeparator() byte

    // Returns a map of error messages that you can replace with translated versions using the
    // SetMessages method.
    Messages() map[string]string

    // Sets the messages used for error reporting. You can use this method to set translated error
    // messages as a map of message keys to string. Use Messages to find out what the default map
    // contains.
    SetMessages(newMessages map[string]string)

    // Turn debug on/off. If debug is on, internal panics are not converted to errors, but they are
    // let to propagate out. Debug on can help you find bugs in your user defined functions.
    SetDebug(bool)
    GetDebug() bool
}

MathParser interface provides access to an implementation of the math parser algorithm. NewMathParser() function can be used to get a pointer to this interface. An instance of MathParser is not thread safe. Do not share the same instance between threads. Create a separate instance for each thread or do your own synchronization in the way your application logic requires.

You can create a parser using NewMathParser();

This will return you a MathParser. You can set the expression to parse using MathParser.SetExpression(string); And you can get the result using MathParser.Value();

func NewMathParser

func NewMathParser() MathParser

Returns implementation of MathParser interface.

type Parameter

type Parameter interface {
    Value() float64
}

Parameter is used to supply a parameter value for a user defined function. All functions take a Parameter that enables them to query the current value of the parameter using the Value() function.

Example:

type _cosh struct {
   OneParamFunc
}

func (f *_cosh) Run(p []Parameter) float64 {
  // better to call p[0].Value() once, it can be costly:
  x_ := p[0].Value();
  return (math.Exp(x_) + math.Exp(-x_)) // 0.5;
}

type ParserError

type ParserError interface {
    // Error message
    error
    // Returns the expression string that cannot be parsed.
    InvalidPortionOfExpression() string
    // The sub-expression that is the cause of the error.
    SubExpression() string
}

ParserError may be returned by some methods of MathParser interface if an expression cannot be parsed. These methods are: Parse(), Value()

type VariableResolver

type VariableResolver func(parser MathParser, varName string) float64

VariableResolver function is implemented by the user and used in MathParser.SetVariableResolver(VariableResolver) to enable the Math Parser allow variables that are not defined before parse time. Setting VariableResolver turns off strict variable checking at Parse time such that the parser allows undefined variables to exist in the expression. An undefined variable is one for which no SetVariable was invoked. If set, VariableResolver will be used to return the values of variables at evaluation time. This is typically needed when the problem domain is too large to define all possible variables ahead of time. When MathParser.SetVariableResolver is set, parser will tolerate undefined variables at parse time and it will invoke VariableResolver to retrieve variable values at evaluation time. parser is the current parser instance. varName is the variable whose value is being asked for. Return value of the variable named varName.