tbnpy.expr

The expression language of tbnpy.spec’s distribution parameters and equation nodes. Expressions are parsed with ast against a whitelist (there is no eval) and evaluate on batches of tensors. The function names follow GeNIe’s equation syntax, so equations exported from GeNIe compile unchanged.

In an expression, a discrete parent stands for its label value (A + B adds the labels of A and B); Choose(X, a, b, ...) instead selects on X’s state index. ^ means exponentiation, as in GeNIe.

API

Safe, vectorised expression compiler for declarative tbnpy models.

Turns a string such as:

0.5 * Max(Gamma*H - 4*S_u, 0.3*Gamma*H) * H

into a callable that evaluates on batches of torch tensors. Expressions are parsed with ast and compiled against a whitelist – there is no eval and no access to Python builtins, attributes, subscripts, or comprehensions.

The function vocabulary follows GeNIe’s equation syntax so that networks exported from GeNIe can be imported without rewriting their equations.

Two details of that syntax matter and are handled here:

^ means exponentiation

In Python ^ is bitwise XOR and binds looser than *, so 0.325 * K_a * Gamma * H^2 would parse as (0.325*K_a*Gamma*H) ** 2. The source is rewritten to use ** before parsing, which restores the precedence every engineering notation assumes.

Choose selects on a discrete parent’s state index

Everywhere else a discrete variable resolves to its label value, so A + B means the sum of the labels. Choose(Soil_Type, Pa_sand, Pa_clay) instead uses Soil_Type’s state index, and is checked at compile time to supply exactly one option per state.

class tbnpy.expr.Expression(source: str, scope: Mapping[str, NameSpec], label: str | None = None)[source]

A compiled, vectorised expression.

Parameters:
  • source – The expression text.

  • scope – {name: NameSpec} for every name the expression may reference.

  • label – Optional description used in error messages (e.g. the node name).

Notes

Compilation walks the AST once and builds a tree of closures, so evaluation does no parsing and no dictionary lookup of operators.

exception tbnpy.expr.ExpressionError[source]

Raised when an expression cannot be compiled or is not permitted.

class tbnpy.expr.NameSpec(kind: str, n_states: int | None = None)[source]

What the compiler knows about one name in scope.

kind

One of CONTINUOUS, NUMERIC_STATE, CATEGORICAL.

Type:

str

n_states

Number of states, for discrete names. None for continuous.

Type:

int | None

tbnpy.expr.FUNCTION_NAMES = frozenset({'ACos', 'ASin', 'ATan', 'ATan2', 'Abs', 'Ceil', 'Choose', 'Cos', 'Cosh', 'E', 'Exp', 'Floor', 'If', 'Ln', 'Log', 'Log10', 'Log2', 'Max', 'Min', 'Pi', 'Pow', 'Round', 'Sign', 'Sin', 'Sinh', 'Sqrt', 'Tan', 'Tanh'})

Names callable inside an expression. Choose is handled separately because its first argument is a state index rather than a value.