1use super::functions::*;
6use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
7
8#[allow(dead_code)]
10#[derive(Debug, Clone)]
11pub struct SizeMeasure {
12 pub name: String,
14 pub domain: String,
16}
17impl SizeMeasure {
18 #[allow(dead_code)]
20 pub fn new(name: impl Into<String>, domain: impl Into<String>) -> Self {
21 Self {
22 name: name.into(),
23 domain: domain.into(),
24 }
25 }
26 #[allow(dead_code)]
28 pub fn list_length() -> Self {
29 Self::new("List.length", "List")
30 }
31 #[allow(dead_code)]
33 pub fn nat_id() -> Self {
34 Self::new("id", "Nat")
35 }
36 #[allow(dead_code)]
38 pub fn tree_size() -> Self {
39 Self::new("Tree.size", "Tree")
40 }
41 #[allow(dead_code)]
43 pub fn induced_relation_name(&self) -> String {
44 format!("InvImage.lt_{}", self.name.replace('.', "_"))
45 }
46}
47#[allow(dead_code)]
49#[derive(Debug, Clone)]
50pub enum RecursionTree {
51 Base { label: String },
53 Rec {
55 label: String,
56 decreasing_arg: String,
57 child: Box<RecursionTree>,
58 },
59 Branch {
61 label: String,
62 arms: Vec<RecursionTree>,
63 },
64}
65impl RecursionTree {
66 #[allow(dead_code)]
68 pub fn depth(&self) -> usize {
69 match self {
70 Self::Base { .. } => 0,
71 Self::Rec { child, .. } => 1 + child.depth(),
72 Self::Branch { arms, .. } => arms.iter().map(|a| a.depth()).max().unwrap_or(0),
73 }
74 }
75 #[allow(dead_code)]
77 pub fn recursive_calls(&self) -> usize {
78 match self {
79 Self::Base { .. } => 0,
80 Self::Rec { child, .. } => 1 + child.recursive_calls(),
81 Self::Branch { arms, .. } => arms.iter().map(|a| a.recursive_calls()).sum(),
82 }
83 }
84 #[allow(dead_code)]
86 pub fn is_base(&self) -> bool {
87 matches!(self, Self::Base { .. })
88 }
89}
90#[allow(dead_code)]
92pub struct WfRelBuilder;
93impl WfRelBuilder {
94 #[allow(dead_code)]
97 pub fn inv_image(r: Expr, f: Expr) -> Expr {
98 Expr::App(
99 Box::new(Expr::App(
100 Box::new(Expr::Const(Name::str("InvImage"), vec![])),
101 Box::new(r),
102 )),
103 Box::new(f),
104 )
105 }
106 #[allow(dead_code)]
108 pub fn prod_lex(r: Expr, s: Expr) -> Expr {
109 Expr::App(
110 Box::new(Expr::App(
111 Box::new(Expr::Const(Name::str("Prod.Lex"), vec![])),
112 Box::new(r),
113 )),
114 Box::new(s),
115 )
116 }
117 #[allow(dead_code)]
119 pub fn nat_lt() -> Expr {
120 Expr::Const(Name::str("Nat.lt"), vec![])
121 }
122 #[allow(dead_code)]
124 pub fn measure(f: Expr) -> Expr {
125 Self::inv_image(Self::nat_lt(), f)
126 }
127}
128#[allow(dead_code)]
130#[derive(Debug, Clone, Copy, PartialEq, Eq)]
131pub enum TerminationStrategy {
132 Structural,
134 Measure,
136 Lexicographic,
138 WellFounded,
140 Mutual,
142}
143impl TerminationStrategy {
144 #[allow(dead_code)]
146 pub fn description(self) -> &'static str {
147 match self {
148 Self::Structural => "Structural recursion on an inductive argument",
149 Self::Measure => "Explicit numeric measure function",
150 Self::Lexicographic => "Lexicographic ordering of multiple arguments",
151 Self::WellFounded => "Custom well-founded relation",
152 Self::Mutual => "Mutual recursion with shared termination argument",
153 }
154 }
155 #[allow(dead_code)]
157 pub fn all() -> &'static [TerminationStrategy] {
158 &[
159 Self::Structural,
160 Self::Measure,
161 Self::Lexicographic,
162 Self::WellFounded,
163 Self::Mutual,
164 ]
165 }
166}
167#[allow(dead_code)]
172#[derive(Debug, Clone)]
173pub struct TerminationCert {
174 pub fn_name: String,
176 pub measure_fn: String,
178 pub justification: String,
180 pub verified: bool,
182}
183impl TerminationCert {
184 #[allow(dead_code)]
186 pub fn new(
187 fn_name: impl Into<String>,
188 measure_fn: impl Into<String>,
189 justification: impl Into<String>,
190 verified: bool,
191 ) -> Self {
192 Self {
193 fn_name: fn_name.into(),
194 measure_fn: measure_fn.into(),
195 justification: justification.into(),
196 verified,
197 }
198 }
199 #[allow(dead_code)]
201 pub fn structural(fn_name: impl Into<String>) -> Self {
202 let nm = fn_name.into();
203 Self {
204 measure_fn: format!("structural_measure_{}", nm),
205 justification: "Structural recursion on an inductive argument".to_owned(),
206 fn_name: nm,
207 verified: true,
208 }
209 }
210 #[allow(dead_code)]
212 pub fn well_founded(fn_name: impl Into<String>, measure_fn: impl Into<String>) -> Self {
213 Self::new(fn_name, measure_fn, "Well-founded recursion", true)
214 }
215 #[allow(dead_code)]
217 pub fn lexicographic(fn_name: impl Into<String>, components: Vec<String>) -> Self {
218 let nm = fn_name.into();
219 let just = format!("Lexicographic order on ({}).", components.join(", "));
220 Self::new(nm.clone(), format!("lex_measure_{}", nm), just, true)
221 }
222 #[allow(dead_code)]
224 pub fn is_valid(&self) -> bool {
225 self.verified && !self.fn_name.is_empty() && !self.measure_fn.is_empty()
226 }
227 #[allow(dead_code)]
229 pub fn summary(&self) -> String {
230 format!(
231 "TerminationCert{{ fn='{}', measure='{}', ok={}, justification='{}' }}",
232 self.fn_name, self.measure_fn, self.verified, self.justification
233 )
234 }
235}
236#[allow(dead_code)]
238#[derive(Debug, Default)]
239pub struct TerminationRegistry {
240 certs: Vec<TerminationCert>,
241}
242impl TerminationRegistry {
243 #[allow(dead_code)]
245 pub fn new() -> Self {
246 Self::default()
247 }
248 #[allow(dead_code)]
250 pub fn register(&mut self, cert: TerminationCert) {
251 self.certs.push(cert);
252 }
253 #[allow(dead_code)]
255 pub fn lookup(&self, fn_name: &str) -> Option<&TerminationCert> {
256 self.certs.iter().find(|c| c.fn_name == fn_name)
257 }
258 #[allow(dead_code)]
260 pub fn verified_certs(&self) -> Vec<&TerminationCert> {
261 self.certs.iter().filter(|c| c.verified).collect()
262 }
263 #[allow(dead_code)]
265 pub fn count(&self) -> usize {
266 self.certs.len()
267 }
268}
269#[allow(dead_code)]
271#[derive(Debug, Clone)]
272pub struct LexOrder {
273 pub components: Vec<String>,
275}
276impl LexOrder {
277 #[allow(dead_code)]
279 pub fn new(components: Vec<impl Into<String>>) -> Self {
280 Self {
281 components: components.into_iter().map(Into::into).collect(),
282 }
283 }
284 #[allow(dead_code)]
286 pub fn push(mut self, component: impl Into<String>) -> Self {
287 self.components.push(component.into());
288 self
289 }
290 #[allow(dead_code)]
292 pub fn arity(&self) -> usize {
293 self.components.len()
294 }
295 #[allow(dead_code)]
297 pub fn type_string(&self) -> String {
298 format!("({})", self.components.join(" × "))
299 }
300 #[allow(dead_code)]
305 pub fn check_decrease(&self, values_before: &[u64], values_after: &[u64]) -> bool {
306 let n = self
307 .components
308 .len()
309 .min(values_before.len())
310 .min(values_after.len());
311 for i in 0..n {
312 if values_before[i] < values_after[i] {
313 return false;
314 }
315 if values_before[i] > values_after[i] {
316 return true;
317 }
318 }
319 false
320 }
321}