lean4-htt/src/Init/Grind/Ring/Field.lean
Kyle Miller 0db4ac18e5
feat: beta reduce while elaborating applications (#13807)
This PR modifies the app elaborator to beta reduce arguments while
substituting them into expected types for later arguments. This makes it
consistent with `inferType` and `instantiateMVars`, which both beta
reduce substitutions. In particular, this change ensures that the app
elaborator behaves as if it creates metavariables for each parameter and
assigns elaborated arguments to the metavariables. **Breaking change:**
tactic proofs may need to be modified to remove unnecessary steps, e.g.
`dsimp only` steps that were previously for beta reductions.
2026-05-21 07:26:00 +00:00

244 lines
9.6 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
Copyright (c) 2025 Lean FRO, LLC. or its affiliates. All Rights Reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
module
prelude
public import Init.Grind.Ring.Basic
public import Init.Data.Nat.Div.Basic
import Init.ByCases
import Init.Omega
import Init.RCases
import Init.TacticsExtra
public section
namespace Lean.Grind
/--
A field is a commutative ring with inverses for all non-zero elements.
-/
class Field (α : Type u) extends CommRing α, Inv α, Div α where
/-- An exponentiation operator. -/
[zpow : HPow α Int α]
/-- Division is multiplication by the inverse. -/
div_eq_mul_inv : ∀ a b : α, a / b = a * b⁻¹
/-- Zero is not equal to one: fields are non trivial.-/
zero_ne_one : (0 : α) ≠ 1
/-- The inverse of zero is zero. This is a "junk value" convention. -/
inv_zero : (0 : α)⁻¹ = 0
/-- The inverse of a non-zero element is a right inverse. -/
mul_inv_cancel : ∀ {a : α}, a ≠ 0 → a * a⁻¹ = 1
/-- The zeroth power of any element is one. -/
zpow_zero : ∀ a : α, a ^ (0 : Int) = 1
/-- The (n+1)-st power of any element is the element multiplied by the n-th power. -/
zpow_succ : ∀ (a : α) (n : Nat), a ^ (n + 1 : Int) = a ^ (n : Int) * a
/-- Raising to a negative power is the inverse of raising to the positive power. -/
zpow_neg : ∀ (a : α) (n : Int), a ^ (-n) = (a ^ n)⁻¹
attribute [implicit_reducible] Field.zpow
attribute [instance 100] Field.toInv Field.toDiv Field.zpow
namespace Field
variable [Field α] {a : α}
theorem inv_mul_cancel (h : a ≠ 0) : a⁻¹ * a = 1 := by
rw [CommSemiring.mul_comm, mul_inv_cancel h]
theorem eq_inv_of_mul_eq_one (h : a * b = 1) : a = b⁻¹ := by
by_cases h' : b = 0
· subst h'
rw [Semiring.mul_zero] at h
exfalso
exact zero_ne_one h
· replace h := congrArg (fun x => x * b⁻¹) h
simpa [Semiring.mul_assoc, mul_inv_cancel h', Semiring.mul_one, Semiring.one_mul] using h
theorem inv_one : (1 : α)⁻¹ = 1 :=
(eq_inv_of_mul_eq_one (Semiring.mul_one 1)).symm
theorem inv_inv (a : α) : a⁻¹⁻¹ = a := by
by_cases h : a = 0
· subst h
simp [Field.inv_zero]
· symm
apply eq_inv_of_mul_eq_one
exact mul_inv_cancel h
theorem inv_eq_iff_eq_iff (a b : α) : a⁻¹ = b ↔ a = b⁻¹ := by
constructor
· intro h
rw [← h, inv_inv]
· intro h
rw [h, inv_inv]
theorem inv_neg (a : α) : (-a)⁻¹ = -a⁻¹ := by
by_cases h : a = 0
· subst h
simp [Field.inv_zero, AddCommGroup.neg_zero]
· symm
apply eq_inv_of_mul_eq_one
simp [Ring.neg_mul, Ring.mul_neg, AddCommGroup.neg_neg, Field.inv_mul_cancel h]
theorem inv_eq_zero_iff {a : α} : a⁻¹ = 0 ↔ a = 0 := by
constructor
· intro w
by_cases h : a = 0
· subst h
rfl
· have := congrArg (fun x => x * a) w
-- TODO(kmill): remove after stage0 update
try dsimp at this
rw [Semiring.zero_mul, inv_mul_cancel h] at this
exfalso
exact zero_ne_one this.symm
· intro w
subst w
simp [Field.inv_zero]
theorem zero_eq_inv_iff {a : α} : 0 = a⁻¹ ↔ 0 = a := by
rw [eq_comm, inv_eq_zero_iff, eq_comm]
theorem of_mul_eq_zero {a b : α} : a * b = 0 → a = 0 b = 0 := by
cases (Classical.em (a = 0)); · simp [*, Semiring.zero_mul]
cases (Classical.em (b = 0)); · simp [*, Semiring.mul_zero]
rename_i h₁ h₂
replace h₁ := Field.mul_inv_cancel h₁
replace h₂ := Field.mul_inv_cancel h₂
intro h
replace h := congrArg (· * b⁻¹ * a⁻¹) h; simp [Semiring.zero_mul] at h
rw [Semiring.mul_assoc, Semiring.mul_assoc, ← Semiring.mul_assoc b, h₂, Semiring.one_mul, h₁] at h
have := Field.zero_ne_one (α := α)
simp [h] at this
theorem inv_mul (a b : α) : (a*b)⁻¹ = a⁻¹*b⁻¹ := by
cases (Classical.em (a = 0)); simp [*, Semiring.zero_mul, Field.inv_zero]
cases (Classical.em (b = 0)); simp [*, Semiring.mul_zero, Field.inv_zero]
cases (Classical.em (a*b = 0)); simp [*, Field.inv_zero]
next h => cases (of_mul_eq_zero h) <;> contradiction
next h₁ h₂ h₃ =>
replace h₁ := Field.inv_mul_cancel h₁
replace h₂ := Field.inv_mul_cancel h₂
replace h₃ := Field.mul_inv_cancel h₃
replace h₃ := congrArg (b⁻¹*a⁻¹* ·) h₃; try simp at h₃ -- TODO(kmill): remove simp after stage0 update
rw [Semiring.mul_assoc, Semiring.mul_assoc, ← Semiring.mul_assoc (a⁻¹), h₁, Semiring.one_mul,
← Semiring.mul_assoc, h₂, Semiring.one_mul, Semiring.mul_one, CommRing.mul_comm (b⁻¹)] at h₃
assumption
theorem of_pow_eq_zero (a : α) (n : Nat) : a^n = 0 → a = 0 := by
induction n
next => simp [Semiring.pow_zero]; intro h; have := zero_ne_one (α := α); exfalso; exact this h.symm
next n ih =>
simp [Semiring.pow_succ]; intro h
apply Classical.byContradiction
intro hne
have := Field.mul_inv_cancel hne
replace h := congrArg (· * a⁻¹) h; try simp at h -- TODO(kmill): remove simp after stage0 update
rw [Semiring.mul_assoc, this, Semiring.mul_one, Semiring.zero_mul] at h
have := ih h
contradiction
theorem zpow_natCast (a : α) (n : Nat) : a ^ (n : Int) = a ^ n := by
induction n
next => simp [zpow_zero, Semiring.pow_zero]
next n ih => rw [Int.natCast_add_one, zpow_succ, ih, Semiring.pow_succ]
theorem zpow_one (a : α) : a ^ (1 : Int) = a := by
have : (1 : Int) = 0 + 1 := rfl
rw [this, ← Int.natCast_zero, zpow_succ, Int.natCast_zero, zpow_zero, Semiring.one_mul]
theorem zpow_neg_one (a : α) : a ^ (-1) = a⁻¹ := by
rw [zpow_neg, zpow_one]
theorem zpow_add_one {a : α} (h : a ≠ 0) (n : Int) : a ^ (n + 1) = a ^ n * a := by
match n with
| (n : Nat) => rw [zpow_succ, zpow_natCast]
| -(n + 1 : Nat) =>
rw [zpow_neg, Int.natCast_add, Int.cast_ofNat_Int, Int.neg_add, Int.neg_add_cancel_right,
zpow_neg, zpow_succ, inv_mul, Semiring.mul_assoc, inv_mul_cancel h, Semiring.mul_one]
theorem zpow_sub_one {a : α} (h : a ≠ 0) (n : Int) : a ^ (n - 1) = a ^ n * a⁻¹ := by
have h₁ := zpow_add_one h (-n)
have h₂ : -n + 1 = - (n - 1) := by omega
rw [h₂, zpow_neg, inv_eq_iff_eq_iff] at h₁
rw [h₁, inv_mul, zpow_neg, inv_inv]
theorem zpow_add {a : α} (h : a ≠ 0) (m n : Int) : a ^ (m + n) = a ^ m * a ^ n := by
match n with
| (n : Nat) =>
induction n with
| zero => simp [zpow_zero, Semiring.mul_one]
| succ n ih => rw [Int.natCast_add_one, zpow_succ, ← Int.add_assoc, zpow_add_one h, ih, Semiring.mul_assoc]
| -(n + 1 : Nat) =>
induction n with
| zero => simp [Int.add_neg_one, zpow_sub_one h, zpow_neg_one]
| succ n ih => rw [Int.natCast_add_one, Int.neg_add, Int.add_neg_one, ← Int.add_sub_assoc, zpow_sub_one h, zpow_sub_one h, ih, Semiring.mul_assoc]
theorem div_zero {x : α} : x / 0 = 0 := by rw [div_eq_mul_inv, inv_zero, Semiring.mul_zero]
theorem mul_div {x y z : α} : x * (y / z) = (x * y) / z := by
rw [div_eq_mul_inv, div_eq_mul_inv, Semiring.mul_assoc]
theorem div_mul {x y z : α} : x / y * z = x * z / y := by
rw [div_eq_mul_inv, div_eq_mul_inv, Semiring.mul_assoc, CommSemiring.mul_comm y⁻¹,
Semiring.mul_assoc]
theorem div_add {x y z : α} (hy : y ≠ 0) : x / y + z = (x + y * z) / y := by
rw [div_eq_mul_inv, div_eq_mul_inv, Semiring.right_distrib, CommSemiring.mul_comm y,
Semiring.mul_assoc, Field.mul_inv_cancel hy, Semiring.mul_one]
theorem add_div {x y z : α} (hz : z ≠ 0) : x + y / z = (x * z + y) / z := by
rw [div_eq_mul_inv, div_eq_mul_inv, Semiring.right_distrib, Semiring.mul_assoc,
Field.mul_inv_cancel hz, Semiring.mul_one]
theorem div_div_right {x y z : α} : x / (y / z) = x * z / y := by
rw [div_eq_mul_inv, div_eq_mul_inv, div_eq_mul_inv, inv_mul, inv_inv, CommSemiring.mul_comm y⁻¹,
Semiring.mul_assoc]
theorem div_div_left {x y z : α} : (x / y) / z = x / (y * z) := by
rw [div_eq_mul_inv, div_eq_mul_inv, div_eq_mul_inv, inv_mul, Semiring.mul_assoc]
theorem div_mul_cancel {x y : α} (h : y ≠ 0) : x / y * y = x := by
rw [div_eq_mul_inv, Semiring.mul_assoc, Field.inv_mul_cancel h, Semiring.mul_one]
attribute [local instance] Semiring.natCast in
theorem natCast_ne_zero [IsCharP α 0] {n : Nat} (h : n ≠ 0) : (n : α) ≠ 0 := by
simpa [IsCharP.natCast_eq_zero_iff]
attribute [local instance] Ring.intCast in
theorem intCast_div_of_dvd {x y : Int} (h : y x) (w : (y : α) ≠ 0) :
((x / y : Int) : α) = ((x : α) / (y : α)) := by
obtain ⟨z, rfl⟩ := h
by_cases hy : y = 0
· simp_all [Ring.intCast_zero]
· rw [Int.mul_ediv_cancel_left _ hy]
rw [Ring.intCast_mul, CommSemiring.mul_comm, div_eq_mul_inv, Semiring.mul_assoc,
mul_inv_cancel w, Semiring.mul_one]
attribute [local instance] Semiring.natCast in
theorem natCast_div_of_dvd {x y : Nat} (h : y x) (w : (y : α) ≠ 0) :
((x / y : Nat) : α) = ((x : α) / (y : α)) := by
obtain ⟨z, rfl⟩ := h
by_cases hy : y = 0
· simp_all [Semiring.natCast_zero]
· rw [Nat.mul_div_cancel_left _ (by omega)]
rw [Semiring.natCast_mul, CommSemiring.mul_comm, div_eq_mul_inv, Semiring.mul_assoc,
mul_inv_cancel w, Semiring.mul_one]
-- This is expensive as an instance. Let's see what breaks without it.
@[implicit_reducible]
def noNatZeroDivisors.ofIsCharPZero [IsCharP α 0] : NoNatZeroDivisors α := NoNatZeroDivisors.mk' <| by
intro a b h w
have := IsCharP.natCast_eq_zero_iff (α := α) 0 a
simp only [Nat.mod_zero, h, iff_false] at this
if h : b = 0 then
exact h
else
rw [Semiring.ofNat_eq_natCast] at w
replace w := congrArg (fun x => x * b⁻¹) w
dsimp only [] at w
rw [Semiring.nsmul_eq_ofNat_mul, Semiring.mul_assoc, Field.mul_inv_cancel h, Semiring.mul_one,
Semiring.natCast_zero, Semiring.zero_mul, Semiring.ofNat_eq_natCast] at w
contradiction
end Field
end Lean.Grind