CompiledExpression
pysignet.compilation.compiled_expression.CompiledExpression
Represents a compiled logical expression with variable bindings.
A compiled expression is the result of compiling a logical expression (e.g., And(P(X), Q(Y))) into a differentiable PyTorch computation graph. It supports:
- Evaluation with variable bindings: compiled(X=x, Y=y) -> Tensor
- Partial binding: compiled.partial(X=x) -> CompiledExpression
- Introspection: compiled.free_variables -> Set[str]
- Compiler access: compiled.compiler -> LogicCompiler
CompiledExpression performs PURE EVALUATION - it always returns per-batch results with shape (batch_size,). No batch reduction is applied. For quantification over batch dimensions, wrap with LogicLoss.
Partial binding creates a NEW computation graph with fewer free variables, not just a temporary store of bindings. This enables future optimizations like constant propagation, dead code elimination, and graph rewriting.
IMPORTANT: All inputs must be provided as keyword arguments (e.g., X=tensor). Positional arguments are not supported. This ensures clear, unambiguous variable binding.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
compiled_logic
|
Callable[[dict[str, Tensor]], Tensor]
|
Callable that evaluates the expression given variable bindings as a dict mapping variable names to tensors |
required |
free_variables
|
set[str]
|
Set of variable names that must be bound for evaluation |
required |
predicates
|
dict[str, Predicate]
|
Dict mapping predicate names to Predicate objects |
required |
partial_bindings
|
dict[str, Tensor] | None
|
Dict of variables already bound in this expression (used internally for partial binding) |
None
|
compiler
|
LogicCompiler | None
|
Optional LogicCompiler that produced this expression |
None
|
expr
|
Basic | None
|
Optional original SymPy expression (for repr/debugging) |
None
|
Example
# Create compiled expression
compiled = compiler.compile(expr, predicates)
# Evaluate with full bindings - returns (batch_size,)
result = compiled(X=x, Y=y) # shape: (batch_size,)
# Partial binding
partial = compiled.partial(X=x)
result = partial(Y=y) # shape: (batch_size,)
# Introspection
print(compiled.free_variables) # {'X', 'Y'}
print(partial.free_variables) # {'Y'}
print(compiled.compiler) # TNormCompiler(...)
compiler
property
Return the LogicCompiler that produced this expression.
Returns:
| Type | Description |
|---|---|
LogicCompiler | None
|
LogicCompiler instance or None |
expr
property
Return the original SymPy expression.
Returns:
| Type | Description |
|---|---|
Basic | None
|
SymPy expression or None |
free_variables
property
__call__(*, return_boolean=False, log_mode=False, **variable_bindings)
Evaluate compiled expression with variable bindings.
All free variables must be bound (either via partial bindings stored in this expression, or provided here as keyword arguments).
This method performs PURE EVALUATION - it always returns per-batch results with shape (batch_size,). No batch reduction is applied. For quantification over batch dimensions, wrap with LogicLoss.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
return_boolean
|
bool
|
If True, return boolean satisfaction using hard decisions (threshold at 0.5 for binary, argmax for multiclass). Default is False (soft satisfaction). |
False
|
log_mode
|
bool
|
If True, evaluate in log-space using fused ops (logsigmoid, log_softmax) for numerical stability. Returns log-satisfaction values in (-inf, 0]. Default is False. |
False
|
**variable_bindings
|
Tensor
|
Variable bindings as keyword arguments (e.g., X=x_tensor, Y=y_tensor) |
{}
|
Returns:
| Type | Description |
|---|---|
Tensor
|
If return_boolean is False and log_mode is False: Satisfaction tensor of shape (batch_size,) in [0, 1]. |
Tensor
|
If log_mode is True: Log-satisfaction tensor of shape (batch_size,) in (-inf, 0]. |
Tensor
|
If return_boolean is True: Boolean tensor of shape (batch_size,) indicating whether the formula is satisfied. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If any free variable is not bound |
ValueError
|
If return_boolean=True but expression is not available |
__init__(compiled_logic, free_variables, predicates, partial_bindings=None, compiler=None, expr=None, compiled_logic_log=None)
Initialize CompiledExpression.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
compiled_logic
|
Callable[[dict[str, Tensor]], Tensor]
|
Callable that evaluates expression with inputs as a dict mapping variable names to tensors. |
required |
free_variables
|
set[str]
|
Set of variable names in the original expression |
required |
predicates
|
dict[str, Predicate]
|
Dict of predicate objects |
required |
partial_bindings
|
dict[str, Tensor] | None
|
Dict of variables already bound (default: empty) |
None
|
compiler
|
LogicCompiler | None
|
Optional LogicCompiler that produced this expression |
None
|
expr
|
Basic | None
|
Optional original SymPy expression (for repr/debugging) |
None
|
compiled_logic_log
|
Callable[[dict[str, Tensor]], Tensor] | None
|
Optional callable for log-space evaluation using fused ops (logsigmoid, log_softmax). |
None
|
__repr__()
Return string representation of compiled expression.
Returns:
| Type | Description |
|---|---|
str
|
String showing expression, free variables, and predicates. |
get_trainable_parameters()
partial(**variable_bindings)
Create new CompiledExpression with some variables bound.
This creates a NEW computation graph where the bound variables are substituted with their values. The returned CompiledExpression has fewer free variables.
Future optimizations will use this to: - Constant-fold operations on bound variables - Apply common subexpression elimination - Prune unreachable branches - Rewrite the computation graph for efficiency
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**variable_bindings
|
Tensor
|
Variable bindings to fix (X=x, Y=y) |
{}
|
Returns:
| Type | Description |
|---|---|
CompiledExpression
|
New CompiledExpression with fewer free variables |
Raises:
| Type | Description |
|---|---|
ValueError
|
If no bindings provided |
ValueError
|
If variable is already bound |
ValueError
|
If variable doesn't exist in expression |