Fast numerical expression evaluator for NumPy that accelerates array operations through optimized implementations and multi-threading
—
Pre-compilation of expressions for repeated evaluation with different data, providing optimal performance for expressions used multiple times. The NumExpr class allows creating reusable expression objects that avoid repeated parsing and compilation overhead.
Creates a pre-compiled expression object that can be executed multiple times with different variable values, eliminating parsing and compilation overhead for repeated use.
class NumExpr:
"""
Pre-compiled expression object for repeated evaluation.
This class represents a compiled mathematical expression that can be
executed multiple times with different input data, providing optimal
performance when the same expression structure is used repeatedly.
"""
def __init__(self, ex, signature=(), sanitize=True, **kwargs):
"""
Create a compiled expression object.
Parameters:
- ex (str): Mathematical expression string to compile
- signature (tuple): Variable signature for type checking and optimization
- sanitize (bool): Enable expression sanitization for security
- **kwargs: Additional compilation options
Raises:
ValueError: If expression syntax is invalid
"""
def run(self, *args, **kwargs):
"""
Execute the compiled expression with provided arguments.
Parameters:
- *args: Positional arguments corresponding to variables in signature order
- **kwargs: Named arguments for variable substitution
Returns:
ndarray: Result of expression evaluation
Raises:
ValueError: If argument types or shapes are incompatible
"""
@property
def signature(self):
"""Get the variable signature for this compiled expression."""
@property
def input_names(self):
"""Get the input variable names for this expression."""Usage Examples:
import numpy as np
import numexpr as ne
# Create a compiled expression
expr = ne.NumExpr("a * b + c")
# Execute with different data sets
a1, b1, c1 = np.random.random((3, 10000))
result1 = expr.run(a1, b1, c1)
a2, b2, c2 = np.random.random((3, 5000))
result2 = expr.run(a2, b2, c2)
# Using keyword arguments
result3 = expr.run(a=a1*2, b=b1*3, c=c1/2)
# Complex mathematical expression
complex_expr = ne.NumExpr("sin(x) * exp(-y/scale) + sqrt(x*y)")
x = np.linspace(0, 10, 1000)
y = np.linspace(0, 5, 1000)
for scale in [1, 2, 5, 10]:
result = complex_expr.run(x, y, scale)
# Process result...# Specify variable types for optimized compilation
expr = ne.NumExpr("a * b + c", signature=(('a', 'double'), ('b', 'double'), ('c', 'double')))
# Mixed types
mixed_expr = ne.NumExpr("mask & (values > threshold)",
signature=(('mask', 'bool'), ('values', 'double'), ('threshold', 'double')))# Pre-allocate output array for repeated use
expr = ne.NumExpr("a * 2 + b")
output = np.empty(10000)
for i in range(100):
a = get_data_a(i) # Get new data
b = get_data_b(i)
expr.run(a, b, out=output) # Reuse output array
process_result(output)# Compile different expressions based on runtime conditions
if use_complex_math:
expr = ne.NumExpr("sqrt(real(z)**2 + imag(z)**2)")
else:
expr = ne.NumExpr("sqrt(a**2 + b**2)")
# Use the appropriate compiled expression
result = expr.run(data)# Build complex expressions from components
base_expr = "a * b"
if apply_transformation:
full_expr = f"log({base_expr} + 1)"
else:
full_expr = base_expr
compiled = ne.NumExpr(full_expr)Ideal Cases:
Less Beneficial:
Compiled expressions automatically:
get_num_threads())The NumExpr class is most effective when the same expression structure is used repeatedly with different data, amortizing the compilation cost across multiple evaluations.
Install with Tessl CLI
npx tessl i tessl/pypi-numexpr