Zulip Chat Archive

Stream: new members

Topic: termination of recursive def


An Qi Zhang (Jun 10 2025 at 03:04):

Hello! I've setup some definitions where I have a Set s, and state that the elements of s have an immediate predecessor (i.e. there's a total order). Now I've written a def, let's call it recDef that makes use of the predecessor pred of an element and pred's predecessor pred_pred, that's recursively defined. Now Lean asks to show this def recDef terminates.

I'm not sure how to produce the proof term lean wants to show recDef terminates, or if there are better ways to defining recDef. Perhaps if there's a way to first convert Set s to a List using the predecessor relation, then recursion on a List would be easier to prove termination of?

Here's a MWE to illustrate:

import Mathlib.Data.Set.Defs
import Mathlib.Data.Set.Subsingleton

abbrev SetNat := Set Nat

def SetNat.intermediatePredecessor : SetNat  Nat  Nat  SetNat
| sn, n, n_pred => {n_intermediate  sn | n_pred < n_intermediate  n_intermediate < n}

def SetNat.noIntermediatePredecessor : SetNat  Nat  Nat  Prop
| sn, n, n_pred => sn.intermediatePredecessor n n_pred = 

def Nat.predecessor (n_pred n : Nat) : Prop := n_pred < n

def SetNat.predecessors : SetNat  Nat  SetNat
| sn, n => {n_pred  sn | n_pred.predecessor n}

def SetNat.immediatePredecessors : SetNat  Nat  SetNat
| sn, n => let predecessors := sn.predecessors n
  {n_pred  predecessors | predecessors.noIntermediatePredecessor n n_pred}

def SetNat.predecessorsSubSingleton (sn : SetNat) (n : Nat) : Prop := (sn.immediatePredecessors n).Subsingleton

structure SetNat.predSubSingleton where
  subs :  sn : SetNat,  n : Nat, SetNat.predecessorsSubSingleton sn n

noncomputable def SetNat.pred (sn : SetNat) (n : Nat) (hsn_sub : SetNat.predSubSingleton) : Option Nat :=
  let preds := sn.immediatePredecessors n
  open scoped Classical in
  if h : preds =  then
    none
  else
    have hsubsingle := hsn_sub.subs sn n
    have hempty_or_single := hsubsingle.eq_empty_or_singleton
    some (hempty_or_single.resolve_left h).choose

def Nat.irrelevantRelation (n₁ n₂ : Nat) : Nat := n₁/n₂ + n₂/n₁

/- How do I show lean this terminates? -/
noncomputable def SetNat.predPred (sn : SetNat) (n : Nat) (hsn_sub : SetNat.predSubSingleton) : Option Nat :=
  let pred? := sn.pred n hsn_sub
  match h : pred? with
  | .none => none
  | .some n_pred =>
    have n_pred_of_n : n_pred < n := by
      simp_all [SetNat.pred] -- can't unfold `pred?`, that specifies `n_pred < n` in it's `predecessor` def.
      sorry
    let pred_pred? := sn.predPred n_pred hsn_sub
    match pred_pred? with
    | .none => n_pred
    | .some n_pred_pred => n_pred.irrelevantRelation n_pred_pred
-- termination_by sizeOf (sn.predecessors n)

/- Is it easier to convert SetNat to a list where each element is ordered by SetNat.pred?
Is there a way to convert a Set to a List given an ordering `Prop` such as Nat.predecessor or something like SetNat.immediatePredecessors? -/
def SetNat.toList (sn : SetNat) : List Nat :=
  sorry

Robin Arnez (Jun 12 2025 at 16:11):

Is simp_all +zetaDelta what you want here?

Robin Arnez (Jun 12 2025 at 16:17):

(note: zetaDelta means simp is allowed to unfold let declarations)


Last updated: Dec 20 2025 at 21:32 UTC