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 FunctionGrammarMatcher
OperatorTokenMatcher
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 ConstantFunction
StringFunctionSet
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 Comparative
getVariable()
method to Ele
which
is overwitten by the thread-safe subclass ThreadSafeEle
IllegalParameterException(PostfixMathCommandI pfmc,
int pos,
String expectedMsg, Object actualObject)
run()
methods whose error behaviour is now handled by base class PostfixMathCommand
Logarithm
now has correct values for negative and complex argumentsCheckStack()
protected method from PostfixMathCommand
com.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.StandardEvaluator
NullPrintVisitor
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
, FastEvaluator
BitwiseOperatorTable
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 hypot
NaN
for negative reals rather than complex.Known issues:
Known issues: