- JavaDoc

# Jep Java

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

# Advanced Features

- Manipulating Expressions
- Components
- Configurable Parser
- Serialization
- Threads
- Localization
- Grammar
- Other advanced features
- Use of Design Patterns in Jep

# Threads

On a multiprocessor machine you may wish to evaluate the same expression, or set of expressions, in multiple threads. There are two main ways of evaluation in multiple threads:

1. Use the `ThreadSafeEvaluator` which can use the same expression in multiple threads.
2. Use `ImportationVisitor` to give each thread its own copy of an expression.

In both cases each thread will need its own Jep instance. Each Jep instance will have its own `Evaluator` and `VariableTable` but may share other components. The `LightweightComponentSet` is an easy way to create a Jep instance with minimal memory footprint. The second technique is slightly faster.

## Using `ThreadSafeEvaluator`

Normally variables are evaluated by using a direct reference from a `Node` to a `Variable` object. This would not be thread safe as one thread might change the value of a variable. With the ThreadSafeEvaluator each thread has its own `VariableTable` and when the evaluator encounters a variable node in an expression it looks up its name in the `VariableTable`, effectively performing a hashtable lookup and preserving thread independence.

The Jep instance needs to be set up with

    // create a Jep instance with the ThreadSafeEvaluator
    Jep baseJep = new Jep(new ThreadSafeEvaluator());

    // use thread-safe versions of the assignment and element-of operators
    baseJep.getOperatorTable().getAssign().setPFMC(new ThreadSafeAssign());
    baseJep.getOperatorTable().getEle().setPFMC(new ThreadSafeEle());

    // use thread optimized version of the rand function
    baseJep.addFunction("rand", new ThreadSafeRandom());

Each child thread would be set up with

    // create a child Jep instance
    Jep childJep = new Jep(new LightWeightComponentSet(baseJep));

A full example is

    import com.singularsys.jep.Jep;
    import com.singularsys.jep.JepException;
    import com.singularsys.jep.Variable;
    import com.singularsys.jep.misc.LightWeightComponentSet;
    import com.singularsys.jep.misc.threadsafeeval.ThreadSafeAssign;
    import com.singularsys.jep.misc.threadsafeeval.ThreadSafeEle;
    import com.singularsys.jep.misc.threadsafeeval.ThreadSafeEvaluator;
    import com.singularsys.jep.parser.Node;

    /**
     * Test generated from threads.html
     */
    public class ThreadRunner {

        // Setup and run multiple threads using the same expression
        public void go(String expression, int nThreads) throws JepException {
            // create a Jep instance with the ThreadSafeEvaluator
            Jep baseJep = new Jep(new ThreadSafeEvaluator());

            // use thread-safe versions of the assignment and element-of operators
            baseJep.getOperatorTable().getAssign().setPFMC(new ThreadSafeAssign());
            baseJep.getOperatorTable().getEle().setPFMC(new ThreadSafeEle());

            // Parse a node in the base Jep instance
            Node baseNode = baseJep.parse(expression);

            // create a number of threads each with a different value for x
            EvaluationThread threads[] = new EvaluationThread[nThreads];
            for(int i=0; i<nThreads; ++i) {
                threads[i] = new EvaluationThread(baseJep,baseNode,"x",
                     Math.PI * i / nThreads );
            }

            // run the threads each with a different value for x
            for(int i=0; i<nThreads; ++i) {
                threads[i].start();
            }

            // wait for all threads to finish and print results
            for(int i=0; i<nThreads; ++i) {
                try {
                    threads[i].join();
                } catch (InterruptedException e) {
                }
                System.out.println("Thread "+i+" value "
                  + threads[i].varValue+" result "+threads[i].result);
            }
        }

        // Class to evaluate an expression in a thread
        class EvaluationThread extends Thread {
            Jep childJep;
            Node childNode;
            Variable childVar;
            double varValue;
            double result;

            // set up the tread before running
            EvaluationThread(Jep baseJep, Node baseNode,
                   String varName, double value) throws JepException {
                // create a child Jep instance
                childJep = new Jep(new LightWeightComponentSet(baseJep));
                // just use the baseNode node
                childNode = baseNode;
                // child copy of variable
                childVar = childJep.addVariable(varName);
                varValue = value;
            }

            // Run the thread
            @Override
            public void run() {
                try {
                    // set variable value
                	childVar.setValue(varValue);
                    // Evaluate the expression
                    Object res = childJep.evaluate(childNode);
                    result = ((Double) res);
                } catch (JepException e) {
                    System.out.println(e.getMessage());
                }
            }
       }
    }

## Using `ImportationVisitor`

The ImportationVisitor can import an expression from one jep instance to another

      ImportationVisitor iv = new ImportationVisitor(Jep childJep);
      Node childNode = iv.importEqn(baseNode);

This makes a copy of the expression changing references from one `VariableTable` to another. The new expression in `childNode` can then be evaluated using any evaluator.

The code to use this is very similar to the above, apart from simpler Jep construction, and the line to import the node.

    import com.singularsys.jep.EvaluationException;
    import com.singularsys.jep.Jep;
    import com.singularsys.jep.JepException;
    import com.singularsys.jep.Variable;
    import com.singularsys.jep.misc.LightWeightComponentSet;
    import com.singularsys.jep.misc.threadsafeeval.ThreadSafeRandom;
    import com.singularsys.jep.parser.Node;
    import com.singularsys.jep.walkers.ImportationVisitor;

    /**
     * Test generated from threads.html
     */
    public class ThreadRunner2 {

        // Setup and run multiple threads using the same expression
        public void go(String expression, int nThreads) throws JepException {
            // create a standard Jep
            Jep baseJep = new Jep();

            // use thread optimized version of the rand function
            baseJep.addFunction("rand", new ThreadSafeRandom());

            // Parse a node in the base Jep instance
            Node baseNode = baseJep.parse(expression);

            // create a number of threads each with a different value for x
            EvaluationThread threads[] = new EvaluationThread[nThreads];
            for(int i=0; i<nThreads; ++i) {
                threads[i] = new EvaluationThread(baseJep,baseNode,"x",
                                 Math.PI * i / nThreads);
            }

            // run the threads each with a different value for x
            for(int i=0; i<nThreads; ++i) {
                threads[i].start();
            }

            // wait for all threads to finish and print results
            for(int i=0; i<nThreads; ++i) {
                try {
                    threads[i].join();
                } catch (InterruptedException e) {
                }
                System.out.println("Thread "+i+" value "
                  + threads[i].varValue+" result "+threads[i].result);
            }
        }

        // Class to evaluate an expression in a thread
        class EvaluationThread extends Thread {
            Jep childJep;
            Node childNode;
            Variable childVar;
            double varValue;
            double result;

            // set up the tread before running
            EvaluationThread(Jep baseJep, Node baseNode,
                  String varName, double value) throws JepException {
                // create a child Jep instance
                childJep = new Jep(new LightWeightComponentSet(baseJep));
                // use a child copy of expression
                ImportationVisitor iv = new ImportationVisitor(childJep);
                childNode = iv.importEqn(baseNode);
                // child copy of variable
                childVar = childJep.addVariable(varName);
                varValue = value;
            }

            // Run the thread
            @Override
            public void run() {
                try {
                    // set the variable value
                    childVar.setValue(varValue);
                    // Evaluate the expression
                    Object res = childJep.evaluate(childNode);
                    result = ((Double) res);
                } catch (EvaluationException e) {
                    System.out.println(e.getMessage());
                }
            }
       }
    }

This method does not require special versions of the assignment and element of operators. If the `rand()` function is used then performance is improved by using the ThreadSafeRandom.

A slight variation of the above technique is to use a SerializableExpression. This can handle much longer expressions than `ImportationVisitor`. To create a child copy of a node use

    SerializableExpression se = new SerializableExpression(baseNode);
    childNode = se.toNode(childJep);

See the Serialization help page for more details.

### Light-weight Jep instances

Creation of new Jep instances can have a considerable memory footprint, a Jep instance with a StandardParser takes about 56kB bytes for a Jep instance with a configurable parser takes about 14kB bytes. It is possible to create a light-weight Jep instance which reuses components from an existing Jep instance, such instances only take 1kB. All JepComponents have a `getLightWeightInstance()` method which return an instance suitable for use in multiple threads. Sometimes they just return `this` so the same instance is used, sometime a new instance is created and sometimes `null` is returned for components like the parser which are not needed in separate threads.

The `LightWeightComponentSet` returns a new set of components with no parsing or printing facilities, and copies of the VariableTable and Evaluator so they safe to uses in multiple threads. It can be used to create a new Jep instance for use in a new thread.

    Jep j = new Jep();
    ComponentSet cs = new LightWeightComponentSet(j);
    Jep lwj = new Jep(cs);

The above code will create copies of all variables. The `LightWeightComponentSet(Jep jep,boolean copyConstants)` constructor can be used to just copy constants or leave the table empty.

Most operators and functions like `x+y` or `sin(x)` work fine across multiple threads and to simplify implementation the `LightWeightComponentSet` assume all functions and operators are thread safe just uses the same instances of the `FunctionTable`, `OperatorTable` and all underlying functions. However, some functions, especially those which have side effects, may not be thread safe. Starting in version 4.0 such functions can be marked with the `JepComponent` interface and implement its `getLightWeightInstance()` to return a thread-safe copy of the function.

This feature is used by the `shallowCopy()` methods of `FunctionTable`, `OperatorTableI` and all subclasses. This method will create new instance of the table and copies all functions and operators into the new table calling the `getLightWeightInstance()` method when present.

The `MediumWeightComponentSet` works like the LightWeightComponentSet but ensures thread safe copies of functions are used when needed.

    Jep j = new Jep();
    ComponentSet cs = new MediumWeightComponentSet(j);
    Jep mwj = new Jep(cs);

Standard return values for the getLightWeightInstance() and shallowCopy() method of various Jep components.
Component | getLightWeightInstance() | shallowCopy()
--- | --- | ---
Parser | null | -
Evaluator | new instance | -
VariableTable | new instance, with an empty variables table | -
FunctionTable | this, identical instances of all functions | New table with new instances for PFMC's implementing JepComponent and same instances of other functions.
OperatorTable | this, identical instances of all operators | New table created with new instances created for Operators whose PFMC's implementing JepComponent, and same instances of other operators.
VariableFactory | this | -
NumberFactory | this | -
NodeFactory | new instance | -
PrintVisitor | new instance | -

There are two special classes providing do-nothing implementations with minimal footprint. These are both accessed by singleton static fields: NullParser.NULL_PARSER and PrintVisitor.NULL_PRINT_VISITOR.

## Parsing in Parallel

The com.singularsys.jep.misc.parallelparse packages provides a set of classes to allow parse multiple expressions in parallel. The ConcurrentVariableTable is a thread-safe variable table ensuring that variables can be added in multiple threads without causing conflicts. Each thread also needs its own `Parser` instance, and the package descibes several ways to do this.

## Example applications

Two diagnostic applications com.singularsys.jepexamples.diagnostics.ThreadSafeSpeedTest com.singularsys.jepexamples.diagnostics.ThreadSpeedTest are available for testing the two different approaches to evaluation. The first uses the `ThreadSafeEvaluator` and the second uses the `ImportationVisitor`. Both evaluate the same expression with half a million different values and compare the results when the work is split over multiple threads. Results will depend on the number of processors available and other tasks running on the system.

The com.singularsys.jeptests.system.ThreadTest runs a number of JUnit tests on the system, including the examples in this page.

The Fractal application calculates fractal images using Light-weight Jep instances and the importationVisitor.

The com.singularsys.jeptests.unit.misc.parallelparsing.ParallelParsingTest demonstrates different methods of parsing in parallel.