Wiki
Clone wikimikulas / mexpr / index
Mexpr
Mexpr is a library supporting writing mathematical expressions and their evaluation.
Scientific applications sometimes need to enter some formulas and evaluate them or show them in a graph. The formula is not a part of the application but user usually wishes to enter own formula and evaluate it.
ExpressionParser
Simplest expression
Main class to use is ExpressionParser
Example of use:
ExpressionParser expressionParser = new ExpressionParser("100 * 10 + 25"); double result = expressionParser.evaluateDouble();
Variables
More complex use may contain variables (which can be considered to be some constants):
Easy Variables
Passing a value into variable, like 'x':
ExpressionParser expressionParser = new ExpressionParser("100 * x + 25", Map.of("x", 20)); double result = expressionParser.evaluateDouble();
Settable Variables
Variables can be set without need to recompile expression which would be slow for scientific calculations, like using in equations or drawing a graph.
DoubleHolder xHolder = new DoubleHolder(); // DoubleHolder is a Supplier<Double> with possibility to dynamically change the value ExpressionParser expressionParser = new ExpressionParser("x + 1", Map.of("x", xHolder)); xHolder.accept(10); expressionParser.evaluateDouble(); // 11 xHolder.accept(20); expressionParser.evaluateDouble(); // 21
Typical Use Case
An exception should be expected for the parsing. Depending on exception the input should be changed:
ExpressionParser expressionParser = null; try { expressionParser = new ExpressionParser("100 * x + 25"); } catch (ParseExpressionException e) { if (e instanceof UndefinedVariableException) { expressionParser = new ExpressionParser("100 * x + 25", Map.of(e.getVariableName(), 10)); // setting value for missing x variable } } ... double result = expressionParser.evaluateDouble();
Constants
Also constants like pi
are supported:
ExpressionParser expressionParser = new ExpressionParser("pi * r ^ 2", Map.of("r", 20)); double result = expressionParser.evaluateDouble();
Functions
Expressed Functions
They can be made easily directly by user using a declaring and defining string present in the map.
new ExpressionParser("sin(0.5) + quadr(11)", Map.of("quadr(x)", "11 * x ^ 2 + 21 * x + 31"));
Invalid example:
new ExpressionParser("f(11)", Map.of("f(x)", "x + a"));
new ExpressionParser("f(11)", Map.of("f(x)", "x + a", "a", 20));
new ExpressionParser("f(10, 20)", Map.of("f(x, a)", "x + a", "a", 40)); // 30
Java Functions
Functions can be made by a java class annotated with @FunctionalSupplier
. All such classes with such annotation are ready to use in expression. There are some prepared basic math functions, like sin
, log
, ...
Prepared functions are all functions found on classpath and their package starts with cz.jmare.mexpr.func
but another custom functions with own package may be also added. Prepared functions can be disabled by new Config().withPredefinedClasses(false);
, config is passed as an argument int ExpressionParser constructor.
List of available java functions:
SupplierInfos supplierInfos = SuppliersClassesProvider.getSupplierInfosEmbedded(true); System.out.println(supplierInfos.funcInfos);
Example of use:
ExpressionParser expressionParser = new ExpressionParser("sin(2 * pi)"); double result = expressionParser.evaluateDouble();
They can be used, for example, in graphs.
DoubleHolder xHolder = new DoubleHolder(); ExpressionParser expressionParser = new ExpressionParser("sin(x * 2 * pi)", Map.of("x", xHolder)); for (double x = 0; x < 10; x += 0.01) { xHolder.accept(x); double y = expressionParser.evaluateDouble(); plot(x, y); }
Note: We are creating a DoubleHolder instance which is a Supplier providing a value and it's also a Consumer to set the value. The expression needn't be compiled for each evaluation but rather we only set the value and get a new result.
Useful functions
I often use functions, like sin
, rand
. For example to generate a sine wave with standard deviation of 0.05 such formula may be used:
sin(x * 2 * pi) + rand(-0.1, 0.1)
Or to generate one curve with two frequencies where x = 1
is a border:
sin(x * 2 * pi) * less(x, 1) + sin(x * 2 * pi * 2) * greater(x, 1)
between
function to define a range.
Also functions like log
are often used. Note they can contain various number of parameters and some functions like log
may contain one or two parameters. The second parameter is the base. For base=10
the log10
function can be also used as shortcut.
Application configuration
Use following Maven configuration before start:
<dependency> <groupId>io.bitbucket.janmaren</groupId> <artifactId>mexpr</artifactId> <version>1.1</version> </dependency>
See also expression syntax
Updated