The com.singularsys.extensions.xjep
package provides the XJep
which extends the standard
Jep
class and add various symbolic operations plus a preprocessing
facility allowing symbolic operators and an enhanced variable type.
A simple usage is
XJep xjep = new XJep(); Node node = xjep.parse("1 x^2 + 0"); Node simp = xjep.simplify(node);
Symbolic operations exposed by the class include:
Node clean(Node node)
Node simplify(Node node)
Node expand(Node node)
Node deepCopy(Node node)
Node equals(Node l,Node r)
Node substitute(Node orig,String name,Object
value)
name
with value.
Node substitute(Node orig,String name,Node
replacement)
name
with the expression specified by replacement
.
Node substitute(Node orig,String sub)
x=....
.
Node substitute(Node orig, String[] names,
Object[] values)
Node substitute(Node orig, String[] names,
Node[] replacement)
Node substitute(Node orig, Node[] subs)
x=...
.
Node substituteConstantVariables(Node orig)
pi
and e
by their values.
Node replaceVariablesByEquations(Node node)
Node replaceRHSVariablesByEquations(Node node)
Expression can be interrogated using
Set<Variable> getVarsInEquation(Node n)
which returns a set of all the variables mentioned in a single expression. A more detailed analysis of expression can be found by using the com.singularsys.jep.walkers.TreeAnalyzer class.
The class adds a Node
preprocess(Node node) method, which process any symbolic operations, like
expansion or symbolic differentiation, that appear in an expression.
PFMC's which should be run at pre-processing times should
implement CommandVisitorI.
This adds a
Node process(Node node, Node children[])
method which is executed by the CommandVisitor
whenever the
preprocess(Node)
method is called.
Current preprocessor functions/operators are:
A further PFMC Preprocess causes the preprocessor to be run during evaluation. Note functions marked * are defined in the polynomials package.
XJep jep = new XJep(); // not strictly necessary as set by default jep.getOperatorTable().getAssign().setPFMC(new XAssign()); jep.addFunction("clean", new Clean()); jep.addFunction("subst", new Subst()); jep.addFunction("eqn", new ExtractEqn()); jep.addFunction("eval",new Eval()); jep.addFunction("preprocess", new Preprocess()); // Add polynomial functions jep.addFunction("simplify", new Simplify()); jep.addFunction("expand", new Expand()); jep.addFunction("coeffs", new Coeffs()); jep.addFunction("compare", new Compare(false)); jep.addFunction("symequals", new SymbolicEquals(false)); jep.reinitializeComponents(); Node to_clean = jep.parse("clean(1*x+0)"); Node cleaned = jep.preprocess(to_clean); assertEquals("x",jep.toString(cleaned)); Node to_subst = jep.parse("subst(x^2+y^2,x=z+1,y=w-1)"); Node substituted = jep.preprocess(to_subst); assertEquals("(z+1.0)^2.0+(w-1.0)^2.0",jep.toString(substituted)); Node to_simplify = jep.parse("simplify(x+2*x)"); Node simplified = jep.preprocess(to_simplify); assertEquals("3.0*x",jep.toString(simplified)); Node to_expand = jep.parse("expand((x+1)^2)"); Node expanded = jep.preprocess(to_expand); assertEquals("1.0+2.0*x+x^2.0",jep.toString(expanded)); Node to_coeffs = jep.parse("coeffs(2+3x+4x^2,x)"); Node coeffs = jep.preprocess(to_coeffs); assertEquals("[2.0,3.0,4.0]",jep.toString(coeffs)); Node to_compare = jep.parse("compare(1+2x,x+x+1)"); Node compared = jep.preprocess(to_compare); assertEquals("0",jep.toString(compared)); Node to_symequals = jep.parse("symequals(1+2x,x+x+1)"); Node symequals = jep.preprocess(to_symequals); assertEquals("true",jep.toString(symequals)); Node to_assign = jep.parse("x=z+1"); // define an equation with a variable Node assign = jep.preprocess(to_assign); assertTrue(assign.getPFMC() instanceof XAssign); XVariable var = (XVariable) jep.getVariable("x"); assertTrue(var.hasEquation()); assertEquals("z+1.0",jep.toString(var.getEquation())); Node to_eqn = jep.parse("eqn(x)"); // Node eqn = jep.preprocess(to_eqn); assertEquals("z+1.0",jep.toString(eqn)); Node to_eval = jep.parse("x^eval(n+1)"); jep.setVariable("n",2.0); Node eval = jep.preprocess(to_eval); assertEquals("x^3.0",jep.toString(eval)); Node to_preprocess = jep.parse("preprocess(eqn(x)^eval(n+1))"); Object evaluated = jep.evaluate(to_preprocess); assertTrue(evaluated instanceof Node); assertEquals("(z+1.0)^3.0",jep.toString((Node)evaluated));
The xjep package introduce a new type of variable, XVariable,
which allow variables to be associated with equations. Variable
created by an XJep instance will automatically be of this type. In
the processing step any assignment expression like
y=x^2+1
set equation of the left hand variable to the expression on the
right. The is acheived using the XAssign
Jep function.
The equation for a variable can be recovered by using
XVariable.getEquation()
,
and the value of a variable can be calculated from its equation using
XJep.calcVarValue(name,flag)
.
The flag option controls how any variables in the expression are evaluated. If set to true
then all variables with equations are automatically evaluate. For example
if z=y*y
and y=x+1
then to evaluate z
the equation for variable y
will first be evaluated. And as y appears twice
its equation will be evaluated twice.
If the flag is set to false then equations will only be evaluated as needed. Each variable has
a validValue
flag, this is set to true whenever the value is set
either by calling jep.addVariable(name,value)
or through
evaluating an equation with the variable on the left hand side. This flag can be
cleared by calling
Variable.setValidValue(false)
or by calling
VariableTable.clearValues()
which clears all values. So with the above example the
y
will only be evaluated once.
XJep xjep = new XJep(); xjep.addVariable("x", 3.0); // set variable with no equation Node node1 = xjep.parse("y=x+1"); // equation with variable on lhs xjep.preprocess(node1); // sets the equation for variable y Node node2 = xjep.parse("z=y*y"); xjep.preprocess(node2); // sets equation to variable z // Get equation for variable y XVariable varY = (XVariable) xjep.getVariable("y"); assertEquals("x+1.0",xjep.toString(varY.getEquation())); // calculate the values of z using the calcVarValue method // will also calculate value of variable y Object val = xjep.calcVarValue("z",true); assertEquals(16.0,val); // Clear all the variable values xjep.getVariableTable().clearValues(); // change value of x xjep.setVariable("x", 4.0); // recalculate z, also recalculates y (once) Object val2 = xjep.calcVarValue("z",false); assertEquals(25.0,val2); // changing x without clearing values will use // previously calculated results xjep.setVariable("x", 5.0); Object val3 = xjep.calcVarValue("z",false); assertEquals(25.0,val3); // But setting the flag to true recalculates // Subsequent equations xjep.setVariable("x", 6.0); Object val4 = xjep.calcVarValue("z",true); assertEquals(49.0,val4);
The motivation behind this scheme comes into play if differentiation
when partial derivatives of variables are automatically calculated.
Summary of use of variables in the XJep package:
Class | Method | Action |
Jep | public void addConstant(String name,Object
value) |
Adds a constant variable whose value can not be changed. |
Jep | public void addVariable(String name,Object value) | Adds a variable or change the value of an existing variable. Throws exception on error. |
Jep |
public boolean setVariableValue(String name,Object value) | Sets the value of a mutable variable. Returns false on error. New in Jep 3.5. |
Jep |
public Variable getVariable(String name) | Returns the object representing the variable. |
Jep |
public Object getVariableValue(String name) |
Gets the value of the variable. Does not
re-calculate. |
XJep |
public Object calcVarValue(String name) | Calculates the value of a variable from its
equation. |
XJep |
public preprocess(Node node) |
Causes the equations of variable on the lhs
of an assignment equation to be set. |
XVariable |
public Node getEquation() |
Returns the equation of a variable. |
XVariable |
public Object calcValue() |
Calculates the value of a variable from its
equation. |
VariableTable |
public void clearValues() |
Marks all non constant variables as invalid. |
Various functions are // Add XJep preprocessing functions jep.addFunction("compare", new Compare(xjep, false)); jep.addFunction("expand", new CExpand(xjep.getPolynomialCreator(),jep.addConstant("i",Complex.I))); jep.addFunction("simplify", new Simplify(xjep)); jep.addFunction("coeffs", new Coeffs(xjep)); jep.addFunction("clean", new Clean(xjep)); jep.addFunction("subst", new Subst(xjep)); jep.addFunction("eqn", new ExtractEqn(xjep));