use super::functions::*;
use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct SizeMeasure {
pub name: String,
pub domain: String,
}
impl SizeMeasure {
#[allow(dead_code)]
pub fn new(name: impl Into<String>, domain: impl Into<String>) -> Self {
Self {
name: name.into(),
domain: domain.into(),
}
}
#[allow(dead_code)]
pub fn list_length() -> Self {
Self::new("List.length", "List")
}
#[allow(dead_code)]
pub fn nat_id() -> Self {
Self::new("id", "Nat")
}
#[allow(dead_code)]
pub fn tree_size() -> Self {
Self::new("Tree.size", "Tree")
}
#[allow(dead_code)]
pub fn induced_relation_name(&self) -> String {
format!("InvImage.lt_{}", self.name.replace('.', "_"))
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub enum RecursionTree {
Base { label: String },
Rec {
label: String,
decreasing_arg: String,
child: Box<RecursionTree>,
},
Branch {
label: String,
arms: Vec<RecursionTree>,
},
}
impl RecursionTree {
#[allow(dead_code)]
pub fn depth(&self) -> usize {
match self {
Self::Base { .. } => 0,
Self::Rec { child, .. } => 1 + child.depth(),
Self::Branch { arms, .. } => arms.iter().map(|a| a.depth()).max().unwrap_or(0),
}
}
#[allow(dead_code)]
pub fn recursive_calls(&self) -> usize {
match self {
Self::Base { .. } => 0,
Self::Rec { child, .. } => 1 + child.recursive_calls(),
Self::Branch { arms, .. } => arms.iter().map(|a| a.recursive_calls()).sum(),
}
}
#[allow(dead_code)]
pub fn is_base(&self) -> bool {
matches!(self, Self::Base { .. })
}
}
#[allow(dead_code)]
pub struct WfRelBuilder;
impl WfRelBuilder {
#[allow(dead_code)]
pub fn inv_image(r: Expr, f: Expr) -> Expr {
Expr::App(
Box::new(Expr::App(
Box::new(Expr::Const(Name::str("InvImage"), vec![])),
Box::new(r),
)),
Box::new(f),
)
}
#[allow(dead_code)]
pub fn prod_lex(r: Expr, s: Expr) -> Expr {
Expr::App(
Box::new(Expr::App(
Box::new(Expr::Const(Name::str("Prod.Lex"), vec![])),
Box::new(r),
)),
Box::new(s),
)
}
#[allow(dead_code)]
pub fn nat_lt() -> Expr {
Expr::Const(Name::str("Nat.lt"), vec![])
}
#[allow(dead_code)]
pub fn measure(f: Expr) -> Expr {
Self::inv_image(Self::nat_lt(), f)
}
}
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TerminationStrategy {
Structural,
Measure,
Lexicographic,
WellFounded,
Mutual,
}
impl TerminationStrategy {
#[allow(dead_code)]
pub fn description(self) -> &'static str {
match self {
Self::Structural => "Structural recursion on an inductive argument",
Self::Measure => "Explicit numeric measure function",
Self::Lexicographic => "Lexicographic ordering of multiple arguments",
Self::WellFounded => "Custom well-founded relation",
Self::Mutual => "Mutual recursion with shared termination argument",
}
}
#[allow(dead_code)]
pub fn all() -> &'static [TerminationStrategy] {
&[
Self::Structural,
Self::Measure,
Self::Lexicographic,
Self::WellFounded,
Self::Mutual,
]
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct TerminationCert {
pub fn_name: String,
pub measure_fn: String,
pub justification: String,
pub verified: bool,
}
impl TerminationCert {
#[allow(dead_code)]
pub fn new(
fn_name: impl Into<String>,
measure_fn: impl Into<String>,
justification: impl Into<String>,
verified: bool,
) -> Self {
Self {
fn_name: fn_name.into(),
measure_fn: measure_fn.into(),
justification: justification.into(),
verified,
}
}
#[allow(dead_code)]
pub fn structural(fn_name: impl Into<String>) -> Self {
let nm = fn_name.into();
Self {
measure_fn: format!("structural_measure_{}", nm),
justification: "Structural recursion on an inductive argument".to_owned(),
fn_name: nm,
verified: true,
}
}
#[allow(dead_code)]
pub fn well_founded(fn_name: impl Into<String>, measure_fn: impl Into<String>) -> Self {
Self::new(fn_name, measure_fn, "Well-founded recursion", true)
}
#[allow(dead_code)]
pub fn lexicographic(fn_name: impl Into<String>, components: Vec<String>) -> Self {
let nm = fn_name.into();
let just = format!("Lexicographic order on ({}).", components.join(", "));
Self::new(nm.clone(), format!("lex_measure_{}", nm), just, true)
}
#[allow(dead_code)]
pub fn is_valid(&self) -> bool {
self.verified && !self.fn_name.is_empty() && !self.measure_fn.is_empty()
}
#[allow(dead_code)]
pub fn summary(&self) -> String {
format!(
"TerminationCert{{ fn='{}', measure='{}', ok={}, justification='{}' }}",
self.fn_name, self.measure_fn, self.verified, self.justification
)
}
}
#[allow(dead_code)]
#[derive(Debug, Default)]
pub struct TerminationRegistry {
certs: Vec<TerminationCert>,
}
impl TerminationRegistry {
#[allow(dead_code)]
pub fn new() -> Self {
Self::default()
}
#[allow(dead_code)]
pub fn register(&mut self, cert: TerminationCert) {
self.certs.push(cert);
}
#[allow(dead_code)]
pub fn lookup(&self, fn_name: &str) -> Option<&TerminationCert> {
self.certs.iter().find(|c| c.fn_name == fn_name)
}
#[allow(dead_code)]
pub fn verified_certs(&self) -> Vec<&TerminationCert> {
self.certs.iter().filter(|c| c.verified).collect()
}
#[allow(dead_code)]
pub fn count(&self) -> usize {
self.certs.len()
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct LexOrder {
pub components: Vec<String>,
}
impl LexOrder {
#[allow(dead_code)]
pub fn new(components: Vec<impl Into<String>>) -> Self {
Self {
components: components.into_iter().map(Into::into).collect(),
}
}
#[allow(dead_code)]
pub fn push(mut self, component: impl Into<String>) -> Self {
self.components.push(component.into());
self
}
#[allow(dead_code)]
pub fn arity(&self) -> usize {
self.components.len()
}
#[allow(dead_code)]
pub fn type_string(&self) -> String {
format!("({})", self.components.join(" × "))
}
#[allow(dead_code)]
pub fn check_decrease(&self, values_before: &[u64], values_after: &[u64]) -> bool {
let n = self
.components
.len()
.min(values_before.len())
.min(values_after.len());
for i in 0..n {
if values_before[i] < values_after[i] {
return false;
}
if values_before[i] > values_after[i] {
return true;
}
}
false
}
}