Expression Compiler
SRToolkit.utils.expression_compiler
Functions for compiling symbolic expressions into executable Python callables.
expr_to_executable_function
expr_to_executable_function(expr: Union[List[str], Node], symbol_library: SymbolLibrary = SymbolLibrary.default_symbols()) -> Callable[[np.ndarray, Optional[np.ndarray]], np.ndarray]
Compile an expression into an executable Python function.
The returned callable evaluates the expression over a batch of inputs and a vector
of constant values. To use a backend other than NumPy, set
symbol_library.preamble to the required import statements.
Examples:
>>> executable_fun = expr_to_executable_function(["X_0", "+", "1"])
>>> executable_fun(np.array([[1], [2], [3], [4]]), np.array([]))
array([2, 3, 4, 5])
>>> executable_fun = expr_to_executable_function(["pi"])
>>> executable_fun(np.array([[1], [2], [3], [4]]), np.array([1]))
array([3.14159265, 3.14159265, 3.14159265, 3.14159265])
>>> executable_fun = expr_to_executable_function(["C"])
>>> executable_fun(np.array([[1], [2], [3], [4]]), np.array([1]))
array([1, 1, 1, 1])
>>> tree = tokens_to_tree(["X_0", "+", "1"], SymbolLibrary.default_symbols(1))
>>> executable_fun = expr_to_executable_function(tree)
>>> executable_fun(np.array([[1], [2], [3], [4]]), np.array([]))
array([2, 3, 4, 5])
>>> # In case you need libraries other than numpy for the evaluation of your expressions,
>>> # you can add them to the preamble in the SymbolLibrary. Here is how a preamble would look like:
>>> symbol_library = SymbolLibrary.default_symbols(1)
>>> symbol_library.preamble = ["import numpy as np"]
>>> # Usually this is done when initializing the SymbolLibrary as SymbolLibrary(preamble=preamble)
>>> executable_fun = expr_to_executable_function(tree, symbol_library)
>>> executable_fun(np.array([[1], [2], [3], [4]]), np.array([]))
array([2, 3, 4, 5])
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
expr
|
Union[List[str], Node]
|
Expression as a token list in infix notation or a Node tree. |
required |
symbol_library
|
SymbolLibrary
|
Defines token semantics (NumPy function strings, preamble imports). Defaults to SymbolLibrary.default_symbols. |
default_symbols()
|
Returns:
| Type | Description |
|---|---|
Callable[[ndarray, Optional[ndarray]], ndarray]
|
A callable |
Raises:
| Type | Description |
|---|---|
Exception
|
If |
Source code in SRToolkit/utils/expression_compiler.py
expr_to_error_function
expr_to_error_function(expr: Union[List[str], Node], symbol_library: SymbolLibrary = SymbolLibrary.default_symbols()) -> Callable[[np.ndarray, np.ndarray, np.ndarray], float]
Compile an expression into a callable that computes the RMSE against target values.
To use a backend other than NumPy, set symbol_library.preamble to the required
import statements.
Examples:
>>> executable_fun = expr_to_error_function(["X_0", "+", "1"])
>>> print(float(executable_fun(np.array([[1], [2], [3], [4]]), np.array([]), np.array([2, 3, 4, 5]))))
0.0
>>> tree = tokens_to_tree(["X_0", "+", "1"], SymbolLibrary.default_symbols(1))
>>> executable_fun = expr_to_error_function(tree)
>>> print(float(executable_fun(np.array([[1], [2], [3], [4]]), np.array([]), np.array([2, 3, 4, 5]))))
0.0
>>> # In case you need libraries other than numpy for the evaluation of your expressions,
>>> # you can add them to the preamble in the SymbolLibrary. Here is how a preamble would look like:
>>> symbol_library = SymbolLibrary.default_symbols(1)
>>> symbol_library.preamble = ["import numpy as np"]
>>> # Usually this is done when initializing the SymbolLibrary as SymbolLibrary(preamble=preamble)
>>> executable_fun = expr_to_error_function(tree, symbol_library)
>>> print(float(executable_fun(np.array([[1], [2], [3], [4]]), np.array([]), np.array([2, 3, 4, 5]))))
0.0
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
expr
|
Union[List[str], Node]
|
Expression as a token list in infix notation or a Node tree. |
required |
symbol_library
|
SymbolLibrary
|
Defines token semantics (NumPy function strings, preamble imports). Defaults to SymbolLibrary.default_symbols. |
default_symbols()
|
Returns:
| Type | Description |
|---|---|
Callable[[ndarray, ndarray, ndarray], float]
|
A callable |
Raises:
| Type | Description |
|---|---|
Exception
|
If |
Source code in SRToolkit/utils/expression_compiler.py
tree_to_function_rec
tree_to_function_rec(tree: Node, symbol_library: SymbolLibrary, var_counter: int = 0, const_counter: int = 0) -> Tuple[List[str], str, int, int]
Recursively convert a parse tree into lines of Python code for expression evaluation.
This is a low-level helper for expr_to_executable_function and expr_to_error_function. Call those functions directly unless you need fine-grained control over code generation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tree
|
Node
|
Root of the subtree to convert. |
required |
symbol_library
|
SymbolLibrary
|
Provides NumPy function strings for each token. |
required |
var_counter
|
int
|
Running count of intermediate variables, used to generate unique
names. Default |
0
|
const_counter
|
int
|
Running count of constants consumed; used to index into the |
0
|
Returns:
| Type | Description |
|---|---|
Tuple[List[str], str, int, int]
|
A 4-tuple |
Raises:
| Type | Description |
|---|---|
Exception
|
If the tree contains a token that is neither a recognized symbol nor a numeric literal. |