leanprover / leanprover/lean4

Missing property required to prove termination when using decreasing_by

Open
#14,496 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Lean
Stars
9.2k
Forks
990
Avg merge
1d 17h
Merged PRs (30d)
175

Description

Prerequisites
Description

Some inductive types have missing properties for proving termination in certain functions . The code below shows two functions defined for an inductive type. Both functions use recursion in the same way, and require manual termination proofs. For some reason, the second function has a missing property which makes it impossible to prove termination.

inductive Typ where
  | int 
  | rcrd (fields : List (Typ × String))

def Typ.size : Typ → Nat
  | .int => 1
  | .rcrd fields => 
    fields.foldl (· + ·.fst.size) 0
decreasing_by
  induction fields
  · grind
  · grind 

def Typ.simplify : Typ → Typ
  | .int => .int
  | .rcrd fields =>
    .rcrd (fields.map (·.map (·.simplify) (id)))
decreasing_by
  induction fields
  · grind
  · -- Impossible due to missing property : x✝ = x✝¹.1
Steps to Reproduce
  1. Paste the code above into the lean4 nightly playground

Expected behavior: Possible to prove termination for both functions.

Actual behavior: Missing property for the second function makes termination proof impossible.

Versions

Version: "4.34.0, commit 3259610687883ec1ea48c481aba2469f2f83facf"

Additional Information

This issue is also observed when using Sum instead of Prod in the inductive type. Likewise, the example below might be related and has an interesting solution which unfortunately does not work for the list case:

inductive Typ2 where
  | int 
  | rcrd (hd : Typ2 × String) (fields : List (Typ2 × String))
deriving Inhabited

def Typ2.size : Typ2 → Nat
  | .int => 1
  | .rcrd hd fields => 
    fields.foldl (· + ·.fst.size) hd.fst.size
decreasing_by
  induction fields
  · grind
  · grind 
  grind

def Typ2.simplify : Typ2 → Typ2
  | .int => .int
  | .rcrd hd fields =>
    .rcrd (hd.map (·.simplify) (id)) (fields.map (·.map (·.simplify) (id)))
decreasing_by
  · grind -- Impossible due to missing property : x✝ = hd.1
  · grind -- Impossible due to missing property : x✝ = x✝¹.1

def Typ2.simplify2 : Typ2 → Typ2
  | .int => .int
  | .rcrd ⟨tp, name⟩ fields =>
    .rcrd ⟨tp.simplify2, name⟩ (fields.map (·.map (·.simplify2) (id)))
decreasing_by
  · grind -- Now possible
  · grind -- Impossible due to missing property : x✝ = x✝¹.1

def Typ2.simplify3 : Typ2 → Typ2
  | .int => .int
  | .rcrd ⟨tp, name⟩ fields =>
    .rcrd ⟨tp.simplify3, name⟩ (fields.map (fun ⟨tp, name⟩ => ⟨tp.simplify3, name⟩ ))
decreasing_by
  · grind -- Now possible
  · grind -- Still Impossible due to missing property : tp = x✝.1

def Typ2.simplify4 : Typ2 → Typ2
  | .int => .int
  | .rcrd ⟨tp, name⟩ [] => .rcrd ⟨tp.simplify4, name⟩ []
  | .rcrd hd (⟨tp1,name1⟩::xs) =>
    match (Typ2.rcrd hd xs).simplify4 with
    | .rcrd hd fields => .rcrd hd (⟨tp1.simplify, name1⟩::fields)
    | _ => panic! "Unreachable"
  decreasing_by
  · grind -- Now possible
  · grind -- Now possible

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the minimal Typ.simplify example in the Lean nightly playground, then compare its decreasing_by obligations with Typ.size and the working Typ2 variants. Trace how termination obligations are generated for recursive calls under List.map and product projections. Done means the reported missing equality property is available so the supplied termination proofs succeed.

Written by the indexing model from the issue text.

Assessment

Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.