Zulip Chat Archive
Stream: general
Topic: metavariable bug
Kevin Buzzard (Feb 15 2022 at 09:13):
I tried to get a mathlib-free version but I need swap
which is apparently not in core. The below code looks really innocent but honestly you might want to look away instead of at the tactic state after the dsimp.
import tactic.interactive -- needed for `swap`
example {X : Type}
(S : set X)
(P : set X → Prop)
(x : X) :
(∃ (U : set X), (P U ∧ U ⊆ S) ∧ x ∈ U) →
(∃ (U : set X), P U ∧ U ⊆ S ∧ x ∈ U) :=
begin
intro h,
cases h with U hU,
cases hU with h1 h2,
cases h1 with h3 h4,
split,
swap,
intro x,
swap,
dsimp at *, -- this causes the problem
exact ⟨h3, h4, h2⟩,
end
Arthur Paulino (Feb 15 2022 at 13:16):
just dsimp
does very little on the goal and is accepted. dsimp at *
does much more unfolding on the goal and, naively looking at the goal state only, doesn't touch anything but the goal too (but is not accepted).
Arthur Paulino (Feb 15 2022 at 13:52):
More digging: if I extract the goal before split
, the bug doesn't show up anymore:
example {X : Type}
(S : set X)
(P : set X → Prop)
(x : X)
(U : set X)
(h2 : x ∈ U)
(h3 : P U)
(h4 : U ⊆ S) :
∃ (U : set X), P U ∧ U ⊆ S ∧ x ∈ U :=
begin
split,
swap,
intro x,
swap,
dsimp at *, -- this no longer causes the problem
exact ⟨h3, h4, h2⟩,
end
Arthur Paulino (Feb 15 2022 at 13:59):
So maybe the bug is either in intro
, cases
or dsimp
Arthur Paulino (Feb 15 2022 at 15:43):
This is the code that runs for the wildcard location of dsimp
:
do n ← revert_all,
dsimp_target s u {zeta := ff ..cfg},
intron n
If I change the order, as in:
do n ← revert_all,
intron n,
dsimp_target s u {zeta := ff ..cfg}
The problem disappears. Is this approach problematic?
Alex J. Best (Feb 15 2022 at 15:46):
Doing revert and then intro is a no-op, the point of those lines is to move all hypotheses into the goal, dsimp the resulting thing and then extract all the hypotheses again. Maybe there is a better way to accomplish this though
Alex J. Best (Feb 15 2022 at 15:49):
It would be good to look at the git history why the wildcard case is special cased, and see if the mathlib build breaks if it is removed
Arthur Paulino (Feb 15 2022 at 15:49):
Hm, from the fact that it says "goals accomplished" but the kernel rejects it, can we conclude that the current way to do it is actually inconsistent?
Arthur Paulino (Feb 15 2022 at 15:50):
Alex J. Best said:
It would be good to look at the git history why the wildcard case is special cased, and see if the mathlib build breaks if it is removed
There's a comment on the wildcard code saying:
/- Remark: we cannot revert frozen local instances.
We disable zeta expansion because to prevent `intron n` from failing.
Another option is to put a "marker" at the current target, and
implement `intro_upto_marker`. -/
Alex J. Best (Feb 15 2022 at 15:50):
I'd guess that there is in fact a deeper bug that should be found
Alex J. Best (Feb 15 2022 at 15:51):
I don't think the comment makes too much difference, even with zeta expansion enabled the bug still occurs
Alex J. Best (Feb 15 2022 at 15:51):
set_option trace.dsimplify true
example {X : Type}
(S : set X)
(P : set X → Prop)
(x : X) :
(∃ (U : set X), (P U)) →
(∃ (U : set X), P U) :=
begin
intro h,
cases h with U hU,
split,
swap,
intro x,
swap,
-- rw id,
dsimp at *, -- this causes the problem
exact hU,
end
is the best MWE I have
Alex J. Best (Feb 15 2022 at 15:52):
It seems to me that dsimp
is removing an id
application that is necessary to tell lean the types of everything involved
Arthur Paulino (Feb 15 2022 at 15:53):
set_option trace.dsimplify true
example {X : Type}
(S : set X)
(P : set X → Prop)
(x : X) :
(∃ (U : set X), (P U)) →
(∃ (U : set X), P U) :=
begin
intro h,
cases h with U hU,
split,
work_on_goal 1 {intro x},
dsimp at *, -- this causes the problem
exact hU,
end
is just a tad smaller, but doesn't remove anything significant
Arthur Paulino (Feb 15 2022 at 15:59):
This is dsimp_target
:
meta def dsimp_target (s : option simp_lemmas := none) (u : list name := []) (cfg : dsimp_config := {}) : tactic unit :=
do
s ← get_simp_lemmas_or_default s,
t ← target >>= instantiate_mvars,
s.dsimplify u t cfg >>= unsafe_change
And this is unsafe_change
:
/-- Change the target of the main goal.
The input expression must be definitionally equal to the current target.
The tactic does not check whether `e`
is definitionally equal to the current target. The error will only be detected by the kernel type checker. -/
meta def unsafe_change (e : expr) : tactic unit :=
change e ff
Alex J. Best (Feb 15 2022 at 16:01):
Even using safe change (change e tt
) it has the same behaviour
Arthur Paulino (Feb 15 2022 at 16:08):
So if change e tt
is resulting on "goals accomplished", then is it safe to conclude that such change type checks at that point?
Arthur Paulino (Feb 15 2022 at 16:09):
If not, then we might need to dive in C code to find the bug
Alex J. Best (Feb 15 2022 at 16:16):
Weirdly enough running recover
or even
trace result
after the last exact line makes the proof succeed
Arthur Paulino (Feb 15 2022 at 16:28):
Okay this is beyond my understanding. I can only hope it won't happen in Lean 4 :sweat_smile:
Arthur Paulino (Feb 15 2022 at 17:10):
Even smaller #mwe:
example (P : set nat → Prop) :
(∃ (U : set nat), P U) → (∃ (U : set nat), P U) :=
begin
intro h,
cases h with U hU,
split,
work_on_goal 1 {intro x},
dsimp at *, -- this causes the problem
exact hU,
end
Mario Carneiro (Feb 16 2022 at 04:39):
This is a very weird bug. Calling (() <$ tactic.result),
alone fixes the issue, so it's almost certainly a bug in the C++ code
Mario Carneiro (Feb 16 2022 at 04:47):
Oh, this is even more fun:
open tactic
example (P : set nat → Prop) (h : ∃ U : set nat, P U) : ∃ U : set nat, P U :=
begin
cases h with U hU,
split,
work_on_goal 1 {intro x},
dsimp at *, -- this causes the problem
-- result, -- (1)
exact hU,
-- result, -- (2)
end
You get an error iff (2) is enabled and (1) is disabled
Last updated: Dec 20 2023 at 11:08 UTC