Mathematical Functions ParserOk, let's talk about mathematical functions capture & their interpretation in a scientific program, when you want to give to the user the ability to enter his own function in character string shape. For example, with an equation solving program ("Enter the equation to solve ...") or even with a function plotter ("Enter the equation to plot f(x) = ..."). Once the string captured, a subroutine interprets this string and evaluates the function as is. Such subroutine is called usually a parser of mathematical expressions. Within the project Opale, under LGPL licence, we have developed a parser in Java. First of all used in the function plotter & differential equation solving project, and then everywhere where a mathematical expression must be evaluated. The applet, below, allows you to test a part of the functionalities of this parser. This is the first version, so don't hesitate to report any bugs . To use this applet, enter a mathematical expression in the first line, which can contain variables such as x, y, z & t ; in the next lines you can enter the value of those variables (0 per default) and by clicking on the button the result will be displayed in the last line. In the next lines, we'll talk briefly about the design used in the parser ; then a description of its functionalities and its evolution. We'll talk also about its use in your java programs. Parser design : Abstract
In this section, we'll present briefly a method to program a parser without any details. The goal is to evaluate a mathematical expression containing usual operators (+,-,*,/), numbers, variables (x,y,...), constants (Pi,...) and functions (cos, sin, exp ...).
First of all, you need to build a tree from the string ; second of all, walk thru the tree from the root to evaluate the expression value. The most delicate part of this algorithm is the construction of the tree. Once built, it must be stored in an adapted data structure and it can be evaluate as many time as needed (for several values of x for example) without rebuilding it before each evaluation. The corresponding tree to our exmample is : The evaluation of the expression is realized as we said by walking thru the tree from its root. Practically it can done easily with a recursive algorithm. Opale parser functionalitiesThe parser provided by Opale is just at its first version. The applet of this page allows to test quickly its validity on expressions containing variables as x,y,z or t. Nevertheless all the abilities given by this parser are not accessible in this applet. We enumerate then, in bulk, the functionalities of this first version :
Let's talk about futur :
How to use it ?You can download the parser as an independant unit to use in your program. Here is the archive oparser.jar which contains all necessary classes to use it. This work is under licence LGPL and we invite you to read carrefully this licence before any use. Let's talk a bit of the use of those classes in your programs. The most important classes are only 4 and are in the oparser package. It would be better to insert the line 'import oparser.*;' in your program and to set the environment variable CLASSPATH carefully : in fact it must contains the full path to oparser.jar or you must compile each time with the correct classpath : You can read the on-line classes documentation (not yet completed). Example 1 :The base class is Parser. Let's begin by a simple example which evaluate an expression : import oparser.*; public class Test1 { public static void main(String[] arg) { Parser parser = new Parser("4-2*sin(x-Pi)*2"); parser.addVar("x"); parser.parseString(); parser.setVar("x",1); System.out.println(parser.eval()); parser.setVar("x","Pi"); System.out.println(parser.eval()); } } For any compilation problems, don't hesitate to contact us. This example is easy : we create a parser object by giving the string to translate. Then, we declare the used variables, here "x", with the method addVar(String). We call the method parseString() to build the tree. Once the tree built, we can set variables value with setVar(String, double) or setVar(String, String), and then evaluate the expression as many times as needed with the method eval(). Example 2 :Here is another example with 2 variables x,y. We evaluate the expression sqrt(x*x+y*y) for several values of those variables in a loop. import oparser.*; public class Test2 { public static void main(String[] arg) { Parser parser = new Parser("sqrt(x^2+y^2)"); parser.addVar("x"); parser.addVar("y"); parser.parseString(); for (int i=0;i<5;i++) for (int j=0;j<5;j++) { parser.setVar("x",i); parser.setVar("y",j); System.out.println("sqrt("+i+"*"+i+"+"+j+"*"+j+") = "+parser.eval()); } } } Dont forget that we build the tree with the method parseString() only once before evaluation. Example 3 :Let's finish with an example where this time we define a user function. import oparser.*; public class Test3 { public static void main(String[] arg) { SUnaryFunction f = new SUnaryFunction("f","z","3*z-z*z"); System.out.println("f(2) = "+f.eval(2)); Parser parser = new Parser("2*f(x)*f(x)"); parser.addVar("x"); parser.addFunc(f); parser.parseString(); parser.setVar("x",-2); System.out.println("2*f(-2)*f(-2) = "+parser.eval()); } } In this example, with SUnaryFunction class, we define a function, called user function, with a character string. In our case, we define the function called "f", with the variable "z" by f(z) = 3*z-z*z. We display then first value of f(2) by calling method eval() of SUnaryFunction class. Then we remark that it's possible to use in a Parser instance our user function "f". You just need, after creating a Parser, to indicate to it functions to be known with the method addFunc(SUnaryFunction). In our example we give it the function f. Then, as previously we indicate the variable (here x : it's of course possible to define a function of z and use it after as a function of another variable, here x). At the end, we display the result with the method eval as previously. Don't hesitate to give your opinion or question on this topic. Opale Team : January 31 2004 23:14:10. |