designspace.Expr#

class designspace.Expr#

Bases: object

An expression: the shared base of conditions and arithmetic.

Expressions are trees, not values. Writing ds.param(“x”) < 3 builds a comparison node; nothing is evaluated until a configuration is supplied. That is what lets the library analyse constraints (derive the dependency graph, compute margins, narrow domains) rather than merely run them.

Every node reports .kind, .children, and .params, so a consumer can walk a constraint without knowing the node types.

Two Python operators are deliberately refused. and/or/not and in coerce their operands to bools, which would silently collapse an expression into True; using them raises TypeError pointing at &, |, ~, and .is_in().

property kind: str#

A short string naming the node type.

Examples

>>> ds.param("x").kind
'ref'
>>> (ds.param("x") < 3).kind
'lt'
property children: tuple[Expr, ...]#

The node’s operands, in order.

Together with .kind this is enough to walk or rebuild any expression tree. A leaf has none.

Examples

>>> [c.kind for c in (ds.param("x") < 3).children]
['ref', 'literal']
property params: frozenset[str]#

Every parameter path this expression references.

What the dependency graph is built from, and how a constraint knows which parameters it belongs to.

Examples

>>> sorted((ds.param("x") + ds.param("y") < 3).params)
['x', 'y']
is_active() BoolExpr#

Whether the referenced parameter is active, as a condition.

Lets a constraint ask about presence rather than value: “if the cache is switched on at all, then …”. Distinct from reading the value, which would be unknown for an inactive parameter.

Returns:

A condition, true when the parameter is present.

Return type:

BoolExpr

Examples

>>> s = ds.space(
...     ds.param("use_cache").bool(),
...     ds.param("cache_mb").integer(64, 512).when(ds.param("use_cache")),
...     ds.param("workers").integer(1, 8),
... )
>>> s = s.require(
...     ds.param("cache_mb").is_active().implies(ds.param("workers") <= 4)
... )
>>> s.is_feasible({"use_cache": True, "cache_mb": 128, "workers": 2})
True
>>> s.is_feasible({"use_cache": True, "cache_mb": 128, "workers": 8})
False
>>> s.is_feasible({"use_cache": False, "workers": 8})
True