Zulip Chat Archive
Stream: lean4
Topic: Structural recursion
Sofia (Nov 06 2021 at 13:39):
Hey again. I'm having an issue with structural recursion. Any hints?
The depth
function is structurally recursive in the 4th argument, the surface. Yet the errors pretend the 4th doesn't exist. Is there some class I need to implement or something?
inductive Surface
| Unresolved
| Inside
| Outside
| Ambiguious (inner : Array Surface)
instance : Inhabited Surface := ⟨Surface.Unresolved⟩
def depth (x y d : Nat) : Surface -> Nat
| Surface.Ambiguious a => depth (y >>> 1) x (d + 1) (a.get! y)
| _ => d
: error: fail to show termination for
depth
with errors
argument #1 was not used for structural recursion
failed to eliminate recursive application
depth (y >>> 1) x (d + 1) (Array.get! a y)
argument #2 was not used for structural recursion
failed to eliminate recursive application
depth (y >>> 1) x (d + 1) (Array.get! a y)
argument #3 was not used for structural recursion
failed to eliminate recursive application
depth (y >>> 1) x (d + 1) (Array.get! a y)
structural recursion cannot be used
'termination_by' modifier missing
Sofia (Nov 06 2021 at 14:05):
Tried inlining the array (for a fixed length) as Ambiguious (a b c d e f g h : Surface)
, no luck. Doesn't change the result.
Sofia (Nov 06 2021 at 14:06):
Inlining as in, matching on x directly, then selecting the variant... Guess I can do that in the top level match maybe?
Sofia (Nov 06 2021 at 14:08):
The hack worked. But ... obviously undesired.
def depth : Nat -> Nat -> Nat -> Surface -> Nat
| 0, y, q, Surface.Ambiguious a b c d e f g h => depth (y >>> 1) 0 (q + 1) a
| 1, y, q, Surface.Ambiguious a b c d e f g h => depth (y >>> 1) 1 (q + 1) b
| 2, y, q, Surface.Ambiguious a b c d e f g h => depth (y >>> 1) 2 (q + 1) c
| 3, y, q, Surface.Ambiguious a b c d e f g h => depth (y >>> 1) 3 (q + 1) d
| 4, y, q, Surface.Ambiguious a b c d e f g h => depth (y >>> 1) 4 (q + 1) e
| 5, y, q, Surface.Ambiguious a b c d e f g h => depth (y >>> 1) 5 (q + 1) f
| 6, y, q, Surface.Ambiguious a b c d e f g h => depth (y >>> 1) 6 (q + 1) g
| 7, y, q, Surface.Ambiguious a b c d e f g h => depth (y >>> 1) 7 (q + 1) h
| _, _, q, _ => q
Sofia (Nov 06 2021 at 14:10):
Reverting and trying that trick with the original code, no dice.
def depth : Nat -> Nat -> Nat -> Surface -> Nat
| x, y, d, Surface.Ambiguious a => depth (y >>> 1) x (d + 1) (a.get! y)
| _, _, d, _ => d
Sofia (Nov 06 2021 at 14:11):
Suspect it might relate to the use of a.get!
because the inhabited case is not structurally recursive, but it is a constant and that constant terminates....
Sebastian Ullrich (Nov 06 2021 at 15:35):
Recursion through arrays is not structural in Lean's sense - a.get! y
is not a strict subterm of the parameter's pattern. But well-founded recursion is simple enough here.
termination_by sizeOfWfRel
Sofia (Nov 06 2021 at 16:03):
I do not see sizeOfWfRel
anywhere. Is that a hint to implement it?
Sofia (Nov 06 2021 at 16:07):
Ah, it is capital F. Case sensitive search!
Sofia (Nov 06 2021 at 16:08):
Can confirm it worked. Thanks. :)
Magic trick aside, I already scratched that code. Was just testing anyway.
Sebastian Ullrich (Nov 06 2021 at 22:26):
Sebastian Ullrich said:
Recursion through arrays is not structural in Lean's sense -
a.get! y
is not a strict subterm of the parameter's pattern. But well-founded recursion is simple enough here.termination_by sizeOfWfRel
Sorry, I didn't know what parts of wellfounded recursion were finished and which weren't. This will need an explicit decreasing_by
proof, and I've made sure that it will fail properly without one from now on.
Sofia (Nov 07 2021 at 14:00):
Huh? No. The termination_by sizeOfWFRel
sufficed.
Sofia (Nov 07 2021 at 14:04):
def depth (x y d : Nat) : Surface -> Nat
| Surface.Ambiguious a => depth y x (d + 1) (a.get! y)
| Surface.Unresolved => d + 1
| _ => d
termination_by sizeOfWFRel
Sebastian Ullrich (Nov 07 2021 at 14:08):
Not really, it was defaulting to admit
Sofia (Nov 07 2021 at 15:20):
I don't know what that means.
Sebastian Ullrich (Nov 07 2021 at 15:28):
It was equivalent to
decreasing_by exact sorry
i.e. it did not actually prove wellfoundedness
Sebastian Ullrich (Nov 07 2021 at 15:29):
Just checking, do you know about partial
in case you do not want to prove something about this function?
Sofia (Nov 07 2021 at 15:31):
I know I can use partial; but my understanding is that colours the function so it cannot be used from total functions?
Sebastian Ullrich (Nov 07 2021 at 15:34):
No, you simply cannot unfold it in proofs
Sofia (Nov 07 2021 at 15:34):
If it was equivalent to such a sorry proof, why do I not see any errors and I'm able to run the program?
Sofia (Nov 07 2021 at 15:34):
Hmm. Okay. I guess this is related to how assert! and panic! exist at all?
Sebastian Ullrich (Nov 07 2021 at 15:36):
Yes, all three require Inhabited
Sofia (Nov 07 2021 at 15:41):
Ah, I see. Explains the no proving false part trivially. :D
Sofia (Nov 07 2021 at 15:41):
Noted, partial functions are not scary. Just more difficult to prove.
Sofia (Nov 07 2021 at 15:43):
How did you see it failed? I see no errors when using the sorry in the proof.
Sebastian Ullrich (Nov 07 2021 at 15:46):
The point of sorry
is to accept an incomplete proof (with a warning when used explicitly). #print axiom depth
before the fix would show that the definition depends on the sorryAx
axiom.
Sofia (Nov 07 2021 at 15:47):
I get this when I try that print?
././Main.lean:112:7: error: expected 'axioms', identifier or string literal
././Main.lean:113:0: error: expected ':'
././Main.lean:113:4: error: 'depth' has already been declared
Sebastian Ullrich (Nov 07 2021 at 15:58):
Yes, please apply the spell check in the first error message
Sebastian Ullrich (Nov 07 2021 at 15:58):
#print axioms depth
Sofia (Nov 07 2021 at 16:03):
I tried that, should have mentioned that didn't work either. ././Main.lean:112:14: error: unknown constant 'depth'
Sofia (Nov 07 2021 at 16:04):
Ah, after the failure.
'depth' depends on axioms: [sorryAx]
Sofia (Nov 07 2021 at 16:04):
Ran it on the wrong line, whoops.
Sofia (Nov 07 2021 at 16:04):
I processed it as a setopt kind of verbose thing.
Sofia (Nov 07 2021 at 16:09):
Is there an option to show this globally?
Sofia (Nov 07 2021 at 16:30):
Seems #print options
is missing on Lean 4. https://leanprover.github.io/reference/other_commands.html#instructions
Sofia (Nov 07 2021 at 16:30):
Either way, I need to sleep. TTYL. o/
Last updated: Dec 20 2023 at 11:08 UTC