Zulip Chat Archive
Stream: general
Topic: trying to define sizes of trees
Frederick Pu (Dec 14 2024 at 21:36):
Can someone please explain why I can define size for this kind of tree:
inductive Tree
| mk (val : Nat) (children : List Tree)
def Tree.size : Tree → Nat
| mk val [] => 1
| mk val (a::l) => a.size + (mk val l).size
but not for the below kind?
protected inductive ComputedAutoDiffTree.DiffTree (α : Type u) (β : Type v) : List Nat → Type (max u v)
| mk
{outShape : List Nat}
(parents : List (Σ shape, ComputedAutoDiffTree.DiffTree α β shape))
(saved_tensors : Σ shapes, ShapedVector (DualTensor α β) shapes)
(ctx : Σ shapes, EFunction α β shapes outShape)
(tensor : DualTensor α β outShape)
: ComputedAutoDiffTree.DiffTree α β outShape
protected def ComputedAutoDiffTree.DiffTree.size {α : Type u} {β : Type v} {shape : List Nat} : ComputedAutoDiffTree.DiffTree α β shape → Nat
| mk [] _ _ _ => 0
| mk (a::l) x y z => a.2.size + (mk l x y z).size
/-
fail to show termination for
ComputedAutoDiffTree.DiffTree.size
with errors
failed to infer structural recursion:
Not considering parameter α of ComputedAutoDiffTree.DiffTree.size:
it is unchanged in the recursive calls
Not considering parameter β of ComputedAutoDiffTree.DiffTree.size:
it is unchanged in the recursive calls
Cannot use parameter #4:
failed to eliminate recursive application
(mk l x y z).size
Cannot use parameter shape:
failed to eliminate recursive application
a.snd.size
Could not find a decreasing measure.
The arguments relate at each recursive call as follows:
(<, ≤, =: relation proved, ? all proofs failed, _: no proof attempted)
shape #1
1) 145:21-29 ? ?
2) 145:32-49 _ _
#1: sizeOf x2
Please use `termination_by` to specify a decreasing measure.
-/
Kyle Miller (Dec 14 2024 at 22:38):
I'll take a look, but something I'd like to point out is that Lean now supports recursive structures. Here's using that along with a relatively clean way to define Tree.size, where you don't need to re-build a Tree with a synthetic node during recursion:
structure Tree where
val : Nat
children : List Tree
mutual
def Tree.size : Tree → Nat
| { children, .. } => Tree.sizeAux children
def Tree.sizeAux : List Tree → Nat
| [] => 1
| x :: xs => x.size + Tree.sizeAux xs
end
Kyle Miller (Dec 14 2024 at 22:38):
Ah, your example isn't a #mwe, which would make it easier to help
Kyle Miller (Dec 14 2024 at 22:39):
Maybe this mutual suggestion might help you?
Frederick Pu (Dec 14 2024 at 23:06):
i think this is mwe:
protected inductive ComputedAutoDiffTree.DiffTree (α : Type u) (β : Type v) : List Nat → Type (max u v)
| mk
(outShape : List Nat)
(parents : List (Σ shape, ComputedAutoDiffTree.DiffTree α β shape))
: ComputedAutoDiffTree.DiffTree α β outShape
protected def ComputedAutoDiffTree.DiffTree.size {α : Type u} {β : Type v} {shape : List Nat} : ComputedAutoDiffTree.DiffTree α β shape → Nat
| mk x [] => 0
| mk x (a::l) => a.2.size + (mk x l).size
/-
fail to show termination for
ComputedAutoDiffTree.DiffTree.size
with errors
failed to infer structural recursion:
Not considering parameter α of ComputedAutoDiffTree.DiffTree.size:
it is unchanged in the recursive calls
Not considering parameter β of ComputedAutoDiffTree.DiffTree.size:
it is unchanged in the recursive calls
Cannot use parameter #4:
failed to eliminate recursive application
(mk x l).size
Cannot use parameter shape:
failed to eliminate recursive application
a.snd.size
-/
Kyle Miller (Dec 14 2024 at 23:12):
This seems to work:
protected def ComputedAutoDiffTree.DiffTree.size {α : Type u} {β : Type v} {shape : List Nat}
(t : ComputedAutoDiffTree.DiffTree α β shape) : Nat :=
match t with
| mk x [] => 0
| mk x (a::l) =>
have : sizeOf a.snd < 1 + sizeOf x + (1 + sizeOf a + sizeOf l) := by
cases a
simp
omega
a.2.size + (mk x l).size
termination_by sizeOf t
I guess the complexity is that Lean isn't able to automatically see that that a.2 is smaller in the recursive call.
Kyle Miller (Dec 14 2024 at 23:12):
(I got this have line by adding the termination_by then reading the error message.)
Frederick Pu (Dec 14 2024 at 23:14):
what is sizeOf?
Frederick Pu (Dec 14 2024 at 23:15):
cause isnt a.snd a DiffTree, so the type class instance wouldnt be defined yet right?
Kyle Miller (Dec 14 2024 at 23:20):
There's a SizeOf instance defined by inductive/structure whenever they're defining recursive types, and it provides this sizeOf function.
Frederick Pu (Dec 14 2024 at 23:22):
so how would i generalize this to the original type?
Frederick Pu (Dec 14 2024 at 23:26):
like im thinking about smth like
protected def ComputedAutoDiffTree.DiffTree.size {α : Type u} {β : Type v} {shape : List Nat} : ComputedAutoDiffTree.DiffTree α β shape → Nat
| mk [] _ _ _ => 0
| mk (a::l) x y z =>
have : sizeOf a.snd < 1 + (1 + sizeOf a + sizeOf l) + sizeOf x.snd + sizeOf y.snd + sizeOf z := by
cases x
cases y
cases z
simp
omega
a.2.size + (mk l x y z).size
termination_by
t => sizeOf t
but im not too sure what the motivation for the original solution was
Kyle Miller (Dec 14 2024 at 23:31):
That seems sensible — are you running into any issue?
Frederick Pu (Dec 14 2024 at 23:31):
nvm im slow ur supposed to do cases on a
protected def ComputedAutoDiffTree.DiffTree.size {α : Type u} {β : Type v} {shape : List Nat} : ComputedAutoDiffTree.DiffTree α β shape → Nat
| mk [] _ _ _ => 0
| mk (a::l) x y z =>
have : sizeOf a.snd < 1 + (1 + sizeOf a + sizeOf l + sizeOf x + sizeOf y + sizeOf z) := by
cases a
simp
omega
a.2.size + (mk l x y z).size
termination_by
x => sizeOf x
Frederick Pu (Dec 14 2024 at 23:32):
im still confused for what the intuition is tho
Kyle Miller (Dec 14 2024 at 23:32):
I did cases so that sizeOf a.snd would simplify
Kyle Miller (Dec 14 2024 at 23:32):
and so that sizeOf a would expand
Kyle Miller (Dec 14 2024 at 23:32):
omega doesn't know any relationship between sizeOf a.snd and sizeOf a, so it was to help it out.
Frederick Pu (Dec 14 2024 at 23:33):
no like why is that specific hypothesis enough to convince termination_by
Kyle Miller (Dec 14 2024 at 23:34):
Kyle Miller said:
(I got this
haveline by adding thetermination_bythen reading the error message.)
I copied it from the error message
Kyle Miller (Dec 14 2024 at 23:34):
I didn't think hard about it.
Frederick Pu (Dec 14 2024 at 23:35):
oh lol
Frederick Pu (Dec 14 2024 at 23:35):
sorry i just had exams so im legit room temp iq rn
Kyle Miller (Dec 14 2024 at 23:36):
It looks like the way it's working is that you take the sum of the sizeOf the arguments to ComputedAutoDiffTree.DiffTree.size, and if that's greater than sizeOf the recursive call to the function with a.snd, then it's able to argue the function terminates.
Kyle Miller (Dec 14 2024 at 23:37):
(And by "able to argue" that actually means "able to construct some term that implements the recursive function". If you #print the function you'll likely see some Nat.brecOn that's implementing the recursion.)
Frederick Pu (Dec 14 2024 at 23:44):
whats brecOn?
Frederick Pu (Dec 15 2024 at 04:15):
would you happen to know why rfl isn't working in this case?
protected inductive ComputedAutoDiffTree.DiffTree (α : Type u) (β : Type v) : List Nat → Type (max u v)
| mk : ComputedAutoDiffTree.DiffTree α β outShape
protected def ComputedAutoDiffTree.DiffTree.valid {α : Type u} {β : Type v} {shape : List Nat} : ComputedAutoDiffTree.DiffTree α β shape → Prop :=
fun x => True
protected inductive AutoDiffTree.DiffTree (α : Type u) (β : Type v) : List Nat → Type (max u v)
| mk
(outShape : List Nat)
(parents : Array (Σ shape, AutoDiffTree.DiffTree α β shape))
: AutoDiffTree.DiffTree α β outShape
| ofComputed {shape : List Nat}: ComputedAutoDiffTree.DiffTree α β shape → AutoDiffTree.DiffTree α β shape
def AutoDiffTree.DiffTree.valid {α : Type u} {β : Type v} {shape : List Nat} : AutoDiffTree.DiffTree α β shape → Prop
| mk _ #[] => True
| ofComputed computedTree => computedTree.valid
| mk _ parents => ∀ x ∈ parents, x.2.valid
termination_by
t => sizeOf t
decreasing_by
have : sizeOf x < sizeOf parents := Array.sizeOf_lt_of_mem (by assumption)
cases x
simp
simp at this
omega
example {α : Type u} {β : Type v} {shape : List Nat} (x : ComputedAutoDiffTree.DiffTree α β shape) : (AutoDiffTree.DiffTree.ofComputed x).valid = x.valid :=
rfl
/-
type mismatch
rfl
has type
?m.4183 = ?m.4183 : Prop
but is expected to have type
(AutoDiffTree.DiffTree.ofComputed x).valid = x.valid : Prop
-/
Last updated: May 02 2025 at 03:31 UTC