boundlab.ExprGroup#

class boundlab.ExprGroup[source]#

Bases: Expr, TyDict, Generic

A typed sum of components: at most one Expr per class.

Linear primitives map over the members; ub/lb add the members’ bounds (sound since the components are summed). Build one with from_sum(), which merges same-class addends via add and never nests groups.

Methods

__init__

absub

Bound on the magnitude: \(\max(|lb|, ub) \ge \sup |x|\).

add

Same-class addition; __add__ dispatches here when classes match and otherwise groups the addends in an ExprGroup.

broadcast_to

chw

Center/halfwidth form: c = (ub + lb) / 2, w = (ub - lb) / 2.

classset

The set of component classes present in this value.

clear

convert_from

Hook: build an instance of cls representing exactly expr, or None when this class cannot.

convert_to

Hook: convert self into expr_type, or None when this class does not know how.

copy

einsum

Apply the linear map described by an integer-label einsum.

from_exprlike

Lift a tensor/scalar into a broadcast Bias; pass Expr through.

from_sum

Normalized sum of arbitrary components.

fromkeys

Create a new dictionary with keys from iterable and values set to value.

get

Return the value for key if key is in the dictionary, else default.

items

keys

keyset

lb

Sound elementwise lower bound on every concrete value represented.

lbub

(lb, ub) in one call; components override it when computing both at once is cheaper than two passes.

matmul

mean

numel

pop

If the key is not found, return the default if given; otherwise, raise a KeyError.

popitem

Remove and return a (key, value) pair as a 2-tuple.

reshape

rmatmul

setdefault

Insert key with a value of default if key is not in the dictionary.

split

Split into (matching, rest) so that matching + rest == self.

squeeze

sum

to

Convert to another component class, exactly.

to_intervals

Collapse to the box hull Bias(c) + Noise(w).

torch_print

Diagnostics as a TensorFormat.

transpose

tree_flatten

tree_unflatten

ub

Sound elementwise upper bound on every concrete value represented.

unsqueeze

update

If E is present and has a .keys() method, then does: for k in E.keys(): D[k] = E[k] If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v In either case, this is followed by: for k in F: D[k] = F[k]

values

__init__(*exprs)[source]#
static from_sum(*args)[source]#

Normalized sum of arbitrary components.

Same-class addends are merged with add, Zeros vanish, and the result collapses to a bare component (or Zeros) whenever fewer than two classes remain.

property shape_dtype: ShapeDtype#

Allocation-free (shape, dtype) metadata of the value.

tree_flatten()[source]#
classmethod tree_unflatten(auxiliary, children)[source]#
einsum(subscripts, *operands)[source]#

Apply the linear map described by an integer-label einsum.

subscripts holds one label tuple per input followed by the output labels (see boundlab.utils.einsum_parser()). This is the single linear primitive: __mul__, __matmul__, sum and mean all lower to it, so implementing it soundly makes every derived linear operation sound.

reshape(*shape)[source]#
transpose(*perm)[source]#
broadcast_to(*shape)[source]#
add(other)[source]#

Same-class addition; __add__ dispatches here when classes match and otherwise groups the addends in an ExprGroup.

ub()[source]#

Sound elementwise upper bound on every concrete value represented.

lb()[source]#

Sound elementwise lower bound on every concrete value represented.

lbub()[source]#

(lb, ub) in one call; components override it when computing both at once is cheaper than two passes.

chw()[source]#

Center/halfwidth form: c = (ub + lb) / 2, w = (ub - lb) / 2.

torch_print(group='reason')[source]#

Diagnostics as a TensorFormat.

The result is safe to hand to Torch diagnostic output under tracing: only plain arrays cross the callback boundary, never expression metadata (which may hold tracers, e.g. reason weights).

split(u: type[U], /) → tuple[U, Expr][source]#
split(u: type[U], v: type[V], /) → tuple[ExprGroup[U | V], Expr]
split(u: type[U], v: type[V], w: type[W], /) → tuple[ExprGroup[U | V | W], Expr]
split(u: type[U], v: type[V], w: type[W], x: type[X], /) → tuple[ExprGroup[U | V | W | X], Expr]

Split into (matching, rest) so that matching + rest == self.

The main way handlers peel off the component class they transform while passing the remainder through untouched.

property T: Self#
__add__(other)#
__mul__(other)#
classmethod __new__(*args, **kwargs)#
absub()#

Bound on the magnitude: \(\max(|lb|, ub) \ge \sup |x|\).

classset()#

The set of component classes present in this value.

A single component reports {type(self)}, an ExprGroup its member classes, and Zeros the empty set. Handlers use this to decide which part of a value they know how to transform.

clear() → None.  Remove all items from D.#
classmethod convert_from(expr)#

Hook: build an instance of cls representing exactly expr, or None when this class cannot. One half of to().

convert_to(expr_type)#

Hook: convert self into expr_type, or None when this class does not know how. The other half of to().

copy() → a shallow copy of D#
property dtype: dtype#
static from_exprlike(expr, shape)#

Lift a tensor/scalar into a broadcast Bias; pass Expr through.

classmethod fromkeys(iterable, value=None, /)#

Create a new dictionary with keys from iterable and values set to value.

get(key, default=None, /)#

Return the value for key if key is in the dictionary, else default.

items() → a set-like object providing a view on D's items#
keys() → a set-like object providing a view on D's keys#
keyset()#
matmul(other)#
mean(axis, keepdims=False)#
property ndim: int#
numel()#
pop(k[, d]) → v, remove specified key and return the corresponding value.#

If the key is not found, return the default if given; otherwise, raise a KeyError.

popitem()#

Remove and return a (key, value) pair as a 2-tuple.

Pairs are returned in LIFO (last-in, first-out) order. Raises KeyError if the dict is empty.

rmatmul(other)#
setdefault(key, default=None, /)#

Insert key with a value of default if key is not in the dictionary.

Return the value for key if key is in the dictionary, else default.

property shape: Sequence[Any]#
squeeze(axes=None)#
sum(axis, keepdims=False)#
to(expr_type)#

Convert to another component class, exactly.

Identity short-circuits; otherwise the target’s convert_from is tried, then this class’s convert_to. Raises TypeError when neither side knows the conversion — conversions never approximate.

to_intervals(name='')#

Collapse to the box hull Bias(c) + Noise(w).

Sound but lossy: every correlation between error symbols is dropped, so downstream cancellation (x - x = 0) no longer happens.

unsqueeze(axes)#
update([E, ]**F) → None.  Update D from mapping/iterable E and F.#

If E is present and has a .keys() method, then does: for k in E.keys(): D[k] = E[k] If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v In either case, this is followed by: for k in F: D[k] = F[k]

values() → an object providing a view on D's values#