/-
Copyright (c) 2014 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro

! This file was ported from Lean 3 source module algebra.char_zero.lemmas
! leanprover-community/mathlib commit acee671f47b8e7972a1eb6f4eed74b4b3abce829
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Data.Nat.Cast.Field
import Mathbin.Algebra.GroupPower.Lemmas

/-!
# Characteristic zero (additional theorems)

> THIS FILE IS SYNCHRONIZED WITH MATHLIB4.
> Any changes to this file require a corresponding PR to mathlib4.

A ring `R` is called of characteristic zero if every natural number `n` is non-zero when considered
as an element of `R`. Since this definition doesn't mention the multiplicative structure of `R`
except for the existence of `1` in this file characteristic zero is defined for additive monoids
with `1`.

## Main statements

* Characteristic zero implies that the additive monoid is infinite.
-/

namespace Nat

variable {R : Type _} [AddMonoidWithOne R] [CharZero R]

#print Nat.castEmbedding /-
/-- `nat.cast` as an embedding into monoids of characteristic `0`. -/
@[simps]
def castEmbedding : ℕ ↪ R :=
  ⟨coe, cast_injective⟩
#align nat.cast_embedding Nat.castEmbedding
-/

#print Nat.cast_pow_eq_one /-
@[simp]
theorem cast_pow_eq_one {R : Type _} [Semiring R] [CharZero R] (q : ℕ) (n : ℕ) (hn : n ≠ 0) :
    (q : R) ^ n = 1 ↔ q = 1 := by
  rw [← cast_pow, cast_eq_one]
  exact pow_eq_one_iff hn
#align nat.cast_pow_eq_one Nat.cast_pow_eq_one
-/

/- warning: nat.cast_div_char_zero -> Nat.cast_div_charZero is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} [_inst_3 : DivisionSemiring.{u1} k] [_inst_4 : CharZero.{u1} k (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} k (NonAssocSemiring.toAddCommMonoidWithOne.{u1} k (Semiring.toNonAssocSemiring.{u1} k (DivisionSemiring.toSemiring.{u1} k _inst_3))))] {m : Nat} {n : Nat}, (Dvd.Dvd.{0} Nat Nat.hasDvd n m) -> (Eq.{succ u1} k ((fun (a : Type) (b : Type.{u1}) [self : HasLiftT.{1, succ u1} a b] => self.0) Nat k (HasLiftT.mk.{1, succ u1} Nat k (CoeTCₓ.coe.{1, succ u1} Nat k (Nat.castCoe.{u1} k (AddMonoidWithOne.toNatCast.{u1} k (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} k (NonAssocSemiring.toAddCommMonoidWithOne.{u1} k (Semiring.toNonAssocSemiring.{u1} k (DivisionSemiring.toSemiring.{u1} k _inst_3)))))))) (HDiv.hDiv.{0, 0, 0} Nat Nat Nat (instHDiv.{0} Nat Nat.hasDiv) m n)) (HDiv.hDiv.{u1, u1, u1} k k k (instHDiv.{u1} k (DivInvMonoid.toHasDiv.{u1} k (GroupWithZero.toDivInvMonoid.{u1} k (DivisionSemiring.toGroupWithZero.{u1} k _inst_3)))) ((fun (a : Type) (b : Type.{u1}) [self : HasLiftT.{1, succ u1} a b] => self.0) Nat k (HasLiftT.mk.{1, succ u1} Nat k (CoeTCₓ.coe.{1, succ u1} Nat k (Nat.castCoe.{u1} k (AddMonoidWithOne.toNatCast.{u1} k (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} k (NonAssocSemiring.toAddCommMonoidWithOne.{u1} k (Semiring.toNonAssocSemiring.{u1} k (DivisionSemiring.toSemiring.{u1} k _inst_3)))))))) m) ((fun (a : Type) (b : Type.{u1}) [self : HasLiftT.{1, succ u1} a b] => self.0) Nat k (HasLiftT.mk.{1, succ u1} Nat k (CoeTCₓ.coe.{1, succ u1} Nat k (Nat.castCoe.{u1} k (AddMonoidWithOne.toNatCast.{u1} k (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} k (NonAssocSemiring.toAddCommMonoidWithOne.{u1} k (Semiring.toNonAssocSemiring.{u1} k (DivisionSemiring.toSemiring.{u1} k _inst_3)))))))) n)))
but is expected to have type
  forall {k : Type.{u1}} [_inst_3 : DivisionSemiring.{u1} k] [_inst_4 : CharZero.{u1} k (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} k (NonAssocSemiring.toAddCommMonoidWithOne.{u1} k (Semiring.toNonAssocSemiring.{u1} k (DivisionSemiring.toSemiring.{u1} k _inst_3))))] {m : Nat} {n : Nat}, (Dvd.dvd.{0} Nat Nat.instDvdNat n m) -> (Eq.{succ u1} k (Nat.cast.{u1} k (Semiring.toNatCast.{u1} k (DivisionSemiring.toSemiring.{u1} k _inst_3)) (HDiv.hDiv.{0, 0, 0} Nat Nat Nat (instHDiv.{0} Nat Nat.instDivNat) m n)) (HDiv.hDiv.{u1, u1, u1} k k k (instHDiv.{u1} k (DivisionSemiring.toDiv.{u1} k _inst_3)) (Nat.cast.{u1} k (Semiring.toNatCast.{u1} k (DivisionSemiring.toSemiring.{u1} k _inst_3)) m) (Nat.cast.{u1} k (Semiring.toNatCast.{u1} k (DivisionSemiring.toSemiring.{u1} k _inst_3)) n)))
Case conversion may be inaccurate. Consider using '#align nat.cast_div_char_zero Nat.cast_div_charZeroₓ'. -/
@[simp, norm_cast]
theorem cast_div_charZero {k : Type _} [DivisionSemiring k] [CharZero k] {m n : ℕ} (n_dvd : n ∣ m) :
    ((m / n : ℕ) : k) = m / n :=
  by
  rcases eq_or_ne n 0 with (rfl | hn)
  · simp
  · exact cast_div n_dvd (cast_ne_zero.2 hn)
#align nat.cast_div_char_zero Nat.cast_div_charZero

end Nat

section

variable (M : Type _) [AddMonoidWithOne M] [CharZero M]

/- warning: char_zero.ne_zero.two -> CharZero.NeZero.two is a dubious translation:
lean 3 declaration is
  forall (M : Type.{u1}) [_inst_1 : AddMonoidWithOne.{u1} M] [_inst_2 : CharZero.{u1} M _inst_1], NeZero.{u1} M (AddZeroClass.toHasZero.{u1} M (AddMonoid.toAddZeroClass.{u1} M (AddMonoidWithOne.toAddMonoid.{u1} M _inst_1))) (OfNat.ofNat.{u1} M 2 (OfNat.mk.{u1} M 2 (bit0.{u1} M (AddZeroClass.toHasAdd.{u1} M (AddMonoid.toAddZeroClass.{u1} M (AddMonoidWithOne.toAddMonoid.{u1} M _inst_1))) (One.one.{u1} M (AddMonoidWithOne.toOne.{u1} M _inst_1)))))
but is expected to have type
  forall (M : Type.{u1}) [_inst_1 : AddMonoidWithOne.{u1} M] [_inst_2 : CharZero.{u1} M _inst_1], NeZero.{u1} M (AddMonoid.toZero.{u1} M (AddMonoidWithOne.toAddMonoid.{u1} M _inst_1)) (OfNat.ofNat.{u1} M 2 (instOfNat.{u1} M 2 (AddMonoidWithOne.toNatCast.{u1} M _inst_1) (instAtLeastTwoHAddNatInstHAddInstAddNatOfNat (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0)))))
Case conversion may be inaccurate. Consider using '#align char_zero.ne_zero.two CharZero.NeZero.twoₓ'. -/
instance CharZero.NeZero.two : NeZero (2 : M) :=
  ⟨by
    have : ((2 : ℕ) : M) ≠ 0 := Nat.cast_ne_zero.2 (by decide)
    rwa [Nat.cast_two] at this⟩
#align char_zero.ne_zero.two CharZero.NeZero.two

end

section

variable {R : Type _} [NonAssocSemiring R] [NoZeroDivisors R] [CharZero R] {a : R}

/- warning: add_self_eq_zero -> add_self_eq_zero is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : NonAssocSemiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1))) (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1)))] [_inst_3 : CharZero.{u1} R (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} R (NonAssocSemiring.toAddCommMonoidWithOne.{u1} R _inst_1))] {a : R}, Iff (Eq.{succ u1} R (HAdd.hAdd.{u1, u1, u1} R R R (instHAdd.{u1} R (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1)))) a a) (OfNat.ofNat.{u1} R 0 (OfNat.mk.{u1} R 0 (Zero.zero.{u1} R (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1))))))) (Eq.{succ u1} R a (OfNat.ofNat.{u1} R 0 (OfNat.mk.{u1} R 0 (Zero.zero.{u1} R (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1)))))))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : NonAssocSemiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1)) (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R _inst_1))] [_inst_3 : CharZero.{u1} R (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} R (NonAssocSemiring.toAddCommMonoidWithOne.{u1} R _inst_1))] {a : R}, Iff (Eq.{succ u1} R (HAdd.hAdd.{u1, u1, u1} R R R (instHAdd.{u1} R (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1)))) a a) (OfNat.ofNat.{u1} R 0 (Zero.toOfNat0.{u1} R (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R _inst_1))))) (Eq.{succ u1} R a (OfNat.ofNat.{u1} R 0 (Zero.toOfNat0.{u1} R (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R _inst_1)))))
Case conversion may be inaccurate. Consider using '#align add_self_eq_zero add_self_eq_zeroₓ'. -/
@[simp]
theorem add_self_eq_zero {a : R} : a + a = 0 ↔ a = 0 := by
  simp only [(two_mul a).symm, mul_eq_zero, two_ne_zero, false_or_iff]
#align add_self_eq_zero add_self_eq_zero

/- warning: bit0_eq_zero -> bit0_eq_zero is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : NonAssocSemiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1))) (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1)))] [_inst_3 : CharZero.{u1} R (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} R (NonAssocSemiring.toAddCommMonoidWithOne.{u1} R _inst_1))] {a : R}, Iff (Eq.{succ u1} R (bit0.{u1} R (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1))) a) (OfNat.ofNat.{u1} R 0 (OfNat.mk.{u1} R 0 (Zero.zero.{u1} R (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1))))))) (Eq.{succ u1} R a (OfNat.ofNat.{u1} R 0 (OfNat.mk.{u1} R 0 (Zero.zero.{u1} R (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1)))))))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : NonAssocSemiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1)) (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R _inst_1))] [_inst_3 : CharZero.{u1} R (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} R (NonAssocSemiring.toAddCommMonoidWithOne.{u1} R _inst_1))] {a : R}, Iff (Eq.{succ u1} R (bit0.{u1} R (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1))) a) (OfNat.ofNat.{u1} R 0 (Zero.toOfNat0.{u1} R (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R _inst_1))))) (Eq.{succ u1} R a (OfNat.ofNat.{u1} R 0 (Zero.toOfNat0.{u1} R (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R _inst_1)))))
Case conversion may be inaccurate. Consider using '#align bit0_eq_zero bit0_eq_zeroₓ'. -/
@[simp]
theorem bit0_eq_zero {a : R} : bit0 a = 0 ↔ a = 0 :=
  add_self_eq_zero
#align bit0_eq_zero bit0_eq_zero

/- warning: zero_eq_bit0 -> zero_eq_bit0 is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : NonAssocSemiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1))) (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1)))] [_inst_3 : CharZero.{u1} R (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} R (NonAssocSemiring.toAddCommMonoidWithOne.{u1} R _inst_1))] {a : R}, Iff (Eq.{succ u1} R (OfNat.ofNat.{u1} R 0 (OfNat.mk.{u1} R 0 (Zero.zero.{u1} R (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1)))))) (bit0.{u1} R (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1))) a)) (Eq.{succ u1} R a (OfNat.ofNat.{u1} R 0 (OfNat.mk.{u1} R 0 (Zero.zero.{u1} R (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1)))))))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : NonAssocSemiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1)) (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R _inst_1))] [_inst_3 : CharZero.{u1} R (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} R (NonAssocSemiring.toAddCommMonoidWithOne.{u1} R _inst_1))] {a : R}, Iff (Eq.{succ u1} R (OfNat.ofNat.{u1} R 0 (Zero.toOfNat0.{u1} R (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R _inst_1)))) (bit0.{u1} R (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1))) a)) (Eq.{succ u1} R a (OfNat.ofNat.{u1} R 0 (Zero.toOfNat0.{u1} R (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R _inst_1)))))
Case conversion may be inaccurate. Consider using '#align zero_eq_bit0 zero_eq_bit0ₓ'. -/
@[simp]
theorem zero_eq_bit0 {a : R} : 0 = bit0 a ↔ a = 0 :=
  by
  rw [eq_comm]
  exact bit0_eq_zero
#align zero_eq_bit0 zero_eq_bit0

/- warning: bit0_ne_zero -> bit0_ne_zero is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : NonAssocSemiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1))) (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1)))] [_inst_3 : CharZero.{u1} R (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} R (NonAssocSemiring.toAddCommMonoidWithOne.{u1} R _inst_1))] {a : R}, Iff (Ne.{succ u1} R (bit0.{u1} R (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1))) a) (OfNat.ofNat.{u1} R 0 (OfNat.mk.{u1} R 0 (Zero.zero.{u1} R (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1))))))) (Ne.{succ u1} R a (OfNat.ofNat.{u1} R 0 (OfNat.mk.{u1} R 0 (Zero.zero.{u1} R (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1)))))))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : NonAssocSemiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1)) (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R _inst_1))] [_inst_3 : CharZero.{u1} R (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} R (NonAssocSemiring.toAddCommMonoidWithOne.{u1} R _inst_1))] {a : R}, Iff (Ne.{succ u1} R (bit0.{u1} R (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1))) a) (OfNat.ofNat.{u1} R 0 (Zero.toOfNat0.{u1} R (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R _inst_1))))) (Ne.{succ u1} R a (OfNat.ofNat.{u1} R 0 (Zero.toOfNat0.{u1} R (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R _inst_1)))))
Case conversion may be inaccurate. Consider using '#align bit0_ne_zero bit0_ne_zeroₓ'. -/
theorem bit0_ne_zero : bit0 a ≠ 0 ↔ a ≠ 0 :=
  bit0_eq_zero.Not
#align bit0_ne_zero bit0_ne_zero

/- warning: zero_ne_bit0 -> zero_ne_bit0 is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : NonAssocSemiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1))) (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1)))] [_inst_3 : CharZero.{u1} R (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} R (NonAssocSemiring.toAddCommMonoidWithOne.{u1} R _inst_1))] {a : R}, Iff (Ne.{succ u1} R (OfNat.ofNat.{u1} R 0 (OfNat.mk.{u1} R 0 (Zero.zero.{u1} R (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1)))))) (bit0.{u1} R (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1))) a)) (Ne.{succ u1} R a (OfNat.ofNat.{u1} R 0 (OfNat.mk.{u1} R 0 (Zero.zero.{u1} R (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1)))))))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : NonAssocSemiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1)) (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R _inst_1))] [_inst_3 : CharZero.{u1} R (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} R (NonAssocSemiring.toAddCommMonoidWithOne.{u1} R _inst_1))] {a : R}, Iff (Ne.{succ u1} R (OfNat.ofNat.{u1} R 0 (Zero.toOfNat0.{u1} R (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R _inst_1)))) (bit0.{u1} R (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1))) a)) (Ne.{succ u1} R a (OfNat.ofNat.{u1} R 0 (Zero.toOfNat0.{u1} R (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R _inst_1)))))
Case conversion may be inaccurate. Consider using '#align zero_ne_bit0 zero_ne_bit0ₓ'. -/
theorem zero_ne_bit0 : 0 ≠ bit0 a ↔ a ≠ 0 :=
  zero_eq_bit0.Not
#align zero_ne_bit0 zero_ne_bit0

end

section

variable {R : Type _} [NonAssocRing R] [NoZeroDivisors R] [CharZero R]

/- warning: neg_eq_self_iff -> neg_eq_self_iff is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : NonAssocRing.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))) (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1))))] [_inst_3 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))] {a : R}, Iff (Eq.{succ u1} R (Neg.neg.{u1} R (SubNegMonoid.toHasNeg.{u1} R (AddGroup.toSubNegMonoid.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1))))) a) a) (Eq.{succ u1} R a (OfNat.ofNat.{u1} R 0 (OfNat.mk.{u1} R 0 (Zero.zero.{u1} R (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1))))))))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : NonAssocRing.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (NonUnitalNonAssocRing.toMul.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)) (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R _inst_1)))] [_inst_3 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))] {a : R}, Iff (Eq.{succ u1} R (Neg.neg.{u1} R (AddGroupWithOne.toNeg.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1))) a) a) (Eq.{succ u1} R a (OfNat.ofNat.{u1} R 0 (Zero.toOfNat0.{u1} R (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R _inst_1))))))
Case conversion may be inaccurate. Consider using '#align neg_eq_self_iff neg_eq_self_iffₓ'. -/
theorem neg_eq_self_iff {a : R} : -a = a ↔ a = 0 :=
  neg_eq_iff_add_eq_zero.trans add_self_eq_zero
#align neg_eq_self_iff neg_eq_self_iff

/- warning: eq_neg_self_iff -> eq_neg_self_iff is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : NonAssocRing.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))) (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1))))] [_inst_3 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))] {a : R}, Iff (Eq.{succ u1} R a (Neg.neg.{u1} R (SubNegMonoid.toHasNeg.{u1} R (AddGroup.toSubNegMonoid.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1))))) a)) (Eq.{succ u1} R a (OfNat.ofNat.{u1} R 0 (OfNat.mk.{u1} R 0 (Zero.zero.{u1} R (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1))))))))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : NonAssocRing.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (NonUnitalNonAssocRing.toMul.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)) (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R _inst_1)))] [_inst_3 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))] {a : R}, Iff (Eq.{succ u1} R a (Neg.neg.{u1} R (AddGroupWithOne.toNeg.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1))) a)) (Eq.{succ u1} R a (OfNat.ofNat.{u1} R 0 (Zero.toOfNat0.{u1} R (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R _inst_1))))))
Case conversion may be inaccurate. Consider using '#align eq_neg_self_iff eq_neg_self_iffₓ'. -/
theorem eq_neg_self_iff {a : R} : a = -a ↔ a = 0 :=
  eq_neg_iff_add_eq_zero.trans add_self_eq_zero
#align eq_neg_self_iff eq_neg_self_iff

/- warning: nat_mul_inj -> nat_mul_inj is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : NonAssocRing.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))) (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1))))] [_inst_3 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))] {n : Nat} {a : R} {b : R}, (Eq.{succ u1} R (HMul.hMul.{u1, u1, u1} R R R (instHMul.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1))))) ((fun (a : Type) (b : Type.{u1}) [self : HasLiftT.{1, succ u1} a b] => self.0) Nat R (HasLiftT.mk.{1, succ u1} Nat R (CoeTCₓ.coe.{1, succ u1} Nat R (Nat.castCoe.{u1} R (AddMonoidWithOne.toNatCast.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1))))))) n) a) (HMul.hMul.{u1, u1, u1} R R R (instHMul.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1))))) ((fun (a : Type) (b : Type.{u1}) [self : HasLiftT.{1, succ u1} a b] => self.0) Nat R (HasLiftT.mk.{1, succ u1} Nat R (CoeTCₓ.coe.{1, succ u1} Nat R (Nat.castCoe.{u1} R (AddMonoidWithOne.toNatCast.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1))))))) n) b)) -> (Or (Eq.{1} Nat n (OfNat.ofNat.{0} Nat 0 (OfNat.mk.{0} Nat 0 (Zero.zero.{0} Nat Nat.hasZero)))) (Eq.{succ u1} R a b))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : NonAssocRing.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (NonUnitalNonAssocRing.toMul.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)) (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R _inst_1)))] [_inst_3 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))] {n : Nat} {a : R} {b : R}, (Eq.{succ u1} R (HMul.hMul.{u1, u1, u1} R R R (instHMul.{u1} R (NonUnitalNonAssocRing.toMul.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1))) (Nat.cast.{u1} R (NonAssocRing.toNatCast.{u1} R _inst_1) n) a) (HMul.hMul.{u1, u1, u1} R R R (instHMul.{u1} R (NonUnitalNonAssocRing.toMul.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1))) (Nat.cast.{u1} R (NonAssocRing.toNatCast.{u1} R _inst_1) n) b)) -> (Or (Eq.{1} Nat n (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0))) (Eq.{succ u1} R a b))
Case conversion may be inaccurate. Consider using '#align nat_mul_inj nat_mul_injₓ'. -/
theorem nat_mul_inj {n : ℕ} {a b : R} (h : (n : R) * a = (n : R) * b) : n = 0 ∨ a = b :=
  by
  rw [← sub_eq_zero, ← mul_sub, mul_eq_zero, sub_eq_zero] at h
  exact_mod_cast h
#align nat_mul_inj nat_mul_inj

/- warning: nat_mul_inj' -> nat_mul_inj' is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : NonAssocRing.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))) (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1))))] [_inst_3 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))] {n : Nat} {a : R} {b : R}, (Eq.{succ u1} R (HMul.hMul.{u1, u1, u1} R R R (instHMul.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1))))) ((fun (a : Type) (b : Type.{u1}) [self : HasLiftT.{1, succ u1} a b] => self.0) Nat R (HasLiftT.mk.{1, succ u1} Nat R (CoeTCₓ.coe.{1, succ u1} Nat R (Nat.castCoe.{u1} R (AddMonoidWithOne.toNatCast.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1))))))) n) a) (HMul.hMul.{u1, u1, u1} R R R (instHMul.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1))))) ((fun (a : Type) (b : Type.{u1}) [self : HasLiftT.{1, succ u1} a b] => self.0) Nat R (HasLiftT.mk.{1, succ u1} Nat R (CoeTCₓ.coe.{1, succ u1} Nat R (Nat.castCoe.{u1} R (AddMonoidWithOne.toNatCast.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1))))))) n) b)) -> (Ne.{1} Nat n (OfNat.ofNat.{0} Nat 0 (OfNat.mk.{0} Nat 0 (Zero.zero.{0} Nat Nat.hasZero)))) -> (Eq.{succ u1} R a b)
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : NonAssocRing.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (NonUnitalNonAssocRing.toMul.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)) (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R _inst_1)))] [_inst_3 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))] {n : Nat} {a : R} {b : R}, (Eq.{succ u1} R (HMul.hMul.{u1, u1, u1} R R R (instHMul.{u1} R (NonUnitalNonAssocRing.toMul.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1))) (Nat.cast.{u1} R (NonAssocRing.toNatCast.{u1} R _inst_1) n) a) (HMul.hMul.{u1, u1, u1} R R R (instHMul.{u1} R (NonUnitalNonAssocRing.toMul.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1))) (Nat.cast.{u1} R (NonAssocRing.toNatCast.{u1} R _inst_1) n) b)) -> (Ne.{1} Nat n (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0))) -> (Eq.{succ u1} R a b)
Case conversion may be inaccurate. Consider using '#align nat_mul_inj' nat_mul_inj'ₓ'. -/
theorem nat_mul_inj' {n : ℕ} {a b : R} (h : (n : R) * a = (n : R) * b) (w : n ≠ 0) : a = b := by
  simpa [w] using nat_mul_inj h
#align nat_mul_inj' nat_mul_inj'

/- warning: bit0_injective -> bit0_injective is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : NonAssocRing.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))) (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1))))] [_inst_3 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))], Function.Injective.{succ u1, succ u1} R R (bit0.{u1} R (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : NonAssocRing.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (NonUnitalNonAssocRing.toMul.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)) (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R _inst_1)))] [_inst_3 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))], Function.Injective.{succ u1, succ u1} R R (bit0.{u1} R (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))))
Case conversion may be inaccurate. Consider using '#align bit0_injective bit0_injectiveₓ'. -/
theorem bit0_injective : Function.Injective (bit0 : R → R) := fun a b h =>
  by
  dsimp [bit0] at h
  simp only [(two_mul a).symm, (two_mul b).symm] at h
  refine' nat_mul_inj' _ two_ne_zero
  exact_mod_cast h
#align bit0_injective bit0_injective

/- warning: bit1_injective -> bit1_injective is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : NonAssocRing.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))) (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1))))] [_inst_3 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))], Function.Injective.{succ u1, succ u1} R R (bit1.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))) (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : NonAssocRing.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (NonUnitalNonAssocRing.toMul.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)) (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R _inst_1)))] [_inst_3 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))], Function.Injective.{succ u1, succ u1} R R (bit1.{u1} R (NonAssocRing.toOne.{u1} R _inst_1) (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))))
Case conversion may be inaccurate. Consider using '#align bit1_injective bit1_injectiveₓ'. -/
theorem bit1_injective : Function.Injective (bit1 : R → R) := fun a b h =>
  by
  simp only [bit1, add_left_inj] at h
  exact bit0_injective h
#align bit1_injective bit1_injective

/- warning: bit0_eq_bit0 -> bit0_eq_bit0 is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : NonAssocRing.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))) (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1))))] [_inst_3 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))] {a : R} {b : R}, Iff (Eq.{succ u1} R (bit0.{u1} R (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))) a) (bit0.{u1} R (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))) b)) (Eq.{succ u1} R a b)
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : NonAssocRing.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (NonUnitalNonAssocRing.toMul.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)) (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R _inst_1)))] [_inst_3 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))] {a : R} {b : R}, Iff (Eq.{succ u1} R (bit0.{u1} R (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))) a) (bit0.{u1} R (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))) b)) (Eq.{succ u1} R a b)
Case conversion may be inaccurate. Consider using '#align bit0_eq_bit0 bit0_eq_bit0ₓ'. -/
@[simp]
theorem bit0_eq_bit0 {a b : R} : bit0 a = bit0 b ↔ a = b :=
  bit0_injective.eq_iff
#align bit0_eq_bit0 bit0_eq_bit0

/- warning: bit1_eq_bit1 -> bit1_eq_bit1 is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : NonAssocRing.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))) (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1))))] [_inst_3 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))] {a : R} {b : R}, Iff (Eq.{succ u1} R (bit1.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))) (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))) a) (bit1.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))) (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))) b)) (Eq.{succ u1} R a b)
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : NonAssocRing.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (NonUnitalNonAssocRing.toMul.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)) (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R _inst_1)))] [_inst_3 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))] {a : R} {b : R}, Iff (Eq.{succ u1} R (bit1.{u1} R (NonAssocRing.toOne.{u1} R _inst_1) (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))) a) (bit1.{u1} R (NonAssocRing.toOne.{u1} R _inst_1) (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))) b)) (Eq.{succ u1} R a b)
Case conversion may be inaccurate. Consider using '#align bit1_eq_bit1 bit1_eq_bit1ₓ'. -/
@[simp]
theorem bit1_eq_bit1 {a b : R} : bit1 a = bit1 b ↔ a = b :=
  bit1_injective.eq_iff
#align bit1_eq_bit1 bit1_eq_bit1

/- warning: bit1_eq_one -> bit1_eq_one is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : NonAssocRing.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))) (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1))))] [_inst_3 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))] {a : R}, Iff (Eq.{succ u1} R (bit1.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))) (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))) a) (OfNat.ofNat.{u1} R 1 (OfNat.mk.{u1} R 1 (One.one.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))))))) (Eq.{succ u1} R a (OfNat.ofNat.{u1} R 0 (OfNat.mk.{u1} R 0 (Zero.zero.{u1} R (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1))))))))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : NonAssocRing.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (NonUnitalNonAssocRing.toMul.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)) (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R _inst_1)))] [_inst_3 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))] {a : R}, Iff (Eq.{succ u1} R (bit1.{u1} R (NonAssocRing.toOne.{u1} R _inst_1) (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))) a) (OfNat.ofNat.{u1} R 1 (One.toOfNat1.{u1} R (NonAssocRing.toOne.{u1} R _inst_1)))) (Eq.{succ u1} R a (OfNat.ofNat.{u1} R 0 (Zero.toOfNat0.{u1} R (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R _inst_1))))))
Case conversion may be inaccurate. Consider using '#align bit1_eq_one bit1_eq_oneₓ'. -/
@[simp]
theorem bit1_eq_one {a : R} : bit1 a = 1 ↔ a = 0 := by
  rw [show (1 : R) = bit1 0 by simp, bit1_eq_bit1]
#align bit1_eq_one bit1_eq_one

/- warning: one_eq_bit1 -> one_eq_bit1 is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : NonAssocRing.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))) (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1))))] [_inst_3 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))] {a : R}, Iff (Eq.{succ u1} R (OfNat.ofNat.{u1} R 1 (OfNat.mk.{u1} R 1 (One.one.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1))))))) (bit1.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))) (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))) a)) (Eq.{succ u1} R a (OfNat.ofNat.{u1} R 0 (OfNat.mk.{u1} R 0 (Zero.zero.{u1} R (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1))))))))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : NonAssocRing.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (NonUnitalNonAssocRing.toMul.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)) (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R _inst_1)))] [_inst_3 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (NonAssocRing.toAddCommGroupWithOne.{u1} R _inst_1)))] {a : R}, Iff (Eq.{succ u1} R (OfNat.ofNat.{u1} R 1 (One.toOfNat1.{u1} R (NonAssocRing.toOne.{u1} R _inst_1))) (bit1.{u1} R (NonAssocRing.toOne.{u1} R _inst_1) (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R _inst_1)))) a)) (Eq.{succ u1} R a (OfNat.ofNat.{u1} R 0 (Zero.toOfNat0.{u1} R (MulZeroOneClass.toZero.{u1} R (NonAssocSemiring.toMulZeroOneClass.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R _inst_1))))))
Case conversion may be inaccurate. Consider using '#align one_eq_bit1 one_eq_bit1ₓ'. -/
@[simp]
theorem one_eq_bit1 {a : R} : 1 = bit1 a ↔ a = 0 :=
  by
  rw [eq_comm]
  exact bit1_eq_one
#align one_eq_bit1 one_eq_bit1

end

section

variable {R : Type _} [DivisionRing R] [CharZero R]

/- warning: half_add_self -> half_add_self is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : DivisionRing.{u1} R] [_inst_2 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1))))] (a : R), Eq.{succ u1} R (HDiv.hDiv.{u1, u1, u1} R R R (instHDiv.{u1} R (DivInvMonoid.toHasDiv.{u1} R (DivisionRing.toDivInvMonoid.{u1} R _inst_1))) (HAdd.hAdd.{u1, u1, u1} R R R (instHAdd.{u1} R (Distrib.toHasAdd.{u1} R (Ring.toDistrib.{u1} R (DivisionRing.toRing.{u1} R _inst_1)))) a a) (OfNat.ofNat.{u1} R 2 (OfNat.mk.{u1} R 2 (bit0.{u1} R (Distrib.toHasAdd.{u1} R (Ring.toDistrib.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) (One.one.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1)))))))))) a
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : DivisionRing.{u1} R] [_inst_2 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (Ring.toAddGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1)))] (a : R), Eq.{succ u1} R (HDiv.hDiv.{u1, u1, u1} R R R (instHDiv.{u1} R (DivisionRing.toDiv.{u1} R _inst_1)) (HAdd.hAdd.{u1, u1, u1} R R R (instHAdd.{u1} R (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R (DivisionRing.toRing.{u1} R _inst_1))))))) a a) (OfNat.ofNat.{u1} R 2 (instOfNat.{u1} R 2 (NonAssocRing.toNatCast.{u1} R (Ring.toNonAssocRing.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) (instAtLeastTwoHAddNatInstHAddInstAddNatOfNat (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0)))))) a
Case conversion may be inaccurate. Consider using '#align half_add_self half_add_selfₓ'. -/
@[simp]
theorem half_add_self (a : R) : (a + a) / 2 = a := by rw [← mul_two, mul_div_cancel a two_ne_zero]
#align half_add_self half_add_self

/- warning: add_halves' -> add_halves' is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : DivisionRing.{u1} R] [_inst_2 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1))))] (a : R), Eq.{succ u1} R (HAdd.hAdd.{u1, u1, u1} R R R (instHAdd.{u1} R (Distrib.toHasAdd.{u1} R (Ring.toDistrib.{u1} R (DivisionRing.toRing.{u1} R _inst_1)))) (HDiv.hDiv.{u1, u1, u1} R R R (instHDiv.{u1} R (DivInvMonoid.toHasDiv.{u1} R (DivisionRing.toDivInvMonoid.{u1} R _inst_1))) a (OfNat.ofNat.{u1} R 2 (OfNat.mk.{u1} R 2 (bit0.{u1} R (Distrib.toHasAdd.{u1} R (Ring.toDistrib.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) (One.one.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1)))))))))) (HDiv.hDiv.{u1, u1, u1} R R R (instHDiv.{u1} R (DivInvMonoid.toHasDiv.{u1} R (DivisionRing.toDivInvMonoid.{u1} R _inst_1))) a (OfNat.ofNat.{u1} R 2 (OfNat.mk.{u1} R 2 (bit0.{u1} R (Distrib.toHasAdd.{u1} R (Ring.toDistrib.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) (One.one.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1))))))))))) a
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : DivisionRing.{u1} R] [_inst_2 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (Ring.toAddGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1)))] (a : R), Eq.{succ u1} R (HAdd.hAdd.{u1, u1, u1} R R R (instHAdd.{u1} R (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R (DivisionRing.toRing.{u1} R _inst_1))))))) (HDiv.hDiv.{u1, u1, u1} R R R (instHDiv.{u1} R (DivisionRing.toDiv.{u1} R _inst_1)) a (OfNat.ofNat.{u1} R 2 (instOfNat.{u1} R 2 (NonAssocRing.toNatCast.{u1} R (Ring.toNonAssocRing.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) (instAtLeastTwoHAddNatInstHAddInstAddNatOfNat (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0)))))) (HDiv.hDiv.{u1, u1, u1} R R R (instHDiv.{u1} R (DivisionRing.toDiv.{u1} R _inst_1)) a (OfNat.ofNat.{u1} R 2 (instOfNat.{u1} R 2 (NonAssocRing.toNatCast.{u1} R (Ring.toNonAssocRing.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) (instAtLeastTwoHAddNatInstHAddInstAddNatOfNat (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0))))))) a
Case conversion may be inaccurate. Consider using '#align add_halves' add_halves'ₓ'. -/
@[simp]
theorem add_halves' (a : R) : a / 2 + a / 2 = a := by rw [← add_div, half_add_self]
#align add_halves' add_halves'

/- warning: sub_half -> sub_half is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : DivisionRing.{u1} R] [_inst_2 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1))))] (a : R), Eq.{succ u1} R (HSub.hSub.{u1, u1, u1} R R R (instHSub.{u1} R (SubNegMonoid.toHasSub.{u1} R (AddGroup.toSubNegMonoid.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1))))))) a (HDiv.hDiv.{u1, u1, u1} R R R (instHDiv.{u1} R (DivInvMonoid.toHasDiv.{u1} R (DivisionRing.toDivInvMonoid.{u1} R _inst_1))) a (OfNat.ofNat.{u1} R 2 (OfNat.mk.{u1} R 2 (bit0.{u1} R (Distrib.toHasAdd.{u1} R (Ring.toDistrib.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) (One.one.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1))))))))))) (HDiv.hDiv.{u1, u1, u1} R R R (instHDiv.{u1} R (DivInvMonoid.toHasDiv.{u1} R (DivisionRing.toDivInvMonoid.{u1} R _inst_1))) a (OfNat.ofNat.{u1} R 2 (OfNat.mk.{u1} R 2 (bit0.{u1} R (Distrib.toHasAdd.{u1} R (Ring.toDistrib.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) (One.one.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1))))))))))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : DivisionRing.{u1} R] [_inst_2 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (Ring.toAddGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1)))] (a : R), Eq.{succ u1} R (HSub.hSub.{u1, u1, u1} R R R (instHSub.{u1} R (Ring.toSub.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) a (HDiv.hDiv.{u1, u1, u1} R R R (instHDiv.{u1} R (DivisionRing.toDiv.{u1} R _inst_1)) a (OfNat.ofNat.{u1} R 2 (instOfNat.{u1} R 2 (NonAssocRing.toNatCast.{u1} R (Ring.toNonAssocRing.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) (instAtLeastTwoHAddNatInstHAddInstAddNatOfNat (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0))))))) (HDiv.hDiv.{u1, u1, u1} R R R (instHDiv.{u1} R (DivisionRing.toDiv.{u1} R _inst_1)) a (OfNat.ofNat.{u1} R 2 (instOfNat.{u1} R 2 (NonAssocRing.toNatCast.{u1} R (Ring.toNonAssocRing.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) (instAtLeastTwoHAddNatInstHAddInstAddNatOfNat (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0))))))
Case conversion may be inaccurate. Consider using '#align sub_half sub_halfₓ'. -/
theorem sub_half (a : R) : a - a / 2 = a / 2 := by rw [sub_eq_iff_eq_add, add_halves']
#align sub_half sub_half

/- warning: half_sub -> half_sub is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : DivisionRing.{u1} R] [_inst_2 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1))))] (a : R), Eq.{succ u1} R (HSub.hSub.{u1, u1, u1} R R R (instHSub.{u1} R (SubNegMonoid.toHasSub.{u1} R (AddGroup.toSubNegMonoid.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1))))))) (HDiv.hDiv.{u1, u1, u1} R R R (instHDiv.{u1} R (DivInvMonoid.toHasDiv.{u1} R (DivisionRing.toDivInvMonoid.{u1} R _inst_1))) a (OfNat.ofNat.{u1} R 2 (OfNat.mk.{u1} R 2 (bit0.{u1} R (Distrib.toHasAdd.{u1} R (Ring.toDistrib.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) (One.one.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1)))))))))) a) (Neg.neg.{u1} R (SubNegMonoid.toHasNeg.{u1} R (AddGroup.toSubNegMonoid.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1)))))) (HDiv.hDiv.{u1, u1, u1} R R R (instHDiv.{u1} R (DivInvMonoid.toHasDiv.{u1} R (DivisionRing.toDivInvMonoid.{u1} R _inst_1))) a (OfNat.ofNat.{u1} R 2 (OfNat.mk.{u1} R 2 (bit0.{u1} R (Distrib.toHasAdd.{u1} R (Ring.toDistrib.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) (One.one.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1)))))))))))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : DivisionRing.{u1} R] [_inst_2 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (Ring.toAddGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1)))] (a : R), Eq.{succ u1} R (HSub.hSub.{u1, u1, u1} R R R (instHSub.{u1} R (Ring.toSub.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) (HDiv.hDiv.{u1, u1, u1} R R R (instHDiv.{u1} R (DivisionRing.toDiv.{u1} R _inst_1)) a (OfNat.ofNat.{u1} R 2 (instOfNat.{u1} R 2 (NonAssocRing.toNatCast.{u1} R (Ring.toNonAssocRing.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) (instAtLeastTwoHAddNatInstHAddInstAddNatOfNat (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0)))))) a) (Neg.neg.{u1} R (Ring.toNeg.{u1} R (DivisionRing.toRing.{u1} R _inst_1)) (HDiv.hDiv.{u1, u1, u1} R R R (instHDiv.{u1} R (DivisionRing.toDiv.{u1} R _inst_1)) a (OfNat.ofNat.{u1} R 2 (instOfNat.{u1} R 2 (NonAssocRing.toNatCast.{u1} R (Ring.toNonAssocRing.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) (instAtLeastTwoHAddNatInstHAddInstAddNatOfNat (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0)))))))
Case conversion may be inaccurate. Consider using '#align half_sub half_subₓ'. -/
theorem half_sub (a : R) : a / 2 - a = -(a / 2) := by rw [← neg_sub, sub_half]
#align half_sub half_sub

end

namespace WithTop

instance {R : Type _} [AddMonoidWithOne R] [CharZero R] : CharZero (WithTop R)
    where cast_injective m n h := by rwa [← coe_nat, ← coe_nat n, coe_eq_coe, Nat.cast_inj] at h

end WithTop

section RingHom

variable {R S : Type _} [NonAssocSemiring R] [NonAssocSemiring S]

/- warning: ring_hom.char_zero -> RingHom.charZero is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : NonAssocSemiring.{u1} R] [_inst_2 : NonAssocSemiring.{u2} S], (RingHom.{u1, u2} R S _inst_1 _inst_2) -> (forall [hS : CharZero.{u2} S (AddCommMonoidWithOne.toAddMonoidWithOne.{u2} S (NonAssocSemiring.toAddCommMonoidWithOne.{u2} S _inst_2))], CharZero.{u1} R (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} R (NonAssocSemiring.toAddCommMonoidWithOne.{u1} R _inst_1)))
but is expected to have type
  forall {R : Type.{u2}} {S : Type.{u1}} [_inst_1 : NonAssocSemiring.{u2} R] [_inst_2 : NonAssocSemiring.{u1} S], (RingHom.{u2, u1} R S _inst_1 _inst_2) -> (forall [hS : CharZero.{u1} S (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} S (NonAssocSemiring.toAddCommMonoidWithOne.{u1} S _inst_2))], CharZero.{u2} R (AddCommMonoidWithOne.toAddMonoidWithOne.{u2} R (NonAssocSemiring.toAddCommMonoidWithOne.{u2} R _inst_1)))
Case conversion may be inaccurate. Consider using '#align ring_hom.char_zero RingHom.charZeroₓ'. -/
theorem RingHom.charZero (ϕ : R →+* S) [hS : CharZero S] : CharZero R :=
  ⟨fun a b h => CharZero.cast_injective (by rw [← map_natCast ϕ, ← map_natCast ϕ, h])⟩
#align ring_hom.char_zero RingHom.charZero

/- warning: ring_hom.char_zero_iff -> RingHom.charZero_iff is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : NonAssocSemiring.{u1} R] [_inst_2 : NonAssocSemiring.{u2} S] {ϕ : RingHom.{u1, u2} R S _inst_1 _inst_2}, (Function.Injective.{succ u1, succ u2} R S (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RingHom.{u1, u2} R S _inst_1 _inst_2) (fun (_x : RingHom.{u1, u2} R S _inst_1 _inst_2) => R -> S) (RingHom.hasCoeToFun.{u1, u2} R S _inst_1 _inst_2) ϕ)) -> (Iff (CharZero.{u1} R (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} R (NonAssocSemiring.toAddCommMonoidWithOne.{u1} R _inst_1))) (CharZero.{u2} S (AddCommMonoidWithOne.toAddMonoidWithOne.{u2} S (NonAssocSemiring.toAddCommMonoidWithOne.{u2} S _inst_2))))
but is expected to have type
  forall {R : Type.{u2}} {S : Type.{u1}} [_inst_1 : NonAssocSemiring.{u2} R] [_inst_2 : NonAssocSemiring.{u1} S] {ϕ : RingHom.{u2, u1} R S _inst_1 _inst_2}, (Function.Injective.{succ u2, succ u1} R S (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (RingHom.{u2, u1} R S _inst_1 _inst_2) R (fun (_x : R) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => S) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (RingHom.{u2, u1} R S _inst_1 _inst_2) R S (NonUnitalNonAssocSemiring.toMul.{u2} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} R _inst_1)) (NonUnitalNonAssocSemiring.toMul.{u1} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} S _inst_2)) (NonUnitalRingHomClass.toMulHomClass.{max u2 u1, u2, u1} (RingHom.{u2, u1} R S _inst_1 _inst_2) R S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} S _inst_2) (RingHomClass.toNonUnitalRingHomClass.{max u2 u1, u2, u1} (RingHom.{u2, u1} R S _inst_1 _inst_2) R S _inst_1 _inst_2 (RingHom.instRingHomClassRingHom.{u2, u1} R S _inst_1 _inst_2)))) ϕ)) -> (Iff (CharZero.{u2} R (AddCommMonoidWithOne.toAddMonoidWithOne.{u2} R (NonAssocSemiring.toAddCommMonoidWithOne.{u2} R _inst_1))) (CharZero.{u1} S (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} S (NonAssocSemiring.toAddCommMonoidWithOne.{u1} S _inst_2))))
Case conversion may be inaccurate. Consider using '#align ring_hom.char_zero_iff RingHom.charZero_iffₓ'. -/
theorem RingHom.charZero_iff {ϕ : R →+* S} (hϕ : Function.Injective ϕ) : CharZero R ↔ CharZero S :=
  ⟨fun hR =>
    ⟨by intro a b h <;> rwa [← @Nat.cast_inj R, ← hϕ.eq_iff, map_natCast ϕ, map_natCast ϕ]⟩,
    fun hS => ϕ.char_zero⟩
#align ring_hom.char_zero_iff RingHom.charZero_iff

/- warning: ring_hom.injective_nat -> RingHom.injective_nat is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : NonAssocSemiring.{u1} R] (f : RingHom.{0, u1} Nat R (Semiring.toNonAssocSemiring.{0} Nat Nat.semiring) _inst_1) [_inst_3 : CharZero.{u1} R (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} R (NonAssocSemiring.toAddCommMonoidWithOne.{u1} R _inst_1))], Function.Injective.{1, succ u1} Nat R (coeFn.{succ u1, succ u1} (RingHom.{0, u1} Nat R (Semiring.toNonAssocSemiring.{0} Nat Nat.semiring) _inst_1) (fun (_x : RingHom.{0, u1} Nat R (Semiring.toNonAssocSemiring.{0} Nat Nat.semiring) _inst_1) => Nat -> R) (RingHom.hasCoeToFun.{0, u1} Nat R (Semiring.toNonAssocSemiring.{0} Nat Nat.semiring) _inst_1) f)
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : NonAssocSemiring.{u1} R] (f : RingHom.{0, u1} Nat R (Semiring.toNonAssocSemiring.{0} Nat Nat.semiring) _inst_1) [_inst_3 : CharZero.{u1} R (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} R (NonAssocSemiring.toAddCommMonoidWithOne.{u1} R _inst_1))], Function.Injective.{1, succ u1} Nat R (FunLike.coe.{succ u1, 1, succ u1} (RingHom.{0, u1} Nat R (Semiring.toNonAssocSemiring.{0} Nat Nat.semiring) _inst_1) Nat (fun (_x : Nat) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : Nat) => R) _x) (MulHomClass.toFunLike.{u1, 0, u1} (RingHom.{0, u1} Nat R (Semiring.toNonAssocSemiring.{0} Nat Nat.semiring) _inst_1) Nat R (NonUnitalNonAssocSemiring.toMul.{0} Nat (NonAssocSemiring.toNonUnitalNonAssocSemiring.{0} Nat (Semiring.toNonAssocSemiring.{0} Nat Nat.semiring))) (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1)) (NonUnitalRingHomClass.toMulHomClass.{u1, 0, u1} (RingHom.{0, u1} Nat R (Semiring.toNonAssocSemiring.{0} Nat Nat.semiring) _inst_1) Nat R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{0} Nat (Semiring.toNonAssocSemiring.{0} Nat Nat.semiring)) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R _inst_1) (RingHomClass.toNonUnitalRingHomClass.{u1, 0, u1} (RingHom.{0, u1} Nat R (Semiring.toNonAssocSemiring.{0} Nat Nat.semiring) _inst_1) Nat R (Semiring.toNonAssocSemiring.{0} Nat Nat.semiring) _inst_1 (RingHom.instRingHomClassRingHom.{0, u1} Nat R (Semiring.toNonAssocSemiring.{0} Nat Nat.semiring) _inst_1)))) f)
Case conversion may be inaccurate. Consider using '#align ring_hom.injective_nat RingHom.injective_natₓ'. -/
theorem RingHom.injective_nat (f : ℕ →+* R) [CharZero R] : Function.Injective f :=
  Subsingleton.elim (Nat.castRingHom _) f ▸ Nat.cast_injective
#align ring_hom.injective_nat RingHom.injective_nat

end RingHom


import mynat.definition -- imports the natural numbers {0,1,2,3,4,...}.
import mynat.add -- imports definition of addition on the natural numbers.
import mynat.mul -- imports definition of multiplication on the natural numbers.

namespace mynat -- hide

lemma example1 (x y z : mynat) : x * y + z = x * y + z :=
begin
  refl,
end

end mynat -- hide


import SciLean
-- import SciLean.Mechanics

-- import Lean.Meta.Tactic

set_option synthInstance.maxHeartbeats 5000000
set_option synthInstance.maxSize 2048

open SciLean

def ε : ℝ := 0.001
instance : Fact (ε≠0) := Fact.mk (by native_decide)

@[simp]
theorem pair_add {X Y} [Add X] [Add Y] (x x' : X) (y y' : Y) : (x, y) + (x', y') = (x + x', y + y') := by simp[HAdd.hAdd, Add.add] done

@[simp]
theorem inner_zero  {X} [Hilbert X] (x : X) : ⟪0,x⟫ = 0 := sorry
@[simp]
theorem zero_inner  {X} [Hilbert X] (x : X) : ⟪x,0⟫ = 0 := sorry

def parm (l₁ l₂ : ℝ) (Ω : ℝ×ℝ) : (ℝ^(2:ℕ)) × (ℝ^(2:ℕ)) :=
  let e : ℝ^(2:ℕ) := ⟨0,-1⟩
  let Δx₁ := rotate2d Ω.1 (l₁ * e)
  let Δx₂ := rotate2d Ω.2 (l₂ * e)
  (Δx₁, Δx₁ + Δx₂)
argument Ω
  isSmooth, diff, hasAdjDiff, adjDiff?

set_option trace.Meta.Tactic.simp true

function_properties parm.arg_Ω.diff (l₁ l₂ : ℝ) (Ω dΩ : ℝ×ℝ) : (ℝ^(2:ℕ)) × (ℝ^(2:ℕ))
-- argument Ω
--   isSmooth, diff, hasAdjDiff, adjDiff
argument dΩ
  -- -- isLin := by simp[diff]; infer_instance; done,
  -- isSmooth,
  -- diff  --_simp := parm.arg_Ω.diff l₁ l₂ Ω ddΩ by simp[diff] done,
  -- hasAdjDiff,
  adjDiff -- := parm.arg_Ω.adjDiff l₁ l₂ Ω ddΩ' by simp[adjDiff,diff]; unfold hold;   imp done

def g : ℝ := 9.81

-- instance (priority := high) {X Y} [Vec X] [Vec Y] (f : X → Y) : IsSmooth f := sorry
-- instance (priority := high) {X Y} [SemiHilbert X] [SemiHilbert Y] (f : X → Y) : HasAdjDiff f := sorry

/-
def L (m₁ m₂ : ℝ) (l₁ l₂ : ℝ) (Ω ω : ℝ×ℝ) : ℝ :=
  let e : ℝ^(2:ℕ) := ⟨0,-1⟩
  let x := parm l₁ l₂ Ω
  let v := δ (λ t : ℝ => parm l₁ l₂ (Ω + t * ω)) 0 1
    rewrite_by (simp)
  m₁/2 * ∥v.1∥² - m₁ * g * x.1.y +
  m₂/2 * ∥v.2∥² - m₂ * g * x.2.y
argument Ω
  isSmooth, diff, hasAdjDiff, adjDiff
argument ω
  isSmooth, diff, hasAdjDiff, adjDiff

def momentum (m₁ m₂ : ℝ) (l₁ l₂ : ℝ) (Ω ω : ℝ×ℝ) : ℝ×ℝ :=
  (∂† (λ ω' => L m₁ m₂ l₁ l₂ Ω ω') ω 1)
  rewrite_by
    simp

#print L.arg_Ω.diff

instance : ∀ {X} [Vec X] (x : X), Fact (x≠0) := sorry

set_option trace.Meta.Tactic.simp.discharge true in
def velocity (m₁ m₂ : ℝ) (l₁ l₂ : ℝ) (Ω ω' : ℝ×ℝ) : ℝ×ℝ :=
  ((λ ω => momentum m₁ m₂ l₁ l₂ Ω ω)⁻¹ ω')
  rewrite_by
    simp[momentum]
    simp[L.arg_ω.adjDiff]
    simp only [!?(∀ {X} [Hilbert X] (x y : X) (a : ℝ), ⟪a * x, y⟫ = a * ⟪x,y⟫)]
    simp only [!?(∀ (x y : ℝ^(2:ℕ)) (θ : ℝ), ⟪rotate2d θ x, rotate2d θ y⟫ = ⟪x,y⟫)]
    simp only [!?(∀ {X} [Hilbert X] (x y : X) (a : ℝ), ⟪a * x, a * y⟫ = a * a * ⟪x,y⟫)]
    simp only [!?(∀ {X} [Hilbert X] (x  : X), ⟪x,x⟫ = ∥x∥²)]
    simp; unfold hold; simp

-/


import tactic.basic

inductive typ : Type
| unitT : typ
| arrowT (τ1:typ) (τ2:typ) : typ

inductive exp : Type
| var (x:string) : exp
| unit : exp
| lam (x:string) (τ:typ) (e:exp) : exp
| ap (f:exp) (a:exp) : exp

open exp
open typ

-- FIXME: should move partial functions to separate file
-- Statics:
def context := string → option typ

def update_context (Γ:context) (x:string) (t:typ) : context :=
  λ y, if (x = y) then t else Γ y

notation x `↦` τ `;` Γ := update_context Γ x τ
def empty_ctx : context := (λ _, none)

-- def context_lookup : context → string → option typ
-- | [] x := none
-- | ((y, τ) :: l) x := if x = y then τ else context_lookup l x

inductive has_type : context → exp → typ → Prop
| unit (Γ:context) : has_type Γ unit unitT
| var (Γ:context) (x:string) (τ:typ) (Hvar:Γ x = some τ) : has_type Γ (var x) τ
| lam (Γ:context) (x:string) (τ1 τ2:typ) (e:exp) (Habs:has_type (x↦τ1 ; Γ) e τ2) : has_type Γ (lam x τ1 e) (arrowT τ1 τ2)
| ap  (Γ:context) (f a:exp) (τ1 τ2:typ) (Hfunc:has_type Γ f (arrowT τ1 τ2)) (Hargs:has_type Γ a τ1): has_type Γ (ap f a) τ2

def substitute (x':string) (e':exp) : exp → exp
| unit := unit
| (var x) := if (x' = x) then e' else (var x)
| (lam x τ e) := if (x' = x) then (lam x τ e) else (lam x τ (substitute e))
| (ap f a) := (ap (substitute f) (substitute a))

-- Dynamics
inductive is_val : exp → Prop
| v_unit : is_val unit
| v_lam : ∀ x τ e, is_val (lam x τ e)

-- structural dynamics
inductive is_step : exp → exp → Prop
| ap (x:string) (τ:typ) (e a:exp): is_step (ap (lam x τ e) a) (substitute x a e)
| ap_f (e e' a:exp) (Hstep:is_step e e') : is_step (ap e a) (ap e' a)
-- NOTE: this is call by name. Chosen because it has fewer rules.
--
notation e ` ↦str `:90 e' := is_step e e'

notation Γ ` ⊢ `:90 e:90 ` : `:90 τ:90 := has_type Γ e τ

inductive is_many_step : exp → exp → Prop
| many_steps_reflexive e:exp : is_many_step e e
| many_steps_transitive (e1 e2 e3:exp) (Hsteps:is_many_step e2 e3) (Hstep:is_step e1 e2)
   : is_many_step e1 e3

-- Plan is to prove:
-- a) (∅ ⊢ e:τ) implies SN τ e;
-- b) SN τ e → normalizes e.
-- Proving b is easy by induction, it's basically baked into the definition
-- Proving a by induction on (∅ ⊢ e:τ) will be tricky in the has_type.lam case.

-- def env := finmap (λ _:string, exp)
def env := list (string × exp)
-- def env := alist (λ _:string, exp)

def env_sub : env → exp → exp
| [] e := e
| (⟨x, ex⟩::l) e := env_sub l (substitute x ex e)

instance env_has_mem : has_mem (string × exp) env := list.has_mem

def context_list := list (string × typ)
def mk_context : context_list → context
| [] := empty_ctx
| ((x,τ) :: ctx) := (x↦τ; mk_context ctx)

def is_env_ctx (P:typ → exp → Prop) : env → context_list → Prop
| [] [] := true
| ((x,v)::γ) ((y,τ)::Γ) := x=y ∧ is_env_ctx γ Γ ∧ P τ v
| _ _ := false

-- FIXME: copy/paste from e-lang
def context_included (Γ Γ':context) : Prop :=
  ∀ x y,
    Γ x = some y → Γ' x = some y

def included_update :
∀ Γ Γ' x τ,
 context_included Γ Γ' →
 context_included (x ↦ τ ; Γ) (x ↦ τ ; Γ')
 :=
begin
 introv,
 intros Hinc,
 unfold context_included update_context at *,
 intros x1 y Hlookup,
 by_cases (x = x1),
 { rwa if_pos at *; assumption,
 },
 rw if_neg at * ; try { assumption },
 { apply Hinc, assumption }
end

def empty_included:
  ∀ Γ, context_included empty_ctx Γ :=
begin
  intros,
  intros _ _ H,
  exfalso, unfold empty_ctx at *, contradiction
end

lemma weakening :
  ∀ Γ' Γ e τ,
  context_included Γ' Γ →
  Γ' ⊢ e : τ →
  Γ ⊢ e : τ :=
begin
  introv Hinc Hty,
  induction Hty generalizing Γ,
  { /- case: unit -/ constructor },
  { /- case: var -/ constructor, apply Hinc, assumption },
  { -- case: lam
    constructor,
    apply Hty_ih,
    apply included_update,
    assumption,
  },
  { -- case: ap
    constructor,
    { apply Hty_ih_Hfunc, assumption },
    { apply Hty_ih_Hargs, assumption },
  }
end

lemma sub_property :
∀ x τx v Γ e τ,
empty_ctx ⊢ v : τx →
(x ↦ τx; Γ) ⊢ e : τ →
Γ ⊢ substitute x v e : τ :=
begin
  introv Hty Hty,
  generalize h : (x↦τx;Γ) = Γ',
  rw h at *,
  induction Hty generalizing Γ; subst h,
  { unfold substitute, constructor },
  { unfold substitute,
    unfold update_context at Hty_Hvar,
    by_cases (x = Hty_x),
    {
      simp *,
      simp * at Hty_Hvar,
      injection Hty_Hvar,
      subst h_1,
      apply weakening,
      tactic.swap, assumption,
      apply empty_included
    },
    {
      rw if_neg at *;
      try { tauto },
      constructor,
      assumption
    }
  },
  { -- case: lam
    unfold substitute,
    by_cases (x = Hty_x),
    {
      simp *,
      constructor,
      subst h,
      have h : (x↦Hty_τ1;(x↦τx;Γ)) = (x↦Hty_τ1;Γ),
      { unfold update_context, apply funext, intros y,
        by_cases (x = y),
        { simp * },
        { repeat { rw (if_neg h)} }
      },
      rw <- h,
      assumption
    },
    {
      rw if_neg, tactic.swap, trivial,
      constructor,
      apply Hty_ih,
      unfold update_context,
      apply funext,
      intros y,
      by_cases (x = y),
      { subst h, simp *, rw if_neg, tauto },
      { rw if_neg, tactic.swap, tauto, by_cases (Hty_x = y),
        { simp * },
        { repeat { rw if_neg }, repeat { assumption }},
      },
    },
  },
  { -- case : ap
    unfold substitute,
    constructor,
    { apply Hty_ih_Hfunc, refl },
    { apply Hty_ih_Hargs, refl }
  }
end

lemma substitution_property :
  ∀ γ Γ c e τ P,
  is_env_ctx P γ c →
  (∀ v' τ', (P τ' v') → (empty_ctx ⊢ v' : τ')) →
  Γ = mk_context c →
  Γ ⊢ e : τ →
  empty_ctx ⊢ env_sub γ e : τ
  :=
begin
  introv Henv Hclosed HΓ Hty,
  subst HΓ,
  induction γ generalizing c e,
  {
    induction c,
    { unfold env_sub, unfold empty_ctx, assumption },
    { exfalso, unfold is_env_ctx at Henv, trivial },
  },
  induction c,
  { exfalso, cases γ_hd, unfold is_env_ctx at Henv, trivial },
  cases γ_hd with x v,
  unfold env_sub,
  cases c_hd,
  unfold is_env_ctx at Henv,
  apply (γ_ih c_tl),
  { apply Henv.2.1 },
  cases Henv with Hre Henv,
  subst Hre,
  apply sub_property,
  tactic.swap,
  { exact Hty, },
  { cases c_hd_snd; cases Henv with _ Hsn; apply Hclosed; apply Hsn },
end

lemma env_sub_unit :
∀ γ, env_sub γ unit = unit :=
begin
 intros,
 induction γ,
 { unfold env_sub, },
 { cases γ_hd, unfold env_sub, unfold substitute, assumption },
end

lemma env_sub_ap :
∀ γ f a, (env_sub γ (ap f a)) = (ap (env_sub γ f) (env_sub γ a)) :=
begin
  intros,
  induction γ generalizing f a,
  { unfold env_sub, },
  cases γ_hd,
  unfold env_sub,
  apply γ_ih,
end

lemma env_sub_lam_val :
∀ γ x τ e, is_val (env_sub γ (lam x τ e)) :=
begin
  intros,
  induction γ generalizing e,
  { unfold env_sub, constructor },
  cases γ_hd, unfold env_sub,
  unfold substitute,
  by_cases (γ_hd_fst = x),
  { simp * },
  rw if_neg, tactic.swap, trivial,
  apply γ_ih,
end

lemma sub_lam_ne :
∀ (Γ:context) y ey τ2 e,
(∀ x τx, Γ x = some τx → y ≠ x) →
Γ ⊢ e : τ2 →
(substitute y ey e) = e :=
begin
  introv Hne Hty,
  induction Hty,
  { unfold substitute },
  { unfold substitute, rw if_neg,
    apply Hne,
    { assumption },
  },
  {
    unfold substitute,
    by_cases (y = Hty_x),
    { simp * },
    { rw if_neg, tactic.swap, trivial,
      rw Hty_ih,
      { introv Hlookup,
        unfold update_context at Hlookup,
        by_cases (Hty_x = x),
        { simp * at Hlookup, subst h, tauto },
        { rw if_neg at Hlookup, apply Hne, assumption, assumption },
      }
    }
  },
  {
    unfold substitute,
    rw Hty_ih_Hfunc,
    rw Hty_ih_Hargs,
    repeat { assumption }
  },
end

lemma env_sub_closed :
∀ γ v τ, (empty_ctx ⊢ v : τ) → env_sub γ v = v :=
begin
  introv Hsn,
  generalize h : empty_ctx = Γ,
  rw h at *,
  induction Hsn generalizing γ; subst h,
  { apply env_sub_unit },
  { exfalso, unfold empty_ctx at Hsn_Hvar, contradiction },
  {
    induction γ,
    { unfold env_sub },
    cases γ_hd,
    unfold env_sub,
    unfold substitute,
    by_cases (γ_hd_fst = Hsn_x),
    { simp * },
    { rw if_neg, tactic.swap, trivial,
      rw sub_lam_ne,
      { apply γ_ih },
      tactic.swap, assumption,
      { intros, unfold update_context at *, by_cases Hsn_x = x,
        { simp *, subst h, tauto },
        { rw if_neg at *, unfold empty_ctx at *, contradiction, assumption }
      }
    }
  },
  { rw env_sub_ap,
    rw Hsn_ih_Hfunc,
    rw Hsn_ih_Hargs,
    repeat { trivial },
  },
end

lemma double_substitute :
∀ x τ1 τ2 ex1 ex2 e,
empty_ctx ⊢ ex1 : τ1 →
empty_ctx ⊢ ex2 : τ2 →
(substitute x ex2 (substitute x ex1 e)) = substitute x ex1 e :=
begin
intros,
  induction e,
  { unfold substitute, by_cases (x = e),
    { simp *,
      have h : (substitute e ex2 ex1 = env_sub [(e,ex2)] ex1),
      { unfold env_sub },
      rw h,
      rw env_sub_closed,
      assumption
    },
    {
      rw if_neg, tactic.swap, trivial,
      unfold substitute, rw if_neg, trivial
    }
  },
  { unfold substitute },
  {
    unfold substitute,
    by_cases (x = e_x),
    { simp *, unfold substitute, simp * },
    { rw if_neg, tactic.swap, trivial,
      unfold substitute, rw if_neg, tactic.swap, trivial,
      rw e_ih,
    }
  },
  {
    unfold substitute,
    rw [e_ih_f, e_ih_a]
  }
end

lemma substitute_commute :
∀ x y τx τy ex ey e,
(empty_ctx ⊢ ex : τx) →
(empty_ctx ⊢ ey : τy) →
x ≠ y →
(substitute x ex (substitute y ey e)) = (substitute y ey (substitute x ex e)) :=
begin
  intros,
  induction e,
  { -- case: var
    unfold substitute,
    by_cases (y = e),
    { simp *, subst h,
      rw if_neg, tactic.swap, trivial,
      unfold substitute,
      simp *,
      have h : (substitute x ex ey = env_sub [(x,ex)] ey),
      { unfold env_sub },
      rw h, apply env_sub_closed, assumption
    },
    {
      rw if_neg, tactic.swap, trivial,
      unfold substitute,
      by_cases (x = e),
      {
        simp *,
        have h : (substitute y ey ex = env_sub [(y,ey)] ex),
        { unfold env_sub },
        rw h, rw env_sub_closed, assumption
      },
      {
        rw if_neg, unfold substitute, rw if_neg, repeat { assumption }
      }
    }
  },
  { -- case: unit
    unfold substitute,
  },
  { -- case: lam
    unfold substitute,
    by_cases (y = e_x); by_cases (x = e_x),
    { simp *, unfold substitute, simp * },
    { simp *, unfold substitute, rw if_neg, simp *, assumption },
    { rw if_neg, simp *, unfold substitute, simp *, assumption },
    { rw if_neg, rw if_neg, unfold substitute, simp *, assumption, assumption },
  },
  { -- case: ap
    unfold substitute,
    rw e_ih_f,
    rw e_ih_a,
  }
end


/-
Copyright (c) 2018 Andreas Swerdlow. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Andreas Swerdlow
-/
import algebra.module.linear_map
import tactic.abel

/-!
# Sesquilinear form

This file defines a sesquilinear form over a module. The definition requires a ring antiautomorphism
on the scalar ring. Basic ideas such as
orthogonality are also introduced.

A sesquilinear form on an `R`-module `M`, is a function from `M × M` to `R`, that is linear in the
first argument and antilinear in the second, with respect to an antiautomorphism on `R` (an
antiisomorphism from `R` to `R`).

## Notations

Given any term `S` of type `sesq_form`, due to a coercion, can use the notation `S x y` to
refer to the function field, ie. `S x y = S.sesq x y`.

## References

* <https://en.wikipedia.org/wiki/Sesquilinear_form#Over_arbitrary_rings>

## Tags

Sesquilinear form,
-/

open_locale big_operators

universes u v w

/-- A sesquilinear form over a module  -/
structure sesq_form (R : Type u) (M : Type v) [ring R] (I : R ≃+* Rᵐᵒᵖ)
  [add_comm_group M] [module R M] :=
(sesq : M → M → R)
(sesq_add_left : ∀ (x y z : M), sesq (x + y) z = sesq x z + sesq y z)
(sesq_smul_left : ∀ (a : R) (x y : M), sesq (a • x) y = a * (sesq x y))
(sesq_add_right : ∀ (x y z : M), sesq x (y + z) = sesq x y + sesq x z)
(sesq_smul_right : ∀ (a : R) (x y : M), sesq x (a • y) = (I a).unop * (sesq x y))

namespace sesq_form

section general_ring
variables {R : Type u} {M : Type v} [ring R] [add_comm_group M] [module R M]
variables {I : R ≃+* Rᵐᵒᵖ} {S : sesq_form R M I}

instance : has_coe_to_fun (sesq_form R M I) (λ _, M → M → R) := ⟨sesq⟩

lemma add_left (x y z : M) : S (x + y) z = S x z + S y z := sesq_add_left S x y z

lemma smul_left (a : R) (x y : M) : S (a • x) y = a * (S x y) := sesq_smul_left S a x y

lemma add_right (x y z : M) : S x (y + z) = S x y + S x z := sesq_add_right S x y z

lemma smul_right (a : R) (x y : M) : S x (a • y) = (I a).unop * (S x y) := sesq_smul_right S a x y

lemma zero_left (x : M) : S 0 x = 0 :=
by { rw [←zero_smul R (0 : M), smul_left, zero_mul] }

lemma zero_right (x : M) : S x 0 = 0 :=
by { rw [←zero_smul R (0 : M), smul_right], simp }

lemma neg_left (x y : M) : S (-x) y = -(S x y) :=
by { rw [←@neg_one_smul R _ _, smul_left, neg_one_mul] }

lemma neg_right (x y : M) : S x (-y) = -(S x y) :=
by { rw [←@neg_one_smul R _ _, smul_right], simp }

lemma sub_left (x y z : M) :
  S (x - y) z = S x z - S y z :=
by simp only [sub_eq_add_neg, add_left, neg_left]

lemma sub_right (x y z : M) :
  S x (y - z) = S x y - S x z :=
by simp only [sub_eq_add_neg, add_right, neg_right]

variable {D : sesq_form R M I}
@[ext] lemma ext (H : ∀ (x y : M), S x y = D x y) : S = D :=
by {cases S, cases D, congr, funext, exact H _ _}

instance : has_add (sesq_form R M I) :=
⟨λ S D, { sesq := λ x y, S x y + D x y,
                  sesq_add_left := λ x y z, by {rw add_left, rw add_left, abel},
                  sesq_smul_left := λ a x y, by {rw [smul_left, smul_left, mul_add]},
                  sesq_add_right := λ x y z, by {rw add_right, rw add_right, abel},
                  sesq_smul_right := λ a x y, by {rw [smul_right, smul_right, mul_add]} }⟩

instance : has_zero (sesq_form R M I) :=
⟨{ sesq := λ x y, 0,
            sesq_add_left := λ x y z, (add_zero 0).symm,
            sesq_smul_left := λ a x y, (mul_zero a).symm,
            sesq_add_right := λ x y z, (zero_add 0).symm,
            sesq_smul_right := λ a x y, (mul_zero (I a).unop).symm }⟩

instance : has_neg (sesq_form R M I) :=
⟨λ S, { sesq := λ x y, - (S.1 x y),
                sesq_add_left := λ x y z, by rw [sesq_add_left, neg_add],
                sesq_smul_left := λ a x y, by rw [sesq_smul_left, mul_neg_eq_neg_mul_symm],
                sesq_add_right := λ x y z, by rw [sesq_add_right, neg_add],
                sesq_smul_right := λ a x y, by rw [sesq_smul_right, mul_neg_eq_neg_mul_symm] }⟩

instance : add_comm_group (sesq_form R M I) :=
{ add := (+),
  add_assoc := by { intros, ext,
    unfold coe_fn has_coe_to_fun.coe sesq coe_fn has_coe_to_fun.coe sesq, rw add_assoc },
  zero := 0,
  zero_add := by { intros, ext, unfold coe_fn has_coe_to_fun.coe sesq, rw zero_add },
  add_zero := by { intros, ext, unfold coe_fn has_coe_to_fun.coe sesq, rw add_zero },
  neg := has_neg.neg,
  add_left_neg := by { intros, ext, unfold coe_fn has_coe_to_fun.coe sesq, rw neg_add_self },
  add_comm := by { intros, ext, unfold coe_fn has_coe_to_fun.coe sesq, rw add_comm } }

instance : inhabited (sesq_form R M I) := ⟨0⟩

/-- The proposition that two elements of a sesquilinear form space are orthogonal -/
def is_ortho (S : sesq_form R M I) (x y : M) : Prop :=
S x y = 0

lemma ortho_zero (x : M) :
is_ortho S (0 : M) x := zero_left x

/-- For fixed `y : M`, the `R`-linear map sending `x : M` to `S x y`, where `S` is a
sesquilinear form. -/
@[simps] def linear_map_left (S : sesq_form R M I) (x : M) : M →ₗ[R] R :=
{ to_fun := λ z, S z x,
  map_add' := λ z y, sesq_add_left S _ _ _,
  map_smul' := λ r m, sesq_smul_left S _ _ _ }

/-- For fixed `x : M`, the `add_monoid_hom` sending `y : M` to `S x y`, where `S` is a
sesquilinear form. -/
@[simps] def add_monoid_hom_right (S : sesq_form R M I) (x : M) : M →+ R :=
{ to_fun := λ z, S x z,
  map_zero' := zero_right x,
  map_add' := λ z y, sesq_add_right S _ _ _, }

lemma sum_left {α : Type*} (S : sesq_form R M I) (t : finset α) (g : α → M) (w : M) :
  S (∑ i in t, g i) w = ∑ i in t, S (g i) w :=
(linear_map_left S w).map_sum

lemma sum_right {α : Type*} (S : sesq_form R M I) (t : finset α) (g : α → M) (w : M) :
  S w (∑ i in t, g i) = ∑ i in t, S w (g i) :=
(add_monoid_hom_right S w).map_sum _ t

variables {M₂ : Type w} [add_comm_group M₂] [module R M₂]

/-- Apply the linear maps `f` and `g` to the left and right arguments of the sesquilinear form. -/
def comp (S : sesq_form R M I) (f g : M₂ →ₗ[R] M) : sesq_form R M₂ I :=
{ sesq := λ x y, S (f x) (g y),
  sesq_add_left := by simp [add_left],
  sesq_smul_left := by simp [smul_left],
  sesq_add_right := by simp [add_right],
  sesq_smul_right := by simp [smul_right] }

/-- Apply the linear map `f` to the left argument of the sesquilinear form. -/
def comp_left (S : sesq_form R M I) (f : M →ₗ[R] M) : sesq_form R M I :=
  S.comp f linear_map.id

/-- Apply the linear map `f` to the right argument of the sesquilinear form. -/
def comp_right (S : sesq_form R M I) (f : M →ₗ[R] M) : sesq_form R M I :=
  S.comp linear_map.id f

lemma comp_left_comp_right (S : sesq_form R M I) (f g : M →ₗ[R] M) :
  (S.comp_left f).comp_right g = S.comp f g := rfl

lemma comp_right_comp_left (S : sesq_form R M I) (f g : M →ₗ[R] M) :
  (S.comp_right g).comp_left f = S.comp f g := rfl

lemma comp_comp {M₃ : Type*} [add_comm_group M₃] [module R M₃]
  (S : sesq_form R M₃ I) (l r : M →ₗ[R] M₂) (l' r' : M₂ →ₗ[R] M₃) :
  (S.comp l' r').comp l r = S.comp (l'.comp l) (r'.comp r) := rfl

@[simp] lemma comp_apply (S : sesq_form R M₂ I) (l r : M →ₗ[R] M₂) (v w : M) :
  S.comp l r v w = S (l v) (r w) := rfl

@[simp] lemma comp_left_apply (S : sesq_form R M I) (f : M →ₗ[R] M) (v w : M) :
  S.comp_left f v w = S (f v) w := rfl

@[simp] lemma comp_right_apply (S : sesq_form R M I) (f : M →ₗ[R] M) (v w : M) :
  S.comp_right f v w = S v (f w) := rfl

/-- Let `l`, `r` be surjective linear maps, then two sesquilinear forms are equal if and only if
  the sesquilinear forms resulting from composition with `l` and `r` are equal. -/
lemma comp_injective (S₁ S₂ : sesq_form R M₂ I) {l r : M →ₗ[R] M₂}
  (hl : function.surjective l) (hr : function.surjective r) :
  S₁.comp l r = S₂.comp l r ↔ S₁ = S₂ :=
begin
  split; intros h,
  { ext,
    rcases hl x with ⟨x', rfl⟩,
    rcases hr y with ⟨y', rfl⟩,
    rw [← comp_apply, ← comp_apply, h], },
  { rw h },
end

end general_ring

section comm_ring

variables {R : Type*} [comm_ring R] {M : Type v} [add_comm_group M] [module R M]
  {J : R ≃+* Rᵐᵒᵖ} (F : sesq_form R M J) (f : M → M)

instance to_module : module R (sesq_form R M J) :=
{ smul := λ c S,
  { sesq := λ x y, c * S x y,
    sesq_add_left := λ x y z, by {unfold coe_fn has_coe_to_fun.coe sesq,
      rw [sesq_add_left, left_distrib]},
    sesq_smul_left := λ a x y, by {unfold coe_fn has_coe_to_fun.coe sesq,
      rw [sesq_smul_left, ←mul_assoc, mul_comm c, mul_assoc]},
    sesq_add_right := λ x y z, by {unfold coe_fn has_coe_to_fun.coe sesq,
      rw [sesq_add_right, left_distrib]},
    sesq_smul_right := λ a x y, by {unfold coe_fn has_coe_to_fun.coe sesq,
      rw [sesq_smul_right, ←mul_assoc, mul_comm c, mul_assoc], refl} },
  smul_add := λ c S D, by {ext, unfold coe_fn has_coe_to_fun.coe sesq, rw left_distrib},
  add_smul := λ c S D, by {ext, unfold coe_fn has_coe_to_fun.coe sesq, rw right_distrib},
  mul_smul := λ a c D, by {ext, unfold coe_fn has_coe_to_fun.coe sesq, rw mul_assoc},
  one_smul := λ S, by {ext, unfold coe_fn has_coe_to_fun.coe sesq, rw one_mul},
  zero_smul := λ S, by {ext, unfold coe_fn has_coe_to_fun.coe sesq, rw zero_mul},
  smul_zero := λ S, by {ext, unfold coe_fn has_coe_to_fun.coe sesq, rw mul_zero} }

end comm_ring

section is_domain

variables {R : Type*} [ring R] [is_domain R]
  {M : Type v} [add_comm_group M] [module R M]
  {K : R ≃+* Rᵐᵒᵖ} {G : sesq_form R M K}

theorem ortho_smul_left {x y : M} {a : R} (ha : a ≠ 0) :
  (is_ortho G x y) ↔ (is_ortho G (a • x) y) :=
begin
  dunfold is_ortho,
  split; intro H,
  { rw [smul_left, H, mul_zero] },
  { rw [smul_left, mul_eq_zero] at H,
    cases H,
    { trivial },
    { exact H }}
end

theorem ortho_smul_right {x y : M} {a : R} (ha : a ≠ 0) :
  (is_ortho G x y) ↔ (is_ortho G x (a • y)) :=
begin
  dunfold is_ortho,
  split; intro H,
  { rw [smul_right, H, mul_zero] },
  { rw [smul_right, mul_eq_zero] at H,
    cases H,
    { exfalso,
      -- `map_eq_zero_iff` doesn't fire here even if marked as a simp lemma, probably bcecause
      -- different instance paths
      simp only [mul_opposite.unop_eq_zero_iff] at H,
      exact ha (K.map_eq_zero_iff.mp H), },
    { exact H }}
end

end is_domain

variables {R : Type*} {M : Type*} [ring R] [add_comm_group M] [module R M]
variables {I : R ≃+* Rᵐᵒᵖ} {S : sesq_form R M I}

/-- The proposition that a sesquilinear form is reflexive -/
def is_refl (S : sesq_form R M I) : Prop := ∀ (x y : M), S x y = 0 → S y x = 0

namespace is_refl

variable (H : S.is_refl)

lemma eq_zero : ∀ {x y : M}, S x y = 0 → S y x = 0 := λ x y, H x y

lemma ortho_comm {x y : M} : is_ortho S x y ↔ is_ortho S y x := ⟨eq_zero H, eq_zero H⟩

end is_refl

/-- The proposition that a sesquilinear form is symmetric -/
def is_symm (S : sesq_form R M I) : Prop := ∀ (x y : M), (I (S x y)).unop = S y x

namespace is_symm

variable (H : S.is_symm)
include H

protected lemma eq (x y : M) : (I (S x y)).unop = S y x := H x y

lemma is_refl : S.is_refl := λ x y H1, by { rw [←H], simp [H1], }

lemma ortho_comm {x y : M} : is_ortho S x y ↔ is_ortho S y x := H.is_refl.ortho_comm

end is_symm

/-- The proposition that a sesquilinear form is alternating -/
def is_alt (S : sesq_form R M I) : Prop := ∀ (x : M), S x x = 0

namespace is_alt

variable (H : S.is_alt)
include H

lemma self_eq_zero (x : M) : S x x = 0 := H x

lemma neg (x y : M) :
- S x y = S y x :=
begin
  have H1 : S (x + y) (x + y) = 0,
  { exact self_eq_zero H (x + y) },
  rw [add_left, add_right, add_right,
    self_eq_zero H, self_eq_zero H, ring.zero_add,
    ring.add_zero, add_eq_zero_iff_neg_eq] at H1,
  exact H1,
end

lemma is_refl : S.is_refl :=
begin
  intros x y h,
  rw [← neg H, h, neg_zero],
end

lemma ortho_comm {x y : M} : is_ortho S x y ↔ is_ortho S y x := H.is_refl.ortho_comm

end is_alt

end sesq_form


/-
Copyright (c) 2020 Aaron Anderson, Jalex Stark. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Aaron Anderson, Jalex Stark.
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.data.matrix.char_p
import Mathlib.linear_algebra.char_poly.basic
import Mathlib.linear_algebra.matrix
import Mathlib.ring_theory.polynomial.basic
import Mathlib.algebra.polynomial.big_operators
import Mathlib.group_theory.perm.cycles
import Mathlib.field_theory.finite.basic
import Mathlib.PostPort

universes u v u_1

namespace Mathlib

/-!
# Characteristic polynomials

We give methods for computing coefficients of the characteristic polynomial.

## Main definitions

- `char_poly_degree_eq_dim` proves that the degree of the characteristic polynomial
  over a nonzero ring is the dimension of the matrix
- `det_eq_sign_char_poly_coeff` proves that the determinant is the constant term of the characteristic
  polynomial, up to sign.
- `trace_eq_neg_char_poly_coeff` proves that the trace is the negative of the (d-1)th coefficient of the
  characteristic polynomial, where d is the dimension of the matrix.
  For a nonzero ring, this is the second-highest coefficient.

-/

theorem char_matrix_apply_nat_degree {R : Type u} [comm_ring R] {n : Type v} [DecidableEq n]
    [fintype n] {M : matrix n n R} [nontrivial R] (i : n) (j : n) :
    polynomial.nat_degree (char_matrix M i j) = ite (i = j) 1 0 :=
  sorry

theorem char_matrix_apply_nat_degree_le {R : Type u} [comm_ring R] {n : Type v} [DecidableEq n]
    [fintype n] {M : matrix n n R} (i : n) (j : n) :
    polynomial.nat_degree (char_matrix M i j) ≤ ite (i = j) 1 0 :=
  sorry

theorem char_poly_sub_diagonal_degree_lt {R : Type u} [comm_ring R] {n : Type v} [DecidableEq n]
    [fintype n] (M : matrix n n R) :
    polynomial.degree
          (char_poly M -
            finset.prod finset.univ fun (i : n) => polynomial.X - coe_fn polynomial.C (M i i)) <
        ↑(fintype.card n - 1) :=
  sorry

theorem char_poly_coeff_eq_prod_coeff_of_le {R : Type u} [comm_ring R] {n : Type v} [DecidableEq n]
    [fintype n] (M : matrix n n R) {k : ℕ} (h : fintype.card n - 1 ≤ k) :
    polynomial.coeff (char_poly M) k =
        polynomial.coeff
          (finset.prod finset.univ fun (i : n) => polynomial.X - coe_fn polynomial.C (M i i)) k :=
  sorry

theorem det_of_card_zero {R : Type u} [comm_ring R] {n : Type v} [DecidableEq n] [fintype n]
    (h : fintype.card n = 0) (M : matrix n n R) : matrix.det M = 1 :=
  sorry

theorem char_poly_degree_eq_dim {R : Type u} [comm_ring R] {n : Type v} [DecidableEq n] [fintype n]
    [nontrivial R] (M : matrix n n R) : polynomial.degree (char_poly M) = ↑(fintype.card n) :=
  sorry

theorem char_poly_nat_degree_eq_dim {R : Type u} [comm_ring R] {n : Type v} [DecidableEq n]
    [fintype n] [nontrivial R] (M : matrix n n R) :
    polynomial.nat_degree (char_poly M) = fintype.card n :=
  polynomial.nat_degree_eq_of_degree_eq_some (char_poly_degree_eq_dim M)

theorem char_poly_monic {R : Type u} [comm_ring R] {n : Type v} [DecidableEq n] [fintype n]
    (M : matrix n n R) : polynomial.monic (char_poly M) :=
  sorry

theorem trace_eq_neg_char_poly_coeff {R : Type u} [comm_ring R] {n : Type v} [DecidableEq n]
    [fintype n] [Nonempty n] (M : matrix n n R) :
    coe_fn (matrix.trace n R R) M = -polynomial.coeff (char_poly M) (fintype.card n - 1) :=
  sorry

-- I feel like this should use polynomial.alg_hom_eval₂_algebra_map

theorem mat_poly_equiv_eval {R : Type u} [comm_ring R] {n : Type v} [DecidableEq n] [fintype n]
    (M : matrix n n (polynomial R)) (r : R) (i : n) (j : n) :
    polynomial.eval (coe_fn (matrix.scalar n) r) (coe_fn mat_poly_equiv M) i j =
        polynomial.eval r (M i j) :=
  sorry

theorem eval_det {R : Type u} [comm_ring R] {n : Type v} [DecidableEq n] [fintype n]
    (M : matrix n n (polynomial R)) (r : R) :
    polynomial.eval r (matrix.det M) =
        matrix.det (polynomial.eval (coe_fn (matrix.scalar n) r) (coe_fn mat_poly_equiv M)) :=
  sorry

theorem det_eq_sign_char_poly_coeff {R : Type u} [comm_ring R] {n : Type v} [DecidableEq n]
    [fintype n] (M : matrix n n R) :
    matrix.det M = (-1) ^ fintype.card n * polynomial.coeff (char_poly M) 0 :=
  sorry

@[simp] theorem finite_field.char_poly_pow_card {n : Type v} [DecidableEq n] [fintype n]
    {K : Type u_1} [field K] [fintype K] (M : matrix n n K) :
    char_poly (M ^ fintype.card K) = char_poly M :=
  sorry

@[simp] theorem zmod.char_poly_pow_card {n : Type v} [DecidableEq n] [fintype n] {p : ℕ}
    [fact (nat.prime p)] (M : matrix n n (zmod p)) : char_poly (M ^ p) = char_poly M :=
  eq.mp (Eq._oldrec (Eq.refl (char_poly (M ^ fintype.card (zmod p)) = char_poly M)) (zmod.card p))
    (finite_field.char_poly_pow_card M)

theorem finite_field.trace_pow_card {n : Type v} [DecidableEq n] [fintype n] {K : Type u_1}
    [field K] [fintype K] [Nonempty n] (M : matrix n n K) :
    coe_fn (matrix.trace n K K) (M ^ fintype.card K) =
        coe_fn (matrix.trace n K K) M ^ fintype.card K :=
  sorry

theorem zmod.trace_pow_card {n : Type v} [DecidableEq n] [fintype n] {p : ℕ} [fact (nat.prime p)]
    [Nonempty n] (M : matrix n n (zmod p)) :
    coe_fn (matrix.trace n (zmod p) (zmod p)) (M ^ p) =
        coe_fn (matrix.trace n (zmod p) (zmod p)) M ^ p :=
  sorry

namespace matrix

theorem is_integral {R : Type u} [comm_ring R] {n : Type v} [DecidableEq n] [fintype n]
    (M : matrix n n R) : is_integral R M :=
  Exists.intro (char_poly M) { left := char_poly_monic M, right := aeval_self_char_poly M }

theorem min_poly_dvd_char_poly {n : Type v} [DecidableEq n] [fintype n] {K : Type u_1} [field K]
    (M : matrix n n K) : minpoly K M ∣ char_poly M :=
  minpoly.dvd K M (aeval_self_char_poly M)

end Mathlib


def f : Nat → Bool → Nat
  | 0,  true  => 1
  | 0,  false => 2
  | 1,  true => 3
  | 1,  _ => 4
  | x+2, true => f x true
  | x+2, b => f x (not b)

macro "urfl" : tactic => `(set_option smartUnfolding false in rfl)

theorem f_main_eq : f x b = f.match_1 (fun _ _ => Nat) x b (fun _ => 1) (fun _ => 2) (fun _ => 3) (fun _ => 4) (fun x => f x true) (fun x b => f x (not b)) := by
  split <;> (first | rfl | (conv => lhs; delta f; whnf; simp_match); try urfl)

#check @f_main_eq

def g : List Nat → List Nat → Nat
  | [],         y::ys => y
  | [],         ys    => 0
  | x1::x2::xs, ys    => g xs ys
  | x::xs,      y::ys => g xs ys + y
  | x::xs,      []    => g xs []

theorem g_main_eq (xs ys : List Nat) : g xs ys = g.match_1 (fun _ _ => Nat) xs ys (fun y ys => y) (fun _ => 0) (fun _ _ xs ys => g xs ys) (fun _ xs y ys => g xs ys + y) (fun _ xs => g xs []) := by
  split <;> (first | rfl | (conv => lhs; delta g; whnf; simp_match); try urfl)

#check @g_main_eq

def foo (xs : List Nat) : List Nat :=
  match xs with
  | []    => []
  | x::xs =>
    let y := 2 * x;
    match xs with
    | []    => []
    | x::xs => (y + x) :: foo xs

theorem foo_main_eq (xs : List Nat) : foo xs = foo.match_1 (fun _ => List Nat) xs (fun _ => []) (fun x xs => let y := 2*x; foo.match_1 (fun _ => List Nat) xs (fun _ => []) (fun x xs => (y + x)::foo xs)) := by
  split
  . rfl
  . split
    . rfl
    . rfl

#check @foo_main_eq