0
# Compiled Expressions
1
2
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.
3
4
## Capabilities
5
6
### NumExpr Class
7
8
Creates a pre-compiled expression object that can be executed multiple times with different variable values, eliminating parsing and compilation overhead for repeated use.
9
10
```python { .api }
11
class NumExpr:
12
"""
13
Pre-compiled expression object for repeated evaluation.
14
15
This class represents a compiled mathematical expression that can be
16
executed multiple times with different input data, providing optimal
17
performance when the same expression structure is used repeatedly.
18
"""
19
20
def __init__(self, ex, signature=(), sanitize=True, **kwargs):
21
"""
22
Create a compiled expression object.
23
24
Parameters:
25
- ex (str): Mathematical expression string to compile
26
- signature (tuple): Variable signature for type checking and optimization
27
- sanitize (bool): Enable expression sanitization for security
28
- **kwargs: Additional compilation options
29
30
Raises:
31
ValueError: If expression syntax is invalid
32
"""
33
34
def run(self, *args, **kwargs):
35
"""
36
Execute the compiled expression with provided arguments.
37
38
Parameters:
39
- *args: Positional arguments corresponding to variables in signature order
40
- **kwargs: Named arguments for variable substitution
41
42
Returns:
43
ndarray: Result of expression evaluation
44
45
Raises:
46
ValueError: If argument types or shapes are incompatible
47
"""
48
49
@property
50
def signature(self):
51
"""Get the variable signature for this compiled expression."""
52
53
@property
54
def input_names(self):
55
"""Get the input variable names for this expression."""
56
```
57
58
**Usage Examples:**
59
60
```python
61
import numpy as np
62
import numexpr as ne
63
64
# Create a compiled expression
65
expr = ne.NumExpr("a * b + c")
66
67
# Execute with different data sets
68
a1, b1, c1 = np.random.random((3, 10000))
69
result1 = expr.run(a1, b1, c1)
70
71
a2, b2, c2 = np.random.random((3, 5000))
72
result2 = expr.run(a2, b2, c2)
73
74
# Using keyword arguments
75
result3 = expr.run(a=a1*2, b=b1*3, c=c1/2)
76
77
# Complex mathematical expression
78
complex_expr = ne.NumExpr("sin(x) * exp(-y/scale) + sqrt(x*y)")
79
x = np.linspace(0, 10, 1000)
80
y = np.linspace(0, 5, 1000)
81
for scale in [1, 2, 5, 10]:
82
result = complex_expr.run(x, y, scale)
83
# Process result...
84
```
85
86
87
88
## Advanced Usage Patterns
89
90
### Type-Specific Compilation
91
92
```python
93
# Specify variable types for optimized compilation
94
expr = ne.NumExpr("a * b + c", signature=(('a', 'double'), ('b', 'double'), ('c', 'double')))
95
96
# Mixed types
97
mixed_expr = ne.NumExpr("mask & (values > threshold)",
98
signature=(('mask', 'bool'), ('values', 'double'), ('threshold', 'double')))
99
```
100
101
### Memory-Efficient Patterns
102
103
```python
104
# Pre-allocate output array for repeated use
105
expr = ne.NumExpr("a * 2 + b")
106
output = np.empty(10000)
107
108
for i in range(100):
109
a = get_data_a(i) # Get new data
110
b = get_data_b(i)
111
expr.run(a, b, out=output) # Reuse output array
112
process_result(output)
113
```
114
115
### Conditional Compilation
116
117
```python
118
# Compile different expressions based on runtime conditions
119
if use_complex_math:
120
expr = ne.NumExpr("sqrt(real(z)**2 + imag(z)**2)")
121
else:
122
expr = ne.NumExpr("sqrt(a**2 + b**2)")
123
124
# Use the appropriate compiled expression
125
result = expr.run(data)
126
```
127
128
### Expression Composition
129
130
```python
131
# Build complex expressions from components
132
base_expr = "a * b"
133
if apply_transformation:
134
full_expr = f"log({base_expr} + 1)"
135
else:
136
full_expr = base_expr
137
138
compiled = ne.NumExpr(full_expr)
139
```
140
141
## Performance Considerations
142
143
### When to Use Compiled Expressions
144
145
**Ideal Cases:**
146
- Expressions evaluated many times (>10 iterations)
147
- Complex mathematical expressions with multiple operations
148
- Fixed expression structure with varying data
149
- Performance-critical loops where compilation overhead matters
150
151
**Less Beneficial:**
152
- Simple expressions evaluated once or twice
153
- Very small arrays (< 1000 elements)
154
- Expressions that change frequently
155
156
### Memory and Threading
157
158
Compiled expressions automatically:
159
- Use the current threading configuration (`get_num_threads()`)
160
- Respect VML settings for accelerated functions
161
- Apply chunking strategies for cache optimization
162
- Reuse internal memory allocations across runs
163
164
### Compilation Time vs. Execution Time
165
166
- Compilation overhead: ~0.1-1ms for typical expressions
167
- Execution speedup: 2-15x for medium to large arrays
168
- Break-even point: Usually 2-5 evaluations depending on array size and expression complexity
169
170
The `NumExpr` class is most effective when the same expression structure is used repeatedly with different data, amortizing the compilation cost across multiple evaluations.