Zulip Chat Archive
Stream: Machine Learning for Theorem Proving
Topic: Track checking function in Pantograph
Leni Aniva (Nov 08 2025 at 19:09):
Hi people! I noticed that many people didn't know about the track checking function in Pantograph. It is useful for testing whole-file proofs.
It checks whether a proof conforms to a spec file:
src = """
def f : Nat -> Nat := sorry
theorem property (n : Nat) : f n = n + 1 := sorry
"""
dst = """
def f (x : Nat) := x + 1
theorem property (n : Nat) : f n = n + 1 := rfl
"""
await server.check_track_async(src, dst)
it detects tampering of definitions and introduction of additional axioms, but axioms that are present in both files are fine.
Eric Wieser (Nov 08 2025 at 22:06):
Does it allow this?
src = """
import Mathlib
theorem foo : { (x, y) | x * y < 0} = ∅ := by
sorry
"""
dst = """
import Mathlib
def bar := { (x, y) | x * y < 0}
theorem foo : { (x, y) | x * y < 0} = ∅ := by
simp
"""
await server.check_track_async(src, dst)
Leni Aniva (Nov 08 2025 at 22:33):
Eric Wieser said:
Does it allow this?
src = """ import Mathlib theorem foo : { (x, y) | x * y < 0} = ∅ := by sorry """ dst = """ import Mathlib def bar := { (x, y) | x * y < 0} theorem foo : { (x, y) | x * y < 0} = ∅ := by simp """ await server.check_track_async(src, dst)
Yes. You're free to introduce as many non-axiom definitions as you want. Auxiliary inductives and structures are allowed too
Eric Wieser (Nov 08 2025 at 22:34):
Right, the key thing there is that the meaning of the | changes as a result of the added bar
Leni Aniva (Nov 08 2025 at 22:34):
Eric Wieser said:
Right, the key thing there is that the meaning of the
|changes as a result of the addedbar
if it maps to a different symbol then check track will raise an error about tampering
Eric Wieser (Nov 08 2025 at 22:34):
So just to check, that's "yes, I checked", and not "yes, I'd hope so"?
Leni Aniva (Nov 08 2025 at 22:34):
Eric Wieser said:
So just to check, that's "yes, I checked", and not "yes, I'd hope so"?
There are unit tests in the Pantograph repo concerning this use case if you're interested
Eric Wieser (Nov 08 2025 at 22:35):
To be super clear; in the first case the theorem is about foo._match_1, in the second case it is about bar._match_1. The two are equal, but not without agressive (and possibly in more contrived examples, recursive) unfolding
Leni Aniva (Nov 08 2025 at 22:38):
It is possible to do such unfolding but it is not enabled for this use case. Any divergence in the symbol representation will lead to an error
Eric Wieser (Nov 08 2025 at 22:47):
So for my code sample above I guess the answer is "no, it rejects it"
Leni Aniva (Nov 08 2025 at 22:57):
Eric Wieser said:
So for my code sample above I guess the answer is "no, it rejects it"
Yes. It is rejected. I'm testing if the existing matcher unfolding function can make it an acceptance instead
Jason Rute (Nov 08 2025 at 22:59):
The two are equal
To be clear, you are saying the two versions of foo are definitionally equal? Or something a bit nicer than that? And to check this this, you would have to check for such equality between the before and after terms. It is not enough alone to look just at the terms because one term has foo._match_1 and the other has bar._match_1, right?
@GasStationManager How does SafeVerify behave on this example? @Henrik Böving how will your upcoming tool behave on this example?
Jason Rute (Nov 08 2025 at 23:00):
@Leni Aniva Is this tool similar to those two tools I just mentioned? Can it verify multi-file proofs (something the current version of SafeVerify can't do)?
Leni Aniva (Nov 08 2025 at 23:01):
Jason Rute said:
Leni Aniva Is this tool similar to those too I mentioned above. Can it verify multi-file proofs (something the current version of SafeVerify can't do).?
No it cannot verify multifile proofs because it would mean importing two Lean repos with the same name at the same time. I don't think Lean will allow this kind of operation.
Henrik Böving (Nov 08 2025 at 23:11):
Jason Rute said:
The two are equal
To be clear, you are saying the two versions of
fooare definitionally equal? Or something a bit nicer than that? And to check this this, you would have to check for such equality between the before and after terms. It is not enough alone to look just at the terms because one term hasfoo._match_1and the other hasbar._match_1, right?GasStationManager How does SafeVerify behave on this example? Henrik Böving how will your upcoming tool behave on this example?
reject
Henrik Böving (Nov 08 2025 at 23:11):
SafeVerify will reject too
Henrik Böving (Nov 08 2025 at 23:12):
And they are not definitionally equal, they are at best provably equal. This kind of side effect from introducing other definitions is a bit tricky.
Leni Aniva (Nov 08 2025 at 23:14):
Maybe aggressive matcher unfolding can lead to these two exprs being equal
Henrik Böving (Nov 08 2025 at 23:18):
Note that you should not unfold using matchMatcherApp? if you want to be a trustworthy checker, it relies on unverified informations from env extensions
Leni Aniva (Nov 08 2025 at 23:19):
Henrik Böving said:
Note that you should not unfold using
matchMatcherApp?if you want to be a trustworthy checker, it relies on unverified informations from env extensions
Then how can this system unfold matchers in this case?
Maybe the checker should just unfold every definition that is not present in the spec file.
Henrik Böving (Nov 08 2025 at 23:21):
With my OpenBSD-paranoia-hat on I would say just don't do anything clever and reject, tricks like this will likely bite a trustworthy checker somewhere down the line. If you really want to unfold and avoid looking at env extensions at the same time you can just inspect the definition of the matcher from the environment.
Leni Aniva (Nov 08 2025 at 23:32):
Henrik Böving said:
With my OpenBSD-paranoia-hat on I would say just don't do anything clever and reject, tricks like this will likely bite a trustworthy checker somewhere down the line. If you really want to unfold and avoid looking at env extensions at the same time you can just inspect the definition of the matcher from the environment.
What if I just make unfolding of matchers an optional feature? All the constants still have to go through replay so they'll be checked for their type correctness
Leni Aniva (Nov 08 2025 at 23:33):
Pantograph's definition unfolding function could make this example into an accept
Leni Aniva (Nov 08 2025 at 23:37):
I found a way to achieve acceptance of this example without querying env extensions. The method is to unfold all definitions which are not in the intersection of spec and proof files.
Jason Rute (Nov 08 2025 at 23:40):
With my OpenBSD-paranoia-hat on
I'm constantly trying to balance being paranoid of AI hacks and paranoid that I'm being too paranoid of AI hacks and thereby rejecting perfectly good code. (Maybe I just need to switch to Metamath. :joy:)
Marcelo Fornet (Dec 11 2025 at 21:26):
Eric Wieser said:
To be super clear; in the first case the theorem is about
foo._match_1, in the second case it is aboutbar._match_1. The two are equal, but not without agressive (and possibly in more contrived examples, recursive) unfolding
Can you elaborate a bit more on what are the differences here?
the meaning of the
|changes as a result of the addedbar
In which way does the meaning changes due to adding bar?
Leni Aniva (Dec 11 2025 at 21:26):
Marcelo Fornet said:
Eric Wieser said:
To be super clear; in the first case the theorem is about
foo._match_1, in the second case it is aboutbar._match_1. The two are equal, but not without agressive (and possibly in more contrived examples, recursive) unfoldingCan you elaborate a bit more on what are the differences here?
the meaning of the
|changes as a result of the addedbarIn which way does the meaning changes due to adding
bar?
Adding the bar definition changes how Lean internally represents foo
Marcelo Fornet (Dec 11 2025 at 22:19):
Leni Aniva said:
Marcelo Fornet said:
Eric Wieser said:
To be super clear; in the first case the theorem is about
foo._match_1, in the second case it is aboutbar._match_1. The two are equal, but not without agressive (and possibly in more contrived examples, recursive) unfoldingCan you elaborate a bit more on what are the differences here?
the meaning of the
|changes as a result of the addedbarIn which way does the meaning changes due to adding
bar?Adding the
bardefinition changes how Lean internally representsfoo
why is that the case?
sorry for being annoying, I'm genuinely curious about it
Leni Aniva (Dec 11 2025 at 22:20):
it has something to do with the elaborator generating auxiliary definitions. im not sure whats the exact process
Eric Wieser (Dec 15 2025 at 07:48):
Auxiliary definitions are cached within a file based on their value, I think
Henrik Böving (Dec 15 2025 at 07:49):
Note that one can work around this by keeping the target statement in a separate file as a definition that you just don't touch.
Last updated: Dec 20 2025 at 21:32 UTC