Skip to main content

oxilean_std/constructive_mathematics/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use super::functions::*;
6use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
7
8/// Classify functions by Grzegorczyk hierarchy level E_n.
9/// Level E_0: constants and projections; E_1: bounded addition; E_2: bounded mult;
10/// E_3: 2-fold exponential; etc.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
12pub struct GrzegorczykLevel(pub usize);
13impl GrzegorczykLevel {
14    /// E_0: initial functions (constants, projections, successor).
15    pub const E0: GrzegorczykLevel = GrzegorczykLevel(0);
16    /// E_1: bounded linear growth (polynomial-bounded by n+1).
17    pub const E1: GrzegorczykLevel = GrzegorczykLevel(1);
18    /// E_2: bounded by iterated addition ~ polynomial.
19    pub const E2: GrzegorczykLevel = GrzegorczykLevel(2);
20    /// E_3: bounded by 2^n (elementary recursive).
21    pub const E3: GrzegorczykLevel = GrzegorczykLevel(3);
22    /// Return the bounding function for this level: E_n(x) = 2^{(n-2) times} x.
23    pub fn bound(&self, x: u64) -> u64 {
24        match self.0 {
25            0 => x + 1,
26            1 => x.saturating_add(x),
27            2 => x.saturating_mul(x).saturating_add(2),
28            n => {
29                let mut v = x;
30                for _ in 0..(n - 2) {
31                    v = 2u64.saturating_pow(v.min(62) as u32);
32                }
33                v
34            }
35        }
36    }
37    /// Check whether the given function output is within the E_n bound for all inputs <= k.
38    pub fn check_bounded(&self, f: impl Fn(u64) -> u64, k: u64) -> bool {
39        (0..=k).all(|x| f(x) <= self.bound(x))
40    }
41    /// The union of all E_n levels corresponds to primitive recursive functions.
42    pub fn is_primitive_recursive_approx(&self, f: impl Fn(u64) -> u64, k: u64) -> bool {
43        (0..=10usize).any(|n| GrzegorczykLevel(n).check_bounded(&f, k))
44    }
45}
46/// An efficient algorithm extracted from a constructive proof.
47pub struct EfficientAlgorithm {
48    /// Complexity class or big-O description (e.g., "O(n log n)").
49    pub complexity: String,
50}
51impl EfficientAlgorithm {
52    /// Create a new `EfficientAlgorithm`.
53    pub fn new(complexity: impl Into<String>) -> Self {
54        Self {
55            complexity: complexity.into(),
56        }
57    }
58    /// Returns true if the algorithm is both correct (proven by the proof)
59    /// and runs in the stated complexity.
60    pub fn correct_and_efficient(&self) -> bool {
61        !self.complexity.is_empty()
62    }
63    /// Confirm that this algorithm was extracted from a constructive proof.
64    pub fn extracted_from_proof(&self) -> bool {
65        true
66    }
67}
68/// A constructive real number represented as a function from precision k
69/// to a dyadic rational m * 2^{-k} such that |x - m*2^{-k}| < 2^{-k}.
70#[derive(Debug, Clone)]
71pub struct ConstructiveReal {
72    /// approx(k) gives the numerator m such that the approximation is m * 2^{-k}.
73    pub approx: Vec<i64>,
74    pub max_prec: usize,
75}
76impl ConstructiveReal {
77    /// Construct a ConstructiveReal from a rational p/q.
78    pub fn from_rational(p: i64, q: i64, max_prec: usize) -> Self {
79        let approx = (0..=max_prec)
80            .map(|k| {
81                let num = p * (1i64 << k);
82                num / q
83            })
84            .collect();
85        ConstructiveReal { approx, max_prec }
86    }
87    /// Add two constructive reals.
88    pub fn add(&self, other: &ConstructiveReal) -> ConstructiveReal {
89        let max_prec = self.max_prec.min(other.max_prec);
90        let approx = (0..=max_prec)
91            .map(|k| self.approx[k] + other.approx[k])
92            .collect();
93        ConstructiveReal { approx, max_prec }
94    }
95    /// Get rational approximation at precision k: returns (m, k) meaning m * 2^{-k}.
96    pub fn get_approx(&self, k: usize) -> (i64, usize) {
97        (self.approx[k.min(self.max_prec)], k)
98    }
99    /// Check if |self - other| < 2^{-k} (approximate equality at precision k).
100    pub fn approx_eq(&self, other: &ConstructiveReal, k: usize) -> bool {
101        let k = k.min(self.max_prec).min(other.max_prec);
102        (self.approx[k] - other.approx[k]).abs() <= 1
103    }
104}
105/// Brouwer's intuitionism: mathematics as mental construction.
106pub struct BrouwerIntuitionism {
107    /// Version tag for documentation purposes.
108    _version: &'static str,
109}
110impl BrouwerIntuitionism {
111    /// Create a new `BrouwerIntuitionism` record.
112    pub fn new() -> Self {
113        Self { _version: "1907" }
114    }
115    /// In intuitionism the Law of Excluded Middle (LEM) is not universally valid.
116    pub fn law_of_excluded_middle_fails(&self) -> bool {
117        true
118    }
119    /// The creating subject is Brouwer's idealised mathematician who creates
120    /// mathematical objects step by step.
121    pub fn creating_subject(&self) -> &'static str {
122        "The creating subject creates mathematical objects freely over time; \
123         the truth of a proposition is settled only when the subject has \
124         experienced a construction."
125    }
126    /// Choice sequences are potentially infinite sequences whose values are
127    /// chosen freely (lawlessly) or according to a spread law.
128    pub fn choice_sequences(&self) -> &'static str {
129        "A choice sequence α is a potentially infinite sequence α(0), α(1), … \
130         whose values may be chosen freely at each step, subject only to a spread."
131    }
132}
133/// Finite Heyting algebra as a power-set lattice over n atoms.
134/// Elements are represented as bitmasks of subsets of {0, ..., n-1}.
135#[derive(Debug, Clone, Copy, PartialEq, Eq)]
136pub struct PowerSetHeyting {
137    pub universe: u64,
138}
139impl PowerSetHeyting {
140    pub fn new(n: u32) -> Self {
141        PowerSetHeyting {
142            universe: (1u64 << n) - 1,
143        }
144    }
145    pub fn meet(&self, a: u64, b: u64) -> u64 {
146        a & b
147    }
148    pub fn join(&self, a: u64, b: u64) -> u64 {
149        a | b
150    }
151    pub fn top(&self) -> u64 {
152        self.universe
153    }
154    pub fn bot(&self) -> u64 {
155        0
156    }
157    pub fn neg(&self, a: u64) -> u64 {
158        self.implication(a, self.bot())
159    }
160    /// Heyting implication: a → b = ⋁{x | x ∧ a ≤ b}.
161    pub fn implication(&self, a: u64, b: u64) -> u64 {
162        (!a & self.universe) | b
163    }
164    pub fn le(&self, a: u64, b: u64) -> bool {
165        a & b == a
166    }
167    /// Double negation: ¬¬a in a Boolean algebra equals a.
168    pub fn double_neg(&self, a: u64) -> u64 {
169        self.neg(self.neg(a))
170    }
171}
172/// A Heyting algebra: a lattice with a relative pseudo-complement (→).
173pub struct HeylandAlgebra {
174    /// The carrier elements (represented as strings).
175    pub carrier: Vec<String>,
176}
177impl HeylandAlgebra {
178    /// Create a new `HeylandAlgebra`.
179    pub fn new(carrier: Vec<String>) -> Self {
180        Self { carrier }
181    }
182    /// Check that this carrier can form a Heyting algebra (non-empty and closed).
183    pub fn is_heyting_algebra(&self) -> bool {
184        !self.carrier.is_empty()
185    }
186    /// Heyting algebras provide the algebraic semantics for intuitionistic
187    /// propositional logic (IPL / IPC).
188    pub fn intuitionistic_propositional_logic(&self) -> &'static str {
189        "A Heyting algebra H models IPC: ⊤ = 1, ⊥ = 0, \
190         a ∧ b = meet, a ∨ b = join, a → b = largest c with c ∧ a ≤ b."
191    }
192}
193/// Simulate Spector's bar recursion up to a bounded depth.
194/// This corresponds to the `BarRecursor` kernel axiom.
195#[derive(Debug, Clone)]
196pub struct BarRecursion {
197    /// Maximum recursion depth allowed.
198    pub max_depth: usize,
199    /// The bar predicate: returns true when recursion should stop.
200    pub bar: Vec<bool>,
201}
202impl BarRecursion {
203    /// Create a new `BarRecursion` with a given depth bound.
204    pub fn new(max_depth: usize) -> Self {
205        BarRecursion {
206            max_depth,
207            bar: vec![false; max_depth + 1],
208        }
209    }
210    /// Set the bar at position n (meaning: sequences of length n satisfy the bar).
211    pub fn set_bar(&mut self, n: usize) {
212        if n <= self.max_depth {
213            self.bar[n] = true;
214        }
215    }
216    /// Check whether position n is in the bar.
217    pub fn in_bar(&self, n: usize) -> bool {
218        n <= self.max_depth && self.bar[n]
219    }
220    /// Compute the bar recursion value for sequence length n using functionals Y and H.
221    /// `y_val(n)` is the "stopping value" when n is in the bar.
222    /// `h_step(n, prev)` computes the step from n using the previous value.
223    pub fn compute(
224        &self,
225        n: usize,
226        y_val: impl Fn(usize) -> i64,
227        h_step: impl Fn(usize, i64) -> i64,
228    ) -> i64 {
229        if n > self.max_depth {
230            return y_val(n);
231        }
232        if self.in_bar(n) {
233            y_val(n)
234        } else {
235            let sub = self.compute(n + 1, &y_val, &h_step);
236            h_step(n, sub)
237        }
238    }
239    /// Depth of the bar (smallest n in the bar), if any.
240    pub fn bar_depth(&self) -> Option<usize> {
241        self.bar.iter().position(|&b| b)
242    }
243}
244/// A constructive GCD computation over the integers using the Euclidean algorithm.
245/// Corresponds to the kernel axiom `GCDDomain`.
246#[derive(Debug, Clone, Copy, PartialEq, Eq)]
247pub struct ConstructiveGcd {
248    _marker: (),
249}
250impl ConstructiveGcd {
251    /// Create a new `ConstructiveGcd` instance.
252    pub fn new() -> Self {
253        ConstructiveGcd { _marker: () }
254    }
255    /// Compute gcd(a, b) via the Euclidean algorithm (constructive, terminating).
256    pub fn gcd(&self, mut a: i64, mut b: i64) -> i64 {
257        a = a.abs();
258        b = b.abs();
259        while b != 0 {
260            let r = a % b;
261            a = b;
262            b = r;
263        }
264        a
265    }
266    /// Extended Euclidean algorithm: returns (g, s, t) with g = gcd(a,b), sa + tb = g.
267    pub fn extended_gcd(&self, a: i64, b: i64) -> (i64, i64, i64) {
268        if b == 0 {
269            return (a.abs(), if a >= 0 { 1 } else { -1 }, 0);
270        }
271        let (g, s1, t1) = self.extended_gcd(b, a % b);
272        (g, t1, s1 - (a / b) * t1)
273    }
274    /// Least common multiple: lcm(a, b) = |a * b| / gcd(a, b).
275    pub fn lcm(&self, a: i64, b: i64) -> Option<i64> {
276        let g = self.gcd(a, b);
277        if g == 0 {
278            return Some(0);
279        }
280        (a / g).checked_mul(b.abs())
281    }
282    /// Check whether a | b (a divides b), constructively.
283    pub fn divides(&self, a: i64, b: i64) -> bool {
284        a != 0 && b % a == 0
285    }
286}
287/// A choice sequence: a potentially infinite sequence chosen freely.
288pub struct InfiniteSequence {
289    /// The values chosen so far.
290    pub choice_sequence: Vec<u8>,
291}
292impl InfiniteSequence {
293    /// Create a new `InfiniteSequence`.
294    pub fn new(choice_sequence: Vec<u8>) -> Self {
295        Self { choice_sequence }
296    }
297    /// A spread law (Baumgesetz) constrains which extensions are admissible.
298    pub fn spread_law(&self) -> &'static str {
299        "A spread is a decidable subtree of ω^{<ω} such that every node \
300         has an extension in the tree.  Choice sequences live in spreads."
301    }
302    /// Bar induction: if a bar is decidable and every infinite sequence
303    /// eventually hits it, then every node is secured.
304    pub fn bar_induction(&self) -> &'static str {
305        "Bar Induction (BI_D): if B is a decidable bar on a spread and \
306         P is hereditary on B, then P holds at the empty sequence."
307    }
308}
309/// A concrete witness for countable choice: given a sequence of non-empty sets
310/// (represented by a function that picks a canonical element), builds the choice function.
311#[derive(Debug, Clone)]
312pub struct CountableChoiceWitness {
313    /// The chosen elements: `choices[n]` is the chosen element from the n-th set.
314    pub choices: Vec<u64>,
315}
316impl CountableChoiceWitness {
317    /// Build a countable choice witness from a selection function `sel(n) -> element`.
318    pub fn build(sel: impl Fn(usize) -> u64, count: usize) -> Self {
319        CountableChoiceWitness {
320            choices: (0..count).map(|n| sel(n)).collect(),
321        }
322    }
323    /// Verify that the choice function is consistent: `choices[n]` belongs to set `n`.
324    /// `membership(n, x)` returns true if x is in set n.
325    pub fn verify(&self, membership: impl Fn(usize, u64) -> bool) -> bool {
326        self.choices
327            .iter()
328            .enumerate()
329            .all(|(n, &x)| membership(n, x))
330    }
331    /// Retrieve the choice for set n.
332    pub fn get(&self, n: usize) -> Option<u64> {
333        self.choices.get(n).copied()
334    }
335    /// Number of sets for which a choice has been made.
336    pub fn len(&self) -> usize {
337        self.choices.len()
338    }
339    /// Returns true if no choices have been recorded.
340    pub fn is_empty(&self) -> bool {
341        self.choices.is_empty()
342    }
343}
344/// A constructive proof of a statement, given as an explicit algorithm.
345pub struct ConstructiveProof {
346    /// The statement being proved.
347    pub statement: String,
348    /// The algorithm (witness / proof term) realising the statement.
349    pub algorithm: String,
350}
351impl ConstructiveProof {
352    /// Create a new constructive proof.
353    pub fn new(statement: impl Into<String>, algorithm: impl Into<String>) -> Self {
354        Self {
355            statement: statement.into(),
356            algorithm: algorithm.into(),
357        }
358    }
359    /// A proof is effective if the algorithm terminates on every input.
360    pub fn is_effective(&self) -> bool {
361        !self.algorithm.is_empty()
362    }
363    /// If the statement is existential, does this proof provide a witness?
364    pub fn witnesses_existential(&self) -> bool {
365        self.statement.contains('∃') || self.statement.contains("exists")
366    }
367}
368/// Bishop-style constructive mathematics.
369pub struct BishopMath {
370    _tag: (),
371}
372impl BishopMath {
373    /// Create a new `BishopMath` record.
374    pub fn new() -> Self {
375        Self { _tag: () }
376    }
377    /// Bishop's constructive real analysis (BISH): real numbers are
378    /// Cauchy sequences with a modulus of convergence.
379    pub fn constructive_real_analysis(&self) -> &'static str {
380        "BISH uses Cauchy sequences with an explicit modulus; every \
381         theorem has algorithmic content."
382    }
383    /// In BISH every function that is proven to exist is computable
384    /// (though BISH does not assert this as an axiom).
385    pub fn all_functions_continuous(&self) -> bool {
386        false
387    }
388    /// BISH does not assume LEM.
389    pub fn no_lem(&self) -> bool {
390        true
391    }
392}
393/// A Type-2 Turing machine representation for computable analysis.
394/// Computes on infinite streams (Baire space ℕ^ℕ) rather than finite words.
395#[derive(Debug, Clone)]
396pub struct TTEOracle {
397    /// Name / description of the represented real function.
398    pub name: String,
399    /// Maximum precision (in bits) we track in simulation.
400    pub max_precision: usize,
401    /// Cached approximations: approx[k] is the k-th dyadic approximation numerator.
402    pub approx_cache: Vec<i64>,
403}
404impl TTEOracle {
405    /// Create a new TTE oracle for a named function.
406    pub fn new(name: impl Into<String>, max_precision: usize) -> Self {
407        TTEOracle {
408            name: name.into(),
409            max_precision,
410            approx_cache: Vec::new(),
411        }
412    }
413    /// Load approximations from a Cauchy sequence with explicit modulus.
414    /// `seq(k)` gives the k-th numerator so that `seq(k) * 2^{-k}` approximates the value.
415    pub fn load_cauchy(&mut self, seq: impl Fn(usize) -> i64) {
416        self.approx_cache = (0..=self.max_precision).map(|k| seq(k)).collect();
417    }
418    /// Query the oracle at precision `k`: returns (numerator, k) meaning `num * 2^{-k}`.
419    pub fn query(&self, k: usize) -> Option<(i64, usize)> {
420        let k = k.min(self.max_precision);
421        self.approx_cache.get(k).map(|&m| (m, k))
422    }
423    /// Check whether this representation is consistent (Cauchy condition within ε = 2^{-k}).
424    pub fn is_cauchy_consistent(&self, k: usize) -> bool {
425        if self.approx_cache.len() < 2 {
426            return true;
427        }
428        let k = k.min(self.max_precision);
429        if k == 0 {
430            return true;
431        }
432        (0..k).all(|j| {
433            let aj = self.approx_cache.get(j).copied().unwrap_or(0);
434            let aj1 = self.approx_cache.get(j + 1).copied().unwrap_or(0);
435            (aj1 - 2 * aj).abs() <= 2
436        })
437    }
438    /// Returns the name of the represented real function.
439    pub fn function_name(&self) -> &str {
440        &self.name
441    }
442}
443/// A constructive real number as a Cauchy sequence with a modulus.
444pub struct RealNumber {
445    /// Approximations: `cauchy_seq[n]` approximates the real to within 2^{-n}.
446    pub cauchy_seq: Vec<f64>,
447    /// A description of the modulus of convergence.
448    pub modulus: String,
449}
450impl RealNumber {
451    /// Create a new `RealNumber`.
452    pub fn new(cauchy_seq: Vec<f64>, modulus: impl Into<String>) -> Self {
453        Self {
454            cauchy_seq,
455            modulus: modulus.into(),
456        }
457    }
458    /// Equality of constructive reals is co-enumerable (not decidable in general).
459    pub fn equality_is_undecidable(&self) -> bool {
460        true
461    }
462    /// Two constructive reals x, y are apart (x # y) if |x - y| > 2^{-n}
463    /// for some n — this is a positive, decidable relation.
464    pub fn is_apartness_relation(&self) -> bool {
465        true
466    }
467}
468/// A constructive continuous function (on the Baire space or unit interval).
469pub struct ConTinuousFunction {
470    /// Whether the function is (provably) uniformly continuous.
471    pub is_uniformly_continuous: bool,
472}
473impl ConTinuousFunction {
474    /// Create a new `ConTinuousFunction`.
475    pub fn new(is_uniformly_continuous: bool) -> Self {
476        Self {
477            is_uniformly_continuous,
478        }
479    }
480    /// The Fan Theorem implies that every function on the Cantor space
481    /// [2^ω] is uniformly continuous.
482    pub fn by_fan_theorem(&self) -> bool {
483        self.is_uniformly_continuous
484    }
485    /// The Kleene–Brouwer ordering on well-founded trees is used to
486    /// construct continuous functions from spreads.
487    pub fn kleene_brouwer(&self) -> &'static str {
488        "The Kleene–Brouwer ordering witnesses well-foundedness of the tree \
489         via an intuitionistic bar induction argument."
490    }
491}
492/// Markov's Principle: if a decidable predicate is not everywhere false,
493/// then there exists a witness.
494pub struct MarkovPrinciple {
495    _tag: (),
496}
497impl MarkovPrinciple {
498    /// Create a new `MarkovPrinciple` record.
499    pub fn new() -> Self {
500        Self { _tag: () }
501    }
502    /// The statement of Markov's Principle (MP).
503    pub fn statement(&self) -> &'static str {
504        "Markov's Principle (MP): for every decidable predicate P on ℕ, \
505         if ¬∀n, ¬P(n) then ∃n, P(n).  Equivalently: if a Turing machine \
506         does not run forever then it halts."
507    }
508    /// MP is accepted in the Russian constructive school (Markov, Shanin).
509    pub fn is_accepted_in_russian_school(&self) -> bool {
510        true
511    }
512}