Totalized arithmetic for stable machine learning without epsilon hacks
ZeroProof replaces epsilon hacks with a principled number system that makes all operations total (no NaNs), keeps gradients stable at singularities, and stays deterministic by design. Drop it into your stack to train near poles without fragile thresholds.
ZeroProof is a Python library that implements Transreal (TR) arithmetic - a revolutionary approach to handling mathematical singularities and undefined operations in machine learning. Instead of using epsilon hacks or arbitrary thresholds, ZeroProof extends real arithmetic with special values that make all operations total (never throwing exceptions).
- 🚀 No NaN propagation - Undefined forms are handled gracefully with the PHI tag
- 🎯 Stable training near poles - Gradients remain bounded even at singularities
- 🔬 Deterministic behavior - No epsilon thresholds or arbitrary choices
- 📐 Clean mathematics - Operations match classical calculus on regular paths
- 🔧 Framework integration - Works with PyTorch, JAX, and NumPy
- ⚡ High performance - Optional JIT compilation with Numba
- 🎛️ Adaptive loss policy - Automatic λ adjustment for target coverage
- 🌊 Saturating gradients - Alternative gradient mode for continuous flow
- ⚙️ Wheel mode - Optional stricter algebra for formal verification
See also: docs/topics/00_getting_started.md for an end‑to‑end sketch.
import zeroproof as zp
# Create transreal scalars
x = zp.real(3.0) # Regular real number
y = zp.real(0.0) # Zero
inf = zp.pinf() # Positive infinity
phi = zp.phi() # Nullity (undefined)
# All operations are total
result = x / y # Returns zp.pinf() instead of raising error
result2 = y / y # Returns zp.phi() (0/0 is undefined)
result3 = inf - inf # Returns zp.phi() (∞ - ∞ is undefined)
# Use in neural networks (layer forward)
from zeroproof.layers import TRRational, ChebyshevBasis
from zeroproof.autodiff.tr_node import TRNode
x_node = TRNode.constant(zp.real(0.3))
layer = zp.layers.TRRational(d_p=3, d_q=2, basis=ChebyshevBasis())
y_node, tag = layer.forward(x_node)- From PyPI (recommended):
pip install zeroproofml- Extras:
pip install zeroproofml[torch]·zeroproofml[jax]·zeroproofml[all]
- From source (dev):
pip install -e .[dev]
ZeroProof extends real numbers with three special values:
- PINF (+∞): Positive infinity as a first-class value
- NINF (-∞): Negative infinity as a first-class value
- PHI (Φ): Nullity representing undefined forms (0/0, ∞-∞, 0×∞, etc.)
All arithmetic operations are total - they always return a valid transreal value:
# Division by zero
zp.real(1.0) / zp.real(0.0) # → PINF
zp.real(-1.0) / zp.real(0.0) # → NINF
zp.real(0.0) / zp.real(0.0) # → PHI
# Infinity arithmetic
zp.pinf() + zp.real(5.0) # → PINF
zp.pinf() - zp.pinf() # → PHI
zp.real(0.0) * zp.pinf() # → PHIGradients flow only through REAL-valued paths:
# If forward pass produces PINF/NINF/PHI, gradients are zero
# This prevents gradient explosions at singularities
loss = model(x) # If any intermediate is non-REAL, that path contributes 0 gradientZeroProof uses float64 by default for maximum precision, with optional modes:
# Default: float64 precision
x = zp.real(1.0 / 3.0)
# Temporary float32 for performance
with zp.precision_context('float32'):
y = zp.real(2.0)
z = x * y # Computed in float32
# Global precision change
zp.PrecisionConfig.set_precision('float16') # For embedded systemsZeroProof automatically adjusts the rejection penalty to achieve target coverage:
# Create model with adaptive loss
from zeroproof.training import create_adaptive_loss
adaptive_loss = create_adaptive_loss(
target_coverage=0.95, # Target 95% REAL outputs
learning_rate=0.01 # Lambda adjustment rate
)
model = zp.layers.TRRational(
d_p=4, d_q=3,
adaptive_loss_policy=adaptive_loss
)
# Train with automatic lambda adjustment
trainer = zp.training.TRTrainer(model)
history = trainer.train(data)
# Monitor coverage and lambda evolution
print(f"Final coverage: {history['coverage'][-1]:.3f}")
print(f"Final λ_rej: {history['lambda_rej'][-1]:.3f}")Choose between two gradient modes for handling singularities:
# Default: Mask-REAL (zero gradients at singularities)
model = zp.layers.TRRational(d_p=3, d_q=2)
# Alternative: Saturating (bounded gradients)
from zeroproof.layers import SaturatingTRRational
model = SaturatingTRRational(
d_p=3, d_q=2,
gradient_mode=zp.autodiff.GradientMode.SATURATING,
saturation_bound=5.0 # Controls gradient bounding
)
# Temporary mode switch
with zp.autodiff.gradient_mode(zp.autodiff.GradientMode.SATURATING):
loss.backward() # Gradients computed with saturationEnable console logging and capture structured training metrics for troubleshooting and reproducibility:
import logging
from zeroproof.utils.logging import StructuredLogger
logging.basicConfig(level=logging.INFO)
logger = StructuredLogger(run_dir="runs/demo")
# ... log per‑step metrics and save JSON/CSV/summarySee docs/debug_logging.md for details, per‑module log levels, and field reference.
ZeroProofML’s advanced stack centers on TR-Rational layers that learn (P/Q) directly—so poles are first-class, not bugs. A global TRPolicy defines ULP-scaled guard bands around numerator/denominator evaluations, can keep signed zeros for directional limits, and toggles deterministic pairwise reductions for all critical sums (rational evaluation, TR-Norm mean/var, TR-Softmax normalization, dense reductions, regularizers) to improve reproducibility. Normalization is epsilon-free via TRNorm, which deterministically bypasses zero-variance cases instead of hiding them behind an eps, and everything stays compatible with the project’s autodiff rules and tag semantics.
On the classification side, TR-Softmax is a rational surrogate that avoids exp overflow/NaNs while preserving differentiability on REAL paths; an optional policy can force a one-hot outcome when any logit is (+\infty). An IEEE-754 bridge converts to/from TR tags ((\pm\infty), (\Phi)) so you can interop cleanly with standard floats. The repo includes runnable examples and plotting styles, plus a robotics RR-arm “parity runner” that builds bucketed datasets by (|\det(J)|), executes ZeroProofML and baseline models on identical splits, and emits compact console summaries and JSON with bucketed MSE and 2D pole metrics—so you can validate stability and near-singularity behavior end-to-end.
Short‑form docs are in docs/ within this repo. Full documentation: ZeroProofML Home Page
- Start here: docs/topics/00_getting_started.md
- Topics index: docs/index.md
- Concepts: docs/topics/01_overview.md, docs/topics/02_foundations.md, docs/topics/03_autodiff_modes.md
- Layers: docs/topics/04_layers.md, docs/layers.md
- Training: docs/topics/05_training_policies.md, docs/adaptive_loss_guide.md
- Sampling: docs/topics/06_sampling_curriculum.md
- Evaluation: docs/topics/07_evaluation_metrics.md
- How‑To Checklists: docs/topics/08_howto_checklists.md
- Benchmarks: docs/benchmarks.md
- Runtime dependencies: kept minimal and specified as version ranges to allow compatibility with distro and cloud environments.
- Optional backends (PyTorch/JAX): provided via extras; not required for
import zeroproof. - Development tooling (tests/linters/typing): grouped under the
devextra. Usepip install -e .[dev].
We aim to test Python 3.10–3.13 in CI. If an upper Python version shows issues, we will document it in the changelog and README until resolved.
-
What does
1/0,-1/0, and0/0return?zp.real(1)/zp.real(0)→PINF(+∞)zp.real(-1)/zp.real(0)→NINF(−∞)zp.real(0)/zp.real(0)→PHI(nullity)- Examples follow TR division tables; no exceptions are raised.
-
What about domain errors like
log(x≤0)orsqrt(x<0)?zp.tr_log(zp.real(0.0))→PHIzp.tr_log(zp.pinf())→PINFzp.tr_sqrt(zp.real(-1.0))→PHI
-
How do tags propagate through computations and gradients?
- Forward:
PHIpropagates;±∞obeys TR tag tables deterministically. - Gradients (default Mask‑REAL): paths that produce non‑REAL tags contribute zero gradient.
- Deterministic reductions: when enabled in policy, sums/products use pairwise trees for stable results.
- Forward:
-
When should I pick Hybrid or Saturating gradients instead of Mask‑REAL?
- Hybrid: when you want zero gradients exactly at singularities but smooth, bounded gradients near them (with hysteresis control).
- Saturating: when you need bounded, continuous gradients across singular regions (e.g., for continuous control).
- Default Mask‑REAL is recommended for strict stability and identifiability.
-
Do you respect IEEE signed zero (−0.0 vs +0.0)?
- Yes. Division by
+0.0vs−0.0yields opposite infinities in accordance with IEEE sign rules. - Policy has
keep_signed_zeroto preserve signed zero in backends that expose it.
- Yes. Division by
-
How do I convert to/from IEEE NaN/Inf?
zp.from_ieee(float('nan'))→PHI;zp.from_ieee(float('inf'))→PINF.zp.to_ieee(zp.phi())→nan;zp.to_ieee(zp.pinf())→inf.
-
What’s different in Wheel mode?
- Stricter algebra with a
BOTTOM (⊥)element:0×∞=⊥,∞+∞=⊥;⊥propagates. - Enable with
with zp.wheel_mode(): ...when you need formal‑verification‑style behavior.
- Stricter algebra with a
We welcome contributions! Please see our Contributing Guide for details.
# Clone the repository
git clone https://github.com/domezsolt/zeroproofml.git
cd zeroproofml
# Install in development mode
pip install -e .[dev]
# Run tests
pytest
# Run property-based tests
pytest -m propertyIf you use ZeroProof in your research, please cite:
@article{zeroproof2025,
title={ZeroProofML: Singularity-Resilient Learning with Transreal Arithmetic and Rational Layers},
author={Zsolt Döme},
journal={https://zenodo.org/records/17220762},
year={2025}
}We gratefully acknowledge the foundational work on algebraic treatments of division-by-zero by Jesper Carlström (wheels), Jan A. Bergstra and Alban Ponse (common meadows), and J. A. D. W. Anderson (transreal arithmetic).
- Core libraries: NumPy, PyTorch, JAX
- Testing & property-based fuzzing: pytest, Hypothesis
- Developer tooling: Black, Ruff, isort, mypy, pre-commit
- CI & reporting: GitHub Actions, Codecov, shields.io
Thanks as well to all contributors, industry partners, and users of ZeroProofML for ideas, bug reports, and feedback.
ZeroProof is released under the MIT License. See LICENSE for details.