Zulip Chat Archive

Stream: new members

Topic: Stuck on trying to prove termination


Anders Larsson (Jun 24 2024 at 18:40):

Is it possible to prove termination to this (overflow prone) function? (The example is derived from some https://github.com/AeneasVerif/aeneas translated Rust code, but this beginner question is about termination).

import Mathlib.Data.Nat.Factorial.Basic
open Nat

def fac (n: UInt8): UInt64 :=
match n.toNat with
| zero => 1
| succ x => n.toUInt64 * fac x.toUInt8

termination_by n.toNat

decreasing_by
  simp_wf
/-  n: UInt8
    x: ℕ
    ⊢ x.toUInt8.toNat < n.toNat
-/
  admit

Kyle Miller (Jun 24 2024 at 19:18):

Here's it partially done:

theorem Nat.toNat_toUInt8 (x : Nat) : x.toUInt8.toNat  x := by
  sorry

def fac (n : UInt8) : UInt64 :=
  match h : n.toNat with
  | .zero => 1
  | .succ x => n.toUInt64 * fac x.toUInt8
termination_by n.toNat
decreasing_by
  simp_wf
  calc
    x.toUInt8.toNat  x := Nat.toNat_toUInt8 x
    _ < x.succ := Nat.lt_add_one x
    _ = n.toNat := h.symm

Kyle Miller (Jun 24 2024 at 19:19):

And a proof of the first fact:

theorem Nat.toNat_toUInt8 (x : Nat) : x.toUInt8.toNat  x := by
  simp only [UInt8.toNat, Nat.toUInt8, UInt8.ofNat, Fin.ofNat]
  exact Nat.mod_le x 256

Anders Larsson (Jun 24 2024 at 19:24):

Nice, collecting more information with:

match h :

made all the difference!

Pieter Cuijpers (Jan 09 2025 at 17:05):

I also have a problem on the same topic.
The code below sketches how I would like the main proof to go.
The real theorem is a bit more complicated, but follows the same scheme.

inductive closure (R : α  α  Prop) : α  α  Prop where
| init (_ : R a b) : closure R a b
| step (_ : closure R a b) (_ : closure R b c) : closure R a c

theorem first_step {R : α  α  Prop} : closure R a b  R a b   c, R a c  closure R c b := by
  intro h
  cases h with
  | init h1 => left; exact h1
  | step h1 h2 =>
    rename_i x; right
    have h_induction := first_step h1
    cases h_induction with
    | inl => exists x
    | inr h3 =>
      obtain c, hc := h3
      exists c
      simp_all
      exact closure.step hc.right h2

The trick now would be to add:

termination_by h => ???
decreasing_by sorry

which I do not know how to set up.
Any help would be appreciated.

Edward van de Meent (Jan 09 2025 at 17:18):

yea, that's not going to work, i think... There's no way you're going to be able to define a measure for this. Instead, i think you're going to need to use the induction tactic

Pieter Cuijpers (Jan 09 2025 at 23:29):

Thanks... indeed, this is what I found, and it works.

theorem first_step {R : α  α  Prop} : closure R a b  R a b   c, R a c  closure R c b := by
  intro h
  induction h with
  | init h1 => left; exact h1
  | step h1 h2 =>
    rename_i x y z i1 i2
    right
    cases i1
    · exists y
    · rename_i h3
      obtain c,hc := h3
      exists c
      simp_all
      exact closure.step hc.right h2

Last updated: May 02 2025 at 03:31 UTC