Zulip Chat Archive

Stream: general

Topic: Deterministic timeout when proving a theorem


Donald Sebastian Leung (Apr 10 2020 at 08:00):

So I'm using Lean v3.7.2 with mathlib commit 732f7109c5cb2ece35481c200faa38fbbb4dc995 and encountered a deterministic timeout when trying to prove a theorem, which is certainly a first for me:

Preloaded.lean:

inductive times_3_plus_5 : set 
| start :
    times_3_plus_5 1
| times_3 :  n,
    times_3_plus_5 n 
    times_3_plus_5 (n * 3)
| plus_5 :  n,
    times_3_plus_5 n 
    times_3_plus_5 (n + 5)

def decide (n : ) : bool :=
  match n % 5 with
  | 0 := ff
  | 2 := 27  n
  | 4 := 9  n
  | _ := tt
  end

def SUBMISSION :=  n, times_3_plus_5 n  decide n = tt
notation `SUBMISSION` := SUBMISSION

Solution.lean:

import Preloaded tactic data.nat.modeq

open times_3_plus_5 nat nat.modeq

theorem decide_works (n : ) :
  times_3_plus_5 n  decide n = tt :=
begin
  split; simp [decide]; intros h,
  { induction h,
    case start : { refl },
    case times_3 : m hm ihm {
      have hm5 : m % 5 < 5 := mod_lt m dec_trivial,
      interval_cases (m % 5),
      { rw lh at ihm, contradiction },
      { have hm1 : m % 5 = 1 % 5, by assumption,
        have hm3 : m * 3 % 5 = 1 * 3 % 5 := modeq_mul_right _ hm1,
        rw hm3,
        refl },
      { rw lh at ihm,
        simp [decide] at *,
        have hm2 : m % 5 = 2 % 5, by assumption,
        have hm3 : m * 3 % 5 = 2 * 3 % 5 := modeq_mul_right _ hm2,
        rw hm3,
        refl },
      { have hm3 : m % 5 = 3 % 5, by assumption,
        have hm4 : m * 3 % 5 = 4 := modeq_mul_right _ hm3,
        rw hm4,
        simp [decide],
        generalize h : m * 3 = m',
        iterate 9 { all_goals { try { cases m' } } },
        { rw h at hm4; contradiction },
        { omega },
        { omega },
        { have hm1 : m = 1, by omega, subst hm1, cases lh },
        { omega },
        { omega },
        { have hm2 : m = 2, by omega, subst hm2, cases lh },
        { omega },
        { omega },
        { omega } },
      { sorry }
    },
    case plus_5 : { sorry } },
  { sorry }
end

As far as I can see, all the tactics I've used so far succeed, but I get a red squiggly line just below the theorem in theorem decide_works ..., and upon hovering my mouse over it, it says (deterministic) timeout. The thing is, I've written proofs that take way longer than this one to compile (> 30s compared to maybe about 10s on this one) and have not seen such an error before so was this timing restriction added recently, or am I missing something?

Kenny Lau (Apr 10 2020 at 08:05):

yay you're translating more kata

Kenny Lau (Apr 10 2020 at 08:06):

deterministic timeout has always existed (and always will)

Kenny Lau (Apr 10 2020 at 08:06):

the multitude of omega may or may not be the cause

Donald Sebastian Leung (Apr 10 2020 at 08:31):

So a tactic-mode proof cannot have too many steps? In that case maybe I'll try extracting out a few lemmas and see if it helps.

Mario Carneiro (Apr 10 2020 at 08:34):

You can turn off the timeout, and I think it is disabled by default if you run lean via the command line

Donald Sebastian Leung (Apr 10 2020 at 08:54):

Thanks. In any case, it seems that it was indeed the excessive use of omega which caused the timeout. I pulled out all uses of omega into separate lemmas and that seems to have solved my timeout issues, at least for now.

Kevin Buzzard (Apr 10 2020 at 09:13):

I think there is some underlying weirdness going on here. Here's a situation where I prove one goal with omega in two different situations, and it takes 0.08 seconds in the first and 3 seconds in the second one on my machine, to solve exactly the same goal.

import  tactic data.nat.modeq

inductive times_3_plus_5 : set 
| start :
    times_3_plus_5 1
| times_3 :  n,
    times_3_plus_5 n 
    times_3_plus_5 (n * 3)
| plus_5 :  n,
    times_3_plus_5 n 
    times_3_plus_5 (n + 5)

def decide (n : ) : bool :=
  match n % 5 with
  | 0 := ff
  | 2 := 27  n
  | 4 := 9  n
  | _ := tt
  end

open times_3_plus_5 nat nat.modeq

-- I can make Lean solve the following goal in 0 seconds and in 3 seconds with the same tactic

/-
n m : ℕ,
hm : times_3_plus_5 m,
ihm : decide._match_1 m (m % 5) = tt,
hm5 : m % 5 < 5,
lh : m % 5 = 3,
hm3 : m % 5 = 3 % 5,
hm4 : m * 3 % 5 = 4,
h : m * 3 = 7
⊢ 9 ≤ 7
-/

set_option profiler true

example (n m : )
(hm : times_3_plus_5 m)
(ihm : decide._match_1 m (m % 5) = tt)
(hm5 : m % 5 < 5)
(lh : m % 5 = 3)
(hm3 : m % 5 = 3 % 5)
(hm4 : m * 3 % 5 = 4)
(h : m * 3 = 7)
: 9  7 := by omega -- <- finishes almost instantly

-- Now look in the middle of a proof

theorem decide_works (n : ) :
  times_3_plus_5 n  decide n = tt :=
begin
  split; simp [decide]; intros h,
  { induction h,
    case start : { refl },
    case times_3 : m hm ihm {
      have hm5 : m % 5 < 5 := mod_lt m dec_trivial,
      interval_cases (m % 5),
      { rw lh at ihm, contradiction },
      { have hm1 : m % 5 = 1 % 5, by assumption,
        have hm3 : m * 3 % 5 = 1 * 3 % 5 := modeq_mul_right _ hm1,
        rw hm3,
        refl },
      { rw lh at ihm,
        simp [decide] at *,
        have hm2 : m % 5 = 2 % 5, by assumption,
        have hm3 : m * 3 % 5 = 2 * 3 % 5 := modeq_mul_right _ hm2,
        rw hm3,
        refl },
      { have hm3 : m % 5 = 3 % 5, by assumption,
        have hm4 : m * 3 % 5 = 4 := modeq_mul_right _ hm3,
        rw hm4,
        simp [decide],
        generalize h : m * 3 = m',
        iterate 9 { all_goals { try { cases m' } } },
        { rw h at hm4; contradiction },
        { omega },
        { omega },
        { have hm1 : m = 1, by omega, subst hm1, cases lh },
        { omega },
        { omega },
        { have hm2 : m = 2, by omega, subst hm2, cases lh },
        { omega}, -- <- this omega takes 3 seconds; replace with sorry and observe profiler change
        sorry,sorry},sorry},sorry},sorry,end -- <- look at profiler output here

Kevin Buzzard (Apr 10 2020 at 09:14):

@Gabriel Ebner how can that happen?

Kevin Buzzard (Apr 10 2020 at 09:18):

How do I begin to debug this? All I know is how to turn the profiler on. Are there hidden metavariable goals?

Kevin Buzzard (Apr 10 2020 at 09:21):

Aah! If I type recover before the omega, then all of a sudden I have 5 goals.

Kevin Buzzard (Apr 10 2020 at 09:22):

Does this indicate that something is not clearing up as it should be?

Kevin Buzzard (Apr 10 2020 at 09:25):

Oh -- is that actually expected behaviour of recover when one is in a sub-{} block?

Kevin Buzzard (Apr 10 2020 at 09:26):

example (P Q : Prop) (hp : P) (hq : Q) : P  Q :=
begin
  split,
  { recover, exact hq, exact hp},
end

Maybe I'm back to square 1.

Gabriel Ebner (Apr 10 2020 at 09:28):

I can see two possible ways this could happen: 1) 7 is not the same as 7. You could enable pp.all and check if the two goals are actually the same. 2) omega is non-deterministic because it depends on the state of the caches, the order of the assumptions, the names of the assumptions, the hash codes of the expressions, etc.

Gabriel Ebner (Apr 10 2020 at 09:30):

I hope that omega only looks at the current goal and not at other metavariables. So I don't think it's got anything to do with recover.

Kevin Buzzard (Apr 10 2020 at 09:30):

7 is indeed not the same as 7. They're both nats though.

Kevin Buzzard (Apr 10 2020 at 09:31):

(nat.succ (nat.succ (nat.succ (nat.succ (nat.succ (nat.succ (nat.succ nat.zero))))))) v (@bit1.{0} nat nat.has_one nat.has_add (@bit1.{0} nat nat.has_one nat.has_add (@has_one.one.{0} nat nat.has_one)))

Kevin Buzzard (Apr 10 2020 at 09:32):

Oh nice Gabriel -- this is exactly it!

Kevin Buzzard (Apr 10 2020 at 09:33):

import tactic.omega

set_option profiler true

example (m : )
(hm5 : m % 5 < 5)
(lh : m % 5 = 3)
(hm3 : m % 5 = 3 % 5)
(hm4 : m * 3 % 5 = 4)
(h : m * 3 = 7)
: 9  7 := begin
 omega -- <- finishes almost instantly
end

example (m : )
(hm5 : m % 5 < 5)
(lh : m % 5 = 3)
(hm3 : m % 5 = 3 % 5)
(hm4 : m * 3 % 5 = 4)
(h : m * 3 = 7)
: 9  (nat.succ (nat.succ (nat.succ (nat.succ (nat.succ (nat.succ (nat.succ nat.zero))))))) := begin
 omega -- <- takes three seconds
end

Kevin Buzzard (Apr 10 2020 at 09:33):

The prettyprinter displays them both as 7 and they're both nats

Gabriel Ebner (Apr 10 2020 at 09:41):

Here's what's happening: as a preprocessing step, omega replaces nat.succ by + 1: https://github.com/leanprover-community/mathlib/blob/f723f37531502d76e9f7a3a27c225884918a70b5/src/tactic/omega/nat/main.lean#L24 So instead of 7 it sees 0 + 1 + 1 + 1 + 1 + 1 + 1 +1.

Kevin Buzzard (Apr 10 2020 at 09:44):

#2376

Kevin Buzzard (Apr 10 2020 at 17:30):

@Donald Sebastian Leung there is some issue with omega taking too long, but in your code above if you replace iterate 9 { all_goals { try { cases m' } } }, with iterate 9 { all_goals { try { cases m'; simp } } }, you might be back on track.


Last updated: Dec 20 2023 at 11:08 UTC