- JavaDoc

# JEP

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

# Advanced Features

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

# Serialization and Threads

Starting with Jep 3.1, parsed expressions, the main Jep class, and its sub-components are all serializable. This allows persistent storage and transfer between applications. Issues regarding threads and the use of multiple Jep instances are also discussed in this section.

## What needs to be serialized?

Depending on your needs you may choose from three different serialization options:

- Expressions only: If the source and destination have the same set up for Jep, with the same set of functions and operators the this form will take the minimum size.
- VariableTable and expressions: this will also save the values of variables
- Full serialization: serializes the Jep instance, together with its configuration and settings.

## Serializing an expression

The Node class itself is not serializable. Instead, a wrapper class com.singularsys.jep.walkers.SerializableExpression is used to provide a compact serializable representation of a node. The class is constructed using `new SerializedExpression(Node n)` and the `Node toNode(Jep j)` method is used to extract the node in the context of a given Jep instance.

To serialize use:

    //  Set-up jep
    Jep j = new Jep();

    // create an ObjectOutputStream
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);

    // parse an expression
    Node n = j.parse("1+cos(2 th)");

    // Create a SerializableExpression
    SerializableExpression se = new SerializableExpression(n);

    // write the SerializedExpression
    oos.writeObject(se);
    oos.close();

    // extract the bytes
    byte bytes[] = baos.toByteArray();

To deserialize the expression use:

    //  Set-up jep
    Jep j2 = new Jep();

    // Create an ObjectInputStream from the set of bytes
    ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
    ObjectInputStream ois = new ObjectInputStream(bais);

    // Deserialize the SerializableExpression
    SerializableExpression se2 = (SerializableExpression) ois.readObject();

    // Create a node
    Node n2 = se2.toNode(j2);
    ois.close();

Alternatively, the serialized expression could be written to a file

    ....
    File f = new File(....);
    FileOutputStream fos = new FileOutputStream(f);
    ObjectOutputStream oos = new ObjectOutputStream(fos);

    // write objects
    oos.writeObject(se);
    oos.close();

    FileInputStream fis = new FileInputStream(f);
    ObjectInputStream ois = new ObjectInputStream(fis);

    // read objects
    SerializableExpression se2 = (SerializableExpression) ois.readObject();
    ois.close();

### Serializing the VariableTable and an expression

If you wish to serialize the values of variables for later use, then the VariableTable can be serialized. Again this methods assumes the same version and configuration of the Jep instances.

    Jep j = new Jep();

    // Setup the ObjectOutputStream
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);

    // Serialize the VariableTable
    oos.writeObject(j.getVariableTable());

    // Serialize the expression
    Node n = j.parse("a+cos(2 th)");
    SerializableExpression se = new SerializableExpression(n);
    oos.writeObject(se);

    oos.close();
    byte bytes[] = baos.toByteArray();

To deserialize

    //  Set-up jep
    Jep j2 = new Jep();

    // Create an ObjectInputStream
    ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
    ObjectInputStream ois = new ObjectInputStream(bais);

    // Deserialize the SymbolTable
    VariableTable vt2 = (VariableTable) ois.readObject();

    // Set the SymbolTable as that used by the jep instance
    j2.setComponent(vt2);

    // Deserialize the expression
    SerializableExpression se2 = (SerializableExpression) ois.readObject();
    Node n2 = se2.toNode(j2);
    ois.close();

### Serializing the Jep instance

The Jep class and all its components are serializable, meaning that the configuration of the Jep instance can be stored. This includes the full set of variables, functions, operators, and various settings. If the ConfigurableParser is used, then its configuration is also stored. Note that changes made to the standard JavaCC parser are not recorded.

A typical setup will take 7KB with the standard parser and 12KB with the configurable parser.

    Jep j = new Jep();

    // Setup the ObjectOutputStream
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);

    // Serialize the VariableTable
    oos.writeObject(j);

    // Serialize the expression
    Node n = j.parse("a+cos(2 th)");
    SerializableExpression se = new SerializableExpression(n);
    oos.writeObject(se);

    oos.close();
    byte bytes[] = baos.toByteArray();

To deserialize

    // Create an ObjectInputStream from the set of bytes
    ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
    ObjectInputStream ois = new ObjectInputStream(bais);

    // Deserialize the Jep instance
    Jep j2 = (Jep) ois.readObject();

    // Deserialize the expression
    SerializableExpression se2 = (SerializableExpression) ois.readObject();
    Node n2 = se2.toNode(j2);
    ois.close();

### Importing equations

The SerializedExpression class can also be used to produce copies of a node without having to serialize and deserialize.

    // Create first instance
    Jep j = new Jep();

    // Parse equation using first instance
    Node n = j.parse("a+cos(2 th)");

    // Create a SerializableExpression
    SerializableExpression se = new SerializableExpression(n);

    // Create second instance
    Jep j2 = new Jep();

    // Import expression into second instance
    Node n2 = se.toNode(j2);

### Multiple threads

On a multi-processor machine you may wish to evaluate the same expression, or set of expressions, in multiple threads. Typically each thread will have its own Jep instance and its own copy of the expression.

The following is a skeleton implementation:

    public class ThreadRunner {
    	class EvaluationThread extends Thread {
    		Jep myJep;
    		Node myNode;
    		double result;

    		EvaluationThread(SerializableExpression se, String varName, double value) throws Exception {
    			myJep = new Jep();
    			myNode = se.toNode(myJep);
    			myJep.addVariable(varName, value);
    		}

    		public void run() {
    		    try {
    			    Object res = myJep.evaluate(myNode);
    			    result = ((Double) res);
    		    } catch (EvaluationException e) {
    				System.out.println(e.getMessage());
    		    }
    		}
    	}

    	// Setup and run multiple threads using the same expression
    	go(String expression, int nThreads) throws Exception {
    		Jep baseJep = new Jep();
    		Node baseNode = baseJep.parse(expression);
    		// Create a SerializableExpression
    		SerializableExpression se = new SerializableExpression(baseNode);

    		// create and run 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(se,"x",Math.Pi * i/ nThreads);
    			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+" result "+threads[i].result);
    		}
    	}
    }

In practice the code will be more complex than this, the expression may be evaluated multiple times, and more than one variable will be used. You may wish to move the initialization of the Jep instance and extraction of nodes into the run method.

### 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. Its possible to create a light-weight Jep instance which reuses components from an existing Jep instance, such instances only take 1kB.

Such instances have no parsing facility and their own copies of the VaraibleTable and Evaluator so are safe to uses in multiple threads.

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

Note that the new instance will share the FunctionTable and its associated PostfixMathCommands, see the LightWeightComponentSet LightWeightComponentSet documentation for issues which mary arise and workarounds.