Releases: aratraw/delta_analysis
Δ‑analysis v0.2: Full‑stack exact numerics — from lazy series summations to DEC on arbitrary grids
Δ‑analysis Library — v0.2 Release Notes
Date: 2026‑05‑04
DOI (paper): 10.5281/zenodo.18761044
DOI (software, v0.1): 10.5281/zenodo.18934082
License: PolyForm Small Business License 1.0.0
Version 0.2 represents a comprehensive re‑engineering of the Δ‑analysis library. The codebase has been transformed from an initial research prototype into a stable, high‑performance platform for exact constructive computation. This release incorporates a complete redesign of the arithmetic engine, integrates the geometry and numerical modules into a unified framework, and provides extensive human‑written documentation backed by over 400 test cases.
Below we provide a technical summary of the implementation work and the resulting capabilities of the library.
1. Rational Arithmetic Engine — Complete Redesign
The rational number subsystem has been rewritten from the ground up to achieve three simultaneous goals: exactness of all arithmetic operations, compactness of internal representations, and performance that meets or exceeds the raw Boost.Multiprecision backend on which it is built.
1.1 Eager Rational: Zero‑Overhead Wrapper
The Rational class is implemented as a thin wrapper over boost::multiprecision::rational_adaptor<cpp_int_backend<...>>. Backend parameters were tuned empirically:
MinBits = 128— integers up to 128 bits (approximately 38 decimal digits) are stored directly on the stack via Boost's small‑object optimisation, avoiding heap allocation for the vast majority of intermediate valuesMaxBits = 0— unlimited precision is available when needed; no artificial bound on representable magnitudesigned_magnitudewithunchecked— standard representation without runtime overhead for sign checks or range validationet_off— expression templates are disabled, giving the library full control over when evaluation occurs and eliminating the indirection cost of Boost's own lazy layer
The result is an eager rational type whose performance is indistinguishable from raw Boost.Multiprecision (measured difference ≤ 1%, within benchmark noise), validated on workloads of up to 500 000 terms with random, dyadic, and harmonic‑series fractions.
1.2 Lazy Rational Engine: Architecture
The LazyRational class introduces a mutable, move‑only expression graph with deferred evaluation. Key design elements:
-
Mutable tree construction. Binary arithmetic operators mutate the left operand in place:
a + babsorbs the tree ofbintoa, amortised O(1) per operation. This enables chained accumulationacc + term1 + term2 + ...without constructing intermediate objects. Copy semantics are intentionally deleted; explicit deep copies are obtained via.clone() -
Dirty / clean state machine. A lazy expression begins in a dirty state — a local, un‑validated tree of
DirtyNodeobjects. Thecanonicalize()method converts it into a clean state, where the entire expression is represented by a single integer index into the global node pool. The transition involves algebraic simplification and hash‑consing, after which the node is immutable and shared -
Heterogeneous SUM and PRODUCT nodes. Leaf constants are stored directly in
leaf_valuesvectors rather than as separateCONSTchild nodes. This reduces node count, flattens the tree, and is essential for efficient batching during evaluation
1.3 Global Node Pool and Hash‑Consing
The clean node pool (delta::internal::NodePool) is a thread‑local, append‑only vector with several hash‑consing caches:
constant_cache: mapsValue → CONSTnode indexsum_product_cache: maps canonicalised operand sets toSUM/PRODUCTnode indicesunary_cache: maps(LazyOp, children, eps_idx)tuples to indices forNEG,RECIP,SQRT,EXP,LOG,SIN,COS,ACOS,PI,E,POW
The caches guarantee that structurally identical sub‑expressions are represented by a single node. Structural equality between clean expressions reduces to integer comparison of their clean_index_ values.
Pool allocation uses a next_free_index hint with chunked growth of 4096 nodes. Slots are only reclaimed by the garbage collector, never reused individually. This simplifies reference counting and makes pool indices stable between GC cycles.
1.4 Garbage Collection as Deferred Computation
When the pool occupancy exceeds 90% of max_size (default 1 000 000 nodes), collect_garbage() is triggered:
- All live clean
LazyRationalobjects are identified via the clean object registry (g_clean_rationals, a thread‑local unordered set) - Each live root's entire subtree is evaluated to a single
Value - A new pool is created; each evaluated value is stored as a
CONSTnode at the same index as the original root - The old pool is discarded
Thus, garbage collection is the computational step that forces deferred evaluation. It is not an incidental cleanup; it is the moment all outstanding lazy work is settled.
The clean object registry also enables reset_pool() — a full teardown that destroys all clean trees, reinstates every LazyRational object as a dirty zero, and creates an empty pool. This is used between independent computation phases.
1.5 Algebraic Simplification
The simplify_tree() function (in simplify_impl.h) performs constructive rewrites on a TempNode tree during canonicalization:
- Flattening of nested
SUMandPRODUCTnodes - Removal of neutral elements (0 in sums, 1 in products)
- Grouping of identical scalar constants (
a + a → 2*a) and identical sub‑expressions (A + A → 2*A,A * A → A^2) - Distributivity:
a*b + a*c → a*(b+c)when common factors are detected - Cancellation:
x + NEG(x) → 0,x * RECIP(x) → 1 - Inverse functions:
NEG(NEG(x)) → x,EXP(LOG(x)) → x,LOG(EXP(x)) → x - Power simplifications:
x^0 → 1,x^1 → x,1^y → 1,(x^a)^b → x^(a*b)for integer exponents
Simplification is not a default — it must be requested or is triggered implicitly by eval(). The destructive eval_inplace(true) path skips it entirely, avoiding its cost for unstructured sums where it provides no benefit. Benchmarks show that simplification can reduce evaluation time by 10–1000× on structured expressions, but is a net loss for flat sums.
1.6 Evaluation and Pyramidal Compact Reduction
Dirty tree evaluation uses evaluate_tree(), which performs post‑order traversal with intermediate result caching. For SUM nodes, pyramidal compact reduction (PCR) groups terms into batches of 32 and reduces them hierarchically. This minimises intermediate rational growth by ensuring that additions occur in a balanced tree rather than a linear chain.
eval_inplace(true)uses destructive PCR: it moves leaf values out of the node, modifies them in place, and produces a single constant result, replacing the dirty tree with a cleanCONSTnodeeval()copies the necessary data and preserves the original tree
PCR with batch size 32 was chosen because it keeps the results of summing 32 random fractions within 128 bits for typical inputs, allowing the stack‑allocated small‑integer path of Boost's backend to dominate.
2. Transcendental Functions — Implementation and Mutual Consistency
All elementary transcendental functions are provided in both eager (returning Rational) and lazy (creating LazyRational nodes) forms. They accept an explicit absolute error bound ε (default 1e‑30).
2.1 Hybrid Evaluation Strategy
A function‑by‑function decision was made on when to use a floating‑point path versus a pure rational series path, based on extensive benchmarks:
- Float path (
cpp_dec_float_100): Used forsin,cos,exp,π,acos,asin,atan,tanwhen ε ≥ 1e‑35. The float path is 2–3× faster at moderate precision but loses relative accuracy for large arguments or very small ε - Series path (pure rational): Used for
sqrt,log,eat all precisions; used for all functions when ε < 1e‑35. Forexp, the series path is also forced when |x| > 20 because the float path's mantissa cannot preserve relative accuracy at extreme magnitudes
2.2 Specific Implementations
-
Square root: Newton's method with an integer floor‑sqrt initial guess (
isqrt(num*den) / den). This yields compact rationals (a few hundred bits for typical inputs) and avoids the representation bloat that plagued earlier versions usingx/2as the initial guess. The integer root is extracted via a fast Newton method ondumb_int, with a preliminary mod‑256 filter for quick rejection of non‑squares -
Exponential: Scaling‑and‑squaring combined with a Padé approximant, with the order chosen adaptively based on ε. Argument reduction multiplies ε by
2^(exp_bits + k + 2)to guarantee that, after squaring, the absolute error remains within tolerance. The reduction threshold is 2.0 — lowering it to 1.0 was empirically shown to produce bloated intermediate fractions that cripple downstream operations (log(exp(x))became catastrophically slow) -
Logarithm: Argument reduction to [1/2, 2] via
k·ln(2), then the arctanh seriesln((1+y)/(1-y)) = 2(y + y³/3 + y⁵/5 + …)withy = (m‑1)/(m+1).ln(2)is computed once and cached -
Sine and Cosine: Binary splitting of the Maclaurin series with exact rational reduction modulo 2π. The binary splitting formula:
P, Q, T = merge((P_L, Q_L, T_L), (P_R, Q_R, T_R)) P = P_L * P_R Q = Q_L * Q_R T = T_L * Q_R + P_L * T_Rprevents intermediate rational swell far more effectively than iterative term‑by‑term summation
-
π (Pi): Chudnovsky algorithm with binary splitting, providing approximately 14.18 decimal digits per term. For small N (< 16), a recurrence is used; ...
delta_analysis v0.1: Initial implementation of discrete analysis foundations
Release v0.1.0 – Δ‑analysis Library: A Constructive Refounding of Mathematical Analysis
We are thrilled to announce the first public release of the Δ‑analysis library, a modern C++20 implementation of a radical reformulation of mathematical analysis. Instead of assuming a pre‑existing continuum, Δ‑analysis builds everything from a single elementary operation: between any two addresses a new one can be inserted. This process generates finite grids that converge to a continuum – but the continuum is never a primitive; it remains a regulative horizon.
This library strives to translate the theoretical framework (detailed in our 900‑page monograph, DOI:10.5281/zenodo.18761044) into a practical tool for constructive numerical methods, adaptive algorithms, and explorations of non‑classical geometries (p‑adic, tree‑based, matrix spaces, etc.).
✨ Key Features Right Now
1. Regulative Ideas as First‑Class Citizens
Choose the geometric structure of your computation:
- Linear order with Euclidean metric (classical real analysis).
- p‑adic metric for non‑archimedean experiments.
- Tree‑based betweenness (binary strings) with ultrametric – integrate the Dirichlet function without measure theory.
- Matrix‑valued addresses (
Eigen::MatrixXd) for tensor field approximations.
Easily add your own by implementing simple concepts (Betweenness,Metric).
2. Flexible Grid Refinement
- Static operators: midpoint, fixed‑λ, user‑defined.
- Dynamic operators: change the insertion rule with the level.
- Adaptive operators: insert points based on the function’s local variation – the library’s
AdaptiveDeltaPathclusters points where they are needed most, dramatically accelerating convergence for functions with sharp features.
3. Operational Functions
Store and extend function values consistently across refinement levels. Specialised for UniformGrid, it provides O(1) access – ideal for repeated evaluations in loops.
4. Calculus on Grids
- Riemann sums (left, right, tagged, tree‑adapted).
- Continuity checks with arbitrary moduli (
PowerModulus,LogarithmicModulus). - Differentiability checks comparing one‑sided difference quotients against a convergence modulus.
5. Performance & Reliability
- OpenMP acceleration for computing maximal oscillation (optional).
- Double buffering in
DeltaPath::advance()to minimise allocations. - Exact rational arithmetic with configurable precision (dynamic or stack‑allocated via Boost.Multiprecision).
- Comprehensive test suite (95%+ coverage) and Google Benchmarks to track performance.
6. Examples & Benchmarks
- Dirichlet function on binary strings – becomes locally constant under the tree regulative idea; its integral converges to ½.
- Adaptive refinement of |x‑0.5| – points cluster at the corner, runtime stays almost constant as accuracy increases.
- Matrix‑valued functions – integrate the identity on [0·I, I] and obtain 0.5·I.
- Non‑commutativity demo – applying λ=1/3 and λ=2/3 in different orders yields different intermediate grids, proving that Δ‑analysis captures the process, not just the limit.
🚀 Quick Start
#include <delta/core/adaptive_delta_path.h>
#include <delta/core/rational.h>
#include <iostream>
using namespace delta;
int main() {
// Function with a corner: |x - 1/2|
auto func = [](const Rational& x) {
return abs(x - Rational(1,2));
};
// Adaptive operator with threshold 0.1 and epsilon 0.05
AdaptiveOperator adapt_op(Rational(1,10), Rational(1,20));
std::vector<Rational> init = {0_r, 1_r};
// Build adaptive path – threshold 0.01
auto path = AdaptiveDeltaPath<Rational, Rational, Rational,
LessBetweenness, EuclideanMetric,
EuclideanValueMetric, AdaptiveOperator>(
init, func, adapt_op, Rational(1,100)
);
// Perform 10 refinement steps
for (int i = 0; i < 10; ++i) path.advance();
std::cout << "Points after adaptive refinement: " << path.size() << "\n";
// Points cluster around 0.5, while linear parts remain coarse.
return 0;
}For more examples, see the examples/ and tests/ directories.
📦 Building
Requirements:
- CMake 3.15+
- C++20 compiler (MSVC 19.29+, GCC 11+, Clang 14+)
- vcpkg recommended for dependencies (Boost, Eigen3, fmt, Google Test, Google Benchmark)
Using CMake Presets (Windows/Linux/macOS):
# Configure and build (example for Windows Debug)
cmake --preset x64-debug
cmake --build out/build/x64-debug
# Run tests
cd out/build/x64-debug
ctest --output-on-failureSee the README for detailed instructions.
📚 Documentation & Theory
- Full mathematical exposition: Zenodo DOI:10.5281/zenodo.18761044 (900+ pages).
- Doxygen comments in headers – the primary reference for the API.
- Test suite – every feature is demonstrated and verified.
📄 License
This project is dual‑licensed:
- Non‑commercial use: CC BY‑NC‑SA 4.0
- Commercial use: separate agreement required – contact timohaishimcev@gmail.com
🙏 Acknowledgements
- Boost.Multiprecision for the
Rationaltype. - Eigen for linear algebra.
- {fmt} for modern formatting.
- Google Test and Google Benchmark for testing and benchmarking.
🔮 What’s Next?
- Extended regulative ideas: graphs, categories, stochastic processes.
- Δ‑differential equations: adaptive solvers with rigorous error bounds.
- Higher dimensions: tensor grids and finite element style refinement.
- Performance optimisations: GPU support, parallel adaptive refinement.
We welcome issues, discussions, and ideas. Pull requests are generally not accepted (the library follows a planned roadmap), but exceptional contributions aligned with the vision may be considered.
Explore the discrete foundations of analysis and numerical methods with Δ‑analysis.
Star the repo, try the code, and let us know what you build!