[back] [home] [content] [continue]
Working with functions means repeated evaluation of the same expression
but with different arguments.
We know that's exactly what the mathExpr
library is constructed
for (see philosophy).
To be able to call a function repeatedly with different arguments, take one
of the two ways:
Create a new ExpressionConfiguration
.
ExpressionConfiguration config=new ExpressionConfiguration(RealType.TYPE);
Define a Function
.
config.defineFunction("f", new String[] {"x"}, "x^2");
Define a Variable
.
Real a=new Real(); config.defineVariable("a", a, RealType.TYPE);
Set the expression to a simple call of the defined function with "a" as the argument.
config.setExpression("f(a)");
Iterate the evaluations with a new value for "a" every step.
Real[] result=new Real[10]; for(int i=0; i<result.length; i++) { a.assign(i); result[i]=new Real((Real)config.evaluateExpression()); //it's very important to create a new Real object for every //result, because each evaluation returns the same result object //(there is none instantiation during an evaluation) }
Note: At the first time the method evaluateExpression()
is called, the evaluator-tree will be built up. Every more callings access
to this evaluator-tree. That means: The result object returned by the
method evaluateExpression()
will be the same after any time but with a new value.
That's why the multiple-evaluation is very high
performant.
Note: It's also possible to use the method
defineVariable(String,Object,Type)
within the iteration to change
the variable's value but it's not recommended, because every call would
expect a new value Object
what causes a lower performance.
Example:
//...first commands like the correct example above... Real[] result=new Real[10]; for(int i=0; i<result.length; i++) { config.defineVariable("a", new Real(i), RealType.TYPE); result[i]=new Real((Real)config.evaluateExpression()); }
Note: Never set the expression during the iteration like the following example is showing. The evaluator-tree is rebuilt again and again in every iteration which lowers the performance enormously.
//...first commands like the correct example above... Real[] result=new Real[10]; for(int i=0; i<result.length; i++) { //set new expression -> evaluator-tree not excisting yet config.setExpression("f("+i+")"); //creating the evaluator-tree (never within iteration!) result[i]=config.evaluateExpression(); }
Note: Change the value of the variable but never change its
Type
.
If you changed the Type
of a variable the current evaluator-tree
would become invalid and has to be rebuilt. Example: (UML-Diagramme von den verschieden Evaluator-Baumen)
ExpressionConfiguration config=new ExpressionConfiguration(RealType.TYPE); config.defineFunction("f", new String[] {"x"}, "x^2"); config.setExpression("f(a)"); //variable "a" is real config.defineVariable("a", new Real(1), RealType.TYPE); //first time evaluateExpression() is called -> evaluator-tree will be built up Object o1=config.evaluateExpression(); //variable "a" now complex config.defineVariable("a", new Complex(1), ComplexType.TYPE); //no evaluator-tree will be built up because the expression wasn't resetted, //but the current evaluator-tree is invalid now and a ClassCastException will be the result. try { Object o2=config.evaluateExpression(); } catch(ClassCastException ex) { ex.printStackTrace(); }
Create a new ExpressionConfiguration
.
ExpressionConfiguration config=new ExpressionConfiguration(RealType.TYPE);
The current Expression
of your ExpressionConfiguration
represents the function definition.
//x:->x^2 config.setExpression("x^2");
One (or more) defined variables represent the function parameters.
Real x=new Real(); config.defineVariable("x", x, RealType.TYPE);
Iterate the evaluations with a new value for "x" every step.
Real[] result=new Real[10]; for(int i=0; i<result.length; i++) { x.assign(i); result[i]=new Real((Real)config.evaluateExpression()); }
Two examples according to this concept were already realized. See
mathExpr.example.GenericComplexFunction
and
mathExpr.example.GenericSurfaceParametrizer
.