- JavaDoc

# JEP

- Introduction
- Basic Usage
- Variables
- Data types
- Operators
- Functions
- BigDecimal
- FAQ
- Migration
- Version History

# Advanced Features

- Manipulating Expressions
- Components
- Configurable Parser
- Serialization
- Grammar

# Fast evaluation of mathematical equations in Java - extensions to JEP

The org.lsmp.djep.rpe and org.lsmp.djep.mrpe packages offers fast evaluation routines for expressions involving scalars or matrices respectively. These offer a 5-10 times speed improvement over the standard JEP evaluation and approach the speed obtainable by native java code.

## Scaler expressions

To optimise the speed of evaluation, separate packages are provided for equations involving doubles, i.e. standard single valued functions and those involving vectors and matrices. The `org.lsmp.djep.rpe` package provides support for non vector equations.

To use do

      JEP j = new XJep();
      j.addStandardConstants();
      j.addStandardFunctions();
      j.addComplex();
      j.setAllowUndeclared(true);
      j.setImplicitMul(true);
      j.setAllowAssignment(true);

      RpEval rpe = new RpEval(j);

      Node node = j.parse("cos(pi/3)^2");
      RpCommandList list = rpe.compile(node);
      double val = rpe.evaluate(list);
      System.out.println(val);
      rpe.cleanUp();

### Variable

Variable values in the evaluator are stored in a 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 value of the corresponding jep value.

### How it works

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

      Constant no 1 (4) (pushes constant onto stack)
      Constant no 2 (5)
      Constant no 3 (6)
      Multiply scalers (multiplies last two entries on stack)
      -  (6*5), the result (30) is pushed onto the top of the stack
      Add scalers (adds last two entries on stack)
      -  (30+4) the result (34) is pushed onto top of the stack

The evaluate method executes these methods sequentially using a stack and returns the last object on the stack.

### Implementation notes

A few cautionary notes: Its very unlikely to be thread safe. It only works over doubles, expressions with complex numbers or strings will cause problems. It only works for expressions involving scalers.

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

- Everything is final which maximise 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.

### Example applications

- org.lsmp.djepExamples.RpSpeed runs some speed test applications.
- org.lsmp.djepExamples.RpeConsole an interactive console application.

### Supported functions

Functions which take double arguments and return double results are supported. Other functions which return strings or complex numbers will raise exceptions when used.

Some functions have been optimised for speed these are: `sin, cos, tan, sec, cosec, cot, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh, abs, exp, log, ln, sqrt, atan2, if` these are hand coded in the routines for high performance.

Other jep functions which take double arguments and return double results are also supported. These can be used directly and no additional calls are required.

To improve performance four interfaces org.lsmp.djep.RealNullaryFunction (0 arguments) org.lsmp.djep.RealUnaryFunction (1 argument) org.lsmp.djep.RealBinaryFunction (2 arguments) org.lsmp.djep.RealNaryFunction (any number of arguments) have been created, a PostfixMathCommand which implements one of these interfaces will be faster to evaluate.

### Performance

The table below indicates the evaluation speeds. Times are in milliseconds for a million evaluations.

Expression | Speed using JEP | Speed using rpe | Speed using Java
--- | --- | --- | ---
5 | 156 | 47
x | 297 | 78
1+x | 781 | 94
x^2 | 844 | 109
x*x | 781 | 94
5*x | 797 | 94
cos(x) | 656 | 156 | 79
1+x+x^2 | 1828 | 172
1+x+x^2+x^3 | 2844 | 281
1+x+x^2+x^3+x^4 | 3891 | 312
1+x+x^2+x^3+x^4+x^5 | 4891 | 375
1+x(1+x(1+x(1+x(1+x)))) | 4766 | 391 | 62
if(x>0.5,1,0) | 1219 | 219

This indicates a speed up of between 3 and 13 times as fast.