blob: d0352a718216ac458863beb91769f1fbd7edeefc [file]
/-
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.Data.Int.Order
public import all Init.Grind.ToInt
public section
namespace Lean.Grind
/--
A type where addition is right-cancellative, i.e. `a + c = b + c` implies `a = b`.
-/
class AddRightCancel (M : Type u) [Add M] where
/-- Addition is right-cancellative. -/
add_right_cancel : ∀ a b c : M, a + c = b + c → a = b
class AddCommMonoid (M : Type u) extends Zero M, Add M where
/-- Zero is the right identity for addition. -/
add_zero : ∀ a : M, a + 0 = a
/-- Addition is commutative. -/
add_comm : ∀ a b : M, a + b = b + a
/-- Addition is associative. -/
add_assoc : ∀ a b c : M, a + b + c = a + (b + c)
attribute [instance 100] AddCommMonoid.toZero AddCommMonoid.toAdd
class AddCommGroup (M : Type u) extends AddCommMonoid M, Neg M, Sub M where
/-- Negation is the left inverse of addition. -/
neg_add_cancel : ∀ a : M, -a + a = 0
/-- Subtraction is addition of the negative. -/
sub_eq_add_neg : ∀ a b : M, a - b = a + -b
attribute [instance 100] AddCommGroup.toAddCommMonoid AddCommGroup.toNeg AddCommGroup.toSub
/--
A module over the natural numbers, i.e. a type with zero, addition, and scalar multiplication by natural numbers,
satisfying appropriate compatibilities.
Equivalently, an additive commutative monoid.
Use `IntModule` if the type has negation.
-/
class NatModule (M : Type u) extends AddCommMonoid M where
/-- Scalar multiplication by natural numbers. -/
[nsmul : HMul Nat M M]
/-- Scalar multiplication by zero is zero. -/
zero_nsmul : ∀ a : M, 0 * a = 0
/-- Scalar multiplication by a successor. -/
add_one_nsmul : ∀ n : Nat, ∀ a : M, (n + 1) * a = n * a + a
attribute [instance 100] NatModule.toAddCommMonoid NatModule.nsmul
/--
A module over the integers, i.e. a type with zero, addition, negation, subtraction, and scalar multiplication by integers,
satisfying appropriate compatibilities.
Equivalently, an additive commutative group.
-/
class IntModule (M : Type u) extends AddCommGroup M where
/-- Scalar multiplication by natural numbers. -/
[nsmul : HMul Nat M M]
/-- Scalar multiplication by integers. -/
[zsmul : HMul Int M M]
/-- Scalar multiplication by zero is zero. -/
zero_zsmul : ∀ a : M, (0 : Int) * a = 0
/-- Scalar multiplication by one is the identity. -/
one_zsmul : ∀ a : M, (1 : Int) * a = a
/-- Scalar multiplication is distributive over addition in the integers. -/
add_zsmul : ∀ n m : Int, ∀ a : M, (n + m) * a = n * a + m * a
/-- Scalar multiplication by natural numbers is consistent with scalar multiplication by integers. -/
zsmul_natCast_eq_nsmul : ∀ n : Nat, ∀ a : M, (n : Int) * a = n * a
attribute [instance 100] IntModule.toAddCommGroup IntModule.zsmul
namespace IntModule
variable {M : Type u} [IntModule M]
instance (priority := 100) toNatModule [I : IntModule M] : NatModule M :=
{ I with
zero_nsmul a := by rw [← zsmul_natCast_eq_nsmul, Int.natCast_zero, zero_zsmul]
add_one_nsmul n a := by rw [← zsmul_natCast_eq_nsmul, Int.natCast_add_one, add_zsmul,
zsmul_natCast_eq_nsmul, one_zsmul] }
end IntModule
namespace AddCommMonoid
variable {M : Type u} [AddCommMonoid M]
theorem zero_add (a : M) : 0 + a = a := by
rw [add_comm, add_zero]
theorem add_left_comm (a b c : M) : a + (b + c) = b + (a + c) := by
rw [← add_assoc, ← add_assoc, add_comm a]
end AddCommMonoid
namespace AddCommGroup
variable {M : Type u} [AddCommGroup M]
open AddCommMonoid
theorem add_neg_cancel (a : M) : a + -a = 0 := by
rw [add_comm, neg_add_cancel]
theorem add_left_inj {a b : M} (c : M) : a + c = b + c ↔ a = b :=
⟨fun h => by simpa [add_assoc, add_neg_cancel, add_zero] using (congrArg (· + -c) h),
fun g => congrArg (· + c) g⟩
theorem add_right_inj (a b c : M) : a + b = a + c ↔ b = c := by
rw [add_comm a b, add_comm a c, add_left_inj]
theorem neg_zero : (-0 : M) = 0 := by
rw [← add_left_inj 0, neg_add_cancel, add_zero]
theorem neg_neg (a : M) : -(-a) = a := by
rw [← add_left_inj (-a), neg_add_cancel, add_neg_cancel]
theorem neg_eq_zero (a : M) : -a = 0 ↔ a = 0 :=
⟨fun h => by
replace h := congrArg (-·) h
simpa [neg_neg, neg_zero] using h,
fun h => by rw [h, neg_zero]⟩
theorem neg_add (a b : M) : -(a + b) = -a + -b := by
rw [← add_left_inj (a + b), neg_add_cancel, add_assoc (-a), add_comm a b, ← add_assoc (-b),
neg_add_cancel, zero_add, neg_add_cancel]
theorem neg_sub (a b : M) : -(a - b) = b - a := by
rw [sub_eq_add_neg, neg_add, neg_neg, sub_eq_add_neg, add_comm]
theorem sub_self (a : M) : a - a = 0 := by
rw [sub_eq_add_neg, add_neg_cancel]
theorem sub_eq_iff {a b c : M} : a - b = c ↔ a = c + b := by
rw [sub_eq_add_neg]
constructor
next => intro; subst c; rw [add_assoc, neg_add_cancel, add_zero]
next => intro; subst a; rw [add_assoc, add_comm b, neg_add_cancel, add_zero]
theorem sub_eq_zero_iff {a b : M} : a - b = 0 ↔ a = b := by
simp [sub_eq_iff, zero_add]
theorem add_sub_cancel {a b : M} : a + b - b = a := by
rw [sub_eq_add_neg, add_assoc, add_neg_cancel, add_zero]
theorem sub_add_cancel {a b : M} : a - b + b = a := by
rw [sub_eq_add_neg, add_assoc, neg_add_cancel, add_zero]
theorem neg_eq_iff (a b : M) : -a = b ↔ a = -b := by
constructor
· intro h
rw [← neg_neg a, h]
· intro h
rw [← neg_neg b, h]
end AddCommGroup
namespace NatModule
variable {M : Type u} [NatModule M]
theorem one_nsmul (a : M) : 1 * a = a := by
rw [← Nat.zero_add 1, add_one_nsmul, zero_nsmul, AddCommMonoid.zero_add]
theorem add_nsmul (n m : Nat) (a : M) : (n + m) * a = n * a + m * a := by
induction m with
| zero => rw [Nat.add_zero, zero_nsmul, AddCommMonoid.add_zero]
| succ m ih => rw [add_one_nsmul, ← Nat.add_assoc, add_one_nsmul, ih, AddCommMonoid.add_assoc]
theorem nsmul_zero (n : Nat) : n * (0 : M) = 0 := by
induction n with
| zero => rw [zero_nsmul]
| succ n ih => rw [add_one_nsmul, ih, AddCommMonoid.zero_add]
theorem nsmul_add (n : Nat) (a b : M) : n * (a + b) = n * a + n * b := by
induction n with
| zero => rw [zero_nsmul, zero_nsmul, zero_nsmul, AddCommMonoid.zero_add]
| succ n ih => rw [add_one_nsmul, add_one_nsmul, add_one_nsmul, ih, AddCommMonoid.add_assoc,
AddCommMonoid.add_left_comm (n * b), AddCommMonoid.add_assoc]
theorem mul_nsmul (n m : Nat) (a : M) : (n * m) * a = n * (m * a) := by
induction n with
| zero => simp [zero_nsmul]
| succ n ih =>
rw [Nat.add_one_mul, add_nsmul, ih, add_nsmul, one_nsmul]
instance (priority := 100) (M : Type u) [NatModule M] : SMul Nat M where
smul a x := a * x
end NatModule
namespace IntModule
open NatModule AddCommGroup
instance (priority := 100) (M : Type u) [IntModule M] : SMul Int M where
smul a x := a * x
variable {M : Type u} [IntModule M]
theorem neg_zsmul (n : Int) (a : M) : (-n) * a = - (n * a) := by
apply (add_left_inj (n * a)).mp
rw [← add_zsmul, Int.add_left_neg, zero_zsmul, neg_add_cancel]
theorem zsmul_zero (n : Int) : n * (0 : M) = 0 := by
match n with
| (n : Nat) => rw [zsmul_natCast_eq_nsmul, NatModule.nsmul_zero]
| -(n + 1 : Nat) => rw [neg_zsmul, zsmul_natCast_eq_nsmul, NatModule.nsmul_zero, neg_zero]
theorem zsmul_add (n : Int) (a b : M) : n * (a + b) = n * a + n * b := by
match n with
| (n : Nat) => rw [zsmul_natCast_eq_nsmul, NatModule.nsmul_add, zsmul_natCast_eq_nsmul, zsmul_natCast_eq_nsmul]
| -(n + 1 : Nat) => rw [neg_zsmul, zsmul_natCast_eq_nsmul, NatModule.nsmul_add,
neg_zsmul, zsmul_natCast_eq_nsmul, neg_zsmul, zsmul_natCast_eq_nsmul, neg_add]
theorem zsmul_neg (n : Int) (a : M) : n * (-a) = - (n * a) := by
apply (add_left_inj (n * a)).mp
rw [← zsmul_add, neg_add_cancel, neg_add_cancel, zsmul_zero]
theorem zsmul_sub (k : Int) (a b : M) : k * (a - b) = k * a - k * b := by
rw [sub_eq_add_neg, zsmul_add, zsmul_neg, ← sub_eq_add_neg]
theorem sub_zsmul (k₁ k₂ : Int) (a : M) : (k₁ - k₂) * a = k₁ * a - k₂ * a := by
rw [Int.sub_eq_add_neg, add_zsmul, neg_zsmul, ← sub_eq_add_neg]
private theorem mul_zsmul_aux (n : Nat) (m : Int) (a : M) :
((n : Int) * m) * a = (n : Int) * (m * a) := by
induction n with
| zero => simp [zero_zsmul]
| succ n ih =>
rw [Int.natCast_add, Int.add_mul, add_zsmul, Int.natCast_one,
Int.one_mul, add_zsmul, one_zsmul, ih]
theorem mul_zsmul (n m : Int) (a : M) : (n * m) * a = n * (m * a) := by
match n with
| (n : Nat) => exact mul_zsmul_aux n m a
| -(n + 1 : Nat) => rw [Int.neg_mul, neg_zsmul, mul_zsmul_aux, neg_zsmul]
end IntModule
/--
We say a module has no natural number zero divisors if
`k ≠ 0` and `k * a = k * b` implies `a = b` (here `k` is a natural number and `a` and `b` are element of the module).
For a module over the integers this is equivalent to
`k ≠ 0` and `k * a = 0` implies `a = 0`.
(See the alternative constructor `NoNatZeroDivisors.mk'`,
and the theorem `eq_zero_of_mul_eq_zero`.)
-/
class NoNatZeroDivisors (α : Type u) [NatModule α] where
/-- If `k * a ≠ k * b` then `k ≠ 0` or `a ≠ b`.-/
no_nat_zero_divisors : ∀ (k : Nat) (a b : α), k ≠ 0 → k * a = k * b → a = b
export NoNatZeroDivisors (no_nat_zero_divisors)
namespace NoNatZeroDivisors
/-- Alternative constructor for `NoNatZeroDivisors` when we have an `IntModule`. -/
def mk' {α} [IntModule α]
(eq_zero_of_mul_eq_zero : ∀ (k : Nat) (a : α), k ≠ 0 → k * a = 0 → a = 0) :
NoNatZeroDivisors α where
no_nat_zero_divisors k a b h₁ h₂ := by
rw [← AddCommGroup.sub_eq_zero_iff, ← IntModule.zsmul_natCast_eq_nsmul,
← IntModule.zsmul_natCast_eq_nsmul, ← IntModule.zsmul_sub,
IntModule.zsmul_natCast_eq_nsmul] at h₂
rw [← AddCommGroup.sub_eq_zero_iff]
apply eq_zero_of_mul_eq_zero k (a - b) h₁ h₂
theorem eq_zero_of_mul_eq_zero {α : Type u} [NatModule α] [NoNatZeroDivisors α] {k : Nat} {a : α}
: k ≠ 0 → k * a = 0 → a = 0 := by
intro h₁ h₂
replace h₁ : k ≠ 0 := by intro h; simp [h] at h₁
exact no_nat_zero_divisors k a 0 h₁ (by rwa [NatModule.nsmul_zero])
end NoNatZeroDivisors
instance [ToInt α (IntInterval.co lo hi)] [AddCommGroup α] [ToInt.Zero α (IntInterval.co lo hi)] [ToInt.Add α (IntInterval.co lo hi)] : ToInt.Neg α (IntInterval.co lo hi) where
toInt_neg x := by
have := (ToInt.Add.toInt_add (-x) x).symm
rw [AddCommGroup.neg_add_cancel, ToInt.Zero.toInt_zero, ← ToInt.Zero.wrap_zero (α := α)] at this
rw [IntInterval.wrap_eq_wrap_iff] at this
simp at this
rw [← ToInt.wrap_toInt]
rw [IntInterval.wrap_eq_wrap_iff]
simpa
instance [ToInt α (IntInterval.co lo hi)] [AddCommGroup α] [ToInt.Add α (IntInterval.co lo hi)] [ToInt.Neg α (IntInterval.co lo hi)] : ToInt.Sub α (IntInterval.co lo hi) :=
ToInt.Sub.of_sub_eq_add_neg AddCommGroup.sub_eq_add_neg (by simp)
end Lean.Grind