Skip to main content

oxilean_std/wellfounded/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use super::functions::*;
6use oxilean_kernel::Node;
7use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
8
9/// Sigma-type measure: `f : α → Nat` witnesses well-foundedness of `(<) ∘ f`.
10#[allow(dead_code)]
11#[derive(Debug, Clone)]
12pub struct SizeMeasure {
13    /// Name of the measure function.
14    pub name: String,
15    /// Expected domain type name.
16    pub domain: String,
17}
18impl SizeMeasure {
19    /// Create a measure.
20    #[allow(dead_code)]
21    pub fn new(name: impl Into<String>, domain: impl Into<String>) -> Self {
22        Self {
23            name: name.into(),
24            domain: domain.into(),
25        }
26    }
27    /// Standard measure for lists: the length function.
28    #[allow(dead_code)]
29    pub fn list_length() -> Self {
30        Self::new("List.length", "List")
31    }
32    /// Standard measure for natural numbers: identity.
33    #[allow(dead_code)]
34    pub fn nat_id() -> Self {
35        Self::new("id", "Nat")
36    }
37    /// Standard measure for trees: size function.
38    #[allow(dead_code)]
39    pub fn tree_size() -> Self {
40        Self::new("Tree.size", "Tree")
41    }
42    /// Produce a declaration body for the induced well-founded relation.
43    #[allow(dead_code)]
44    pub fn induced_relation_name(&self) -> String {
45        format!("InvImage.lt_{}", self.name.replace('.', "_"))
46    }
47}
48/// A ranked proof tree for tracking structural recursion depth.
49#[allow(dead_code)]
50#[derive(Debug, Clone)]
51pub enum RecursionTree {
52    /// A base case (leaf).
53    Base { label: String },
54    /// A recursive case with a child proof tree.
55    Rec {
56        label: String,
57        decreasing_arg: String,
58        child: Box<RecursionTree>,
59    },
60    /// A branching point (e.g., `match` with multiple arms).
61    Branch {
62        label: String,
63        arms: Vec<RecursionTree>,
64    },
65}
66impl RecursionTree {
67    /// Return the maximum depth of the recursion tree.
68    #[allow(dead_code)]
69    pub fn depth(&self) -> usize {
70        match self {
71            Self::Base { .. } => 0,
72            Self::Rec { child, .. } => 1 + child.depth(),
73            Self::Branch { arms, .. } => arms.iter().map(|a| a.depth()).max().unwrap_or(0),
74        }
75    }
76    /// Return the number of recursive calls.
77    #[allow(dead_code)]
78    pub fn recursive_calls(&self) -> usize {
79        match self {
80            Self::Base { .. } => 0,
81            Self::Rec { child, .. } => 1 + child.recursive_calls(),
82            Self::Branch { arms, .. } => arms.iter().map(|a| a.recursive_calls()).sum(),
83        }
84    }
85    /// Return `true` if the tree is simply a base case.
86    #[allow(dead_code)]
87    pub fn is_base(&self) -> bool {
88        matches!(self, Self::Base { .. })
89    }
90}
91/// Well-founded relation builder: constructs `InvImage r f` and `Prod.Lex`.
92#[allow(dead_code)]
93pub struct WfRelBuilder;
94impl WfRelBuilder {
95    /// Build the expression for `InvImage r f`:
96    /// a well-founded relation on `α` induced by `f : α → β` and `r` on `β`.
97    #[allow(dead_code)]
98    pub fn inv_image(r: Expr, f: Expr) -> Expr {
99        Expr::App(
100            Node::new(Expr::App(
101                Node::new(Expr::Const(Name::str("InvImage"), vec![])),
102                Node::new(r),
103            )),
104            Node::new(f),
105        )
106    }
107    /// Build `Prod.Lex r s`: lexicographic product of relations.
108    #[allow(dead_code)]
109    pub fn prod_lex(r: Expr, s: Expr) -> Expr {
110        Expr::App(
111            Node::new(Expr::App(
112                Node::new(Expr::Const(Name::str("Prod.Lex"), vec![])),
113                Node::new(r),
114            )),
115            Node::new(s),
116        )
117    }
118    /// The standard `Nat.lt` well-founded relation.
119    #[allow(dead_code)]
120    pub fn nat_lt() -> Expr {
121        Expr::Const(Name::str("Nat.lt"), vec![])
122    }
123    /// The measure-induced relation `InvImage Nat.lt f`.
124    #[allow(dead_code)]
125    pub fn measure(f: Expr) -> Expr {
126        Self::inv_image(Self::nat_lt(), f)
127    }
128}
129/// Heuristic for choosing a termination proof strategy.
130#[allow(dead_code)]
131#[derive(Debug, Clone, Copy, PartialEq, Eq)]
132pub enum TerminationStrategy {
133    /// Recurse on structurally smaller arguments.
134    Structural,
135    /// Use an explicit numeric measure function.
136    Measure,
137    /// Use a lexicographic tuple of measures.
138    Lexicographic,
139    /// Use a well-founded relation other than `<`.
140    WellFounded,
141    /// Multiple-argument mutual recursion.
142    Mutual,
143}
144impl TerminationStrategy {
145    /// Return a description of the strategy.
146    #[allow(dead_code)]
147    pub fn description(self) -> &'static str {
148        match self {
149            Self::Structural => "Structural recursion on an inductive argument",
150            Self::Measure => "Explicit numeric measure function",
151            Self::Lexicographic => "Lexicographic ordering of multiple arguments",
152            Self::WellFounded => "Custom well-founded relation",
153            Self::Mutual => "Mutual recursion with shared termination argument",
154        }
155    }
156    /// Return all available strategies.
157    #[allow(dead_code)]
158    pub fn all() -> &'static [TerminationStrategy] {
159        &[
160            Self::Structural,
161            Self::Measure,
162            Self::Lexicographic,
163            Self::WellFounded,
164            Self::Mutual,
165        ]
166    }
167}
168/// Proof-relevant termination certificates.
169///
170/// A `TerminationCert` pairs a measure function with evidence that the
171/// measure strictly decreases on each recursive call.
172#[allow(dead_code)]
173#[derive(Debug, Clone)]
174pub struct TerminationCert {
175    /// Name of the function being certified.
176    pub fn_name: String,
177    /// Name of the measure function (`measure : domain → Nat`).
178    pub measure_fn: String,
179    /// Human-readable justification.
180    pub justification: String,
181    /// Whether automated verification succeeded.
182    pub verified: bool,
183}
184impl TerminationCert {
185    /// Construct a certificate.
186    #[allow(dead_code)]
187    pub fn new(
188        fn_name: impl Into<String>,
189        measure_fn: impl Into<String>,
190        justification: impl Into<String>,
191        verified: bool,
192    ) -> Self {
193        Self {
194            fn_name: fn_name.into(),
195            measure_fn: measure_fn.into(),
196            justification: justification.into(),
197            verified,
198        }
199    }
200    /// Returns a structural recursion certificate (always verified).
201    #[allow(dead_code)]
202    pub fn structural(fn_name: impl Into<String>) -> Self {
203        let nm = fn_name.into();
204        Self {
205            measure_fn: format!("structural_measure_{}", nm),
206            justification: "Structural recursion on an inductive argument".to_owned(),
207            fn_name: nm,
208            verified: true,
209        }
210    }
211    /// Returns a well-founded recursion certificate.
212    #[allow(dead_code)]
213    pub fn well_founded(fn_name: impl Into<String>, measure_fn: impl Into<String>) -> Self {
214        Self::new(fn_name, measure_fn, "Well-founded recursion", true)
215    }
216    /// Returns a certificate backed by lexicographic ordering.
217    #[allow(dead_code)]
218    pub fn lexicographic(fn_name: impl Into<String>, components: Vec<String>) -> Self {
219        let nm = fn_name.into();
220        let just = format!("Lexicographic order on ({}).", components.join(", "));
221        Self::new(nm.clone(), format!("lex_measure_{}", nm), just, true)
222    }
223    /// Returns `true` if the certificate is valid.
224    #[allow(dead_code)]
225    pub fn is_valid(&self) -> bool {
226        self.verified && !self.fn_name.is_empty() && !self.measure_fn.is_empty()
227    }
228    /// Produce a summary string.
229    #[allow(dead_code)]
230    pub fn summary(&self) -> String {
231        format!(
232            "TerminationCert{{ fn='{}', measure='{}', ok={}, justification='{}' }}",
233            self.fn_name, self.measure_fn, self.verified, self.justification
234        )
235    }
236}
237/// A registry of termination certificates indexed by function name.
238#[allow(dead_code)]
239#[derive(Debug, Default)]
240pub struct TerminationRegistry {
241    certs: Vec<TerminationCert>,
242}
243impl TerminationRegistry {
244    /// Create an empty registry.
245    #[allow(dead_code)]
246    pub fn new() -> Self {
247        Self::default()
248    }
249    /// Register a certificate.
250    #[allow(dead_code)]
251    pub fn register(&mut self, cert: TerminationCert) {
252        self.certs.push(cert);
253    }
254    /// Look up the certificate for a function.
255    #[allow(dead_code)]
256    pub fn lookup(&self, fn_name: &str) -> Option<&TerminationCert> {
257        self.certs.iter().find(|c| c.fn_name == fn_name)
258    }
259    /// Return all verified certificates.
260    #[allow(dead_code)]
261    pub fn verified_certs(&self) -> Vec<&TerminationCert> {
262        self.certs.iter().filter(|c| c.verified).collect()
263    }
264    /// Return the total number of registered certificates.
265    #[allow(dead_code)]
266    pub fn count(&self) -> usize {
267        self.certs.len()
268    }
269}
270/// A combinator for building lexicographic well-founded orderings.
271#[allow(dead_code)]
272#[derive(Debug, Clone)]
273pub struct LexOrder {
274    /// Component measure names in decreasing priority.
275    pub components: Vec<String>,
276}
277impl LexOrder {
278    /// Construct from a list of measure component names.
279    #[allow(dead_code)]
280    pub fn new(components: Vec<impl Into<String>>) -> Self {
281        Self {
282            components: components.into_iter().map(Into::into).collect(),
283        }
284    }
285    /// Add an additional (lowest-priority) component.
286    #[allow(dead_code)]
287    pub fn push(mut self, component: impl Into<String>) -> Self {
288        self.components.push(component.into());
289        self
290    }
291    /// Return the number of components.
292    #[allow(dead_code)]
293    pub fn arity(&self) -> usize {
294        self.components.len()
295    }
296    /// Describe the lex order as a tuple type string.
297    #[allow(dead_code)]
298    pub fn type_string(&self) -> String {
299        format!("({})", self.components.join(" × "))
300    }
301    /// Verify that a concrete sequence of `(before, after)` pairs is
302    /// lexicographically decreasing using the given values for each component.
303    ///
304    /// `values_before\[i\]` and `values_after\[i\]` are `u64` values of component `i`.
305    #[allow(dead_code)]
306    pub fn check_decrease(&self, values_before: &[u64], values_after: &[u64]) -> bool {
307        let n = self
308            .components
309            .len()
310            .min(values_before.len())
311            .min(values_after.len());
312        for i in 0..n {
313            if values_before[i] < values_after[i] {
314                return false;
315            }
316            if values_before[i] > values_after[i] {
317                return true;
318            }
319        }
320        false
321    }
322}