An ultra-high-performance mathematical expression parsing and evaluation engine for Java. Version 2.0.x introduces a breakthrough Block Vectorization Engine (VectorTurboEvaluator) and SIMDVectorTurboEvaluator powered by the Java Vector API (jdk.incubator.vector).
By processing data pipelines natively inside hardware registers, ParserNG completely eliminates runtime allocation overhead and flattens interpreter branches. It matches dynamic bytecode compilation frameworks (like Janino) ns for ns on massive datasets by leveraging bare-metal SIMD hardware capabilities.
These 2 classes are responsible independently for bulk evaluations in ParserNG.
The SIMDVectorTurboEvaluator is the hardware-accelerated bulk processing powerhouse of ParserNG. It is specifically built to leverage the cutting-edge JDK 21 Vector API (jdk.incubator.vector), allowing the JVM to compile mathematical evaluation pipelines directly into native SIMD (Single Instruction, Multiple Data) CPU instructions such as AVX or ARM NEON.
Instead of processing array elements one by one, it binds operations across hardware vector lanes to process large chunks of data in a single CPU clock cycle.
- Performance Profile: Unmatched throughput on large mathematical datasets, executing bulk computations significantly faster than lightweight runtime bytecode compilers like Janino.
- Environment Requirements: Requires Java 21+ and the explicit runtime configuration flag:
--add-modules jdk.incubator.vector. - Best Used For: High-frequency, massive data streams, heavy numerical integration, spatial data grids, and large-scale bulk vector transformations where hardware acceleration is fully available.
The VectorTurboEvaluator is the standard, highly portable bulk evaluation engine embedded directly within the core architecture of ParserNG. It processes mathematical expressions across data arrays using highly optimized sequential loops and zero-allocation memory profiles powered by our foundational interpretation algorithms.
It achieves the absolute peak of pure interpreted execution speed without binding itself to specialized hardware architecture features.
- Performance Profile: Extremely fast with zero warm-up time or compilation overhead, outperforming standard loop-based expression evaluators on small to medium-sized data batches.
- Environment Requirements: Highly backward-compatible and portable. It runs anywhere the core library runs (Java 8+), requiring no special JVM incubator module flags or environment modifications.
- Best Used For: Cross-platform systems (including Android and legacy enterprise backend servers), environments where adding specialized JVM flags is restricted, or applications handling small-to-medium dataset arrays where CPU-level SIMD orchestration overhead isn't justified.
To use SIMDVectorTurboEvaluator(e.g. on modern servers(JDK 21+) and laptops(JDK21+)), add the 2 dependencies below to your application's pom.xml:
<dependency>
<groupId>com.github.gbenroscience</groupId>
<artifactId>parser-ng</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>com.github.gbenroscience</groupId>
<artifactId>parser-ng-simd</artifactId>
<version>2.0.7</version>
</dependency>To use VectorTurboEvaluator(e.g. on Android and legacy systems supporting <JDK21), add to your application's pom.xml:
<dependency>
<groupId>com.github.gbenroscience</groupId>
<artifactId>parser-ng</artifactId>
<version>2.0.7</version>
</dependency>They benchmark at almost same speed and same allocation, and you can use workers to increase their throughput
| Feature | SIMDVectorTurboEvaluator |
VectorTurboEvaluator |
|---|---|---|
| Execution Layer | Hardware CPU Vector Lanes (SIMD) | Highly Optimized Sequential CPU Loops |
| Minimum Java Version | Java 21+ | Java 8+ |
| JVM Configuration | Requires --add-modules jdk.incubator.vector |
Zero configuration (Works out of the box) |
| Portability | Limited to environments supporting JDK 21+ | Universal (Cross-platform, Android, Desktop) |
| Optimal Data Scale | Massive datasets (Thousands to millions of data points) | Same |
| Warm-Up Overhead | Negligible, but bound to vector lane size queries | Absolute zero |
- Hardware-Level SIMD Execution: Automatically binds operations to modern CPU vector tracks (AVX-512, AVX2, or ARM Neon) via the Java Incubator Vector API.
- Outperforming Bytecode Compilation: Beats runtime bytecode compilation by eliminating pointer-chasing and maximizing instruction-level parallelism.
- Zero Allocation on Hot Paths: Eradicates heap-allocation overhead inside heavy processing loops, preventing Garbage Collection (GC) spikes in real-time or high-frequency calculation environments.
- Advanced Memory Layout Topology: Supports standard multi-dimensional matrices (
double[][]) as well as linear high-performance, column-major stride-mapped arrays (double[]). - Flexible Execution Models: Transparently shifts between standard sequential tiled loops, chunk-batched blocks, and asynchronous multi-threaded thread pools.
- Vectorized User-Defined Functions (UDFs): Parse, compile, and execute multi-parameter custom functions efficiently across deep data lanes.
The following benchmark profile demonstrates evaluation throughput across massive data scales. As record pools increase, ParserNG's manual block vectorization scales aggressively, beating Janino by up to 2x.
-
Data Scales Evaluated:
$1,000,000$ and$67,108,864$ floating-point elements. -
Topology Scaling:
MathEvalBenchmarkForSIMDutilizes 2 parallel execution worker threads.
Benchmark (dataSize) (expression) Mode Cnt Score Error Units
SIMDTurboBenchStrict.parserNG 20000000 12*x1 + 3*x2 - 4*x3 + 5*x1 - x2 - 4*x3 + 2*x1 + x2 avgt 30 119332280.333 ± 6177102.571 ns/op
SIMDTurboBenchStrict.parserNG 20000000 0.39894228 / x1 * exp(-((x2 - x3) * (x2 - x3)) / (2 * x1 * x1)) avgt 30 340918896.667 ± 50455197.573 ns/op
SIMDTurboBenchStrict.janino 20000000 12*x1 + 3*x2 - 4*x3 + 5*x1 - x2 - 4*x3 + 2*x1 + x2 avgt 30 120395246.000 ± 1390845.402 ns/op
SIMDTurboBenchStrict.janino 20000000 0.39894228 / x1 * exp(-((x2 - x3) * (x2 - x3)) / (2 * x1 * x1)) avgt 30 386854016.667 ± 5069567.669 ns/op
On an intensive mathematical workload executing exp models), a single-threaded ParserNG run registers at
When utilizing multi-threaded parallel execution splits via MathEvalBenchmarkForSIMD (2 parallel workers), ParserNG drops computation time to
Evaluate expressions across independent variables using standard data layouts:
import com.github.gbenroscience.parser.MathExpression;
import com.github.gbenroscience.simd.turbo.tools.VectorTurboEvaluator;
import com.github.gbenroscience.simd.turbo.tools.VectorTurboEvaluator.BatchedVectorCompositeExpression;
MathExpression me = new MathExpression("(1 / (x1 * sqrt(2 * 3.14159))) * exp((-(x2 - x3)^2) / (2 * x1^2))");//Gaussian
int stride = meLinear.getVariablesNames().length
BatchedVectorCompositeExpression evaluator = (BatchedVectorCompositeExpression) new VectorTurboEvaluator(me).compile();
int totalElements = 2000;
double[][] inputs = new double[stride][totalElements]; // x1, x2, x3 tracks
double[] outputVector = new double[totalElements];
for (int i = 0; i < dataSize; i++) {
// 1. Populate the 2D SoA layout for the standard evaluator
inputs[0][i] = 1.5 + rand.nextDouble() * 5.0; // x1
inputs[1][i] = rand.nextDouble() * 5.0; // x2
inputs[2][i] = rand.nextDouble() * 2.0; // x3
}
evaluator.applyBulk(inputs, outputVector);OR
import com.github.gbenroscience.parser.MathExpression;
import com.github.gbenroscience.simd.turbo.SIMDCompositeExpression;
import com.github.gbenroscience.simd.turbo.tools.FlatMatrixF;
import com.github.gbenroscience.simd.turbo.tools.SIMDVectorTurboEvaluator;
MathExpression me = new MathExpression("(1 / (x1 * sqrt(2 * 3.14159))) * exp((-(x2 - x3)^2) / (2 * x1^2))");//Gaussian
int stride = meLinear.getVariablesNames().length
SIMDVectorTurboEvaluator.SIMDVectorCompositeExpression evaluator = (SIMDVectorTurboEvaluator.SIMDVectorCompositeExpression) new SIMDVectorTurboEvaluator(me).compile();
int totalElements = 2000;
double[][] inputs = new double[stride][totalElements]; // x1, x2, x3 tracks
double[] outputVector = new double[totalElements];
for (int i = 0; i < dataSize; i++) {
// 1. Populate the 2D SoA layout for the standard evaluator
inputs[0][i] = 1.5 + rand.nextDouble() * 5.0; // x1
inputs[1][i] = rand.nextDouble() * 5.0; // x2
inputs[2][i] = rand.nextDouble() * 2.0; // x3
}
evaluator.applyBulk(inputs, outputVector);Evaluate expressions across independent variables using standard data layouts:
import com.github.gbenroscience.parser.MathExpression;
import com.github.gbenroscience.simd.turbo.tools.VectorTurboEvaluator;
import com.github.gbenroscience.simd.turbo.tools.VectorTurboEvaluator.BatchedVectorCompositeExpression;
MathExpression me = new MathExpression("(1 / (x1 * sqrt(2 * 3.14159))) * exp((-(x2 - x3)^2) / (2 * x1^2))");
int stride = meLinear.getVariablesNames().length
BatchedVectorCompositeExpression evaluator = (BatchedVectorCompositeExpression) new VectorTurboEvaluator(me).compile();
double[]flatVariables = new double[stride * dataSize];
int totalElements = 200000;
double[] outputVector = new double[totalElements];
for (int i = 0; i < dataSize; i++) {
// 2. Calculate the flat interleaved base address for timestep 'i'
// For i=0, base=0. For i=1, base=3. For i=2, base=6...
int base = i * stride;
// 3. Populate the flat interleaved array perfectly
for (int k = 0; k < stride; k++) {
flatVariables[base + k] = 1.5 + rand.nextDouble() * 5.0;
}
}
evaluator.applyBulk(flatVariables, outputVector);Eliminate spatial extraction jumps and optimize CPU L1/L2 data cache usage by linearizing your input parameters into a flat 1D segment buffer:
int totalElements = 2000;
int varCount = 3;
double[] flatInputs = new double[varCount * totalElements];
double[] outputVector = new double[totalElements];
// Distribute tracking segments via column-major indexing strides
for (int i = 0; i < totalElements; i++) {
flatInputs[(0 * totalElements) + i] = 1.5 + (i * 0.1); // x1 segment
flatInputs[(1 * totalElements) + i] = 2.0 + (i * 0.5); // x2 segment
flatInputs[(2 * totalElements) + i] = 0.5; // x3 segment
}
evaluator.applyBulk(flatInputs, outputVector);Enforce fixed matrix block chunk allocations to tightly align loop boundaries with specific target sizes:
int batchSize = 128;
evaluator.applyBulkBatched(flatInputs, outputVector, batchSize);Leverage an integrated multi-threaded background executor structure to divide large-scale workloads across multiple processor cores:
evaluator.applyBulkParallel(flatInputs, outputVector);Compute custom nested algebraic function assignments natively inside the evaluation pass:
MathExpression me = new MathExpression("f(x,y,z)=3*x+4*y+sin(z-2);f(x+3,y-2,2*z-3)");
BatchedVectorCompositeExpression evaluator = (BatchedVectorCompositeExpression) new VectorTurboEvaluator(me).compile();
double[] inputs = new double[]{5.0, 4.0, 1.0}; // x, y, z arrays
double[] output = new double[1];
evaluator.applyBulk(inputs, output);
@Test
void testGelu() throws Throwable {
MathExpression me = new MathExpression("x * 0.5 * (1 + tanh(0.79788456 * (x + 0.044715 * x * x * x)))");
BatchedVectorCompositeExpression evaluator = (BatchedVectorCompositeExpression) new VectorTurboEvaluator(me).compile();
int sz = 200;
FlatMatrixF in1 = new FlatMatrixF(sz, sz);
FlatMatrixF.randomFill(in1);
FlatMatrixF out = new FlatMatrixF(sz, sz);
double n = 10000;
double t = System.nanoTime();
for (int i = 0; i < n; i++) {
evaluator.applyMatrixKernel(new FlatMatrixF[]{in1}, out, "gelu");
}
double t1 = System.nanoTime() - t;
System.out.println("timed at = " + (t1/n) + "ns--- answer: ");
//System.out.println("timed at = " + (t1/n) + "ns--- answer: " + out);
assertTrue(true);
}
@Test
void testSwiglu() throws Throwable {
MathExpression me = new MathExpression("x * 0.5 * (1 + tanh(0.79788456 * (x + 0.044715 * x * x * x)))");
BatchedVectorCompositeExpression evaluator = (BatchedVectorCompositeExpression) new VectorTurboEvaluator(me).compile();
int sz = 200;
FlatMatrixF in1 = new FlatMatrixF(sz, sz);
FlatMatrixF.randomFill(in1);
FlatMatrixF in2 = new FlatMatrixF(sz, sz);
FlatMatrixF.randomFill(in2);
FlatMatrixF out = new FlatMatrixF(sz, sz);
double n = 10000;
double t = System.nanoTime();
for (int i = 0; i < n; i++) {
evaluator.applyMatrixKernel(new FlatMatrixF[]{in1, in2}, out, "swiglu");
}
double t1 = System.nanoTime() - t;
System.out.println("timed at = " + (t1/n) + "ns--- answer: ");
//System.out.println("timed at = " + (t1/n) + "ns--- answer: " + out);
assertTrue(true);
}
The supported matrix fuctions at the moment are:
- matmul
- matmul_bias_gelu
- matmul_add_sin
- softmax
- relu
- gelu
- q8_quantize
- q8_dequant
- q8_absmax_quant
- rope_split
- accum_v
- matmul_1xn_axpy
- matmul_bias_relu
- rms_norm
- layer_norm
- matmul_bias_silu
- mha_attention
Because this module targets explicit low-level CPU vector registers, it requires Java 21 or later, along with JVM incubator arguments to activate the platform layer.
Ensure the following parameter flags are appended to your runtime run targets or test configurations:
--add-modules jdk.incubator.vector
Add the matching compilation module allocations inside your engine pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<release>21</release>
<compilerArgs>
<arg>--add-modules</arg>
<arg>jdk.incubator.vector</arg>
</compilerArgs>
</configuration>
</plugin>