Zulip Chat Archive
Stream: lean4
Topic: Newcomer question about termination proof
Youngju Song (Aug 23 2024 at 03:28):
Hi,
I am coming from Coq and have just started playing with Lean.
I have trouble proving the following example, even after some Googling:
inductive Tree :=
| Leaf (v: Int)
| Node (ts: List Tree)
def map (f: Int → Int): Tree → Tree := λ tr =>
match tr with
| .Leaf v => .Leaf (f v)
| .Node ts => .Node (List.map (map f) ts)
termination_by tr => tr._sizeOf_1
decreasing_by
. simp [InvImage]
sorry -- How can I get some relation between `ts` and `a✝`?
Can someone help me with this? Thank you in advance :)
Daniel Weber (Aug 23 2024 at 04:28):
In general when you have a decreasing_by
proof you should start it with simp_wf
. It's also better to use sizeOf
instead of directly accessing ._sizeOf_1
. You also don't need to give the termination_by
, the size is used by default
Daniel Weber (Aug 23 2024 at 04:28):
you can use ts.attach
to keep a membership proof attached to the elements
inductive Tree :=
| Leaf (v: Int)
| Node (ts: List Tree)
def map (f: Int → Int): Tree → Tree := λ tr =>
match tr with
| .Leaf v => .Leaf (f v)
| .Node ts => .Node (ts.attach.map (fun x ↦ map f x.1))
decreasing_by
simp_wf
have := List.sizeOf_lt_of_mem x.2
omega
Daniel Weber (Aug 23 2024 at 04:31):
Note that there is syntactic sugar for a function which is just a match
, so you can do this:
inductive Tree :=
| Leaf (v: Int)
| Node (ts: List Tree)
def map (f: Int → Int): Tree → Tree
| .Leaf v => .Leaf (f v)
| .Node ts => .Node (ts.attach.map (fun x ↦ map f x.1))
decreasing_by
simp_wf
have := List.sizeOf_lt_of_mem x.2
omega
Youngju Song (Aug 23 2024 at 04:49):
@Daniel Weber Thank you for the answer and advices! This is quite different from Coq and very interesting.
Youngju Song (Aug 23 2024 at 05:29):
@Daniel Weber I have one follow up question:
- Is there a systematic way to figure out the definitions that are "derived" from
inductive Tree := ...
? - I have tried this
def Tree.size (tr: Tree): Nat := sizeOf tr
and, apparently,sizeOf
function is non-computable. Reading the comments forSizeOf
typeclass, I am curious if there is a fundamental issue in making this computable. Do you have any idea? (I understand that for "large" types,sizeOf
just returns the default (1), but it is s till computable)
Kim Morrison (Aug 23 2024 at 05:55):
Rather than dealing with decreasing_by
in every function on Tree
, it's nice to set up an appropriate measure first:
inductive Tree :=
| Leaf (v: Int)
| Node (ts: List Tree)
namespace Tree
def height : Tree → Nat
| Leaf _ => 0
| Node ts => (ts.attach.map (fun x => height x.1)).maximum?.getD 0 + 1
decreasing_by
simp_wf
have := List.sizeOf_lt_of_mem x.2
omega
theorem height_lt : ∀ {t: Tree} {ts: List Tree}, t ∈ ts → height t < height (Node ts) := by
intro t ts h
simp only [height]
sorry
def map (f: Int → Int): Tree → Tree
| .Leaf v => .Leaf (f v)
| .Node ts => .Node (ts.attach.map (fun x => have := height_lt x.2; map f x.1))
termination_by t => height t
end Tree
Kim Morrison (Aug 23 2024 at 05:55):
(sorry
left as an exercise :-)
Youngju Song (Aug 27 2024 at 00:07):
@Kim Morrison Thank you for the suggestion and the template code! I was able to prove it as follows:
theorem height_lt : ∀ {t: Tree} {ts: List Tree}, t ∈ ts → height t < height (Node ts) := by
intro t ts h
simp only [height]
rw [@Nat.lt_succ]
rw [@List.attach_map_coe]
generalize H : (List.map height ts).maximum? = tmp
cases tmp with
| none =>
simp_all
| some x =>
simp_all
rw [List.maximum?_eq_some_iff'] at H
cases H with
| _ A B =>
apply B
apply List.mem_map_of_mem height
assumption
Do you have any advice on making this proof more concise? Specifically, I wonder if there is a shorthand for (i) successive generalize
and cases
, and (ii) cases H with | _ A B =>
. In Coq, (i) is done in a single destruct
tactic, and (ii) is done with destruct H as [A B]
.
Kim Morrison (Aug 27 2024 at 02:36):
(i) you can just write match H : (List.map height ts).maximum? with
Kim Morrison (Aug 27 2024 at 02:36):
(ii) you might like rcases
Youngju Song (Aug 28 2024 at 00:25):
@Kim Morrison That works well. Thank you for the advice!
Last updated: May 02 2025 at 03:31 UTC