boundlab.polysp.legendre.Relu#
- class boundlab.polysp.legendre.Relu[source]#
Bases:
LegendreHandlerLegendre relaxation of ReLU (orders 1–6, closed-form coefficients).
On a crossing interval the projection integrals split at the kink; the resulting coefficients are polynomial in \(c/a\), evaluated in closed form per order.
quartic_boundis zero — ReLU is piecewise linear, so the spline residual evaluation is exact up to the kink handling — and the optional Adam refinement tightens the per-element coefficients further.Methods
Elementwise range of the residual
fn - pover[c - hw, c + hw].Whether this handler applies to these operands (default: always).
The scalar function being approximated (elementwise, differentiable).
Transform the operands; sub-operations go through
interp.<op>so the enclosing domain's handlers apply to them too.Implemented based on.
Legendre coefficients plus a sound symmetric bound on the residual.
A copy of this handler that takes precedence over
otherwhen both are ready for the same call.Elementwise bound on
|fn''''|over[lb, ub](forspline3_ibp).- optimizer: AdamConfig | None#
- legendre_coeffs(c, hw, **kwargs)[source]#
Implemented based on:
l(i) = (2n+1)/(2a^n) integrate(relu(a x + b) legendrep(n,x), {x,-1,1}) l(0) = -1/4 (cb - 1) (a + 2 b + a cb) l(1) = -1/4 (cb2m1(1) * 3 b + 2 (cb - 1) (1 + cb + cb^2)) l(2) = -5/16 cb2m1(2) (a + 4 b cb + 3 a cb^2) l(3) = -7/16 cb2m1(3) (-b + 5 b cb^2 + 4 a cb^3) l(4) = -3/32 cb2m1(4) (-a - 18 b cb - 10 a cb^2 + 42 b cb^3 + 35 a cb^4) l(5) = -11/32 cb2m1(5) (b - 14 b cb^2 - 10 a cb^3 + 21 b cb^4 + 18 a cb^5) l(6) = -13/256 cb2m1(6) (a + 40 b cb + 21 a cb^2 - 240 b cb^3 - 189 a cb^4 + 264 b cb^5 + 231 a cb^6) where cb = clip(-b/a, -1, 1) cb2m1(n) = (cb^2 - 1) / a^n
cbandcb2m1are handled safely fora == 0.
- approx_lbub(polyc, c, hw)[source]#
Elementwise range of the residual
fn - pover[c - hw, c + hw].The interpolant
phas degree <= 3, so the residual’s fourth derivative isfn''''andquartic_boundapplies unchanged.
- __init__(op='relu', order=2, nintvl=None, optimizer=<factory>, opt_iters=500)#
- condition(*args, **kwargs)#
Whether this handler applies to these operands (default: always).
- handle(interp, x, **kwargs)#
Transform the operands; sub-operations go through
interp.<op>so the enclosing domain’s handlers apply to them too.
- optimized_polynomial(c, hw, **kwargs)#
Legendre coefficients plus a sound symmetric bound on the residual.
The residual’s center is folded into
li[0]so the returned noise is the tightest symmetric enclosure offn - p.Non-finite values saturate soundly instead of leaking NaN into the bounds: bad coefficients (overflow, out-of-domain inputs) are zeroed before the residual is bounded against them, and an overflowing residual bound becomes an infinite noise with a finite center.
With an
optimizer, every element independently keeps the coefficients of the tightest residual width seen anywhere along the trajectory — the closed form is iterate 0, so no element ever ends looser than it — and the noise is recomputed from that selection.
- override_handler(other)#
A copy of this handler that takes precedence over
otherwhen both are ready for the same call.