Skip to content

Commit cea0638

Browse files
kim-emIvanRenisonRuben-VandeVelde
committed
feat: fin_omega, a wrapper around omega to help with Fin arithmetic goals. (#16651)
This is a hack, and that results in `omega` having to deal with a lot of case splitting, but it is usable. The simp set could probably be expanded a bit, and I've left a comment inviting such changes. This was inspired by #15817, and in particular replaces the new proof added in that PR with `by fin_omega`. Co-authored-by: Iván Renison <85908989+IvanRenison@users.noreply.github.com> Co-authored-by: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com>
1 parent 54358ec commit cea0638

File tree

4 files changed

+85
-24
lines changed

4 files changed

+85
-24
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2251,6 +2251,7 @@ import Mathlib.Data.Int.Cast.Prod
22512251
import Mathlib.Data.Int.CharZero
22522252
import Mathlib.Data.Int.ConditionallyCompleteOrder
22532253
import Mathlib.Data.Int.Defs
2254+
import Mathlib.Data.Int.DivMod
22542255
import Mathlib.Data.Int.GCD
22552256
import Mathlib.Data.Int.Interval
22562257
import Mathlib.Data.Int.LeastGreatest

Mathlib/Data/Fin/Basic.lean

Lines changed: 61 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ Authors: Robert Y. Lewis, Keeley Hoek
55
-/
66
import Mathlib.Algebra.NeZero
77
import Mathlib.Data.Nat.Defs
8+
import Mathlib.Data.Int.DivMod
89
import Mathlib.Logic.Embedding.Basic
910
import Mathlib.Logic.Equiv.Set
1011
import Mathlib.Tactic.Common
12+
import Mathlib.Tactic.Attr.Register
1113

1214
/-!
1315
# The finite type with `n` elements
@@ -190,6 +192,7 @@ protected theorem heq_ext_iff {k l : ℕ} (h : k = l) {i : Fin k} {j : Fin l} :
190192

191193
end coe
192194

195+
193196
section Order
194197

195198
/-!
@@ -332,6 +335,58 @@ theorem one_lt_last [NeZero n] : 1 < last (n + 1) := by
332335

333336
end Order
334337

338+
/-! ### Coercions to `ℤ` and the `fin_omega` tactic. -/
339+
340+
open Int
341+
342+
theorem coe_int_sub_eq_ite {n : Nat} (u v : Fin n) :
343+
((u - v : Fin n) : Int) = if v ≤ u then (u - v : Int) else (u - v : Int) + n := by
344+
rw [Fin.sub_def]
345+
split
346+
· rw [ofNat_emod, Int.emod_eq_sub_self_emod, Int.emod_eq_of_lt] <;> omega
347+
· rw [ofNat_emod, Int.emod_eq_of_lt] <;> omega
348+
349+
theorem coe_int_sub_eq_mod {n : Nat} (u v : Fin n) :
350+
((u - v : Fin n) : Int) = ((u : Int) - (v : Int)) % n := by
351+
rw [coe_int_sub_eq_ite]
352+
split
353+
· rw [Int.emod_eq_of_lt] <;> omega
354+
· rw [Int.emod_eq_add_self_emod, Int.emod_eq_of_lt] <;> omega
355+
356+
theorem coe_int_add_eq_ite {n : Nat} (u v : Fin n) :
357+
((u + v : Fin n) : Int) = if (u + v : ℕ) < n then (u + v : Int) else (u + v : Int) - n := by
358+
rw [Fin.add_def]
359+
split
360+
· rw [ofNat_emod, Int.emod_eq_of_lt] <;> omega
361+
· rw [ofNat_emod, Int.emod_eq_sub_self_emod, Int.emod_eq_of_lt] <;> omega
362+
363+
theorem coe_int_add_eq_mod {n : Nat} (u v : Fin n) :
364+
((u + v : Fin n) : Int) = ((u : Int) + (v : Int)) % n := by
365+
rw [coe_int_add_eq_ite]
366+
split
367+
· rw [Int.emod_eq_of_lt] <;> omega
368+
· rw [Int.emod_eq_sub_self_emod, Int.emod_eq_of_lt] <;> omega
369+
370+
-- Write `a + b` as `if (a + b : ℕ) < n then (a + b : ℤ) else (a + b : ℤ) - n` and
371+
-- similarly `a - b` as `if (b : ℕ) ≤ a then (a - b : ℤ) else (a - b : ℤ) + n`.
372+
attribute [fin_omega] coe_int_sub_eq_ite coe_int_add_eq_ite
373+
374+
-- Rewrite inequalities in `Fin` to inequalities in `ℕ`
375+
attribute [fin_omega] Fin.lt_iff_val_lt_val Fin.le_iff_val_le_val
376+
377+
-- Rewrite `1 : Fin (n + 2)` to `1 : ℤ`
378+
attribute [fin_omega] val_one
379+
380+
/--
381+
Preprocessor for `omega` to handle inequalities in `Fin`.
382+
Note that this involves a lot of case splitting, so may be slow.
383+
-/
384+
-- Further adjustment to the simp set can probably make this more powerful.
385+
-- Please experiment and PR updates!
386+
macro "fin_omega" : tactic => `(tactic|
387+
{ try simp only [fin_omega, ← Int.ofNat_lt, ← Int.ofNat_le] at *
388+
omega })
389+
335390
section Add
336391

337392
/-!
@@ -1439,9 +1494,8 @@ instance uniqueFinOne : Unique (Fin 1) where
14391494
@[simp]
14401495
theorem coe_fin_one (a : Fin 1) : (a : ℕ) = 0 := by simp [Subsingleton.elim a 0]
14411496

1442-
lemma eq_one_of_neq_zero (i : Fin 2) (hi : i ≠ 0) : i = 1 :=
1443-
fin_two_eq_of_eq_zero_iff
1444-
(by simpa only [one_eq_zero_iff, succ.injEq, iff_false, reduceCtorEq] using hi)
1497+
lemma eq_one_of_neq_zero (i : Fin 2) (hi : i ≠ 0) : i = 1 := by
1498+
fin_omega
14451499

14461500
@[simp]
14471501
theorem coe_neg_one : ↑(-1 : Fin (n + 1)) = n := by
@@ -1454,15 +1508,7 @@ theorem last_sub (i : Fin (n + 1)) : last n - i = Fin.rev i :=
14541508
Fin.ext <| by rw [coe_sub_iff_le.2 i.le_last, val_last, val_rev, Nat.succ_sub_succ_eq_sub]
14551509

14561510
theorem add_one_le_of_lt {n : ℕ} {a b : Fin (n + 1)} (h : a < b) : a + 1 ≤ b := by
1457-
cases' a with a ha
1458-
cases' b with b hb
1459-
cases n
1460-
· simp only [Nat.zero_add, Nat.lt_one_iff] at ha hb
1461-
simp [ha, hb]
1462-
simp only [le_iff_val_le_val, val_add, lt_iff_val_lt_val, val_mk, val_one] at h ⊢
1463-
rwa [Nat.mod_eq_of_lt, Nat.succ_le_iff]
1464-
rw [Nat.succ_lt_succ_iff]
1465-
exact h.trans_le (Nat.le_of_lt_succ hb)
1511+
cases n <;> fin_omega
14661512

14671513
theorem exists_eq_add_of_le {n : ℕ} {a b : Fin n} (h : a ≤ b) : ∃ k ≤ b, b = a + k := by
14681514
obtain ⟨k, hk⟩ : ∃ k : ℕ, (b : ℕ) = a + k := Nat.exists_eq_add_of_le h
@@ -1473,27 +1519,18 @@ theorem exists_eq_add_of_le {n : ℕ} {a b : Fin n} (h : a ≤ b) : ∃ k ≤ b,
14731519
theorem exists_eq_add_of_lt {n : ℕ} {a b : Fin (n + 1)} (h : a < b) :
14741520
∃ k < b, k + 1 ≤ b ∧ b = a + k + 1 := by
14751521
cases n
1476-
· cases' a with a ha
1477-
cases' b with b hb
1478-
simp only [Nat.zero_add, Nat.lt_one_iff] at ha hb
1479-
simp [ha, hb] at h
1522+
· omega
14801523
obtain ⟨k, hk⟩ : ∃ k : ℕ, (b : ℕ) = a + k + 1 := Nat.exists_eq_add_of_lt h
14811524
have hkb : k < b := by omega
1482-
refine ⟨⟨k, hkb.trans b.is_lt⟩, hkb, ?_, ?_⟩
1483-
· rw [Fin.le_iff_val_le_val, Fin.val_add_one]
1484-
split_ifs <;> simp [Nat.succ_le_iff, hkb]
1525+
refine ⟨⟨k, hkb.trans b.is_lt⟩, hkb, by fin_omega, ?_⟩
14851526
simp [Fin.ext_iff, Fin.val_add, ← hk, Nat.mod_eq_of_lt b.is_lt]
14861527

14871528
lemma pos_of_ne_zero {n : ℕ} {a : Fin (n + 1)} (h : a ≠ 0) :
14881529
0 < a :=
14891530
Nat.pos_of_ne_zero (val_ne_of_ne h)
14901531

14911532
lemma sub_succ_le_sub_of_le {n : ℕ} {u v : Fin (n + 2)} (h : u < v) : v - (u + 1) < v - u := by
1492-
have h' : u + 1 ≤ v := add_one_le_of_lt h
1493-
apply lt_def.mpr
1494-
simp only [sub_val_of_le h', sub_val_of_le (Fin.le_of_lt h)]
1495-
refine Nat.sub_lt_sub_left h (lt_def.mp ?_)
1496-
exact lt_add_one_iff.mpr (Fin.lt_of_lt_of_le h v.le_last)
1533+
fin_omega
14971534

14981535
end AddGroup
14991536

Mathlib/Data/Int/DivMod.lean

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/-
2+
Copyright (c) 2024 Lean FRO. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Kim Morrison
5+
-/
6+
7+
/-!
8+
# Basic lemmas about division and modulo for integers
9+
10+
-/
11+
12+
namespace Int
13+
14+
/-! ### `emod` -/
15+
16+
theorem emod_eq_sub_self_emod {a b : Int} : a % b = (a - b) % b :=
17+
(emod_sub_cancel a b).symm
18+
19+
theorem emod_eq_add_self_emod {a b : Int} : a % b = (a + b) % b :=
20+
add_emod_self.symm

Mathlib/Tactic/Attr/Register.lean

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,6 @@ register_simp_attr nontriviality
8484

8585
/-- A stub attribute for `is_poly`. -/
8686
register_label_attr is_poly
87+
88+
/-- A simp set for the `fin_omega` wrapper around `omega`. -/
89+
register_simp_attr fin_omega

0 commit comments

Comments
 (0)