intervalNets is a robust PyTorch-first toolkit focused on three core capabilities:
- an overloaded
model.eval(interval)pathway (enabled viaenable_interval_eval(...)) for interval propagation through neural networks with outward-rounded arithmetic, including roundoff-aware bounds; - rigorous enclosure of Lebesgue/Lp norms over interval domains via
model.lpnorm(domain, p, iterations=...); - interval Jacobian enclosure via
model.eval_jacobian(domain)and Sobolev-style norms viamodel.sobolev_norm(domain, p, iterations=...). The current implementation follows the same interval-enclosure + adaptive-refinement strategy outlined in the preprint Certified and accurate computation of function space norms of deep neural networks (arXiv:2603.06431).
The current implementation uses a midpoint-radius interval representation and is explicitly optimized for repeated affine propagation of interval vectors through matrices:
[ A x_{\text{mid}} \pm |A| x_{\text{rad}}. ]
This design gives fast, vectorized propagation for neural network workloads (especially nn.Linear
and Jacobian composition). The resulting boxes are conservative enclosures, but they are not
always the tightest possible interval enclosure one could compute with more expensive methods.
- interval construction and arithmetic operations use outward rounding to account for floating-point roundoff errors,
- degenerate intervals
[x, x]are supported, - interval propagation currently supports
nn.Sequential,nn.Flatten,nn.Linear,nn.ReLU,nn.Sigmoid,nn.Tanh,nn.Softplus,nn.LeakyReLU,nn.Softmax,nn.Identity, plusIntervalAdd/IntervalCatbranch combinators, - ReLU propagation preserves mathematically exact zero images (
[0, 0]) for non-positive pre-activation intervals; only non-exact branches are outward-padded, - linear and Jacobian propagation are implemented with midpoint-radius matrix formulas for speed; this favors runtime performance over globally minimal box tightness,
model.eval(interval),model.eval_jacobian(...),model.lpnorm(...), andmodel.sobolev_norm(...)are attached through a single opt-in monkey patch (enable_interval_eval()), and the selectedenclosure_modeis reused for bothmodel.eval(interval)and sequential pre-activation propagation insidemodel.eval_jacobian(...),enable_interval_eval(enclosure_mode="slope")accepts"box"or"slope"(default: slope-aware affine relaxation fornn.Sequentialchains ofnn.Linear+nn.ReLU, with conservative fallback to"box"for unsupported layers),- slope mode is particularly useful for dependency-heavy patterns such as
Linear(rotation) -> ReLU -> Linear(rotation^{-1}): plain box propagation can overestimate strongly, while slope-aware relaxations keep substantially tighter certified bounds, - for additional tightness,
interval_forward_refine(model, interval, enclosure_mode="slope", splits_per_dim=...)subdivides the input box and hulls sub-box outputs (higher cost, tighter bounds), model.lpnorm(domain, p, iterations, theta=0.5)andmodel.sobolev_norm(domain, p, iterations, theta=0.5)use Dörfler-type bulk marking (with uncertainty indicators) and adaptive bisection to return outward-rounded certified norm enclosures; rigorously constant boxes with zero Jacobian are skipped during Sobolev refinement.- both norm routines accept optional
forward_refine_splits/forward_refine_max_cellsarguments to tighten per-box forward enclosures during integration.
From the repository root (either approach works):
# Option A: install dependencies directly
pip install -r requirements.txt
# Option B: install the package in editable mode
pip install -e .Then you can import it normally:
from intervalnets import IntervalTensor, enable_interval_eval
from torch import nn
enable_interval_eval(enclosure_mode="slope")
model = nn.Sequential(nn.Linear(2, 1))
interval = IntervalTensor.from_bounds([1.0, 2.0], [1.5, 2.5])
output = model.eval(interval)
# optional tighter forward enclosures for Linear+ReLU chains
enable_interval_eval(enclosure_mode="slope")
domain = IntervalTensor.from_bounds([0.0, 0.0], [1.0, 1.0])
lp_bounds = model.lpnorm(domain, p=2.0, iterations=8)
w1p_bounds = model.sobolev_norm(domain, p=2.0, iterations=8)If you are in a notebook or script inside the repository, add src/ to sys.path first:
import sys
from pathlib import Path
repo_root = Path.cwd().resolve()
while not (repo_root / "src" / "intervalnets").exists() and repo_root != repo_root.parent:
repo_root = repo_root.parent
sys.path.insert(0, str(repo_root / "src"))After that, from intervalnets import ... will work from the checkout as well.
- the core
Intervaltype uses only the Python standard library, - PyTorch integration is optional and requires installing PyTorch separately,
- the included notebook now auto-detects the repo root and adds
src/tosys.pathfor convenience.
For worked examples, see:
notebooks/test_suite.ipynbfor quick feature checks and sanity tests,notebooks/reproduce_lp_w1p_experiments.ipynbfor reproducible certifiedL^pandW^{1,p}experiments aligned with arXiv:2603.06431 (intentionally excludingW^{2,p}).
Yes—good idea. The notebook pipeline now exports figures under
notebooks/notebooks/artifacts/, and they can be embedded directly in this
README.
- Johannes Gründler, Moritz Maibaum, Philipp Petersen, Certified and accurate computation of function space norms of deep neural networks, arXiv:2603.06431 (2026). https://arxiv.org/abs/2603.06431
intervalNets was created by Moritz Maibaum and Philipp Petersen, with development support from OpenAI Codex.



