Skip to content

Commit b0a12cb

Browse files
authored
feat: mark Nat power and divisibility theorems for grind (#11519)
This PR marks `Nat` power and divisibility theorems for `grind`. We use the new `grind_pattern` constraints to control theorem instantiation. Examples: ```lean example {x m n : Nat} (h : x = 4 ^ (m + 1) * n) : x % 4 = 0 := by grind example (a m n o p : Nat) : a ∣ n → a ∣ m * n * o * p := by grind example {a b x m n : Nat} : n > 0 → x = b * 4^m * a → a = 9^n → m > 0 → x % 6 = 0 := by grind example {a n : Nat} : m > 4 → a = 2^(m^n) → a % 2 = 0 := by grind ``` Closes #11515 Remark: We are adding support for installing extra theorems to `lia` (aka `cutsat`). The example at #11515 can already be solved by `grind` with this PR, but we still need to add the new theorems to the set for `lia`. cc @kim-em
1 parent ab606ba commit b0a12cb

File tree

5 files changed

+89
-7
lines changed

5 files changed

+89
-7
lines changed

src/Init/Data/Nat/Dvd.lean

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,15 @@ protected theorem dvd_trans {a b c : Nat} (h₁ : a ∣ b) (h₂ : b ∣ c) : a
2727
protected theorem dvd_mul_left_of_dvd {a b : Nat} (h : a ∣ b) (c : Nat) : a ∣ c * b :=
2828
Nat.dvd_trans h (Nat.dvd_mul_left _ _)
2929

30+
grind_pattern Nat.dvd_mul_left_of_dvd => a ∣ b, c * b where
31+
guard a ∣ b
32+
3033
protected theorem dvd_mul_right_of_dvd {a b : Nat} (h : a ∣ b) (c : Nat) : a ∣ b * c :=
3134
Nat.dvd_trans h (Nat.dvd_mul_right _ _)
3235

36+
grind_pattern Nat.dvd_mul_right_of_dvd => a ∣ b, b * c where
37+
guard a ∣ b
38+
3339
protected theorem eq_zero_of_zero_dvd {a : Nat} (h : 0 ∣ a) : a = 0 :=
3440
let ⟨c, H'⟩ := h; H'.trans c.zero_mul
3541

src/Init/Data/Nat/Lemmas.lean

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,6 +1086,17 @@ protected theorem pow_add (a m n : Nat) : a ^ (m + n) = a ^ m * a ^ n := by
10861086
| zero => rw [Nat.add_zero, Nat.pow_zero, Nat.mul_one]
10871087
| succ _ ih => rw [Nat.add_succ, Nat.pow_succ, Nat.pow_succ, ih, Nat.mul_assoc]
10881088

1089+
theorem div_pow_of_pos (a n : Nat) : n > 0 → a ∣ a ^ n := by
1090+
cases n <;> simp [Nat.pow_add]
1091+
exact Nat.dvd_mul_left a (a ^ _)
1092+
1093+
grind_pattern div_pow_of_pos => a ^ n where
1094+
is_value a
1095+
guard n > 0
1096+
1097+
grind_pattern Nat.pow_pos => a ^ n where
1098+
guard a > 0
1099+
10891100
protected theorem pow_add' (a m n : Nat) : a ^ (m + n) = a ^ n * a ^ m := by
10901101
rw [← Nat.pow_add, Nat.add_comm]
10911102

tests/lean/run/grind_11515.lean

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
example {x m n : Nat} (h : x = 4 ^ (m + 1) * n) : x % 4 = 0 := by
2+
grind
3+
4+
/--
5+
info: Try these:
6+
[apply] grind only [usr Nat.div_pow_of_pos, usr Nat.dvd_mul_right_of_dvd]
7+
[apply] grind =>
8+
instantiate only [usr Nat.div_pow_of_pos]
9+
instantiate only [usr Nat.dvd_mul_right_of_dvd]
10+
lia
11+
-/
12+
#guard_msgs in
13+
example {x m n : Nat} (h : x = 4 ^ (m + 1) * n) : x % 4 = 0 := by
14+
grind?
15+
16+
example {x m n : Nat} (h : x = 4 ^ (m + 1) * n) : x % 4 = 0 := by
17+
grind only [usr Nat.div_pow_of_pos, usr Nat.dvd_mul_right_of_dvd]
18+
19+
example {x m n : Nat} (h : x = 4 ^ (m + 1) * n) : x % 4 = 0 := by
20+
grind =>
21+
instantiate only [usr Nat.div_pow_of_pos]
22+
instantiate only [usr Nat.dvd_mul_right_of_dvd]
23+
lia
24+
25+
example {x m n : Nat} (h₁ : x = 4 ^ (m + 1) * n) : x % 4 = 0 := by
26+
grind
27+
28+
example {x m n : Nat} (h₁ : x = 4 ^ m * n) : m > 0 → x % 4 = 0 := by
29+
grind
30+
31+
example {x m n : Nat} (h₁ : x = n * 4 ^ (m + 1) * n) : x % 4 = 0 := by
32+
grind
33+
34+
example {a b x m n : Nat} (h₁ : x = b * a * 4 ^ (m + 1) * n) : x % 4 = 0 := by
35+
grind
36+
37+
example {a b x m n : Nat} (h₁ : x = b * 4 ^ m * a * 3 ^ n) : n > 0 → m > 0 → x % 12 = 0 := by
38+
grind
39+
40+
example {a b x m n : Nat} (h₁ : x = b * 4 ^ m * a * 3 ^ n) : n > 0 → m > 0 → x % 6 = 0 := by
41+
grind
42+
43+
example (m n : Nat) (h : 4 ∣ m) : 4 ∣ m * n := by
44+
grind
45+
46+
example (a m n : Nat) (h : a ∣ m) : a ∣ m * n := by
47+
grind
48+
49+
example (a m n o p : Nat) : a ∣ m → a ∣ m * n * o * p := by
50+
grind
51+
52+
example {a b x m n : Nat}
53+
: x = b * 4 ^ m * a → a = 3^n → n > 0 → m > 0 → x % 12 = 0 := by
54+
grind
55+
56+
example {a b x m n : Nat}
57+
: n > 0 → x = b * 4^m * a → a = 9^n → m > 0 → x % 6 = 0 := by
58+
grind
59+
60+
example {a n : Nat}
61+
: a = 2^(3^n) → a % 2 = 0 := by
62+
grind
63+
64+
example {a n : Nat}
65+
: m > 4 → a = 2^(m^n) → a % 2 = 0 := by
66+
grind

tests/lean/run/grind_lint_bitvec.lean

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ import Lean.Elab.Tactic.Grind.LintExceptions
77
#guard_msgs in
88
#grind_lint inspect (min := 30) BitVec.msb_replicate
99

10+
-- TODO: Reduce limit after we add support for `no_value` constraint
1011
-- `BitVec.msb_signExtend` is reasonable at 22.
1112
#guard_msgs in
12-
#grind_lint inspect (min := 25) BitVec.msb_signExtend
13+
#grind_lint inspect (min := 26) BitVec.msb_signExtend
1314

1415
/-! Check BitVec namespace: -/
1516

17+
-- TODO: Reduce limit after we add support for `no_value` constraint. It was `20`
1618
#guard_msgs in
17-
#grind_lint check (min := 20) in BitVec
19+
#grind_lint check (min := 23) in BitVec

tests/lean/run/grind_match_cond_issue.lean

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
/--
22
error: `grind` failed
3-
case grind.2.2.1.1
3+
case grind.1
44
n m a : Nat
55
ih : ∀ {a : Nat}, a ^ 2 = 4 ^ m * n → False
66
h : a ^ 2 = 4 ^ (m + 1) * n
7-
h_1 : ¬4 * 4 ^ m = 4 ^ m
8-
h_2 : ¬4 * 4 ^ m = 4 ^ m
9-
h_3 : n = 4 ^ m
10-
h_4 : ↑a = 4
7+
h_1 : ↑a = 4
118
⊢ False
129
-/
1310
#guard_msgs in

0 commit comments

Comments
 (0)