Class RpEval

java.lang.Object
com.singularsys.extensions.fastreal.AbstractEval
com.singularsys.extensions.fastreal.RpEval
All Implemented Interfaces:
GenericVisitor<Void,Void,ParseException>, JepComponent, Serializable

public final class RpEval extends AbstractEval
A fast evaluation algorithm for equations over Doubles, does not work with vectors or matrices. This is based around reverse polish notation and is optimised for speed at every opportunity.

To use do

 Jep j = ...;
 Node node = ...; 
 RpEval rpe = new RpEval(j);
 RpCommandList list = rpe.compile(node);
 double val = rpe.evaluate(list);
 System.out.println(val);
 rpe.cleanUp();
 

Variable values in the evaluator are stored in an array. The array index of a variable can be found using

 Variable v = j.getVar("x");
 int ref = rpe.getVarRef(v);
 
and the value of the variable set using
 rpe.setVarValue(ref,0.1234);
 
Variable values can also be set using the standard Variable.setValue() or (slower) Jep.setVarVal(name,vlaue) methods. Setting the value of a jep variable will automatically update the corresponding rpe value but there will be a performance hit. Setting the value of the rpe variable does not change the corresponding jep value.

The compile methods converts the expression represented by node into a string of commands. For example the expression "1+2*3" will be converted into the sequence of commands

 Constant no 1 (pushes constant onto stack)
 Constant no 2
 Constant no 3
 Multiply scalars (multiplies last two entries on stack)
 Add scalars (adds last two entries on stack)
 
The evaluate method executes these methods sequentially using a stack and returns the last object on the stack.

A few cautionary notes:

  • It only works over doubles expressions with complex numbers or strings will cause problems.
  • It only works for expressions involving scalars.
  • It is safe to use individual RpEval instances in separate threads, using the same instance in separate threads is like to cause exceptions. The RpCommandList objects created by compile are immutable and are safe to use across threads. The duplicate() method creates a copy of the RpEval object which can evaluate the same commandList in separate threads.

Implementation notes A lot of things have been done to make it as fast as possible:

  • Everything is final which maximizes the possibility for in-lining.
  • All object creation happens during compile.
  • All calculations done using double values.
  • Each operator/function is hand coded. To extend functionality you will have to modify the source.

This class and the RpCommandList can be serialized, allowing an expression to be stored or transmitted. The serialized form stores the constants, variables and custom functions used. It does not save the associated Jep instance. This allows a deserialized instance to be used with a deserialized RpCommandList. If a Jep instance is serialized in the same stream as the RpEval instance then the AbstractEval.init(Jep) should be called on deserialization.

Since Jep 4.1, extension 2.2, the parent class now implements GenericVisitor some method signatures have changed to be more specific.

Author:
Rich Morris Created on 14-Apr-2004
See Also:
  • Constructor Details

    • RpEval

      public RpEval(Jep jep)
  • Method Details

    • compile

      public RpCommandList compile(Node node) throws JepException
      Compile the expressions to produce a set of commands in reverse Polish notation.
      Throws:
      JepException
    • visit

      public Void visit(ASTConstant node, Void data) throws ParseException
      Description copied from interface: GenericVisitor
      Visit a constant node
      Parameters:
      node - current node
      data - context data
      Returns:
      the result of visiting the node
      Throws:
      ParseException
    • visit

      public Void visit(ASTVarNode node, Void data) throws ParseException
      Description copied from interface: GenericVisitor
      Visit a variable node
      Parameters:
      node - current node
      data - context data
      Returns:
      the result of visiting the node
      Throws:
      ParseException
    • visit

      public Void visit(ASTOpNode node, Void data) throws ParseException
      Description copied from interface: GenericVisitor
      Visit an operator node
      Parameters:
      node - current node
      data - context data
      Returns:
      the result of visiting the node
      Throws:
      ParseException
    • visit

      public Void visit(ASTFunNode node, Void data) throws ParseException
      Description copied from interface: GenericVisitor
      Visit a function node
      Parameters:
      node - current node
      data - context data
      Returns:
      the result of visiting the node
      Throws:
      ParseException
    • evaluate

      public double evaluate(RpCommandList comList) throws EvaluationException
      Evaluate the expression.
      Parameters:
      comList - list of commands
      Returns:
      the double value of the equation
      Throws:
      EvaluationException
    • cleanUp

      public void cleanUp()
      Removes observers and other cleanup needed when evaluator no longer used.
    • getVariable

      public Variable getVariable(int ref)
      Gets the Jep Variable for a give reference number
      Parameters:
      ref - reference number for the variable
      Returns:
      corresponding Jep variable, or null if no jep instance
    • getVarRef

      public int getVarRef(Variable var) throws JepException
      Gets the reference number for a given variable
      Parameters:
      var - Jep Variable
      Returns:
      reference number for the variable
      Throws:
      JepException - if there is a miss-match in sizes of the internal representation. This can be caused if the method is called using a lightweight instance with no
    • getVarRef

      public int getVarRef(String varName) throws JepException
      Gets the reference number for a given variable
      Parameters:
      varName - name of variable
      Returns:
      reference number for the variable
      Throws:
      JepException - if no jep instance, can happen if using a lightweight instance
    • setVarValue

      public void setVarValue(int ref, double val)
      Sets the value of a variable
      Parameters:
      ref - reference number for the variable
      val - the value to set the variable
    • getVarValue

      public double getVarValue(int ref)
      Gets the value of a variable
      Parameters:
      ref - reference number for the variable
    • updateJepVariables

      public void updateJepVariables()
      Copies all the values from the Rpe variable to the corresponding Jep variables.
    • updateFromJepVariables

      public void updateFromJepVariables() throws EvaluationException
      If the variables used by Jep has a valid value set the corresponding mrpe value
      Throws:
      EvaluationException - if the jep variable has different dimensions to the mrpe variable
      Since:
      Jep 4.0/Extensions 2.1
    • toString

      public String toString()
      Overrides:
      toString in class Object
    • getConstantValue

      protected Object getConstantValue(short ref)
      Specified by:
      getConstantValue in class AbstractEval
    • toString

      public String toString(RpCommand com)
      Enhanced RpCommand to String conversion. Used when rpe instance is available, prints the values of the constants, variables and functions.
      Parameters:
      com - an RpCommand to convert
      Returns:
      string representation
    • duplicate

      public RpEval duplicate()
      Returns a copy of the RpEval object which is safe to use for evaluation in a new thread. RpEval rpe1 = new RpEval(jep); RpCommandList com = rpe1.compile(node); int varRef = rpe1.getVarRef(jep.getVar("x")); RpEval rpe2 = rpe1.duplicate(); rpe2.setVarValue(ref,0.5); double result = rpe2.evaluate(com); Since Jep 4.0, extension 2.1 just calls getLightWeightInstance() with a cast See AbstractEval.duplicateCustomFunctions(AbstractEval, Jep) for handling of custom functions.
      Returns:
      a new instance
    • getLightWeightInstance

      public JepComponent getLightWeightInstance()
      Creates a new instance which can be used in a separate thread without a jep instance. Variables can only referred to using the setVarValue(int, double) and getVarValue(int). RpEval rpe1 = new RpEval(jep); RpCommandList com = rpe1.compile(node); int varRef = rpe1.getVarRef(jep.getVar("x")); RpEval rpe2 = (RpEval) rpe1.getLightWeightInstance(); rpe2.setVarValue(ref,0.5); double result = rpe2.evaluate(com); See AbstractEval.duplicateCustomFunctions(AbstractEval, Jep) for handling of custom functions.
      Returns:
      a new instance
    • getLightWeightInstance

      public JepComponent getLightWeightInstance(Jep jep)
      Create a new instance which can be used in a separate thread. This uses a Jep instance and the variable references can be found using getVarRef(Variable) and getVarRef(String) and the variable for the given reference, found using getVariable(int). See AbstractEval.duplicateCustomFunctions(AbstractEval, Jep) for handling of custom functions.
      Parameters:
      jep -
      Returns:
      a new instance
    • toString

      public String toString(RpCommandList coms1)