Skip to content

Commit ad4663c

Browse files
committed
feat: norm_num ext for Int.floor (#13647)
I tried this a while ago in leanprover-community/mathlib3#16502; this is now just one of the handlers from that PR.
1 parent 9efc417 commit ad4663c

File tree

2 files changed

+55
-1
lines changed

2 files changed

+55
-1
lines changed

Mathlib/Data/Rat/Floor.lean

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ instance : FloorRing ℚ :=
4949

5050
protected theorem floor_def {q : ℚ} : ⌊q⌋ = q.num / q.den := Rat.floor_def' q
5151

52-
theorem floor_int_div_nat_eq_div {n : ℤ} {d : ℕ} : ⌊(↑n : ℚ) / (↑d : ℚ)⌋ = n / (↑d : ℤ) := by
52+
theorem floor_int_div_nat_eq_div (n : ℤ) (d : ℕ) : ⌊(↑n : ℚ) / (↑d : ℚ)⌋ = n / (↑d : ℤ) := by
5353
rw [Rat.floor_def]
5454
obtain rfl | hd := @eq_zero_or_pos _ _ d
5555
· simp
@@ -78,6 +78,48 @@ theorem round_cast (x : ℚ) : round (x : α) = round x := by
7878
theorem cast_fract (x : ℚ) : (↑(fract x) : α) = fract (x : α) := by
7979
simp only [fract, cast_sub, cast_intCast, floor_cast]
8080

81+
section NormNum
82+
83+
open Mathlib.Meta.NormNum Qq
84+
85+
theorem isNat_intFloor {R} [LinearOrderedRing R] [FloorRing R] (r : R) (m : ℕ) :
86+
IsNat r m → IsNat ⌊r⌋ m := by rintro ⟨⟨⟩⟩; exact ⟨by simp⟩
87+
88+
theorem isInt_intFloor {R} [LinearOrderedRing R] [FloorRing R] (r : R) (m : ℤ) :
89+
IsInt r m → IsInt ⌊r⌋ m := by rintro ⟨⟨⟩⟩; exact ⟨by simp⟩
90+
91+
theorem isInt_intFloor_ofIsRat (r : α) (n : ℤ) (d : ℕ) :
92+
IsRat r n d → IsInt ⌊r⌋ (n / d) := by
93+
rintro ⟨inv, rfl⟩
94+
constructor
95+
simp only [invOf_eq_inv, ← div_eq_mul_inv, Int.cast_id]
96+
rw [← floor_int_div_nat_eq_div n d, ← floor_cast (α := α), Rat.cast_div,
97+
cast_intCast, cast_natCast]
98+
99+
/-- `norm_num` extension for `Int.floor` -/
100+
@[norm_num ⌊_⌋]
101+
def evalIntFloor : NormNumExt where eval {u αZ} e := do
102+
match u, αZ, e with
103+
| 0, ~q(ℤ), ~q(@Int.floor $α $instR $instF $x) =>
104+
match ← derive x with
105+
| .isBool .. => failure
106+
| .isNat sα nb pb => do
107+
assertInstancesCommute
108+
return .isNat q(inferInstance) _ q(isNat_intFloor $x _ $pb)
109+
| .isNegNat sα nb pb => do
110+
assertInstancesCommute
111+
-- floor always keeps naturals negative, so we can shortcut `.isInt`
112+
return .isNegNat q(inferInstance) _ q(isInt_intFloor _ _ $pb)
113+
| .isRat dα q n d h => do
114+
let _i ← synthInstanceQ q(LinearOrderedField $α)
115+
assertInstancesCommute
116+
have z : Q(ℤ) := mkRawIntLit ⌊q⌋
117+
letI : $z =Q ⌊$n / $d⌋ := ⟨⟩
118+
return .isInt q(inferInstance) z ⌊q⌋ q(isInt_intFloor_ofIsRat _ $n $d $h)
119+
| _, _, _ => failure
120+
121+
end NormNum
122+
81123
end Rat
82124

83125
theorem Int.mod_nat_eq_sub_mul_floor_rat_div {n : ℤ} {d : ℕ} : n % d = n - d * ⌊(n : ℚ) / d⌋ := by

test/norm_num_ext.lean

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,18 @@ example : ∏ i ∈ Finset.range 9, Nat.sqrt (i + 1) = 96 := by norm_num1
389389

390390
end big_operators
391391

392+
section floor
393+
394+
variable (R : Type*) [LinearOrderedRing R] [FloorRing R]
395+
variable (K : Type*) [LinearOrderedField K] [FloorRing K]
396+
397+
example : ⌊(-1 : R)⌋ = -1 := by norm_num
398+
example : ⌊(2 : R)⌋ = 2 := by norm_num
399+
example : ⌊(15 / 16 : K)⌋ + 1 = 1 := by norm_num
400+
example : ⌊(-15 / 16 : K)⌋ + 1 = 0 := by norm_num
401+
402+
end floor
403+
392404
section jacobi
393405

394406
-- Jacobi and Legendre symbols

0 commit comments

Comments
 (0)