Jep 3 Releases | Jep 2 Releases | Jep 1 Releases
A modularized version of Jep for use with Java 11 is available in the modules directory.
The code is written to be compatible with both long term support versions Java SE 1.8 and Java SE 1.11.
Most functions can work fine in multiple threads, there are some which need special treatment.
These functions can be indicated by implementing JepComponent which
provides a getLightWeightInstance() to return a thread-safe copy of the function.
By when using the FunctionTable and OperatorTable
in multiple threads their getLightWeightInstance() methods will just return
this which is more memory efficient in the default case. This is the behaviour in Jep 3.4 and earlier.
Starting in version 4.0, both FunctionTable and OperatorTableI
have shallowCopy() methods. This will create new instance of the table and copies all functions
operators into the new table. If the function implements JepComponent then its getLightWeightInstance()
is called to return a thread-safe version.
There is also a MediumWeightComponentSet class which can be used to create a Jep
instance which insures thread-safe versions of functions. To use
Jep jep = new Jep(); Jep copy = new Jep(new MediumWeightComponentSet(jep));and the copy instance can be safely used in new thread.
To implement this functionality FunctionTable, and EmptyOperatorTable have
protected threadSafeMapCopy()
methods which returns a copy of the internal map respecting JepComponents.
They also have protected FunctionTable(Map<,>), EmptyOperatorTable(Map<,>)
constructors. This allows subclasses
it easily implement this behaviour
class MyFunctionTable extends FunctionTable {
...
protected MyFunctionTable(Map<String, PostfixMathCommandI> tbl) {
super(tbl);
}
public FunctionTable shallowCopy() {
Map<String,PostfixMathCommandI> newMap = this.threadSafeMapCopy();
FunctionTable ft = new MyFunctionTable(newMap);
return ft;
}
All sub-classes also implement these constructors.
The Jep 3.5 release had a broken implementation of getLightWeightInstance() which would always return an empty table.
A new UncheckedEvaluator evaluator which does no checking of intermediate values during evaluation. Produces a 10-20% speed increase.
Slight change in the logic of the FastEvaluator. Test for
functions which implement CallbackEvaluationI happens after
tests for UnaryFunction etc.
The UnaryFunction, BinaryFunction and NaryBinaryFunction
have static factory methods which allow creation using lambda functions.
For example
// Function using explicit class
UnaryFunction recip = UnaryFunction.instanceOf(
x -> 1.0 / ((Number) x).doubleValue());
// Function where arguments are of an explicit type
UnaryFunction neg = UnaryFunction.instanceOf(Integer.class, x -> -x );
// Function using a method reference
UnaryFunction cubrt = UnaryFunction.instanceOf(Double.class,Math::cbrt);
// Binary function
BinaryFunction diff = BinaryFunction.instanceOf(Number.class,
(x,y) -> x.doubleValue() - y.doubleValue());
// NaryBinaryFunction
NaryBinaryFunction sum = NaryBinaryFunction.instanceOf(
(x,y) -> ((Number) x).doubleValue() + ((Number) y).doubleValue());
ImmutableComplex class who's values cannot be changed, and the results
of all operations yield immutable results.
Complex.ZERO, Complex.ONE, Complex.I
are now immutable, but for compatibility results of operations using these constants
can be changed. These constants use the Complex.NonPropagatingImmutableComplex
inner class.
power(Complex w) methods checks to see if the argument is an integer, if so
the power(int n) method is used. This in turn calls either fastPower(int n), or powerI(int n).
The first of these is faster but may be less accurate for large powers. A new powerD(double d)
is also introduced which uses the general double algorithm [r:th] -> [r^d:d th].
SpeedTestComplex diagnostic class.
standard.Complex.ToStringImaginaryWithI removed and properties
standard.Complex.ToStringNoBracketsRealWithI={0}
standard.Complex.ToStringNoBracketsNegRealWithI=-{0}
standard.Complex.ToStringNoBracketsImaginaryWithI={1} i
standard.Complex.ToStringNoBracketsImaginaryWithNegI={1} i
standard.Complex.ToStringBracketsRealWithI={0}
standard.Complex.ToStringBracketsNegRealWithI=-{0}
standard.Complex.ToStringBracketsImaginaryWithI={1} i
standard.Complex.ToStringBracketsImaginaryWithNegI={1} i
added.
MacroFunction which could give incorrect results on recursive functions.
Complex.reciprocal() gave incorrect results when im!=0.
PostfixTreeWalker the visit() methods are now called with the
correct number of children in cases when supressExaminingChildren(Node) returns true.
Parsing
BracketedSequenceGrammarMatcher FunctionSequenceGrammarMatcher
which parses lists and sequences, but the sequences separator , is treated
as a normal operator, and sequences passed using the ShuntingYard.
StandardConfigurableParser
so a multi-character symbol would be recognised before a single character matching operator.
NumberTokenMatcher so that 1..2 is not misinterpreted.
Functions and operators
Operator class has a new duplicate() method creating
a new operator with an identical set of fields.
EmptyOperatorTable now has methods
addOperator(new_op,existing_op)
insertOperator(new_op,existing_op)
appendOperator(new_op,existing_op) which don't require an explicit key to
be specified.
TernaryConditional function now use lazy evaluation.
TernaryOperator implements PrintRulesI.
NullWrappedPassThroughFunction for functions which should not be wrapped in the NullWrappedFunctionTable.
MacroFunction now has a working getLightWeightInstance() method.
It has a new constructor allowing a node tree to be specified. This allows use in threads which do not have parsers.
Fields now made protected to allow subclasses. Now catches stack errors on evaluation.
Power.power(int) to be strictly positive,
as it was too fragile.
Printing
PrintVisitor allows operators to implement PrintRulesI.
PrintVisitor now has public visibility for the testLeft(), testMid()
and testRight() functions allowing them to be used in a PrintRule.
allows operators to implement PrintRulesI.
java.text.DecimalFormatSymbols to set the strings used.
Variables
VariableFactory.copyVariable(Variable var) now copies all informations
about the source variable, including constant flag, valid value flag,
and hooks.VariableTable.copyVariablesFrom(VariableTable vt)
and VariableTable.copyConstantsFrom(VariableTable vt)
copies all informations about the source variable, including constant flag, valid value flag,
and hooks. If there already is a variable with the same name all properties are
copied and pre-existing hooks deleted.
Light weight components, hooks and serialization
ImportationVisitor now ensures it gets its operators and functions
from the specific Jep instance.
LightWeightComponentSet makes lightweight instances
of the additional components.
Node.HookKey is now Serializable and information on hooks is includes in
SerializableExpression. Some care is needed to ensure implementations of HookKey are properly
deserialized, the the use of SerializableExpression between versions.
DeepCopyVisitor copies information about hooks on each node.
HookRemover walker which removes hooks from nodes.
Collection<HookKey> hookKeys()
methods of Node and Variable when no keys set.
Other changes
JepRuntimeException for use in cases where a normal JepException cannot be thrown.
JepMessages class has new String format(String key,Object ... args) methods
to make it easier to use a message to formats its arguments.
Examples and tests
Fractal example application reworked to use multi-thread approach.
Localization:
com.singularsys.jep.JepMessages.com.singularsys.jep.messages.properties provides default English messagescom.singularsys.jeptests.system.MessagesTest which checks Exceptions are thrown and prints all messages produced by Jep in the current locale.Threads
threadsafeevaluator package which allows the same expression
to be evaluated in multiple threads/Jep instances without needing to transfer.ImportationVisitor class which allows quicker transfer of an expression
between multiple threads/Jep instances.ThreadSpeedTest compares evaluation speed with multiple threads.
This was previously named ThreadTest Both in the com.singularsys.jepexamples.diagnostics package.ThreadSafeSpeedTest class used to tests speeds using the ThreadSafeEvaluator.Bound variables:
ConfigurableParser:
LookaheadNIterator which allows any given number of characters of lookahead.GrammarParser.parsePrefixSuffix() allowing GrammarMatchers to ask the parser for a prefix-terminal-suffix
like "-2", "x", "5!" or "sin(x)". Implement in the ShuntingYard parserSingleArgFunctionMatcher which can parse expressions like "sin 30" with a single simple argument and no brackets.ShuntingYard allowing test matching of prefix expressionsprev() for Lookahead2Itterator allow last token consumed to be examined, useful for debugging messages.setInputIterator()
method for Lookahead2Itterator allows nested gramatical parsers.errorToken() method for improved error reporting in FunctionGrammarMatcherOperatorTokenMatcher one OperatorToken
will be produced for each operator encountered, allowing line and column numbers to be recorded.
Changed constructors for OperatorToken.GrammarParserFactory and TokenizerFactory now implement JepComponent and these
can now be specified with jep.setComponent() which simplifies the construction process.com.singularsys.jep.configurableparser.matchers.SingleArgFunctionMatcher
which can parse functions like "sin 30" with no brackets and a single argument.OperatorAsFunctionGrammarMatcher which allows all operators to
be used like functions so it possible to parse +(1,2,3,4).VariableTable has a method removeNonConstants() which removes all
non-constant variables.
Variable can have annotation using the setHook(HookKey key, Object value)
and Object getHook(HookKey key) methods. These use the Node.HookKey interface.
ComponentSubset class to hold a partial set of components.
Functions:
NullaryFunction base class for functions with zero arguments.
Implemented by Random and ThreadSafeRandom and ConstantFunctionStringFunctionSet from com.singularsys.jep.functions.strings to
com.singularsys.jep.misc to remove package dependence.Average have altered functions specifying the Add, Divide methods used.CallbackEvaluationI.Runnable interfaces, impacting three classes
Case, Switch and SwitchDefault, but no functional change.getID() to ComparativegetVariable() method to Ele which
is overwitten by the thread-safe subclass ThreadSafeEleIllegalParameterException(PostfixMathCommandI pfmc,
int pos,
String expectedMsg, Object actualObject)
run() methods whose error behaviour is now handled by base class PostfixMathCommandLogarithm now has correct values for negative and complex argumentsCheckStack() protected method from PostfixMathCommandcom.singularsys.jep.misc.threadsafeeval.ThreadSafeRandom provides a faster random function
based on Java's ThreadLocalRandomFactorial moved out of the ExtendedOperatorSet into its own class. The function throws exception when argument is greater than 20 causing overflow.ExtendedOperatorSet no longer includes a ternary conditional operator as duplicate that in the JavaOperatorSet.JepComponent interface. Their init(Jep) method will be called
whenever Jep is reinitialised. Likewise their getLightWeightInstance() will
be called when building a function table for use in a separate thread.
BigDecimals:
BigDecFunctionTable now provide the if(cond,val1,val2),
abs(val), signum(val), min(val1,val2,...), max(val1,val2,...), average(val1,val2,...),
round(val), round(val,dp), roundSF(val,s), rint(val), rint(val,dp), ceil(val), floor(val)
functions by default.BigDecAbs, BigDecRound, BigDecRoundSigFig,
BigDecSignum functions.BigDecAdd etc. reworked so they work with the
Min, Max and Average functions.BigDecTieBreakComparative to allow predictable behaviour
for min/max when given
two equal big decimal numbers with different precisionsNullWapper package:
NullWrapped...
All function base classes and interfaces now moved to com.singularsys.jep.misc.functions. This will break existing code using this package.getWrappedFunction(PostfixMathCommandI) and getSpecialFunction(PostfixMathCommandI)
functions moved to NullWrappedFunctionFactory. Breaks backward compatibility.com.singularsys.jepexamples.diagnostics.DestructiveTests diagnostic tool
which checks the size of expressions which can be parsed/evaluated before Stack overflows.Operator now has an optional printSymbol property which can be used when printing out equations.
This is of use when alphabetical operator names like "AND" are used, here the printSymbol is set to " AND " so that
spaces appear when printing and
X==Y AND Z==W is printed correctly.StandardEvaluatorNullPrintVisitor class for reduced memory footprint.ElementOf function which can test if the first argument is in a list of items.
elementOf(x,"north","south","east","west")IllegalParameterException which allows details for expected result to be specified by a string.PostfixMathCommand.run() method which throws an exception reintroduced.OperatorAsFunctionGrammarMatcher which allows specific operators to be treated as function so you can have
+(1,2,3,4).Complex for testing equality using double ==.buildFunctionNode(String,Node) to NodeFactory.VariableTableObserver now has a switch to allow/dis-allow watching in change of variable values.Console applications can set a double format to format numbers in printf like formats.Jep.setVariable(String,Object) which works like addVariable but does not throw exceptions.trapUnsetValues field FastEvaluator with corresponding getter and setters. Detects is a variable has an unset value.RealComponents for the usercase where pure real evaluation is needed, function like sqrt(-1) return NaN rather than a complex number.DoNothingVisitor now has a method childrenHaveChanged(Node, Node[])
method to test if new children are different from the original.
StandardVariableTable and RealVariableTable now allow delayed
initialisation with constants added when the VariableFactory is set in the init method.
PostfixMathCommand.checkStack() method removed as of little utility.CallbackEvaluationI.Runnable removed.Ele.Ele uses caught ArrayOutOfBounds exceptions rather than explicit checks.Ele.NodeFactory.VariableTable.clearValues() called, but evaluators return previous values.SymbolTokenMatcher when parsing alternate symbols for operators.NaryBinaryFunction when given more than 2 arguments. (Not normally produced during parsing)Logarithm (Log base 10) with complex arguments. Was giving results as natural logarithm.a*(-b).
RealEvaluator, FastEvaluatorBitwiseOperatorTable and JavaOperatorTable no longer set the basis operators
instead using those in the supplied argument.LightWeightComponentSet now uses the NullPrintVisitor.Operator, FastEvaluator and PrintVisitor to protected to allow use by subclasses SimpleNode remove corresponding constructors in subclasses.Real, Str, BitComp now implement UnaryFunction.BitAnd, BitOr BitXor LShift RShift URShift
now implement BinaryFunction.FromBase, Switch, SwitchDefault, ToBase,
RShift, and URShift now implement NaryFunction.NodeFactory now have varargs parameters simplify the number of methods and several places they are called from. Will
require corresponding changes in subclasses.basicIndetifierMatcher and dottedIndetifierMatcher, replace with
basicIdentifierMatcher and dottedIdentifierMatcher deprecate old versions.
StackCheckingFastEvaluator in the package com.singularsys.jeptests.system
which can be used to detect some stack corruption errors.PrintVisitor in Full Bracket mode does no longer puts brackets around variables and positive constants
as there is no ambiguity.sqrt() function to the standard set of functions.
getAdditionComponent(Class<?>) method to find components which instance a particular class.append(String) method allowing classes which implement PrintRulesI to append text to the output.VariableTable has a new method clearValues() which clears the valid-value flag of
all non constant values. Constants are always valid.round function now uses Math.round and a new rint function is added which calls Math.rint. These differ in how 1.5 is rounded (rint rounds up to nearest even value, round always rounds down).calc(List) method makes it easier to create sub-classes which act on lists of objects.min([1,[2,3]]) can be computed. The Comparative parameter can be set by sub classes.TokenizerFactory, GrammarParserFactory which
allow different objects to be used for the tokenizing and parsing steps.ShuntingYard some methods made protected.Tokenizer constructor changed, line and column numbering start from 1.OperatorTokenMatcher improved handling of operators with word characters.GrammarParser has an additional method public void setIterator(Lookahead2Iterator<Token>) setting the iterator used by parseSubExpression().MacroFunction has an additional constructor for use with non recursive functions.com.singularsys.jep.misc.lineNumbering to allow line number information to be stored in nodes in the parse tree. With classes LineNumberingNodeFactory,
LineNumberingShuntingYard.com.singularsys.jep.misc.nullwrapper which provides functions and operators which propagate null values through results. These classes can be wrapped
around other classes to add this functionality to existing classes.com.singularsys.jep.walkers so they can be used as JepComponents.system and unit packages.
Jep(JepComponent... comp) which makes it easier
to construct Jep with a specific set of components.
For example, new Jep(new StandardConfigurableParser()).Jep.getOperatorTable()
now returns OperatorTableI which may break some code.getName(), getValue() making it easier to extract values without a cast.
setHook(), getHook() allowing annotation of nodes with key-value pairs.
BinaryFunction
just needs to define an Object eval(Object l, Object r) method.
EvaluationException provides standardised error
messages, for the common case of wrong arguments being passed to user functions.
int asInt() to convert arguments to a specified type.
General Changes:
Changes to the configurable parser:
0x1F) a | b, bit shifting a << 2) in BitwiseOperatorTable a?b:c, x+=1, ++x syntax a[1][1] accesses the first element of a two-dimensional array)Known issues:
Jep.addVariable does not notify the user when the specified value can not be set. This happens when a constant is already defined with the same name.avg, min, and max functionslog10, sinh, cosh, tanh, and hypotNaN for negative reals rather than complex.Known issues:
Known issues: