boundlab.zono.exp_linearizer#
- boundlab.zono.exp_linearizer(ub, lb)[source]#
Minimal-area exp relaxation (DeepT, Section 4.5).
The returned zonotope
y = slope·x + mu + beta·ε(with ε ∈ [-1, 1]) over-approximatesexp(x)on[lb, ub]and guaranteesmu - beta ≥ 0so downstream handlers (reciprocal/ softmax) never see a non-positive lower bound.Strategy:
For each element, try the single-slope “minimal area” relaxation: tangent at
t_optas the lower envelope, parallel secant line through(ub_c, exp(ub_c))as the upper envelope.If the tangent gives a non-positive offset (e.g.
lb > 0) or the fp32 precision would lose that offset againstexp(ub), fall back to the interval relaxationslope = 0,mu = beta = exp(ub)/2, which yields[0, exp(ub)]— loose but guaranteedmu - beta = 0bit-exactly (so downstreamublbcannot go negative).Clamp
lb/ubto ±30 to keepexpnumerically safe; the underflow/overflow branches use the interval fallback.
Examples
>>> import torch >>> import boundlab.expr as expr >>> from boundlab.zono.exp import exp_linearizer >>> x = expr.ConstVal(torch.tensor([0.0])) + 0.1 * expr.LpEpsilon([1]) >>> ub, lb = x.ublb() >>> b = exp_linearizer(ub, lb) >>> b.bias.shape torch.Size([1])