Skip to content

Commit f40d72e

Browse files
authored
feat: typeclasses for grind to work with ordered modules (#8347)
This PR adds draft typeclasses for `grind` to process facts about ordered modules. These interfaces will evolve as the implementation develops.
1 parent 10fdfc5 commit f40d72e

File tree

9 files changed

+285
-3
lines changed

9 files changed

+285
-3
lines changed

src/Init/Grind.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ import Init.Grind.Util
1515
import Init.Grind.Offset
1616
import Init.Grind.PP
1717
import Init.Grind.CommRing
18+
import Init.Grind.Module
1819
import Init.Grind.Ext

src/Init/Grind/Module.lean

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/-
2+
Copyright (c) 2025 Lean FRO, LLC. or its affiliates. All Rights Reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Kim Morrison
5+
-/
6+
module
7+
8+
prelude
9+
import Init.Grind.Module.Basic
10+
import Init.Grind.Module.Int

src/Init/Grind/Module/Basic.lean

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/-
2+
Copyright (c) 2025 Lean FRO, LLC. or its affiliates. All Rights Reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Kim Morrison
5+
-/
6+
module
7+
8+
prelude
9+
import Init.Data.Int.Order
10+
11+
namespace Lean.Grind
12+
13+
class NatModule (M : Type u) extends Zero M, Add M, HSMul Nat M M where
14+
add_zero : ∀ a : M, a + 0 = a
15+
zero_add : ∀ a : M, 0 + a = a
16+
add_comm : ∀ a b : M, a + b = b + a
17+
add_assoc : ∀ a b c : M, a + b + c = a + (b + c)
18+
zero_smul : ∀ a : M, 0 • a = 0
19+
one_smul : ∀ a : M, 1 • a = a
20+
add_smul : ∀ n m : Nat, ∀ a : M, (n + m) • a = n • a + m • a
21+
smul_zero : ∀ n : Nat, n • (0 : M) = 0
22+
smul_add : ∀ n : Nat, ∀ a b : M, n • (a + b) = n • a + n • b
23+
mul_smul : ∀ n m : Nat, ∀ a : M, (n * m) • a = n • (m • a)
24+
25+
class IntModule (M : Type u) extends Zero M, Add M, Neg M, Sub M, HSMul Int M M where
26+
add_zero : ∀ a : M, a + 0 = a
27+
zero_add : ∀ a : M, 0 + a = a
28+
add_comm : ∀ a b : M, a + b = b + a
29+
add_assoc : ∀ a b c : M, a + b + c = a + (b + c)
30+
zero_smul : ∀ a : M, (0 : Int) • a = 0
31+
one_smul : ∀ a : M, (1 : Int) • a = a
32+
add_smul : ∀ n m : Int, ∀ a : M, (n + m) • a = n • a + m • a
33+
neg_smul : ∀ n : Int, ∀ a : M, (-n) • a = - (n • a)
34+
smul_zero : ∀ n : Int, n • (0 : M) = 0
35+
smul_add : ∀ n : Int, ∀ a b : M, n • (a + b) = n • a + n • b
36+
mul_smul : ∀ n m : Int, ∀ a : M, (n * m) • a = n • (m • a)
37+
neg_add_cancel : ∀ a : M, -a + a = 0
38+
sub_eq_add_neg : ∀ a b : M, a - b = a + -b
39+
40+
instance IntModule.toNatModule (M : Type u) [i : IntModule M] : NatModule M :=
41+
{ i with
42+
hSMul a x := (a : Int) • x
43+
smul_zero := by simp [IntModule.smul_zero]
44+
add_smul := by simp [IntModule.add_smul]
45+
smul_add := by simp [IntModule.smul_add]
46+
mul_smul := by simp [IntModule.mul_smul] }
47+
48+
/--
49+
We keep track of rational linear combinations as integer linear combinations,
50+
but with the assurance that we can cancel the GCD of the coefficients.
51+
-/
52+
class RatModule (M : Type u) extends IntModule M where
53+
no_int_zero_divisors : ∀ (k : Int) (a : M), k ≠ 0 → k • a = 0 → a = 0
54+
55+
/-- A preorder is a reflexive, transitive relation `≤` with `a < b` defined in the obvious way. -/
56+
class Preorder (α : Type u) extends LE α, LT α where
57+
le_refl : ∀ a : α, a ≤ a
58+
le_trans : ∀ a b c : α, a ≤ b → b ≤ c → a ≤ c
59+
lt := fun a b => a ≤ b ∧ ¬b ≤ a
60+
lt_iff_le_not_le : ∀ a b : α, a < b ↔ a ≤ b ∧ ¬b ≤ a := by intros; rfl
61+
62+
class IntModule.IsOrdered (M : Type u) [Preorder M] [IntModule M] where
63+
neg_le_iff : ∀ a b : M, -a ≤ b ↔ -b ≤ a
64+
neg_lt_iff : ∀ a b : M, -a < b ↔ -b < a
65+
add_lt_left : ∀ a b c : M, a < b → a + c < b + c
66+
add_lt_right : ∀ a b c : M, a < b → c + a < c + b
67+
smul_pos : ∀ (k : Int) (a : M), 0 < a → (0 < k ↔ 0 < k • a)
68+
smul_neg : ∀ (k : Int) (a : M), a < 0 → (0 < k ↔ k • a < 0)
69+
smul_nonneg : ∀ (k : Int) (a : M), 0 ≤ a → 0 ≤ k → 0 ≤ k • a
70+
smul_nonpos : ∀ (k : Int) (a : M), a ≤ 00 ≤ k → k • a ≤ 0
71+
72+
end Lean.Grind

src/Init/Grind/Module/Int.lean

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/-
2+
Copyright (c) 2025 Lean FRO, LLC. or its affiliates. All Rights Reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Kim Morrison
5+
-/
6+
module
7+
8+
prelude
9+
import Init.Grind.Module.Basic
10+
import Init.Omega
11+
12+
/-!
13+
# `grind` instances for `Int` as an ordered module.
14+
-/
15+
16+
namespace Lean.Grind
17+
18+
instance : IntModule Int where
19+
add_zero := Int.add_zero
20+
zero_add := Int.zero_add
21+
add_comm := Int.add_comm
22+
add_assoc := Int.add_assoc
23+
zero_smul := Int.zero_mul
24+
one_smul := Int.one_mul
25+
add_smul := Int.add_mul
26+
neg_smul := Int.neg_mul
27+
smul_zero := Int.mul_zero
28+
smul_add := Int.mul_add
29+
mul_smul := Int.mul_assoc
30+
neg_add_cancel := Int.add_left_neg
31+
sub_eq_add_neg _ _ := Int.sub_eq_add_neg
32+
33+
instance : Preorder Int where
34+
le_refl := Int.le_refl
35+
le_trans _ _ _ := Int.le_trans
36+
lt_iff_le_not_le := by omega
37+
38+
instance : IntModule.IsOrdered Int where
39+
neg_le_iff := by omega
40+
neg_lt_iff := by omega
41+
add_lt_left := by omega
42+
add_lt_right := by omega
43+
smul_pos k a ha := ⟨fun hk => Int.mul_pos hk ha, fun h => Int.pos_of_mul_pos_left h ha⟩
44+
smul_neg k a ha := ⟨fun hk => Int.mul_neg_of_pos_of_neg hk ha, fun h => Int.pos_of_mul_neg_left h ha⟩
45+
smul_nonpos k a ha hk := Int.mul_nonpos_of_nonneg_of_nonpos hk ha
46+
smul_nonneg k a ha hk := Int.mul_nonneg hk ha
47+
48+
end Lean.Grind
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
-- Tests for `grind` as a module normalization tactic, when only `NatModule`, `IntModule`, or `RatModule` is available.
2+
3+
open Lean.Grind
4+
5+
section NatModule
6+
7+
variable (R : Type u) [NatModule R]
8+
9+
example (a b : R) : a + b = b + a := by grind
10+
example (a : R) : a + 0 = a := by grind
11+
example (a : R) : 0 + a = a := by grind
12+
example (a b c : R) : a + b + c = a + (b + c) := by grind
13+
example (a : R) : 2 • a = a + a := by grind
14+
example (a b : R) : 2 • (b + c) = c + 2 • b + c := by grind
15+
16+
end NatModule
17+
18+
section IntModule
19+
20+
variable (R : Type u) [IntModule R]
21+
22+
example (a b : R) : a + b = b + a := by grind
23+
example (a : R) : a + 0 = a := by grind
24+
example (a : R) : 0 + a = a := by grind
25+
example (a b c : R) : a + b + c = a + (b + c) := by grind
26+
example (a : R) : 2 • a = a + a := by grind
27+
example (a : R) : (-2 : Int) • a = -a - a := by grind
28+
example (a b : R) : 2 • (b + c) = c + 2 • b + c := by grind
29+
example (a b c : R) : 2 • (b + c) - 3 • c + b + b = c + 5 • b - 2 • c := by grind
30+
example (a b c : R) : 2 • (b + c) + (-3 : Int) • c + b + b = c + (5 : Int) • b - 2 • c := by grind
31+
32+
end IntModule
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-- Tests for `grind` as solver for linear equations in an `IntModule` or `RatModule`.
2+
3+
open Lean.Grind
4+
5+
section IntModule
6+
7+
variable (R : Type u) [IntModule R]
8+
9+
-- In an `IntModule`, we should be able to handle relations
10+
-- this is harder, and less important, than being able to do this in `RatModule`.
11+
example (a b : R) (h : a + b = 0) : 3 • a - 7 • b = 9 • a + a := by grind
12+
example (a b c : R) (h : 2 • a + 2 • b = 4 • c) : 3 • a + c = 5 • c - b + (-b) + a := by grind
13+
14+
end IntModule
15+
16+
section RatModule
17+
18+
variable (R : Type u) [RatModule R]
19+
20+
example (a b : R) (h : a + b = 0) : 3 • a - 7 • b = 9 • a + a := by grind
21+
example (a b c : R) (h : 2 • a + 2 • b = 4 • c) : 3 • a + c = 5 • c - b + (-b) + a := by grind
22+
23+
-- In a `RatModule` we can clear common divisors.
24+
example (a : R) (h : a + a = 0) : a = 0 := by grind
25+
example (a b c : R) (h : 2 • a + 2 • b = 4 • c) : 3 • a + c = 5 • c - 3 • b := by grind
26+
27+
end RatModule
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
open Lean.Grind
2+
3+
set_option grind.warning false
4+
5+
variable (R : Type u) [RatModule R] [Preorder R] [IntModule.IsOrdered R]
6+
7+
example (a b c : R) (h : a < b) : a + c < b + c := by grind
8+
example (a b c : R) (h : a < b) : c + a < c + b := by grind
9+
example (a b : R) (h : a < b) : -b < -a := by grind
10+
example (a b : R) (h : a < b) : -a < -b := by grind
11+
12+
example (a b c : R) (h : a ≤ b) : a + c ≤ b + c := by grind
13+
example (a b c : R) (h : a ≤ b) : c + a ≤ c + b := by grind
14+
example (a b : R) (h : a ≤ b) : -b ≤ -a := by grind
15+
example (a b : R) (h : a ≤ b) : -a ≤ -b := by grind
16+
17+
example (a : R) (h : 0 < a) : 0 ≤ a := by grind
18+
example (a : R) (h : 0 < a) : -2 • a < 0 := by grind
19+
20+
example (a b c : R) (_ : a ≤ b) (_ : b ≤ c) : a ≤ c := by grind
21+
example (a b c : R) (_ : a ≤ b) (_ : b < c) : a < c := by grind
22+
example (a b c : R) (_ : a < b) (_ : b ≤ c) : a < c := by grind
23+
example (a b c : R) (_ : a < b) (_ : b < c) : a < c := by grind
24+
25+
example (a : R) (h : 2 • a < 0) : a < 0 := by grind
26+
example (a : R) (h : 2 • a < 0) : 0 ≤ -a := by grind
27+
28+
example (a b : R) (_ : a < b) (_ : b < a) : False := by grind
29+
example (a b : R) (_ : a < b ∧ b < a) : False := by grind
30+
example (a b : R) (_ : a < b) : a ≠ b := by grind
31+
32+
example (a b c e v0 v1 : R) (h1 : v0 = 5 • a) (h2 : v1 = 3 • b) (h3 : v0 + v1 + c = 10 • e) :
33+
v0 + 5 • e + (v1 - 3 • e) + (c - 2 • e) = 10 • e := by
34+
grind
35+
36+
example (x y z : Int) (h1 : 2 * x < 3 * y) (h2 : -4 * x + 2 * z < 0) (h3 : 12 * y - 4 * z < 0) : False := by
37+
grind
38+
example (x y z : R) (h1 : 2 • x < 3 • y) (h2 : -4 • x + 2 • z < 0) (h3 : 12 • y - 4 • z < 0) : False := by
39+
grind
40+
41+
example (x y z : Int) (h1 : 2 * x < 3 * y) (h2 : -4 * x + 2 * z < 0) (h3 : x * y < 5) (h3 : 12 * y - 4 * z < 0) :
42+
False := by grind
43+
example (x y z : R) (h1 : 2 • x < 3 • y) (h2 : -4 • x + 2 • z < 0) (h3 : 12 • y - 4 • z < 0) :
44+
False := by grind
45+
46+
example (x y z : Int) (hx : x ≤ 3 * y) (h2 : y ≤ 2 * z) (h3 : x ≥ 6 * z) : x = 3*y := by
47+
grind
48+
example (x y z : R) (hx : x ≤ 3 • y) (h2 : y ≤ 2 • z) (h3 : x ≥ 6 • z) : x = 3 • y := by
49+
grind
50+
51+
example (x y z : Int) (h1 : 2 * x < 3 * y) (h2 : -4 * x + 2 * z < 0) (h3 : x * y < 5) : ¬ 12*y - 4* z < 0 := by
52+
grind
53+
example (x y z : R) (h1 : 2 • x < 3 • y) (h2 : -4 • x + 2 • z < 0) : ¬ 12 • y - 4 • z < 0 := by
54+
grind
55+
56+
example (x y z : Int) (hx : ¬ x > 3 * y) (h2 : ¬ y > 2 * z) (h3 : x ≥ 6 * z) : x = 3 * y := by
57+
grind
58+
example (x y z : R) (hx : ¬ x > 3 • y) (h2 : ¬ y > 2 • z) (h3 : x ≥ 6 • z) : x = 3 • y := by
59+
grind
60+
61+
example (x y z : Nat) (hx : x ≤ 3 * y) (h2 : y ≤ 2 * z) (h3 : x ≥ 6 * z) : x = 3 * y := by
62+
grind
63+
example (x y z : R) (hx : x ≤ 3 • y) (h2 : y ≤ 2 • z) (h3 : x ≥ 6 • z) : x = 3 • y := by
64+
grind

tests/lean/run/infoFromFailure.lean

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,21 @@ info: B.foo "hello" : String × String
1616
---
1717
trace: [Meta.synthInstance] ❌️ Add String
1818
[Meta.synthInstance] new goal Add String
19-
[Meta.synthInstance.instances] #[@Lean.Grind.Semiring.toAdd]
19+
[Meta.synthInstance.instances] #[@Lean.Grind.Semiring.toAdd, @Lean.Grind.NatModule.toAdd, @Lean.Grind.IntModule.toAdd]
20+
[Meta.synthInstance] ✅️ apply @Lean.Grind.IntModule.toAdd to Add String
21+
[Meta.synthInstance.tryResolve] ✅️ Add String ≟ Add String
22+
[Meta.synthInstance] new goal Lean.Grind.IntModule String
23+
[Meta.synthInstance.instances] #[@Lean.Grind.RatModule.toIntModule]
24+
[Meta.synthInstance] ✅️ apply @Lean.Grind.RatModule.toIntModule to Lean.Grind.IntModule String
25+
[Meta.synthInstance.tryResolve] ✅️ Lean.Grind.IntModule String ≟ Lean.Grind.IntModule String
26+
[Meta.synthInstance] no instances for Lean.Grind.RatModule String
27+
[Meta.synthInstance.instances] #[]
28+
[Meta.synthInstance] ✅️ apply @Lean.Grind.NatModule.toAdd to Add String
29+
[Meta.synthInstance.tryResolve] ✅️ Add String ≟ Add String
30+
[Meta.synthInstance] new goal Lean.Grind.NatModule String
31+
[Meta.synthInstance.instances] #[Lean.Grind.IntModule.toNatModule]
32+
[Meta.synthInstance] ✅️ apply Lean.Grind.IntModule.toNatModule to Lean.Grind.NatModule String
33+
[Meta.synthInstance.tryResolve] ✅️ Lean.Grind.NatModule String ≟ Lean.Grind.NatModule String
2034
[Meta.synthInstance] ✅️ apply @Lean.Grind.Semiring.toAdd to Add String
2135
[Meta.synthInstance.tryResolve] ✅️ Add String ≟ Add String
2236
[Meta.synthInstance] new goal Lean.Grind.Semiring String
@@ -47,7 +61,21 @@ trace: [Meta.synthInstance] ❌️ Add String
4761
/--
4862
trace: [Meta.synthInstance] ❌️ Add Bool
4963
[Meta.synthInstance] new goal Add Bool
50-
[Meta.synthInstance.instances] #[@Lean.Grind.Semiring.toAdd]
64+
[Meta.synthInstance.instances] #[@Lean.Grind.Semiring.toAdd, @Lean.Grind.NatModule.toAdd, @Lean.Grind.IntModule.toAdd]
65+
[Meta.synthInstance] ✅️ apply @Lean.Grind.IntModule.toAdd to Add Bool
66+
[Meta.synthInstance.tryResolve] ✅️ Add Bool ≟ Add Bool
67+
[Meta.synthInstance] new goal Lean.Grind.IntModule Bool
68+
[Meta.synthInstance.instances] #[@Lean.Grind.RatModule.toIntModule]
69+
[Meta.synthInstance] ✅️ apply @Lean.Grind.RatModule.toIntModule to Lean.Grind.IntModule Bool
70+
[Meta.synthInstance.tryResolve] ✅️ Lean.Grind.IntModule Bool ≟ Lean.Grind.IntModule Bool
71+
[Meta.synthInstance] no instances for Lean.Grind.RatModule Bool
72+
[Meta.synthInstance.instances] #[]
73+
[Meta.synthInstance] ✅️ apply @Lean.Grind.NatModule.toAdd to Add Bool
74+
[Meta.synthInstance.tryResolve] ✅️ Add Bool ≟ Add Bool
75+
[Meta.synthInstance] new goal Lean.Grind.NatModule Bool
76+
[Meta.synthInstance.instances] #[Lean.Grind.IntModule.toNatModule]
77+
[Meta.synthInstance] ✅️ apply Lean.Grind.IntModule.toNatModule to Lean.Grind.NatModule Bool
78+
[Meta.synthInstance.tryResolve] ✅️ Lean.Grind.NatModule Bool ≟ Lean.Grind.NatModule Bool
5179
[Meta.synthInstance] ✅️ apply @Lean.Grind.Semiring.toAdd to Add Bool
5280
[Meta.synthInstance.tryResolve] ✅️ Add Bool ≟ Add Bool
5381
[Meta.synthInstance] new goal Lean.Grind.Semiring Bool

tests/lean/run/info_trees.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ info: • command @ ⟨82, 0⟩-⟨82, 40⟩ @ Lean.Elab.Command.elabDeclaration
6161
⊢ 0 ≤ n
6262
after no goals
6363
• Nat.zero_le n : 0 ≤ n @ ⟨1, 1⟩†-⟨1, 1⟩† @ Lean.Elab.Term.elabApp
64-
[.] Nat.zero_le : some LE.le.{0} Nat instLENat (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0)) _uniq.41 @ ⟨1, 0⟩†-⟨1, 0⟩†
64+
[.] Nat.zero_le : some LE.le.{0} Nat instLENat (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0)) _uniq.42 @ ⟨1, 0⟩†-⟨1, 0⟩†
6565
• Nat.zero_le : ∀ (n : Nat), 0 ≤ n @ ⟨1, 0⟩†-⟨1, 0⟩†
6666
• n : Nat @ ⟨1, 5⟩†-⟨1, 5⟩† @ Lean.Elab.Term.elabIdent
6767
[.] n : some Nat @ ⟨1, 5⟩†-⟨1, 5⟩†

0 commit comments

Comments
 (0)