Skip to content

Commit f07e974

Browse files
committed
feat: make ring work for semifields (#28494)
Generalize `ring`'s division ring theorems to division semiring. This means `ring` will work for commutative division semirings aka semifields. From [#mathlib4 > ring for NNReal @ 💬](https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/ring.20for.20NNReal/near/534664969)
1 parent b2b88d7 commit f07e974

File tree

2 files changed

+28
-24
lines changed

2 files changed

+28
-24
lines changed

Mathlib/Tactic/Ring/Basic.lean

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -899,16 +899,16 @@ def evalPow {a : Q($α)} {b : Q(ℕ)} (va : ExSum sα a) (vb : ExSum sℕ b) :
899899
structure Cache {α : Q(Type u)} (sα : Q(CommSemiring $α)) where
900900
/-- A ring instance on `α`, if available. -/
901901
rα : Option Q(Ring $α)
902-
/-- A division ring instance on `α`, if available. -/
903-
: Option Q(DivisionRing $α)
902+
/-- A division semiring instance on `α`, if available. -/
903+
dsα : Option Q(DivisionSemiring $α)
904904
/-- A characteristic zero ring instance on `α`, if available. -/
905905
czα : Option Q(CharZero $α)
906906

907907
/-- Create a new cache for `α` by doing the necessary instance searches. -/
908908
def mkCache {α : Q(Type u)} (sα : Q(CommSemiring $α)) : MetaM (Cache sα) :=
909909
return {
910910
rα := (← trySynthInstanceQ q(Ring $α)).toOption
911-
:= (← trySynthInstanceQ q(DivisionRing $α)).toOption
911+
dsα := (← trySynthInstanceQ q(DivisionSemiring $α)).toOption
912912
czα := (← trySynthInstanceQ q(CharZero $α)).toOption }
913913

914914
theorem cast_pos {n : ℕ} : IsNat (a : R) n → a = n.rawCast + 0
@@ -975,22 +975,22 @@ def evalAtom (e : Q($α)) : AtomM (Result (ExSum sα) e) := do
975975
| none => (q(atom_pf $e) : Expr)
976976
| some (p : Q($e = $a')) => (q(atom_pf' $p) : Expr)⟩
977977

978-
theorem inv_mul {R} [DivisionRing R] {a₁ a₂ a₃ b₁ b₃ c}
978+
theorem inv_mul {R} [DivisionSemiring R] {a₁ a₂ a₃ b₁ b₃ c}
979979
(_ : (a₁⁻¹ : R) = b₁) (_ : (a₃⁻¹ : R) = b₃)
980980
(_ : b₃ * (b₁ ^ a₂ * (nat_lit 1).rawCast) = c) :
981981
(a₁ ^ a₂ * a₃ : R)⁻¹ = c := by subst_vars; simp
982982

983-
nonrec theorem inv_zero {R} [DivisionRing R] : (0 : R)⁻¹ = 0 := inv_zero
983+
nonrec theorem inv_zero {R} [DivisionSemiring R] : (0 : R)⁻¹ = 0 := inv_zero
984984

985-
theorem inv_single {R} [DivisionRing R] {a b : R}
985+
theorem inv_single {R} [DivisionSemiring R] {a b : R}
986986
(_ : (a : R)⁻¹ = b) : (a + 0)⁻¹ = b + 0 := by simp [*]
987987
theorem inv_add {a₁ a₂ : ℕ} (_ : ((a₁ : ℕ) : R) = b₁) (_ : ((a₂ : ℕ) : R) = b₂) :
988988
((a₁ + a₂ : ℕ) : R) = b₁ + b₂ := by
989989
subst_vars; simp
990990

991991
section
992992

993-
variable ( : Q(DivisionRing $α))
993+
variable (dsα : Q(DivisionSemiring $α))
994994

995995
/-- Applies `⁻¹` to a polynomial to get an atom. -/
996996
def evalInvAtom (a : Q($α)) : AtomM (Result (ExBase sα) q($a⁻¹)) := do
@@ -1009,16 +1009,16 @@ def ExProd.evalInv {a : Q($α)} (czα : Option Q(CharZero $α)) (va : ExProd sα
10091009
| .const c hc =>
10101010
let ra := Result.ofRawRat c a hc
10111011
match ← (Lean.observing? <|
1012-
NormNum.evalInv.core q($a⁻¹) a ra q(DivisionRing.toDivisionSemiring) czα :) with
1012+
NormNum.evalInv.core q($a⁻¹) a ra dsα czα :) with
10131013
| some rc =>
10141014
let ⟨zc, hc⟩ := rc.toRatNZ.get!
10151015
let ⟨c, pc⟩ := rc.toRawEq
10161016
pure ⟨c, .const zc hc, pc⟩
10171017
| none =>
1018-
let ⟨_, vc, pc⟩ ← evalInvAtom sα a
1018+
let ⟨_, vc, pc⟩ ← evalInvAtom sα dsα a
10191019
pure ⟨_, vc.toProd (ExProd.mkNat sℕ 1).2, q(toProd_pf $pc)⟩
10201020
| .mul (x := a₁) (e := _a₂) _va₁ va₂ va₃ => do
1021-
let ⟨_b₁, vb₁, pb₁⟩ ← evalInvAtom sα a₁
1021+
let ⟨_b₁, vb₁, pb₁⟩ ← evalInvAtom sα dsα a₁
10221022
let ⟨_b₃, vb₃, pb₃⟩ ← va₃.evalInv czα
10231023
let ⟨c, vc, (pc : Q($_b₃ * ($_b₁ ^ $_a₂ * Nat.rawCast 1) = $c))⟩ ←
10241024
evalMulProd sα vb₃ (vb₁.toProd va₂)
@@ -1034,23 +1034,24 @@ def ExSum.evalInv {a : Q($α)} (czα : Option Q(CharZero $α)) (va : ExSum sα a
10341034
match va with
10351035
| ExSum.zero => pure ⟨_, .zero, (q(inv_zero (R := $α)) : Expr)⟩
10361036
| ExSum.add va ExSum.zero => do
1037-
let ⟨_, vb, pb⟩ ← va.evalInv sα czα
1037+
let ⟨_, vb, pb⟩ ← va.evalInv sα dsα czα
10381038
pure ⟨_, vb.toSum, (q(inv_single $pb) : Expr)⟩
10391039
| va => do
1040-
let ⟨_, vb, pb⟩ ← evalInvAtom sα a
1040+
let ⟨_, vb, pb⟩ ← evalInvAtom sα dsα a
10411041
pure ⟨_, vb.toProd (ExProd.mkNat sℕ 1).2 |>.toSum, q(atom_pf' $pb)⟩
10421042

10431043
end
10441044

1045-
theorem div_pf {R} [DivisionRing R] {a b c d : R} (_ : b⁻¹ = c) (_ : a * c = d) : a / b = d := by
1045+
theorem div_pf {R} [DivisionSemiring R] {a b c d : R}
1046+
(_ : b⁻¹ = c) (_ : a * c = d) : a / b = d := by
10461047
subst_vars; simp [div_eq_mul_inv]
10471048

10481049
/-- Divides two polynomials `va, vb` to get a normalized result polynomial.
10491050
10501051
* `a / b = a * b⁻¹`
10511052
-/
1052-
def evalDiv {a b : Q($α)} (rα : Q(DivisionRing $α)) (czα : Option Q(CharZero $α)) (va : ExSum sα a)
1053-
(vb : ExSum sα b) : AtomM (Result (ExSum sα) q($a / $b)) := do
1053+
def evalDiv {a b : Q($α)} (rα : Q(DivisionSemiring $α)) (czα : Option Q(CharZero $α))
1054+
(va : ExSum sα a) (vb : ExSum sα b) : AtomM (Result (ExSum sα) q($a / $b)) := do
10541055
let ⟨_c, vc, pc⟩ ← vb.evalInv sα rα czα
10551056
let ⟨d, vd, (pd : Q($a * $_c = $d))⟩ ← evalMul sα va vc
10561057
pure ⟨d, vd, q(div_pf $pc $pd)⟩
@@ -1074,14 +1075,14 @@ theorem neg_congr {R} [Ring R] {a a' b : R} (_ : a = a')
10741075
theorem sub_congr {R} [Ring R] {a a' b b' c : R} (_ : a = a') (_ : b = b')
10751076
(_ : a' - b' = c) : (a - b : R) = c := by subst_vars; rfl
10761077

1077-
theorem inv_congr {R} [DivisionRing R] {a a' b : R} (_ : a = a')
1078+
theorem inv_congr {R} [DivisionSemiring R] {a a' b : R} (_ : a = a')
10781079
(_ : a'⁻¹ = b) : (a⁻¹ : R) = b := by subst_vars; rfl
10791080

1080-
theorem div_congr {R} [DivisionRing R] {a a' b b' c : R} (_ : a = a') (_ : b = b')
1081+
theorem div_congr {R} [DivisionSemiring R] {a a' b b' c : R} (_ : a = a') (_ : b = b')
10811082
(_ : a' / b' = c) : (a / b : R) = c := by subst_vars; rfl
10821083

10831084
/-- A precomputed `Cache` for `ℕ`. -/
1084-
def Cache.nat : Cache sℕ := { rα := none, := none, czα := some q(inferInstance) }
1085+
def Cache.nat : Cache sℕ := { rα := none, dsα := none, czα := some q(inferInstance) }
10851086

10861087
/-- Checks whether `e` would be processed by `eval` as a ring expression,
10871088
or otherwise if it is an atom or something simplifiable via `norm_num`.
@@ -1101,7 +1102,7 @@ def isAtomOrDerivable {u} {α : Q(Type u)} (sα : Q(CommSemiring $α))
11011102
pure <| some (evalCast sα (← derive e))
11021103
catch _ => pure (some none)
11031104
let .const n _ := (← withReducible <| whnf e).getAppFn | els
1104-
match n, c.rα, c. with
1105+
match n, c.rα, c.dsα with
11051106
| ``HAdd.hAdd, _, _ | ``Add.add, _, _
11061107
| ``HMul.hMul, _, _ | ``Mul.mul, _, _
11071108
| ``HSMul.hSMul, _, _
@@ -1122,7 +1123,7 @@ partial def eval {u : Lean.Level} {α : Q(Type u)} (sα : Q(CommSemiring $α))
11221123
try evalCast sα (← derive e)
11231124
catch _ => evalAtom sα e
11241125
let .const n _ := (← withReducible <| whnf e).getAppFn | els
1125-
match n, c.rα, c. with
1126+
match n, c.rα, c.dsα with
11261127
| ``HAdd.hAdd, _, _ | ``Add.add, _, _ => match e with
11271128
| ~q($a + $b) =>
11281129
let ⟨_, va, pa⟩ ← eval sα c a
@@ -1164,17 +1165,17 @@ partial def eval {u : Lean.Level} {α : Q(Type u)} (sα : Q(CommSemiring $α))
11641165
let ⟨c, vc, p⟩ ← evalSub sα rα va vb
11651166
pure ⟨c, vc, q(sub_congr $pa $pb $p)⟩
11661167
| _ => els
1167-
| ``Inv.inv, _, some => match e with
1168+
| ``Inv.inv, _, some dsα => match e with
11681169
| ~q($a⁻¹) =>
11691170
let ⟨_, va, pa⟩ ← eval sα c a
1170-
let ⟨b, vb, p⟩ ← va.evalInv sα c.czα
1171+
let ⟨b, vb, p⟩ ← va.evalInv sα dsα c.czα
11711172
pure ⟨b, vb, q(inv_congr $pa $p)⟩
11721173
| _ => els
1173-
| ``HDiv.hDiv, _, some | ``Div.div, _, some => match e with
1174+
| ``HDiv.hDiv, _, some dsα | ``Div.div, _, some dsα => match e with
11741175
| ~q($a / $b) => do
11751176
let ⟨_, va, pa⟩ ← eval sα c a
11761177
let ⟨_, vb, pb⟩ ← eval sα c b
1177-
let ⟨c, vc, p⟩ ← evalDiv sα c.czα va vb
1178+
let ⟨c, vc, p⟩ ← evalDiv sα dsα c.czα va vb
11781179
pure ⟨c, vc, q(div_congr $pa $pb $p)⟩
11791180
| _ => els
11801181
| _, _, _ => els

MathlibTest/ring.lean

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,3 +234,6 @@ example (x : ℝ) (f : ℝ → ℝ) : True := by
234234
-- Test that `ring_nf` doesn't get confused about bound variables
235235
example : (fun x : ℝ => x * x^2) = (fun y => y^2 * y) := by
236236
ring_nf
237+
238+
-- Test that `ring` works for division without subtraction
239+
example {R : Type} [Semifield R] [CharZero R] {x : R} : x / 2 + x / 2 = x := by ring

0 commit comments

Comments
 (0)