1use super::functions::*;
6use oxilean_kernel::Node;
7use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
8
9#[allow(dead_code)]
11#[derive(Debug, Clone)]
12pub struct SizeMeasure {
13 pub name: String,
15 pub domain: String,
17}
18impl SizeMeasure {
19 #[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 #[allow(dead_code)]
29 pub fn list_length() -> Self {
30 Self::new("List.length", "List")
31 }
32 #[allow(dead_code)]
34 pub fn nat_id() -> Self {
35 Self::new("id", "Nat")
36 }
37 #[allow(dead_code)]
39 pub fn tree_size() -> Self {
40 Self::new("Tree.size", "Tree")
41 }
42 #[allow(dead_code)]
44 pub fn induced_relation_name(&self) -> String {
45 format!("InvImage.lt_{}", self.name.replace('.', "_"))
46 }
47}
48#[allow(dead_code)]
50#[derive(Debug, Clone)]
51pub enum RecursionTree {
52 Base { label: String },
54 Rec {
56 label: String,
57 decreasing_arg: String,
58 child: Box<RecursionTree>,
59 },
60 Branch {
62 label: String,
63 arms: Vec<RecursionTree>,
64 },
65}
66impl RecursionTree {
67 #[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 #[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 #[allow(dead_code)]
87 pub fn is_base(&self) -> bool {
88 matches!(self, Self::Base { .. })
89 }
90}
91#[allow(dead_code)]
93pub struct WfRelBuilder;
94impl WfRelBuilder {
95 #[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 #[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 #[allow(dead_code)]
120 pub fn nat_lt() -> Expr {
121 Expr::Const(Name::str("Nat.lt"), vec![])
122 }
123 #[allow(dead_code)]
125 pub fn measure(f: Expr) -> Expr {
126 Self::inv_image(Self::nat_lt(), f)
127 }
128}
129#[allow(dead_code)]
131#[derive(Debug, Clone, Copy, PartialEq, Eq)]
132pub enum TerminationStrategy {
133 Structural,
135 Measure,
137 Lexicographic,
139 WellFounded,
141 Mutual,
143}
144impl TerminationStrategy {
145 #[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 #[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#[allow(dead_code)]
173#[derive(Debug, Clone)]
174pub struct TerminationCert {
175 pub fn_name: String,
177 pub measure_fn: String,
179 pub justification: String,
181 pub verified: bool,
183}
184impl TerminationCert {
185 #[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 #[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 #[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 #[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 #[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 #[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#[allow(dead_code)]
239#[derive(Debug, Default)]
240pub struct TerminationRegistry {
241 certs: Vec<TerminationCert>,
242}
243impl TerminationRegistry {
244 #[allow(dead_code)]
246 pub fn new() -> Self {
247 Self::default()
248 }
249 #[allow(dead_code)]
251 pub fn register(&mut self, cert: TerminationCert) {
252 self.certs.push(cert);
253 }
254 #[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 #[allow(dead_code)]
261 pub fn verified_certs(&self) -> Vec<&TerminationCert> {
262 self.certs.iter().filter(|c| c.verified).collect()
263 }
264 #[allow(dead_code)]
266 pub fn count(&self) -> usize {
267 self.certs.len()
268 }
269}
270#[allow(dead_code)]
272#[derive(Debug, Clone)]
273pub struct LexOrder {
274 pub components: Vec<String>,
276}
277impl LexOrder {
278 #[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 #[allow(dead_code)]
287 pub fn push(mut self, component: impl Into<String>) -> Self {
288 self.components.push(component.into());
289 self
290 }
291 #[allow(dead_code)]
293 pub fn arity(&self) -> usize {
294 self.components.len()
295 }
296 #[allow(dead_code)]
298 pub fn type_string(&self) -> String {
299 format!("({})", self.components.join(" × "))
300 }
301 #[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}