Skip to main content

adele_ring/
tower.rs

1//! The number tower router. Every value carries a [`TowerLevel`]; operations try
2//! to *stay at the lowest (cheapest) level* they can, dropping down when a result
3//! simplifies (e.g. √2·√2 = 2) and rising only when forced.
4//!
5//! When a caller asks for digits, the request flows *down* the tower: a symbolic
6//! expression is simplified, then (if still not exact) elevated to a computable
7//! real that produces the requested precision.
8
9use num_bigint::BigInt;
10
11use crate::algebraic::AlgebraicNumber;
12use crate::computable::ComputableReal;
13use crate::primes::factorize;
14use crate::rational::RnsRational;
15use crate::rns::{Channels, RnsInt};
16use crate::symbolic::{IdentityGraph, SymbolicExpr};
17
18/// The levels of the number tower, ordered cheapest-first.
19#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
20pub enum TowerLevel {
21    Integer = 0,
22    Rational = 1,
23    Algebraic = 2,
24    Computable = 3,
25    Symbolic = 4,
26}
27
28/// A value somewhere in the number tower.
29#[derive(Clone)]
30pub enum TowerValue {
31    Integer(RnsInt),
32    Rational(RnsRational),
33    Algebraic(AlgebraicNumber),
34    Computable(ComputableReal),
35    Symbolic(SymbolicExpr),
36}
37
38impl TowerValue {
39    /// The level this value currently sits at.
40    pub fn level(&self) -> TowerLevel {
41        match self {
42            TowerValue::Integer(_) => TowerLevel::Integer,
43            TowerValue::Rational(_) => TowerLevel::Rational,
44            TowerValue::Algebraic(_) => TowerLevel::Algebraic,
45            TowerValue::Computable(_) => TowerLevel::Computable,
46            TowerValue::Symbolic(_) => TowerLevel::Symbolic,
47        }
48    }
49
50    /// Best-effort channels for this value (symbolic falls back to the standard set).
51    pub fn channels(&self) -> Channels {
52        match self {
53            TowerValue::Integer(i) => i.channels.clone(),
54            TowerValue::Rational(r) => r.channels.clone(),
55            TowerValue::Algebraic(a) => a.channels.clone(),
56            TowerValue::Computable(c) => c.channels(),
57            TowerValue::Symbolic(_) => Channels::standard(32),
58        }
59    }
60
61    /// Reduce to the lowest valid level (applied to a fixed point).
62    pub fn reduce(&self) -> TowerValue {
63        let mut current = self.clone();
64        loop {
65            let next = current.reduce_once();
66            if next.level() == current.level() {
67                return next;
68            }
69            current = next;
70        }
71    }
72
73    fn reduce_once(&self) -> TowerValue {
74        match self {
75            TowerValue::Algebraic(a) if a.degree() == 1 => {
76                TowerValue::Rational(a.to_rational().unwrap())
77            }
78            TowerValue::Rational(r) if r.is_integer() => {
79                let p = r.to_pair().0;
80                TowerValue::Integer(RnsInt::from_bigint(&p, r.channels.clone()))
81            }
82            TowerValue::Symbolic(e) => {
83                let simplified = IdentityGraph::standard().simplify(e.clone());
84                match symbolic_to_value(&simplified, &self.channels()) {
85                    Some(v) => v,
86                    None => TowerValue::Symbolic(simplified),
87                }
88            }
89            other => other.clone(),
90        }
91    }
92
93    /// Elevate to at least `target` (for mixed-level operations). Symbolic is the
94    /// top; numeric levels rise one step at a time.
95    pub fn elevate_to(&self, target: TowerLevel) -> TowerValue {
96        let mut current = self.clone();
97        while current.level() < target {
98            current = current.elevate_once();
99        }
100        current
101    }
102
103    fn elevate_once(&self) -> TowerValue {
104        match self {
105            TowerValue::Integer(i) => {
106                TowerValue::Rational(RnsRational::new(i.to_bigint(), BigInt::from(1), i.channels.clone()))
107            }
108            TowerValue::Rational(r) => TowerValue::Algebraic(AlgebraicNumber::from_rational(r.clone())),
109            TowerValue::Algebraic(a) => TowerValue::Computable(a.to_computable()),
110            TowerValue::Computable(_) => self.clone(), // cannot rise to symbolic
111            TowerValue::Symbolic(_) => self.clone(),
112        }
113    }
114
115    /// Decimal approximation (levels 0–3; symbolic is simplified/evaluated first).
116    pub fn to_f64(&self) -> Option<f64> {
117        match self {
118            TowerValue::Integer(i) => {
119                Some(RnsRational::new(i.to_bigint(), BigInt::from(1), i.channels.clone()).to_f64())
120            }
121            TowerValue::Rational(r) => Some(r.to_f64()),
122            TowerValue::Algebraic(a) => Some(a.to_f64()),
123            TowerValue::Computable(c) => Some(c.evaluate_f64()),
124            TowerValue::Symbolic(_) => self.reduce().non_symbolic_to_f64(),
125        }
126    }
127
128    fn non_symbolic_to_f64(&self) -> Option<f64> {
129        match self {
130            TowerValue::Symbolic(e) => {
131                // Try to evaluate a transcendental constant numerically.
132                let ch = self.channels();
133                symbolic_to_computable(e, &ch).map(|c| c.evaluate_f64())
134            }
135            other => other.to_f64(),
136        }
137    }
138
139    /// Produce exact digits to `precision` decimal places, as a rational.
140    pub fn digits(&self, precision: u64) -> RnsRational {
141        match self {
142            TowerValue::Integer(i) => {
143                RnsRational::new(i.to_bigint(), BigInt::from(1), i.channels.clone())
144            }
145            TowerValue::Rational(r) => r.clone(),
146            TowerValue::Algebraic(a) => {
147                let mut clone = a.clone();
148                let target = RnsRational::new(
149                    BigInt::from(1),
150                    BigInt::from(10u8).pow((precision + 1) as u32),
151                    a.channels.clone(),
152                );
153                clone.refine_interval(&target);
154                clone.interval.0.midpoint(&clone.interval.1)
155            }
156            TowerValue::Computable(c) => c.evaluate(precision),
157            TowerValue::Symbolic(e) => {
158                let ch = self.channels();
159                let simplified = IdentityGraph::standard().simplify(e.clone());
160                if let Some(v) = symbolic_to_value(&simplified, &ch) {
161                    return v.digits(precision);
162                }
163                match symbolic_to_computable(&simplified, &ch) {
164                    Some(c) => c.evaluate(precision),
165                    None => panic!("cannot produce digits for irreducible symbolic expression"),
166                }
167            }
168        }
169    }
170
171    // ── Arithmetic ──────────────────────────────────────────────────────────
172
173    /// Addition, dropping the result to its lowest valid level.
174    pub fn add(&self, other: &TowerValue) -> TowerValue {
175        self.binop(other, Op::Add).reduce()
176    }
177
178    /// Multiplication, dropping the result to its lowest valid level.
179    pub fn mul(&self, other: &TowerValue) -> TowerValue {
180        self.binop(other, Op::Mul).reduce()
181    }
182
183    fn binop(&self, other: &TowerValue, op: Op) -> TowerValue {
184        let lvl = self.level().max(other.level());
185        if lvl == TowerLevel::Symbolic {
186            let a = self.to_symbolic();
187            let b = other.to_symbolic();
188            let expr = match op {
189                Op::Add => SymbolicExpr::Add(vec![a, b]),
190                Op::Mul => SymbolicExpr::Mul(vec![a, b]),
191            };
192            return TowerValue::Symbolic(IdentityGraph::standard().simplify(expr));
193        }
194        let a = self.elevate_to(lvl);
195        let b = other.elevate_to(lvl);
196        match (a, b) {
197            (TowerValue::Integer(x), TowerValue::Integer(y)) => TowerValue::Integer(match op {
198                Op::Add => x.add(&y),
199                Op::Mul => x.mul(&y),
200            }),
201            (TowerValue::Rational(x), TowerValue::Rational(y)) => TowerValue::Rational(match op {
202                Op::Add => x.add(&y),
203                Op::Mul => x.mul(&y),
204            }),
205            (TowerValue::Algebraic(x), TowerValue::Algebraic(y)) => TowerValue::Algebraic(match op {
206                Op::Add => x.add(&y),
207                Op::Mul => x.mul(&y),
208            }),
209            (TowerValue::Computable(x), TowerValue::Computable(y)) => TowerValue::Computable(match op {
210                Op::Add => x.add(&y),
211                Op::Mul => x.mul(&y),
212            }),
213            _ => unreachable!("levels were equalized before the operation"),
214        }
215    }
216
217    /// Square root: a perfect square drops to `Integer`, otherwise rises to
218    /// `Algebraic`.
219    pub fn sqrt(&self) -> TowerValue {
220        let ch = self.channels();
221        if let TowerValue::Integer(i) = self {
222            let n = i.to_bigint();
223            if let Some(nu) = bigint_to_u64(&n) {
224                let root = (nu as f64).sqrt().round() as u64;
225                if root * root == nu {
226                    return TowerValue::Integer(RnsInt::from_bigint(&BigInt::from(root), ch));
227                }
228                return TowerValue::Algebraic(AlgebraicNumber::sqrt(nu, ch)).reduce();
229            }
230        }
231        // General: take the f64 value and build an algebraic square root if integral.
232        let v = self.to_f64().unwrap_or(f64::NAN);
233        if v >= 0.0 && v.fract() == 0.0 {
234            return TowerValue::Algebraic(AlgebraicNumber::sqrt(v as u64, ch)).reduce();
235        }
236        panic!("sqrt of non-integer values is not supported at the tower level yet");
237    }
238
239    /// sin: checks the symbolic identity graph; otherwise stays symbolic.
240    pub fn sin(&self) -> TowerValue {
241        let expr = SymbolicExpr::Sin(Box::new(self.to_symbolic()));
242        TowerValue::Symbolic(IdentityGraph::standard().simplify(expr)).reduce()
243    }
244
245    fn to_symbolic(&self) -> SymbolicExpr {
246        match self {
247            TowerValue::Integer(i) => SymbolicExpr::Integer(i.to_bigint()),
248            TowerValue::Rational(r) => {
249                let (p, q) = r.to_pair();
250                SymbolicExpr::Rational(p, q)
251            }
252            TowerValue::Symbolic(e) => e.clone(),
253            // Algebraic/Computable have no faithful finite symbolic form here.
254            TowerValue::Algebraic(a) => {
255                if let Some(r) = a.to_rational() {
256                    let (p, q) = r.to_pair();
257                    SymbolicExpr::Rational(p, q)
258                } else {
259                    panic!("cannot lift this algebraic number to symbolic form")
260                }
261            }
262            TowerValue::Computable(_) => panic!("cannot lift a computable real to symbolic form"),
263        }
264    }
265}
266
267#[derive(Clone, Copy)]
268enum Op {
269    Add,
270    Mul,
271}
272
273fn bigint_to_u64(n: &BigInt) -> Option<u64> {
274    use num_traits::ToPrimitive;
275    n.to_u64()
276}
277
278/// Map a fully simplified symbolic expression onto a concrete tower value.
279fn symbolic_to_value(e: &SymbolicExpr, ch: &Channels) -> Option<TowerValue> {
280    match e {
281        SymbolicExpr::Integer(n) => Some(TowerValue::Integer(RnsInt::from_bigint(n, ch.clone()))),
282        SymbolicExpr::Rational(p, q) => {
283            Some(TowerValue::Rational(RnsRational::new(p.clone(), q.clone(), ch.clone())))
284        }
285        SymbolicExpr::Sqrt { radicand } => {
286            let nu = bigint_to_u64(radicand)?;
287            Some(TowerValue::Algebraic(AlgebraicNumber::sqrt(nu, ch.clone())))
288        }
289        SymbolicExpr::ScaledSqrt { coeff: (a, b), rad } => {
290            let nu = bigint_to_u64(rad)?;
291            let s = AlgebraicNumber::sqrt(nu, ch.clone());
292            let coeff = RnsRational::new(a.clone(), b.clone(), ch.clone());
293            Some(TowerValue::Algebraic(s).mul(&TowerValue::Rational(coeff)))
294        }
295        _ => None,
296    }
297}
298
299/// Build a computable real from a symbolic expression (used for digit requests
300/// on transcendentals like π+1).
301fn symbolic_to_computable(e: &SymbolicExpr, ch: &Channels) -> Option<ComputableReal> {
302    match e {
303        SymbolicExpr::Integer(n) => Some(ComputableReal::from_rational(RnsRational::new(
304            n.clone(),
305            BigInt::from(1),
306            ch.clone(),
307        ))),
308        SymbolicExpr::Rational(p, q) => Some(ComputableReal::from_rational(RnsRational::new(
309            p.clone(),
310            q.clone(),
311            ch.clone(),
312        ))),
313        SymbolicExpr::Pi => Some(ComputableReal::pi(ch.clone())),
314        SymbolicExpr::E => Some(ComputableReal::e(ch.clone())),
315        SymbolicExpr::Sqrt { radicand } => {
316            let r = RnsRational::new(radicand.clone(), BigInt::from(1), ch.clone());
317            Some(ComputableReal::sqrt(r))
318        }
319        SymbolicExpr::Add(terms) => {
320            let mut acc: Option<ComputableReal> = None;
321            for t in terms {
322                let c = symbolic_to_computable(t, ch)?;
323                acc = Some(match acc {
324                    Some(a) => a.add(&c),
325                    None => c,
326                });
327            }
328            acc
329        }
330        SymbolicExpr::Mul(factors) => {
331            let mut acc: Option<ComputableReal> = None;
332            for f in factors {
333                let c = symbolic_to_computable(f, ch)?;
334                acc = Some(match acc {
335                    Some(a) => a.mul(&c),
336                    None => c,
337                });
338            }
339            acc
340        }
341        _ => None,
342    }
343}
344
345/// Square-free check helper exposed for completeness (used by examples/tests).
346pub fn is_perfect_square(n: u64) -> bool {
347    let r = (n as f64).sqrt().round() as u64;
348    r * r == n
349}
350
351#[allow(dead_code)]
352fn _uses_factorize() {
353    let _ = factorize(12);
354}
355
356#[cfg(test)]
357mod tests {
358    use super::*;
359
360    fn ch() -> Channels {
361        Channels::standard(32)
362    }
363
364    #[test]
365    fn rational_level() {
366        let v = TowerValue::Rational(RnsRational::from_fraction(2, 3, ch()));
367        assert_eq!(v.level(), TowerLevel::Rational);
368    }
369
370    #[test]
371    fn rational_with_denom_one_reduces_to_integer() {
372        let v = TowerValue::Rational(RnsRational::from_fraction(6, 2, ch()));
373        assert_eq!(v.reduce().level(), TowerLevel::Integer);
374    }
375
376    #[test]
377    fn sqrt2_times_sqrt2_drops_to_integer() {
378        let s = TowerValue::Algebraic(AlgebraicNumber::sqrt(2, ch()));
379        let prod = s.mul(&s);
380        assert_eq!(prod.level(), TowerLevel::Integer);
381        assert_eq!(prod.to_f64().unwrap().round(), 2.0);
382    }
383
384    #[test]
385    fn mixed_level_add() {
386        // Integer 1 + Rational 1/2 = 3/2.
387        let a = TowerValue::Integer(RnsInt::from_i64(1, ch()));
388        let b = TowerValue::Rational(RnsRational::from_fraction(1, 2, ch()));
389        let sum = a.add(&b);
390        assert_eq!(sum.level(), TowerLevel::Rational);
391        assert!((sum.to_f64().unwrap() - 1.5).abs() < 1e-12);
392    }
393
394    #[test]
395    fn pi_plus_one_digits() {
396        // π + 1 stays symbolic, then digits() elevates to computable.
397        let pi = TowerValue::Symbolic(SymbolicExpr::Pi);
398        let one = TowerValue::Integer(RnsInt::from_i64(1, ch()));
399        let sum = pi.add(&one);
400        let d = sum.digits(20);
401        assert!((d.to_f64() - (std::f64::consts::PI + 1.0)).abs() < 1e-12);
402    }
403
404    #[test]
405    fn sin_pi_is_zero() {
406        let pi = TowerValue::Symbolic(SymbolicExpr::Pi);
407        let s = pi.sin();
408        assert_eq!(s.to_f64().unwrap(), 0.0);
409    }
410}