org.lsmp.djep.mrpe.MRpEval Maven / Gradle / Ivy
Show all versions of jep Show documentation
/* @author rich
* Created on 14-Apr-2004
*/
package org.lsmp.djep.mrpe;
import org.nfunk.jep.*;
import org.nfunk.jep.function.*;
import org.lsmp.djep.matrixJep.nodeTypes.*;
import org.lsmp.djep.matrixJep.*;
import org.lsmp.djep.vectorJep.*;
import org.lsmp.djep.vectorJep.values.*;
import org.lsmp.djep.xjep.*;
import java.util.*;
/**
* A fast evaluation algorithm for equations using Vectors and Matrix over the Doubles.
* This is based around reverse polish notation (hence the name M Rp Eval)
* and is optimised for speed at every opportunity.
*
* To use do
*
* MatrixJep j = ...;
* Node node = ...;
* MRpEval rpe = new MRpEval(j);
* MRpCommandList list = rpe.compile(node);
* MRpRes rpRes = rpe.evaluate(list);
* System.out.println(rpRes.toString());
* MatrixValueI mat = rpRes.toVecMat();
* rpe.cleanUp();
*
*
*
* The real use of this class is when an equation (or set of equations)
* need to be repeatedly evaluated with different values for the variables.
* MRpEval use an internal store for variable values different from those
* used in the main Jep classes. Changes in the Jep variable values,
* say by calling {@link org.nfunk.jep.JEP#setVarValue JEP.setVarValue},
* are reflected
* in changes in MRpEval variables, (the converse does not hold).
* A more efficient way is to use int ref=getVarRef(var)
* to return an index number of the variable and then calling
* setVarVal(ref,value)
to set its value.
* For example
*
* MRpCommandList list = rpe.compile(node);
* int ref = rpe.getVarRef(j.getVar("x"));
* for(double x=-1.;x<1.001;x+=0.1) {
* rpe.setVarVal(ref,x);
* rpe.evaluate(list);
* }
*
*
*
* Combining mrpe with differentation requires special techniques
* to cope with that fact that internal equations are used
*
* 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 scalers (multiplies last two entries on stack)
* Add scalers (adds last two entries on stack)
*
* The evaluate method executes these methods sequentially
* using a stack (actually a set of stacks)
* and returns the last object on the stack.
*
* A few cautionary notes: the values returned by evaluate
* are references to internal variables, their values will change
* at the next call to compile or evaluate.
* Its very unlikely to be thread safe. It only works over doubles;
* expressions with complex numbers or strings will cause problems.
* It is tuned to work best for expressions involving scalers and 2, 3 and 4 dimensional vectors and matricies,
* larger vectors and matrices will be noticeably slower.
* The cleanUp function should be used when you no longer need
* the evaluator, this stops the evaluator listening to Variable
* through the java.util.Observer interface.
*
* Implementation notes
* A lot of things have been done to make it as fast as possible:
*
* - Everything is final which maximises the possibility for in-lining.
* - All object creation happens during compile.
* - All calculations done using double values.
* - Vectors and Matrices are instances of VecObj and MatObj optimised for speed.
* For instance a 2 by 2 matrix is an instance of Mat22Obj whose elements
* are represented by the fields a,b,c,d. This eliminates bound checking on arrays.
*
* - Each possible vector and matrix operation has been hand coded, and there are
* a lot of methods (27 just for matrix multiplication!).
* - The values of variables are kept on local arrays for fast access.
* These values are kept in sync with the main Jep Variables by using
* the java.util.Observer interface.
*
*
*
* For each type of vector or matrix (i.e. 2D vecs, 3D vecs, 4D vecs, 2 by 2 matrices ... 4 by 4 matrices.
* there is a corresponding class V2Obj, M22Obj etc.
* which stores the values and another class V2Store, M22Store etc.
* Each Store class contains a stack, a heap and a array of variable values.
* During evaluation objects are pushed and popped from the stack
* when a new object is needed it is taken from the heap.
* The operation is illustrated by the add method for 2 by 2 matrices.
*
* private final class M22Store
* {
* ....
* final void add(){
* M22Obj r = stack[--sp]; // pop from stack
* M22Obj l = stack[--sp]; // pop from stack
* M22Obj res = heap[hp++]; // result is next entry in heap
* res.a = l.a+r.a; // add each componant
* res.b = l.b+r.b;
* res.c = l.c+r.c;
* res.d = l.d+r.d;
* stack[sp++]=res; // push result onto stack
* }
* }
*
*
* @author Rich Morris
* Created on 14-Apr-2004
*/
public final class MRpEval implements ParserVisitor {
private MatrixOperatorSet opSet;
public MRpEval(MatrixJep mjep) {
this.opSet = (MatrixOperatorSet) mjep.getOperatorSet();
}
private MRpEval() {}
/** compile an expression of the type var = node. */
public final MRpCommandList compile(MatrixVariableI var,Node node) throws ParseException
{
MRpCommandList list = compile(node);
ObjStore store = getStoreByDim(var.getDimensions());
short vRef = (short) store.addVar(var);
store.decStack();
list.addCommand(ASSIGN,getDimType(var.getDimensions()),vRef);
return list;
}
/**
* Compile the expressions to produce a set of commands in reverse Polish notation.
*/
public final MRpCommandList compile(Node node) throws ParseException
{
curCommandList = new MRpCommandList();
node.jjtAccept(this,null);
scalerStore.alloc();
v2Store.alloc();
v3Store.alloc();
v4Store.alloc();
vnStore.alloc();
m22Store.alloc();
m23Store.alloc();
m24Store.alloc();
m32Store.alloc();
m33Store.alloc();
m34Store.alloc();
m42Store.alloc();
m43Store.alloc();
m44Store.alloc();
mnnStore.alloc();
Dimensions dims = ((MatrixNodeI) node).getDim();
curCommandList.setFinalType(getDimType(dims));
// returnObj = Tensor.getInstance(dims);
// if(dims.is2D())
// returnMat = (Matrix) returnObj;
return curCommandList;
}
/** Index for each command */
static final short CONST = 0;
static final short VAR = 1;
static final short ADD = 2;
static final short SUB = 3;
static final short MUL = 4;
static final short DIV = 5;
static final short MOD = 6;
static final short POW = 7;
static final short AND = 8;
static final short OR = 9;
static final short NOT = 10;
static final short LT = 11;
static final short LE = 12;
static final short GT = 13;
static final short GE = 14;
static final short NE = 15;
static final short EQ = 16;
static final short LIST = 17;
static final short DOT = 18;
static final short CROSS = 19;
static final short ASSIGN = 20;
static final short VLIST = 21;
static final short MLIST = 22;
static final short FUN = 23;
static final short UMINUS = 24;
/** Constant type scalers - used in the aux field of RpCommand */
private static final short SCALER = 0; // Scalers
private static final short V2 = 2; // 2D vect
private static final short V3 = 3;
private static final short V4 = 4;
private static final short Vn = 5; // n D vec
private static final short M22 = 6; // 2 by 2 mat
private static final short M23 = 7; // 2 by 3 mat
private static final short M24 = 8;
private static final short M32 = 9;
private static final short M33 = 10;
private static final short M34 = 11;
private static final short M42 = 12;
private static final short M43 = 13;
private static final short M44 = 14;
private static final short Mnn = 15; // other mats
private static final short Dtens = 16; // tensors
/** Standard functions **/
private static final short SIN = 1;
private static final short COS = 2;
private static final short TAN = 3;
private static final short ASIN = 4;
private static final short ACOS = 5;
private static final short ATAN = 6;
private static final short SINH = 7;
private static final short COSH = 8;
private static final short TANH = 9;
private static final short ASINH = 10;
private static final short ACOSH = 11;
private static final short ATANH = 12;
private static final short ABS = 13;
private static final short EXP = 14;
private static final short LOG = 15;
private static final short LN = 16;
private static final short SQRT = 17;
private static final short SEC = 18;
private static final short COSEC = 19;
private static final short COT = 20;
// 2 argument functions
// private static final short ANGLE = 21;
// private static final short MODULUS = 22;
/** Hashtable for function name lookup **/
private static final Hashtable functionHash = new Hashtable();
{
functionHash.put("sin",new Short(SIN));
functionHash.put("cos",new Short(COS));
functionHash.put("tan",new Short(TAN));
functionHash.put("asin",new Short(ASIN));
functionHash.put("acos",new Short(ACOS));
functionHash.put("atan",new Short(ATAN));
functionHash.put("sinh",new Short(SINH));
functionHash.put("cosh",new Short(COSH));
functionHash.put("tanh",new Short(TANH));
functionHash.put("asinh",new Short(ASINH));
functionHash.put("acosh",new Short(ACOSH));
functionHash.put("atanh",new Short(ATANH));
functionHash.put("abs",new Short(ABS));
functionHash.put("exp",new Short(EXP));
functionHash.put("log",new Short(LOG));
functionHash.put("ln",new Short(LN));
functionHash.put("sqrt",new Short(SQRT));
functionHash.put("sec",new Short(SEC));
functionHash.put("cosec",new Short(COSEC));
functionHash.put("cot",new Short(COT));
}
/** Contains the constant values **/
private double constVals[] = new double[0];
/**
* Finds the reference number used for this variable.
* @param var
* @return an index used to refer to the variable
* @throws ParseException
*/
public int getVarRef(Variable var) throws ParseException
{
Dimensions dims = ((MatrixVariableI)var).getDimensions();
ObjStore store = getStoreByDim(dims);
int ref = store.addVar((MatrixVariableI) var);
return ref;
}
/**
* Finds the reference number used for this variable.
* @param var
* @return an index used to refer to the variable
* @throws ParseException
*/
public int getVarRef(MatrixVariableI var) throws ParseException
{
Dimensions dims = var.getDimensions();
ObjStore store = getStoreByDim(dims);
int ref = store.addVar(var);
return ref;
}
/**
* Sets value of rpe variable.
*
* @param ref the reference number for the variable
* (found using {@link #getVarRef(org.lsmp.djep.matrixJep.MatrixVariableI)})
* @param val
* @throws ParseException
*/
public final void setVarValue(int ref,MatrixValueI val)
throws ParseException
{
ObjStore store = getStoreByDim(val.getDim());
store.setVarValue(ref,val);
}
/**
* Sets value of rpe variable.
* Only applies to scaler (double variables).
*
* @param ref the reference number for the variable
* (found using {@link #getVarRef(org.lsmp.djep.matrixJep.MatrixVariableI)})
* @param val the value
*/
public final void setVarValue(int ref,double val)
{
scalerStore.setVarValue(ref,val);
}
private final static class ScalerObj extends MRpRes {
double a;
private ScalerObj(double val) {a =val; }
public final Dimensions getDims() { return Dimensions.ONE; }
public final void copyToVecMat(MatrixValueI res) throws ParseException {
if(! res.getDim().is0D()) throw new ParseException("CopyToVecMat: dimension of argument "+res.getDim()+" is not equal to dimension of object "+getDims());
res.setEle(0,new Double(a));
}
public final String toString() { return String.valueOf(a); }
public Object toArray() { return new double[]{a}; }
}
private ScalerObj scalerRes = new ScalerObj(0.0);
private abstract static class VecObj extends MRpRes {
public final void copyToVecMat(MatrixValueI res) throws ParseException {
if(! getDims().equals(res.getDim())) throw new ParseException("CopyToVecMat: dimension of argument "+res.getDim()+" is not equal to dimension of object "+getDims());
copyToVec((MVector) res);
}
public abstract void copyToVec(MVector res);
abstract double[] toArrayVec();
public Object toArray() { return toArrayVec(); }
/**
* Sets the value of th vector frm an array.
*/
// public abstract void fromArray(double array[]);
}
private abstract static class MatObj extends MRpRes {
public final void copyToVecMat(MatrixValueI res) throws ParseException {
if(! getDims().equals(res.getDim())) throw new ParseException("CopyToVecMat: dimension of argument "+res.getDim()+" is not equal to dimension of object "+getDims());
copyToMat((Matrix) res);
}
public abstract void copyToMat(Matrix res);
abstract double[][] toArrayMat();
public Object toArray() { return toArrayMat(); }
}
/**
* Base class for storage for each type of data.
* Each subclass should define
*
* private Obj stack[];
* private Obj heap[];
* private Obj vars[]= new Obj[0];
*
* where Obj is an Object of the specific type, eg V2Obj.
* Memory for the data is allocated from the heap
* and the stack is the current data used for calculations.
* Data for Variables is stored in vars and references to the Variables
* in varRefs.
*/
private abstract static class ObjStore implements Observer {
/** Contains references to Variables of this type */
Hashtable varRefs = new Hashtable();
/** The stack pointer */
int sp=0;
/** Maximum size of stack */
int stackMax=0;
/** The heap pointer */
int hp=0;
final void incStack() {sp++; if(sp > stackMax) stackMax = sp; }
final void incHeap() {hp++;}
final void decStack() throws ParseException {--sp; if(sp <0 ) throw new ParseException("RPEval: stack error");}
/** call this to reset pointers as first step in evaluation */
final void reset() { sp = 0; hp = 0; }
/** Add a reference to this variable.
* @return the index of variable in table
*/
final int addVar(MatrixVariableI var){
Object index = varRefs.get(var);
if(index==null)
{
int size = varRefs.size();
expandVarArray(var);
varRefs.put(var,new Integer(size));
copyFromVar(var,size);
((Variable) var).addObserver(this);
return size;
}
return ((Integer) index).intValue();
}
/** Callback function for Observable Variables.
* Called whenever the value of a variable is changed
* so the private list of variables is kept in sync.
*/
final public void update(Observable obs, Object arg1)
{
MatrixVariableI var = (MatrixVariableI) obs;
Object index = varRefs.get(var);
copyFromVar(var,((Integer) index).intValue());
}
abstract public void setVarValue(int ref,MatrixValueI val);
/** allocates space needed */
abstract void alloc();
/** removed store from list of listeners. */
final void cleanUp()
{
for(Enumeration e=varRefs.keys();e.hasMoreElements();)
{
Variable var = (Variable) e.nextElement();
var.deleteObserver(this);
}
varRefs.clear();
}
/** Copy variable values into into private storage */
abstract void copyFromVar(MatrixVariableI var,int i);
/** Copy values from private storage into JEP variables */
// abstract void copyToVar(MatrixVariableI var,int i);
/** expand size of array used to hold variable values. */
abstract void expandVarArray(MatrixVariableI var);
/** add two objects of same type */
abstract void add();
/** subtract two objects of same type */
abstract void sub();
/** subtract two objects of same type */
abstract void uminus();
/** multiply by a scaler either of left or right */
abstract void mulS();
/** convert a set of scaler values into object of this type */
abstract void makeList();
/** assign a variable to stack value
* @param i index of variable */
abstract void assign(int i);
}
private final class ScalerStore extends ObjStore {
double stack[]=new double[0];
double vars[]= new double[0];
final void alloc() {
stack = new double[stackMax];
}
final void expandVarArray(MatrixVariableI var)
{
double newvars[] = new double[vars.length+1];
System.arraycopy(vars,0,newvars,0,vars.length);
vars = newvars;
}
final void copyFromVar(MatrixVariableI var,int i)
{
if(var.hasValidValue())
{
Scaler val = (Scaler) var.getMValue();
vars[i]=val.doubleValue();
}
}
public void setVarValue(int ref, double val) {
vars[ref] = val;
}
public final void setVarValue(int ref,MatrixValueI val)
{
vars[ref]=((Scaler) val).doubleValue();
}
final void add(){
double r = stack[--sp];
stack[sp-1] += r;
}
final void sub(){
double r = stack[--sp];
stack[sp-1] -= r;
}
final void uminus(){
double r = stack[--sp];
stack[sp++] = -r;
}
final void mulS(){
double r = stack[--sp];
stack[sp-1] *= r;
}
final void divS(){
double r = stack[--sp];
stack[sp-1] /= r;
}
final void mod(){
double r = stack[--sp];
stack[sp-1] %= r;
}
final void pow(){
double r = stack[--sp];
double l = stack[--sp];
stack[sp++] = Math.pow(l,r);
}
final void powN(int n){
double r = stack[--sp];
switch(n){
case 0: r = 1.0; break;
case 1: break;
case 2: r *= r; break;
case 3: r *= r*r; break;
case 4: r *= r*r*r; break;
case 5: r *= r*r*r*r; break;
default:
r = Math.pow(r,n); break;
}
stack[sp++] = r;
}
final void makeList() {
}
final void assign(int i) {
vars[i] = stack[--sp]; ++sp;
}
final void and(){
double r = stack[--sp];
double l = stack[--sp];
if((l != 0.0) && (r != 0.0))
stack[sp++] = 1.0;
else
stack[sp++] = 0.0;
}
final void or(){
double r = stack[--sp];
double l = stack[--sp];
if((l != 0.0) || (r != 0.0))
stack[sp++] = 1.0;
else
stack[sp++] = 0.0;
}
final void not(){
double r = stack[--sp];
if(r == 0.0)
stack[sp++] = 1.0;
else
stack[sp++] = 0.0;
}
final void lt(){
double r = stack[--sp];
double l = stack[--sp];
if(l < r)
stack[sp++] = 1.0;
else
stack[sp++] = 0.0;
}
final void gt(){
double r = stack[--sp];
double l = stack[--sp];
if(l > r)
stack[sp++] = 1.0;
else
stack[sp++] = 0.0;
}
final void le(){
double r = stack[--sp];
double l = stack[--sp];
if(l <= r)
stack[sp++] = 1.0;
else
stack[sp++] = 0.0;
}
final void ge(){
double r = stack[--sp];
double l = stack[--sp];
if(l >= r)
stack[sp++] = 1.0;
else
stack[sp++] = 0.0;
}
final void eq(){
double r = stack[--sp];
double l = stack[--sp];
if(l == r)
stack[sp++] = 1.0;
else
stack[sp++] = 0.0;
}
final void neq(){
double r = stack[--sp];
double l = stack[--sp];
if(l != r)
stack[sp++] = 1.0;
else
stack[sp++] = 0.0;
}
}
ScalerStore scalerStore = new ScalerStore();
/** Base class for vector type storage */
private abstract class VecStore extends ObjStore {
abstract void copyVar(int i,MVector val);
final void copyFromVar(MatrixVariableI var,int i)
{
if(var.hasValidValue())
{
MVector val = (MVector) ((MatrixVariable) var).getMValue();
copyVar(i,val);
}
}
public final void setVarValue(int ref, MatrixValueI val) {
copyVar(ref,(MVector) val);
}
}
private static final class V2Obj extends VecObj {
double a,b;
private static Dimensions dims = Dimensions.TWO;
public Dimensions getDims() { return dims; }
public String toString() { return "["+a+","+b+"]"; }
public void fromVec(MVector val){
a = ((Double) val.getEle(0)).doubleValue();
b = ((Double) val.getEle(1)).doubleValue();
}
public void copyToVec(MVector val){
val.setEle(0,new Double(a));
val.setEle(1,new Double(b));
}
public double[] toArrayVec() { return new double[]{a,b}; }
}
private final class V2Store extends VecStore {
V2Obj stack[];
V2Obj heap[];
V2Obj vars[]= new V2Obj[0];
final void alloc() {
heap = new V2Obj[hp];
for(int i=0;i0) sb.append(",");
sb.append(data[i]);
}
sb.append("]");
return sb.toString();
}
public void fromVec(MVector val){
for(int i=0;i=0;--i)
res.data[i] = scalerStore.stack[--scalerStore.sp];
stack[sp++]=res;
}
final void makeList() {
throw new UnsupportedOperationException("VnObj: makeList cannot be called with no arguments");
}
final void assign(int j) {
VnObj r = stack[sp-1];
VnObj res = vars[j];
for(int i=0;i0) sb.append(',');
sb.append('[');
for(int j=0;j0) sb.append(',');
sb.append(data[i][j]);
}
sb.append(']');
}
sb.append(']');
return sb.toString();
}
public void fromMat(Matrix val){
for(int i=0;i=0;--i)
for(int j=cols-1;j>=0;--j)
res.data[i][j]= scalerStore.stack[--scalerStore.sp];
stack[sp++]=res;
}
final void makeList() {
throw new UnsupportedOperationException("VnObj: makeList cannot be called with no arguments");
}
final void assign(int k) {
MnnObj r = stack[sp-1];
MnnObj res = vars[k];
for(int i=0;i=1)
{
leftnode = (MatrixNodeI) node.jjtGetChild(0);
ldims = leftnode.getDim();
}
if(nChild>=2)
{
rightnode = (MatrixNodeI) node.jjtGetChild(1);
rdims = rightnode.getDim();
}
if(mnode.isOperator())
{
XOperator op = (XOperator) mnode.getOperator();
if(op.isBinary())
if(nChild!=2)
throw new ParseException("RpeEval: binary operator must have two children, but it has "+nChild);
if(op.isUnary())
if(nChild!=1)
throw new ParseException("RpeEval: unary operator must have one child, but it has "+nChild);
if(op == opSet.getAdd())
{
if(!dims.equals(ldims) || !dims.equals(rdims))
throw new ParseException("RpeEval: dims for add must be equal");
curCommandList.addCommand(ADD,getDimType(dims));
decByDim(dims);
incheapByDim(dims);
return null;
}
else if(op == opSet.getSubtract())
{
if(!dims.equals(ldims) || !dims.equals(rdims))
throw new ParseException("RpeEval: dims for add must be equal");
curCommandList.addCommand(SUB,getDimType(dims));
decByDim(dims);
incheapByDim(dims);
return null;
}
else if(op == opSet.getUMinus())
{
curCommandList.addCommand(UMINUS,getDimType(dims));
incheapByDim(dims);
return null;
}
else if(op == opSet.getMultiply())
{
decByDim(rdims);
decByDim(ldims);
incByDim(dims);
incheapByDim(dims);
curCommandList.addCommand(MUL,getDimType(ldims),getDimType(rdims));
return null;
}
else if(op == opSet.getMList())
{
incByDim(dims);
incheapByDim(dims);
for(int j=0;j operator must both be one");
scalerStore.incStack();
decByDim(ldims);
decByDim(rdims);
curCommandList.addCommand(GT,SCALER); return null;
}
else if(op == opSet.getLE())
{
if(!ldims.is0D() || !rdims.is0D())throw new ParseException("Dimensions of operands for <= operator must both be one");
scalerStore.incStack();
decByDim(ldims);
decByDim(rdims);
curCommandList.addCommand(LE,SCALER); return null;
}
else if(op == opSet.getGE())
{
if(!ldims.is0D() || !rdims.is0D())throw new ParseException("Dimensions of operands for >= operator must both be one");
scalerStore.incStack();
decByDim(ldims);
decByDim(rdims);
curCommandList.addCommand(GE,SCALER); return null;
}
else if(op == opSet.getAnd())
{
if(!ldims.is0D() || !rdims.is0D())throw new ParseException("Dimensions of operands for && operator must both be one");
scalerStore.incStack();
decByDim(ldims);
decByDim(rdims);
curCommandList.addCommand(AND,SCALER); return null;
}
else if(op == opSet.getOr())
{
if(!ldims.is0D() || !rdims.is0D())throw new ParseException("Dimensions of operands for || operator must both be one");
scalerStore.incStack();
decByDim(ldims);
decByDim(rdims);
curCommandList.addCommand(OR,SCALER); return null;
}
else if(op == opSet.getNot())
{
if(!ldims.is0D())throw new ParseException("Dimension of operand for not operator must be one");
scalerStore.incStack();
decByDim(rdims);
curCommandList.addCommand(NOT,SCALER); return null;
}
else if(op == opSet.getDivide())
{
if(!rdims.is0D())throw new ParseException("RHS operands of / operator must be a Scaler");
decByDim(rdims);
decByDim(ldims);
incByDim(dims);
incheapByDim(dims);
curCommandList.addCommand(DIV,getDimType(ldims),getDimType(rdims));
return null;
}
else if(op == opSet.getMod())
{
if(!ldims.is0D() || !rdims.is0D())throw new ParseException("Dimensions of operands for || operator must both be one");
scalerStore.incStack();
decByDim(ldims);
decByDim(rdims);
curCommandList.addCommand(MOD,SCALER); return null;
}
else if(op == opSet.getPower())
{
if(!ldims.is0D() || !rdims.is0D())throw new ParseException("Dimensions of operands for || operator must both be one");
scalerStore.incStack();
decByDim(ldims);
decByDim(rdims);
curCommandList.addCommand(POW,SCALER); return null;
}
throw new ParseException("RpeEval: Sorry unsupported operator/function: "+ mnode.getName());
}
// other functions
Short val = (Short) functionHash.get(mnode.getName());
if(val == null)
throw new ParseException("RpeEval: Sorry unsupported operator/function: "+ mnode.getName());
if(mnode.getPFMC().getNumberOfParameters() == 1 && nChild == 1)
{
scalerStore.incStack();
decByDim(ldims);
curCommandList.addCommand(FUN,val.shortValue());
return null;
}
throw new ParseException("RpeEval: Sorry unsupported operator/function: "+ mnode.getName());
}
/***************************** evaluation *****************************/
/** Evaluate the expression.
*
* @return the value after evaluation
*/
public final MRpRes evaluate(MRpCommandList comList)
{
scalerStore.reset();
v2Store.reset();
v3Store.reset();
v4Store.reset();
vnStore.reset();
m22Store.reset();
m23Store.reset();
m24Store.reset();
m32Store.reset();
m33Store.reset();
m34Store.reset();
m42Store.reset();
m43Store.reset();
m44Store.reset();
mnnStore.reset();
// Now actually process the commands
int num = comList.getNumCommands();
for(short commandNum=0;commandNum