Multiple Expression parsing and evaluation

419 views
Skip to first unread message

Rohan

unread,
Mar 26, 2012, 12:57:39 PM3/26/12
to Jep Java Users
Hi All,

I have multiple expressions that need to be parsed and evaluated and I
see the example at http://www.singularsys.com/jep/doc/html/usage.html#multieqn
to understand how Jep handles multi expressions. My questions are

Question 1 :
Can I parse my multiple expressions only once initially and evaluate
them multiple times using the solution specified with
jep.initMultiParse(s); and jep.continueParsing(); I have looked at
the documentation and and have not found any possible solution using
the current API. Is there any way I can get an Iterator over the Nodes
parsed in this Jep instance, so that I can evaluate the parsed nodes
without having to parse them again using initMultiParse(s)?

If the answer to the above questions is a 'No', I will use the
solution which keeps track of the Nodes external to the Jep instance
and evaluate them as needed.

Question 2:
Consider the following example

Jep jep = new Jep();
try {
jep.addVariable("x",3);
Node n1 = jep.parse("y=x^2");
Node n2 = jep.parse("z=x+y");

Object value2 = jep.evaluate(n2);
Object value1 = jep.evaluate(n1);
}
catch(JepException e) { System.out.println(e.getMessage)}

This Throws a JepException "Could not evaluate y: no value set for
the variable. See
com.singularsys.jep.standard.FastEvaluator.setTrapNullValues(boolean)."

Is there a way to handle such a scenario where the order of
expressions being evaluated is not controllable , but all the
expressios are parsed before the evaluation begins. i.e. the evaluator
should have access to all expressions irrespective of the evaluation
order and should be able get the definition and hence the evaluation
of y in the case of above example.

Best,
Rohan

Richard

unread,
Mar 28, 2012, 5:49:18 AM3/28/12
to Jep Java Users
Rohan

On Mar 26, 5:57 pm, Rohan <rohan...@gmail.com> wrote:
> Hi All,
>
> I have multiple expressions that need to be parsed and evaluated and I
> see the example athttp://www.singularsys.com/jep/doc/html/usage.html#multieqn
> to understand how Jep handles multi expressions. My questions are
>
> Question 1 :
> Can I parse my multiple expressions only once initially and evaluate
> them multiple times using the solution specified with
> jep.initMultiParse(s); and jep.continueParsing();

> I have looked at
> the documentation and and have not found any possible solution using
> the current API. Is there any way I can get an Iterator over the Nodes
> parsed in this Jep instance, so that I can evaluate the parsed nodes
> without having to parse them again using initMultiParse(s)?

Yes you can evaluate many equations easily. It may be easiest if you
store the results of parsing in a list

Jep jep = new Jep();
// setup equations to be parsed
String eqns =
"x=5;"+
"y=6;"+
"z=x^2-y^2;"+
"w=z/(x-y);"+
"v=z/(x+y);";
List<Node> nodes = new ArrayList<Node>();
jep.initMultiParse(eqns);
// parse each expression
Node node;
while((node = jep.continueParsing())!=null) {
nodes.add(node);
}
// Now evaluate them in turn
for(Node n:nodes) {
Object res = jep.evaluate(n);
System.out.print("Equation:\t");
jep.println(n);
System.out.println("Result:\t"+res);
}

The evaluation loop can be run as many times as you want. You can use
jep.addVariable(name, value)
to change the values of variables in each loop.

> If the answer to the above questions is a 'No', I will use the
> solution which keeps track of the Nodes external to the Jep instance
> and evaluate them as needed.

> Question 2:
> Consider the following example
>
> Jep jep = new Jep();
> try {
>         jep.addVariable("x",3);
>         Node n1 = jep.parse("y=x^2");
>         Node n2 = jep.parse("z=x+y");
>
>       Object value2 = jep.evaluate(n2);
>       Object value1 = jep.evaluate(n1);}
>
> catch(JepException e) { System.out.println(e.getMessage)}
>
> This Throws a JepException  "Could not evaluate y: no value set for
> the variable. See
> com.singularsys.jep.standard.FastEvaluator.setTrapNullValues(boolean)."
>
> Is there a way to handle such a scenario where the order of
> expressions being evaluated is not controllable , but all the
> expressios are parsed before the evaluation begins. i.e. the evaluator
> should have access to all expressions irrespective of the evaluation
> order and should be able get the definition and hence the evaluation
> of y in the case of above example.
>
> Best,
> Rohan

This is very similar to the "out of order variables" thread in the
group archive
http://groups.google.com/group/jep-users/browse_thread/thread/3073eb988a6a2523?hl=en

It takes a bit of work using the TreeAnalyzer to work out the correct
order of evaluation:

/**
* Returns true if n1 depends on n2. That is if one of the
variables on the
* rhs of n1 is the lhs variable of n2.
*/
boolean dependsOn(Node n1,Node n2) throws JepException {
TreeAnalyzer ta = new TreeAnalyzer(n1.jjtGetChild(1));
List<String> n1rhs = Arrays.asList(ta.getVariableNames());
String n2lhs = n2.jjtGetChild(0).getName();
return n1rhs.contains(n2lhs);
}

/**
* Tests use of TreeAnalyzer to work out the order of
expressions.
* @throws ParseException
* @throws Exception
*/
@Test
public void testExpressionOrderingMultiLine() throws
ParseException, Exception {
Jep jep = new Jep();
// setup equations to be parsed
String eqns =
"Var4 = Var1 + Var3;"+
"Var5 = Var4 + 1;"+
"Var3 = 3 * Var2;";
List<Node> nodes = new ArrayList<Node>();
jep.initMultiParse(eqns);
// parse each expression
Node node;
while((node = jep.continueParsing())!=null) {
nodes.add(node);
}

for(Node n:nodes) {
jep.println(n);
}

int length = nodes.size();

// build an array of dependancies
boolean[][] deps = new boolean[length][length];
for(int i=0;i<length;++i) {
for(int j=0;j<length;++j) {
if(i==j) continue;
if(dependsOn(nodes.get(i),nodes.get(j))) {
System.out.printf("\"%s\" depends on \"%s\"%n",
jep.toString(nodes.get(i)),jep.toString(nodes.get(j)));
deps[i][j]=true;
}
else {
System.out.printf("\"%s\" does not depends on \"%s\"%n",
jep.toString(nodes.get(i)),jep.toString(nodes.get(j)));
deps[i][j]=false;
}
}
}
System.out.println(Arrays.deepToString(deps));


int[] order = new int[length];
Arrays.fill(order, -1);
boolean[] done = new boolean[length];
Arrays.fill(done, false);

for(int loop=0;loop<length;++loop) {

// find an expression A for which (B dep A) is false for
all other B
// exclude those which have already been done
for(int i=0;i<length;++i) {
if(done[i]) continue;

boolean OK=true; // does anything depend on this
for(int j=0;j<length;++j) {
if(done[j]) continue;
if(i==j) continue;
// something depends on this
if(deps[j][i]) OK=false;
}
if(OK) {
order[loop] = i;
done[i] = true;
break;
}
}
if(order[loop]==-1) {
System.out.println("nothing found");
}
}
System.out.println(Arrays.toString(order));
System.out.println(Arrays.toString(done));

jep.addVariable("Var1",1.0);
jep.addVariable("Var2",2.0);
for(int i=length-1;i>=0;--i) {
jep.println(nodes.get(order[i]));
jep.evaluate(nodes.get(order[i]));
}
}

You might be able to modify the code to reorder the list.

Hope that helps

Richards

Rohan Grover

unread,
Mar 30, 2012, 9:51:39 AM3/30/12
to jep-...@googlegroups.com
Thanks Richard! That definitely helped.
Reply all
Reply to author
Forward
0 new messages