Zulip Chat Archive
Stream: general
Topic: Deterministic timeout in rcases
Violeta Hernández (Jul 31 2022 at 22:28):
I'm having trouble with this proof:
import analysis.special_functions.trigonometric.basic
lemma two_mul_cos_cases {n : ℤ} {x : ℝ} (h : 2 * real.cos x = n) :
n ∈ ({-2, -1, 0, 1, 2} : finset ℤ) :=
sorry
example {q : ℚ} : (∃ n : ℤ, 2 * real.cos (real.pi * q) = n) →
int.fract q ∈ ({0, 1 / 3, 1 / 2, 2 / 3} : finset ℚ) :=
begin
rintro ⟨n, hn⟩,
have H := two_mul_cos_cases hn,
simp only [finset.mem_insert, finset.mem_singleton] at H,
rcases H with (rfl|rfl|rfl|rfl|rfl);
sorry
end
The example times out. Changing the conclusion to something simpler makes it much faster. Changing simp only
by rw
or fin_cases
still leads to the timeout.
Violeta Hernández (Jul 31 2022 at 22:33):
Changing the simp only
line so that it also acts on the goal fixes this timeout...
Mario Carneiro (Jul 31 2022 at 22:41):
there is something really fishy going on in the expression ({0, 1 / 3, 1 / 2, 2 / 3} : finset ℚ)
Mario Carneiro (Jul 31 2022 at 22:42):
many basic operations take way longer than they should when that thing is around, and I managed to OOM kill lean while playing around with it
Mario Carneiro (Jul 31 2022 at 22:43):
my guess is that the expression consists of insert
operations which require decidability of rat
and this is blowing up for some reason on those concrete numbers
Violeta Hernández (Jul 31 2022 at 22:44):
You're almost certainly correct, since the problem goes away when I change finset
with multiset
Mario Carneiro (Jul 31 2022 at 22:45):
this is fast:
example {q : ℚ} : (∃ n : ℤ, 2 * cos (pi * q) = n) →
fract q ∈ ({0, 1 / 3, 1 / 2, 2 / 3} : finset ℚ) :=
begin
generalize : (0:ℚ) = a,
generalize : (1/3:ℚ) = b,
generalize : (1/2:ℚ) = c,
generalize : (2/3:ℚ) = d,
rintro ⟨n, hn⟩,
end
but if you comment out the b
and c
or c
and d
lines then suddenly the rintro
becomes really expensive
Mario Carneiro (Jul 31 2022 at 22:46):
which suggests that dec_trivial : 1 / 3 != 1 / 2
is being evaluated and something is not going well
Violeta Hernández (Jul 31 2022 at 22:47):
Is decidability of equality between rational fractions slow?
Mario Carneiro (Jul 31 2022 at 22:47):
it shouldn't be that slow
Mario Carneiro (Jul 31 2022 at 22:48):
ah, there is a gcd involved, maybe that's getting stuck
Mario Carneiro (Jul 31 2022 at 22:54):
Aha: when you whnf fract q ∈ ({a, b, c, d} : finset ℚ)
, you get list.mem (fract q) (list.insert a (list.insert b (list.insert c [d])))
. Since it's using insert
and not cons
this does not make it all the way to the disjunction like you would prefer; and if you put in concrete numbers for a,b,c,d then it will have to evaluate whether they are equal or not before we can tell if it is definitionally a disjunction. This is a problem because lots of stuff likes to call whnf on the goal to find out if it's a prop and other things
Mario Carneiro (Jul 31 2022 at 22:55):
so the correct solution is to start the proof with simp only [finset.mem_insert, finset.mem_singleton],
as you suggested
Mario Carneiro (Jul 31 2022 at 22:58):
oof:
#reduce as_true ((1 / 3 : ℚ) ≠ 1 / 2) -- timeout
Mario Carneiro (Jul 31 2022 at 23:02):
another way to "fix" it is to put local attribute [instance] classical.dec
at the top of the file
Mario Carneiro (Jul 31 2022 at 23:03):
this will make the inserts infer the fake decidability instance, and this will fail to evaluate, meaning the whnf stops trying to reduce it earlier
Mario Carneiro (Jul 31 2022 at 23:04):
when you use the "computable" decidability instance, lean actually tries to compute it, and I suspect that whnf is even reducing proofs in order to evaluate the gcd, which times out
Eric Wieser (Jul 31 2022 at 23:07):
Why would the gcd time out here?
Eric Wieser (Jul 31 2022 at 23:07):
Is this to do with acc.rec being irreducible in the kernel?
Mario Carneiro (Jul 31 2022 at 23:16):
I think something is calling whnf
with a really high reducibility setting
Mario Carneiro (Jul 31 2022 at 23:20):
here's a test you can play with, using the #whnf
command:
section
open lean lean.parser
@[user_command] meta def whnf_cmd (_ : interactive.parse (tk "#whnf")) : lean.parser unit := do
e ← parser.pexpr 0,
(ts, _) ← synthesize_tactic_state_with_variables_as_hyps [e],
of_tactic $ λ _, do {
e ← tactic.to_expr e,
e ← tactic.whnf e tactic.transparency.semireducible,
tactic.trace e } ts
end
#whnf (1 / (3 : ℚ))
At this reducibility setting, it doesn't get evaluated much at all, but if you change semireducible
to all
it will evaluate the outer bit, and you can observe that e.g. (1 / (3 : ℚ)).denom - 3
reduces to 0
Mario Carneiro (Jul 31 2022 at 23:21):
interestingly, #whnf as_true ((1 / (3 : ℚ)) ≠ 1 / 2)
evaluates to true
quickly with all
enabled and does not reduce at lower settings, so I'm not sure what got it stuck in a loop
Last updated: Dec 20 2023 at 11:08 UTC