designspace.Value#
- class designspace.Value(fn: Callable[[...], Any], operands: tuple[Expr, ...], returns: type)#
-
ds.value(fn, *operands, returns=type): an opaque derived quantity: .prop() generalized from one custom param, named property to any operands, arbitrary function. fn is called with exactly the operand values, positionally, and never the config; every operand is checked to be an expression at construction. The referenced params are the union of the operands’ own references, so dependency_graph/ordering/cycle detection are unaffected. Dual-typed like Prop: a returns=bool node is usable directly as a condition, matching the same “bare BoolExpr coerces via bool(value)” convention. returns is one of SCALAR_TYPES.
Exported because it is ds.value()’s return type and no other public type captures it: being both an ArithExpr and a BoolExpr is what lets a returns=bool node serve as a bare condition, which neither base alone expresses.
- fn#
The consumer’s function, called with the operands’ values. Opaque to the library, and not serializable.
- Type:
Callable[…, Any]
- if_inactive(fallback: object) ArithExpr#
Substitute fallback when this expression has no value.
An expression over an inactive parameter, or an aggregate over a list that is switched off, evaluates to unknown, and a constraint that cannot be decided is treated as inapplicable rather than violated. That is usually right, but sometimes the intended reading is “absent means zero”. This says so.
It substitutes only for inactivity. An expression that is unknown because a value has not been chosen yet stays unknown, and an aggregate over an active but empty list keeps its own empty value, which the fallback would otherwise mask.
- Parameters:
fallback (object) – The value to use when the expression is inactive.
- Returns:
An expression that is never unknown for want of activity.
- Return type:
Examples
Without a fallback the budget cannot be decided, so it does not constrain anything:
>>> s = ds.space( ... ds.param("use_cache").bool(), ... ds.param("cache_mb").integer(64, 512).when(ds.param("use_cache")), ... ds.param("heap_mb").integer(64, 512), ... ) >>> total = ds.param("cache_mb") + ds.param("heap_mb") >>> loose = s.require(total <= 512) >>> loose.is_feasible({"use_cache": False, "heap_mb": 512}) True
With one, an absent cache counts as zero and the rule applies:
>>> guarded = s.require(ds.param("cache_mb").if_inactive(0) + ds.param("heap_mb") <= 400) >>> guarded.is_feasible({"use_cache": False, "heap_mb": 512}) False >>> guarded.is_feasible({"use_cache": False, "heap_mb": 256}) True
- implies(other: BoolExpr) BoolExpr#
Material implication: if this holds, other must too.
The natural shape for a conditional rule such as “if we are on GPU, the batch must be at least 32”, and much clearer than the equivalent ~a | b, which it is exactly (down to the fingerprint).
- Parameters:
other (BoolExpr) – The consequent.
- Returns:
A condition, false only when this holds and other does not.
- Return type:
- Raises:
TypeError – If other is not a boolean expression.
Examples
>>> s = ds.space( ... ds.param("gpu").bool(), ... ds.param("batch").integer(1, 64), ... ).require(ds.param("gpu").implies(ds.param("batch") >= 32)) >>> s.is_feasible({"gpu": True, "batch": 64}) True >>> s.is_feasible({"gpu": True, "batch": 8}) False
The rule says nothing when the antecedent is false:
>>> s.is_feasible({"gpu": False, "batch": 8}) True
- 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:
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
- is_in(*values: Any) BoolExpr#
Whether the value is one of values.
The replacement for Python’s in, which cannot be used on an expression: in coerces its result to a bool and would collapse the tree.
- Parameters:
*values (Any) – The values to test membership against.
- Returns:
A condition.
- Return type:
Examples
>>> s = ds.space(ds.param("algo").categorical("a", "b", "c")) >>> s = s.require(ds.param("algo").is_in("a", "b")) >>> s.is_feasible({"algo": "a"}) True >>> s.is_feasible({"algo": "c"}) False