/-
Copyright (c) 2014 Jeremy Avigad. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jeremy Avigad, Leonardo de Moura, Floris van Doorn, Yury Kudryashov, Neil Strickland

! This file was ported from Lean 3 source module algebra.ring.units
! leanprover-community/mathlib commit 448144f7ae193a8990cb7473c9e9a01990f64ac7
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Algebra.Ring.InjSurj
import Mathbin.Algebra.Group.Units

/-!
# Units in semirings and rings

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

universe u v w x

variable {α : Type u} {β : Type v} {γ : Type w} {R : Type x}

open Function

namespace Units

section HasDistribNeg

variable [Monoid α] [HasDistribNeg α] {a b : α}

/-- Each element of the group of units of a ring has an additive inverse. -/
instance : Neg αˣ :=
  ⟨fun u => ⟨-↑u, -↑u⁻¹, by simp, by simp⟩⟩

/- warning: units.coe_neg -> Units.val_neg is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Monoid.{u1} α] [_inst_2 : HasDistribNeg.{u1} α (MulOneClass.toHasMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1))] (u : Units.{u1} α _inst_1), Eq.{succ u1} α ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (Units.{u1} α _inst_1) α (HasLiftT.mk.{succ u1, succ u1} (Units.{u1} α _inst_1) α (CoeTCₓ.coe.{succ u1, succ u1} (Units.{u1} α _inst_1) α (coeBase.{succ u1, succ u1} (Units.{u1} α _inst_1) α (Units.hasCoe.{u1} α _inst_1)))) (Neg.neg.{u1} (Units.{u1} α _inst_1) (Units.hasNeg.{u1} α _inst_1 _inst_2) u)) (Neg.neg.{u1} α (InvolutiveNeg.toHasNeg.{u1} α (HasDistribNeg.toHasInvolutiveNeg.{u1} α (MulOneClass.toHasMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1)) _inst_2)) ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (Units.{u1} α _inst_1) α (HasLiftT.mk.{succ u1, succ u1} (Units.{u1} α _inst_1) α (CoeTCₓ.coe.{succ u1, succ u1} (Units.{u1} α _inst_1) α (coeBase.{succ u1, succ u1} (Units.{u1} α _inst_1) α (Units.hasCoe.{u1} α _inst_1)))) u))
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Monoid.{u1} α] [_inst_2 : HasDistribNeg.{u1} α (MulOneClass.toMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1))] (u : Units.{u1} α _inst_1), Eq.{succ u1} α (Units.val.{u1} α _inst_1 (Neg.neg.{u1} (Units.{u1} α _inst_1) (Units.instNegUnits.{u1} α _inst_1 _inst_2) u)) (Neg.neg.{u1} α (InvolutiveNeg.toNeg.{u1} α (HasDistribNeg.toInvolutiveNeg.{u1} α (MulOneClass.toMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1)) _inst_2)) (Units.val.{u1} α _inst_1 u))
Case conversion may be inaccurate. Consider using '#align units.coe_neg Units.val_negₓ'. -/
/-- Representing an element of a ring's unit group as an element of the ring commutes with
    mapping this element to its additive inverse. -/
@[simp, norm_cast]
protected theorem val_neg (u : αˣ) : (↑(-u) : α) = -u :=
  rfl
#align units.coe_neg Units.val_neg

/- warning: units.coe_neg_one -> Units.coe_neg_one is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Monoid.{u1} α] [_inst_2 : HasDistribNeg.{u1} α (MulOneClass.toHasMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1))], Eq.{succ u1} α ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (Units.{u1} α _inst_1) α (HasLiftT.mk.{succ u1, succ u1} (Units.{u1} α _inst_1) α (CoeTCₓ.coe.{succ u1, succ u1} (Units.{u1} α _inst_1) α (coeBase.{succ u1, succ u1} (Units.{u1} α _inst_1) α (Units.hasCoe.{u1} α _inst_1)))) (Neg.neg.{u1} (Units.{u1} α _inst_1) (Units.hasNeg.{u1} α _inst_1 _inst_2) (OfNat.ofNat.{u1} (Units.{u1} α _inst_1) 1 (OfNat.mk.{u1} (Units.{u1} α _inst_1) 1 (One.one.{u1} (Units.{u1} α _inst_1) (MulOneClass.toHasOne.{u1} (Units.{u1} α _inst_1) (Units.mulOneClass.{u1} α _inst_1))))))) (Neg.neg.{u1} α (InvolutiveNeg.toHasNeg.{u1} α (HasDistribNeg.toHasInvolutiveNeg.{u1} α (MulOneClass.toHasMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1)) _inst_2)) (OfNat.ofNat.{u1} α 1 (OfNat.mk.{u1} α 1 (One.one.{u1} α (MulOneClass.toHasOne.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1))))))
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Monoid.{u1} α] [_inst_2 : HasDistribNeg.{u1} α (MulOneClass.toMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1))], Eq.{succ u1} α (Units.val.{u1} α _inst_1 (Neg.neg.{u1} (Units.{u1} α _inst_1) (Units.instNegUnits.{u1} α _inst_1 _inst_2) (OfNat.ofNat.{u1} (Units.{u1} α _inst_1) 1 (One.toOfNat1.{u1} (Units.{u1} α _inst_1) (InvOneClass.toOne.{u1} (Units.{u1} α _inst_1) (DivInvOneMonoid.toInvOneClass.{u1} (Units.{u1} α _inst_1) (DivisionMonoid.toDivInvOneMonoid.{u1} (Units.{u1} α _inst_1) (Group.toDivisionMonoid.{u1} (Units.{u1} α _inst_1) (Units.instGroupUnits.{u1} α _inst_1))))))))) (Neg.neg.{u1} α (InvolutiveNeg.toNeg.{u1} α (HasDistribNeg.toInvolutiveNeg.{u1} α (MulOneClass.toMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1)) _inst_2)) (OfNat.ofNat.{u1} α 1 (One.toOfNat1.{u1} α (Monoid.toOne.{u1} α _inst_1))))
Case conversion may be inaccurate. Consider using '#align units.coe_neg_one Units.coe_neg_oneₓ'. -/
@[simp, norm_cast]
protected theorem coe_neg_one : ((-1 : αˣ) : α) = -1 :=
  rfl
#align units.coe_neg_one Units.coe_neg_one

instance : HasDistribNeg αˣ :=
  Units.ext.HasDistribNeg _ Units.val_neg Units.val_mul

/- warning: units.neg_divp -> Units.neg_divp is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Monoid.{u1} α] [_inst_2 : HasDistribNeg.{u1} α (MulOneClass.toHasMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1))] (a : α) (u : Units.{u1} α _inst_1), Eq.{succ u1} α (Neg.neg.{u1} α (InvolutiveNeg.toHasNeg.{u1} α (HasDistribNeg.toHasInvolutiveNeg.{u1} α (MulOneClass.toHasMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1)) _inst_2)) (divp.{u1} α _inst_1 a u)) (divp.{u1} α _inst_1 (Neg.neg.{u1} α (InvolutiveNeg.toHasNeg.{u1} α (HasDistribNeg.toHasInvolutiveNeg.{u1} α (MulOneClass.toHasMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1)) _inst_2)) a) u)
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Monoid.{u1} α] [_inst_2 : HasDistribNeg.{u1} α (MulOneClass.toMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1))] (a : α) (u : Units.{u1} α _inst_1), Eq.{succ u1} α (Neg.neg.{u1} α (InvolutiveNeg.toNeg.{u1} α (HasDistribNeg.toInvolutiveNeg.{u1} α (MulOneClass.toMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1)) _inst_2)) (divp.{u1} α _inst_1 a u)) (divp.{u1} α _inst_1 (Neg.neg.{u1} α (InvolutiveNeg.toNeg.{u1} α (HasDistribNeg.toInvolutiveNeg.{u1} α (MulOneClass.toMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1)) _inst_2)) a) u)
Case conversion may be inaccurate. Consider using '#align units.neg_divp Units.neg_divpₓ'. -/
@[field_simps]
theorem neg_divp (a : α) (u : αˣ) : -(a /ₚ u) = -a /ₚ u := by simp only [divp, neg_mul]
#align units.neg_divp Units.neg_divp

end HasDistribNeg

section Ring

variable [Ring α] {a b : α}

/- warning: units.divp_add_divp_same -> Units.divp_add_divp_same is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Ring.{u1} α] (a : α) (b : α) (u : Units.{u1} α (Ring.toMonoid.{u1} α _inst_1)), Eq.{succ u1} α (HAdd.hAdd.{u1, u1, u1} α α α (instHAdd.{u1} α (Distrib.toHasAdd.{u1} α (Ring.toDistrib.{u1} α _inst_1))) (divp.{u1} α (Ring.toMonoid.{u1} α _inst_1) a u) (divp.{u1} α (Ring.toMonoid.{u1} α _inst_1) b u)) (divp.{u1} α (Ring.toMonoid.{u1} α _inst_1) (HAdd.hAdd.{u1, u1, u1} α α α (instHAdd.{u1} α (Distrib.toHasAdd.{u1} α (Ring.toDistrib.{u1} α _inst_1))) a b) u)
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Ring.{u1} α] (a : α) (b : α) (u : Units.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1)))), Eq.{succ u1} α (HAdd.hAdd.{u1, u1, u1} α α α (instHAdd.{u1} α (Distrib.toAdd.{u1} α (NonUnitalNonAssocSemiring.toDistrib.{u1} α (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} α (NonAssocRing.toNonUnitalNonAssocRing.{u1} α (Ring.toNonAssocRing.{u1} α _inst_1)))))) (divp.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1))) a u) (divp.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1))) b u)) (divp.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1))) (HAdd.hAdd.{u1, u1, u1} α α α (instHAdd.{u1} α (Distrib.toAdd.{u1} α (NonUnitalNonAssocSemiring.toDistrib.{u1} α (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} α (NonAssocRing.toNonUnitalNonAssocRing.{u1} α (Ring.toNonAssocRing.{u1} α _inst_1)))))) a b) u)
Case conversion may be inaccurate. Consider using '#align units.divp_add_divp_same Units.divp_add_divp_sameₓ'. -/
@[field_simps]
theorem divp_add_divp_same (a b : α) (u : αˣ) : a /ₚ u + b /ₚ u = (a + b) /ₚ u := by
  simp only [divp, add_mul]
#align units.divp_add_divp_same Units.divp_add_divp_same

/- warning: units.divp_sub_divp_same -> Units.divp_sub_divp_same is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Ring.{u1} α] (a : α) (b : α) (u : Units.{u1} α (Ring.toMonoid.{u1} α _inst_1)), Eq.{succ u1} α (HSub.hSub.{u1, u1, u1} α α α (instHSub.{u1} α (SubNegMonoid.toHasSub.{u1} α (AddGroup.toSubNegMonoid.{u1} α (AddGroupWithOne.toAddGroup.{u1} α (AddCommGroupWithOne.toAddGroupWithOne.{u1} α (Ring.toAddCommGroupWithOne.{u1} α _inst_1)))))) (divp.{u1} α (Ring.toMonoid.{u1} α _inst_1) a u) (divp.{u1} α (Ring.toMonoid.{u1} α _inst_1) b u)) (divp.{u1} α (Ring.toMonoid.{u1} α _inst_1) (HSub.hSub.{u1, u1, u1} α α α (instHSub.{u1} α (SubNegMonoid.toHasSub.{u1} α (AddGroup.toSubNegMonoid.{u1} α (AddGroupWithOne.toAddGroup.{u1} α (AddCommGroupWithOne.toAddGroupWithOne.{u1} α (Ring.toAddCommGroupWithOne.{u1} α _inst_1)))))) a b) u)
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Ring.{u1} α] (a : α) (b : α) (u : Units.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1)))), Eq.{succ u1} α (HSub.hSub.{u1, u1, u1} α α α (instHSub.{u1} α (Ring.toSub.{u1} α _inst_1)) (divp.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1))) a u) (divp.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1))) b u)) (divp.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1))) (HSub.hSub.{u1, u1, u1} α α α (instHSub.{u1} α (Ring.toSub.{u1} α _inst_1)) a b) u)
Case conversion may be inaccurate. Consider using '#align units.divp_sub_divp_same Units.divp_sub_divp_sameₓ'. -/
@[field_simps]
theorem divp_sub_divp_same (a b : α) (u : αˣ) : a /ₚ u - b /ₚ u = (a - b) /ₚ u := by
  rw [sub_eq_add_neg, sub_eq_add_neg, neg_divp, divp_add_divp_same]
#align units.divp_sub_divp_same Units.divp_sub_divp_same

/- warning: units.add_divp -> Units.add_divp is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Ring.{u1} α] (a : α) (b : α) (u : Units.{u1} α (Ring.toMonoid.{u1} α _inst_1)), Eq.{succ u1} α (HAdd.hAdd.{u1, u1, u1} α α α (instHAdd.{u1} α (Distrib.toHasAdd.{u1} α (Ring.toDistrib.{u1} α _inst_1))) a (divp.{u1} α (Ring.toMonoid.{u1} α _inst_1) b u)) (divp.{u1} α (Ring.toMonoid.{u1} α _inst_1) (HAdd.hAdd.{u1, u1, u1} α α α (instHAdd.{u1} α (Distrib.toHasAdd.{u1} α (Ring.toDistrib.{u1} α _inst_1))) (HMul.hMul.{u1, u1, u1} α α α (instHMul.{u1} α (Distrib.toHasMul.{u1} α (Ring.toDistrib.{u1} α _inst_1))) a ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (Units.{u1} α (Ring.toMonoid.{u1} α _inst_1)) α (HasLiftT.mk.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α _inst_1)) α (CoeTCₓ.coe.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α _inst_1)) α (coeBase.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α _inst_1)) α (Units.hasCoe.{u1} α (Ring.toMonoid.{u1} α _inst_1))))) u)) b) u)
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Ring.{u1} α] (a : α) (b : α) (u : Units.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1)))), Eq.{succ u1} α (HAdd.hAdd.{u1, u1, u1} α α α (instHAdd.{u1} α (Distrib.toAdd.{u1} α (NonUnitalNonAssocSemiring.toDistrib.{u1} α (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} α (NonAssocRing.toNonUnitalNonAssocRing.{u1} α (Ring.toNonAssocRing.{u1} α _inst_1)))))) a (divp.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1))) b u)) (divp.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1))) (HAdd.hAdd.{u1, u1, u1} α α α (instHAdd.{u1} α (Distrib.toAdd.{u1} α (NonUnitalNonAssocSemiring.toDistrib.{u1} α (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} α (NonAssocRing.toNonUnitalNonAssocRing.{u1} α (Ring.toNonAssocRing.{u1} α _inst_1)))))) (HMul.hMul.{u1, u1, u1} α α α (instHMul.{u1} α (NonUnitalNonAssocRing.toMul.{u1} α (NonAssocRing.toNonUnitalNonAssocRing.{u1} α (Ring.toNonAssocRing.{u1} α _inst_1)))) a (Units.val.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1))) u)) b) u)
Case conversion may be inaccurate. Consider using '#align units.add_divp Units.add_divpₓ'. -/
@[field_simps]
theorem add_divp (a b : α) (u : αˣ) : a + b /ₚ u = (a * u + b) /ₚ u := by
  simp only [divp, add_mul, Units.mul_inv_cancel_right]
#align units.add_divp Units.add_divp

/- warning: units.sub_divp -> Units.sub_divp is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Ring.{u1} α] (a : α) (b : α) (u : Units.{u1} α (Ring.toMonoid.{u1} α _inst_1)), Eq.{succ u1} α (HSub.hSub.{u1, u1, u1} α α α (instHSub.{u1} α (SubNegMonoid.toHasSub.{u1} α (AddGroup.toSubNegMonoid.{u1} α (AddGroupWithOne.toAddGroup.{u1} α (AddCommGroupWithOne.toAddGroupWithOne.{u1} α (Ring.toAddCommGroupWithOne.{u1} α _inst_1)))))) a (divp.{u1} α (Ring.toMonoid.{u1} α _inst_1) b u)) (divp.{u1} α (Ring.toMonoid.{u1} α _inst_1) (HSub.hSub.{u1, u1, u1} α α α (instHSub.{u1} α (SubNegMonoid.toHasSub.{u1} α (AddGroup.toSubNegMonoid.{u1} α (AddGroupWithOne.toAddGroup.{u1} α (AddCommGroupWithOne.toAddGroupWithOne.{u1} α (Ring.toAddCommGroupWithOne.{u1} α _inst_1)))))) (HMul.hMul.{u1, u1, u1} α α α (instHMul.{u1} α (Distrib.toHasMul.{u1} α (Ring.toDistrib.{u1} α _inst_1))) a ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (Units.{u1} α (Ring.toMonoid.{u1} α _inst_1)) α (HasLiftT.mk.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α _inst_1)) α (CoeTCₓ.coe.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α _inst_1)) α (coeBase.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α _inst_1)) α (Units.hasCoe.{u1} α (Ring.toMonoid.{u1} α _inst_1))))) u)) b) u)
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Ring.{u1} α] (a : α) (b : α) (u : Units.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1)))), Eq.{succ u1} α (HSub.hSub.{u1, u1, u1} α α α (instHSub.{u1} α (Ring.toSub.{u1} α _inst_1)) a (divp.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1))) b u)) (divp.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1))) (HSub.hSub.{u1, u1, u1} α α α (instHSub.{u1} α (Ring.toSub.{u1} α _inst_1)) (HMul.hMul.{u1, u1, u1} α α α (instHMul.{u1} α (NonUnitalNonAssocRing.toMul.{u1} α (NonAssocRing.toNonUnitalNonAssocRing.{u1} α (Ring.toNonAssocRing.{u1} α _inst_1)))) a (Units.val.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1))) u)) b) u)
Case conversion may be inaccurate. Consider using '#align units.sub_divp Units.sub_divpₓ'. -/
@[field_simps]
theorem sub_divp (a b : α) (u : αˣ) : a - b /ₚ u = (a * u - b) /ₚ u := by
  simp only [divp, sub_mul, Units.mul_inv_cancel_right]
#align units.sub_divp Units.sub_divp

/- warning: units.divp_add -> Units.divp_add is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Ring.{u1} α] (a : α) (b : α) (u : Units.{u1} α (Ring.toMonoid.{u1} α _inst_1)), Eq.{succ u1} α (HAdd.hAdd.{u1, u1, u1} α α α (instHAdd.{u1} α (Distrib.toHasAdd.{u1} α (Ring.toDistrib.{u1} α _inst_1))) (divp.{u1} α (Ring.toMonoid.{u1} α _inst_1) a u) b) (divp.{u1} α (Ring.toMonoid.{u1} α _inst_1) (HAdd.hAdd.{u1, u1, u1} α α α (instHAdd.{u1} α (Distrib.toHasAdd.{u1} α (Ring.toDistrib.{u1} α _inst_1))) a (HMul.hMul.{u1, u1, u1} α α α (instHMul.{u1} α (Distrib.toHasMul.{u1} α (Ring.toDistrib.{u1} α _inst_1))) b ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (Units.{u1} α (Ring.toMonoid.{u1} α _inst_1)) α (HasLiftT.mk.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α _inst_1)) α (CoeTCₓ.coe.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α _inst_1)) α (coeBase.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α _inst_1)) α (Units.hasCoe.{u1} α (Ring.toMonoid.{u1} α _inst_1))))) u))) u)
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Ring.{u1} α] (a : α) (b : α) (u : Units.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1)))), Eq.{succ u1} α (HAdd.hAdd.{u1, u1, u1} α α α (instHAdd.{u1} α (Distrib.toAdd.{u1} α (NonUnitalNonAssocSemiring.toDistrib.{u1} α (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} α (NonAssocRing.toNonUnitalNonAssocRing.{u1} α (Ring.toNonAssocRing.{u1} α _inst_1)))))) (divp.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1))) a u) b) (divp.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1))) (HAdd.hAdd.{u1, u1, u1} α α α (instHAdd.{u1} α (Distrib.toAdd.{u1} α (NonUnitalNonAssocSemiring.toDistrib.{u1} α (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} α (NonAssocRing.toNonUnitalNonAssocRing.{u1} α (Ring.toNonAssocRing.{u1} α _inst_1)))))) a (HMul.hMul.{u1, u1, u1} α α α (instHMul.{u1} α (NonUnitalNonAssocRing.toMul.{u1} α (NonAssocRing.toNonUnitalNonAssocRing.{u1} α (Ring.toNonAssocRing.{u1} α _inst_1)))) b (Units.val.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1))) u))) u)
Case conversion may be inaccurate. Consider using '#align units.divp_add Units.divp_addₓ'. -/
@[field_simps]
theorem divp_add (a b : α) (u : αˣ) : a /ₚ u + b = (a + b * u) /ₚ u := by
  simp only [divp, add_mul, Units.mul_inv_cancel_right]
#align units.divp_add Units.divp_add

/- warning: units.divp_sub -> Units.divp_sub is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Ring.{u1} α] (a : α) (b : α) (u : Units.{u1} α (Ring.toMonoid.{u1} α _inst_1)), Eq.{succ u1} α (HSub.hSub.{u1, u1, u1} α α α (instHSub.{u1} α (SubNegMonoid.toHasSub.{u1} α (AddGroup.toSubNegMonoid.{u1} α (AddGroupWithOne.toAddGroup.{u1} α (AddCommGroupWithOne.toAddGroupWithOne.{u1} α (Ring.toAddCommGroupWithOne.{u1} α _inst_1)))))) (divp.{u1} α (Ring.toMonoid.{u1} α _inst_1) a u) b) (divp.{u1} α (Ring.toMonoid.{u1} α _inst_1) (HSub.hSub.{u1, u1, u1} α α α (instHSub.{u1} α (SubNegMonoid.toHasSub.{u1} α (AddGroup.toSubNegMonoid.{u1} α (AddGroupWithOne.toAddGroup.{u1} α (AddCommGroupWithOne.toAddGroupWithOne.{u1} α (Ring.toAddCommGroupWithOne.{u1} α _inst_1)))))) a (HMul.hMul.{u1, u1, u1} α α α (instHMul.{u1} α (Distrib.toHasMul.{u1} α (Ring.toDistrib.{u1} α _inst_1))) b ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (Units.{u1} α (Ring.toMonoid.{u1} α _inst_1)) α (HasLiftT.mk.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α _inst_1)) α (CoeTCₓ.coe.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α _inst_1)) α (coeBase.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α _inst_1)) α (Units.hasCoe.{u1} α (Ring.toMonoid.{u1} α _inst_1))))) u))) u)
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Ring.{u1} α] (a : α) (b : α) (u : Units.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1)))), Eq.{succ u1} α (HSub.hSub.{u1, u1, u1} α α α (instHSub.{u1} α (Ring.toSub.{u1} α _inst_1)) (divp.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1))) a u) b) (divp.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1))) (HSub.hSub.{u1, u1, u1} α α α (instHSub.{u1} α (Ring.toSub.{u1} α _inst_1)) a (HMul.hMul.{u1, u1, u1} α α α (instHMul.{u1} α (NonUnitalNonAssocRing.toMul.{u1} α (NonAssocRing.toNonUnitalNonAssocRing.{u1} α (Ring.toNonAssocRing.{u1} α _inst_1)))) b (Units.val.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1))) u))) u)
Case conversion may be inaccurate. Consider using '#align units.divp_sub Units.divp_subₓ'. -/
@[field_simps]
theorem divp_sub (a b : α) (u : αˣ) : a /ₚ u - b = (a - b * u) /ₚ u :=
  by
  simp only [divp, sub_mul, sub_right_inj]
  assoc_rw [Units.mul_inv, mul_one]
#align units.divp_sub Units.divp_sub

end Ring

end Units

/- warning: is_unit.neg -> IsUnit.neg is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Monoid.{u1} α] [_inst_2 : HasDistribNeg.{u1} α (MulOneClass.toHasMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1))] {a : α}, (IsUnit.{u1} α _inst_1 a) -> (IsUnit.{u1} α _inst_1 (Neg.neg.{u1} α (InvolutiveNeg.toHasNeg.{u1} α (HasDistribNeg.toHasInvolutiveNeg.{u1} α (MulOneClass.toHasMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1)) _inst_2)) a))
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Monoid.{u1} α] [_inst_2 : HasDistribNeg.{u1} α (MulOneClass.toMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1))] {a : α}, (IsUnit.{u1} α _inst_1 a) -> (IsUnit.{u1} α _inst_1 (Neg.neg.{u1} α (InvolutiveNeg.toNeg.{u1} α (HasDistribNeg.toInvolutiveNeg.{u1} α (MulOneClass.toMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1)) _inst_2)) a))
Case conversion may be inaccurate. Consider using '#align is_unit.neg IsUnit.negₓ'. -/
theorem IsUnit.neg [Monoid α] [HasDistribNeg α] {a : α} : IsUnit a → IsUnit (-a)
  | ⟨x, hx⟩ => hx ▸ (-x).IsUnit
#align is_unit.neg IsUnit.neg

/- warning: is_unit.neg_iff -> IsUnit.neg_iff is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Monoid.{u1} α] [_inst_2 : HasDistribNeg.{u1} α (MulOneClass.toHasMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1))] (a : α), Iff (IsUnit.{u1} α _inst_1 (Neg.neg.{u1} α (InvolutiveNeg.toHasNeg.{u1} α (HasDistribNeg.toHasInvolutiveNeg.{u1} α (MulOneClass.toHasMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1)) _inst_2)) a)) (IsUnit.{u1} α _inst_1 a)
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Monoid.{u1} α] [_inst_2 : HasDistribNeg.{u1} α (MulOneClass.toMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1))] (a : α), Iff (IsUnit.{u1} α _inst_1 (Neg.neg.{u1} α (InvolutiveNeg.toNeg.{u1} α (HasDistribNeg.toInvolutiveNeg.{u1} α (MulOneClass.toMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1)) _inst_2)) a)) (IsUnit.{u1} α _inst_1 a)
Case conversion may be inaccurate. Consider using '#align is_unit.neg_iff IsUnit.neg_iffₓ'. -/
@[simp]
theorem IsUnit.neg_iff [Monoid α] [HasDistribNeg α] (a : α) : IsUnit (-a) ↔ IsUnit a :=
  ⟨fun h => neg_neg a ▸ h.neg, IsUnit.neg⟩
#align is_unit.neg_iff IsUnit.neg_iff

/- warning: is_unit.sub_iff -> IsUnit.sub_iff is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Ring.{u1} α] {x : α} {y : α}, Iff (IsUnit.{u1} α (Ring.toMonoid.{u1} α _inst_1) (HSub.hSub.{u1, u1, u1} α α α (instHSub.{u1} α (SubNegMonoid.toHasSub.{u1} α (AddGroup.toSubNegMonoid.{u1} α (AddGroupWithOne.toAddGroup.{u1} α (AddCommGroupWithOne.toAddGroupWithOne.{u1} α (Ring.toAddCommGroupWithOne.{u1} α _inst_1)))))) x y)) (IsUnit.{u1} α (Ring.toMonoid.{u1} α _inst_1) (HSub.hSub.{u1, u1, u1} α α α (instHSub.{u1} α (SubNegMonoid.toHasSub.{u1} α (AddGroup.toSubNegMonoid.{u1} α (AddGroupWithOne.toAddGroup.{u1} α (AddCommGroupWithOne.toAddGroupWithOne.{u1} α (Ring.toAddCommGroupWithOne.{u1} α _inst_1)))))) y x))
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Ring.{u1} α] {x : α} {y : α}, Iff (IsUnit.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1))) (HSub.hSub.{u1, u1, u1} α α α (instHSub.{u1} α (Ring.toSub.{u1} α _inst_1)) x y)) (IsUnit.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α _inst_1))) (HSub.hSub.{u1, u1, u1} α α α (instHSub.{u1} α (Ring.toSub.{u1} α _inst_1)) y x))
Case conversion may be inaccurate. Consider using '#align is_unit.sub_iff IsUnit.sub_iffₓ'. -/
theorem IsUnit.sub_iff [Ring α] {x y : α} : IsUnit (x - y) ↔ IsUnit (y - x) :=
  (IsUnit.neg_iff _).symm.trans <| neg_sub x y ▸ Iff.rfl
#align is_unit.sub_iff IsUnit.sub_iff

namespace Units

/- warning: units.divp_add_divp -> Units.divp_add_divp is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : CommRing.{u1} α] (a : α) (b : α) (u₁ : Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) (u₂ : Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))), Eq.{succ u1} α (HAdd.hAdd.{u1, u1, u1} α α α (instHAdd.{u1} α (Distrib.toHasAdd.{u1} α (Ring.toDistrib.{u1} α (CommRing.toRing.{u1} α _inst_1)))) (divp.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1)) a u₁) (divp.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1)) b u₂)) (divp.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1)) (HAdd.hAdd.{u1, u1, u1} α α α (instHAdd.{u1} α (Distrib.toHasAdd.{u1} α (Ring.toDistrib.{u1} α (CommRing.toRing.{u1} α _inst_1)))) (HMul.hMul.{u1, u1, u1} α α α (instHMul.{u1} α (Distrib.toHasMul.{u1} α (Ring.toDistrib.{u1} α (CommRing.toRing.{u1} α _inst_1)))) a ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) α (HasLiftT.mk.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) α (CoeTCₓ.coe.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) α (coeBase.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) α (Units.hasCoe.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1)))))) u₂)) (HMul.hMul.{u1, u1, u1} α α α (instHMul.{u1} α (Distrib.toHasMul.{u1} α (Ring.toDistrib.{u1} α (CommRing.toRing.{u1} α _inst_1)))) ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) α (HasLiftT.mk.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) α (CoeTCₓ.coe.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) α (coeBase.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) α (Units.hasCoe.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1)))))) u₁) b)) (HMul.hMul.{u1, u1, u1} (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) (instHMul.{u1} (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) (MulOneClass.toHasMul.{u1} (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) (Units.mulOneClass.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))))) u₁ u₂))
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : CommRing.{u1} α] (a : α) (b : α) (u₁ : Units.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1))))) (u₂ : Units.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1))))), Eq.{succ u1} α (HAdd.hAdd.{u1, u1, u1} α α α (instHAdd.{u1} α (Distrib.toAdd.{u1} α (NonUnitalNonAssocSemiring.toDistrib.{u1} α (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} α (NonAssocRing.toNonUnitalNonAssocRing.{u1} α (Ring.toNonAssocRing.{u1} α (CommRing.toRing.{u1} α _inst_1))))))) (divp.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1)))) a u₁) (divp.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1)))) b u₂)) (divp.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1)))) (HAdd.hAdd.{u1, u1, u1} α α α (instHAdd.{u1} α (Distrib.toAdd.{u1} α (NonUnitalNonAssocSemiring.toDistrib.{u1} α (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} α (NonAssocRing.toNonUnitalNonAssocRing.{u1} α (Ring.toNonAssocRing.{u1} α (CommRing.toRing.{u1} α _inst_1))))))) (HMul.hMul.{u1, u1, u1} α α α (instHMul.{u1} α (NonUnitalNonAssocRing.toMul.{u1} α (NonAssocRing.toNonUnitalNonAssocRing.{u1} α (Ring.toNonAssocRing.{u1} α (CommRing.toRing.{u1} α _inst_1))))) a (Units.val.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1)))) u₂)) (HMul.hMul.{u1, u1, u1} α α α (instHMul.{u1} α (NonUnitalNonAssocRing.toMul.{u1} α (NonAssocRing.toNonUnitalNonAssocRing.{u1} α (Ring.toNonAssocRing.{u1} α (CommRing.toRing.{u1} α _inst_1))))) (Units.val.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1)))) u₁) b)) (HMul.hMul.{u1, u1, u1} (Units.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1))))) (Units.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1))))) (Units.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1))))) (instHMul.{u1} (Units.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1))))) (MulOneClass.toMul.{u1} (Units.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1))))) (Units.instMulOneClassUnits.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1))))))) u₁ u₂))
Case conversion may be inaccurate. Consider using '#align units.divp_add_divp Units.divp_add_divpₓ'. -/
@[field_simps]
theorem divp_add_divp [CommRing α] (a b : α) (u₁ u₂ : αˣ) :
    a /ₚ u₁ + b /ₚ u₂ = (a * u₂ + u₁ * b) /ₚ (u₁ * u₂) :=
  by
  simp only [divp, add_mul, mul_inv_rev, coe_mul]
  rw [mul_comm (↑u₁ * b), mul_comm b]
  assoc_rw [mul_inv, mul_inv, mul_one, mul_one]
#align units.divp_add_divp Units.divp_add_divp

/- warning: units.divp_sub_divp -> Units.divp_sub_divp is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : CommRing.{u1} α] (a : α) (b : α) (u₁ : Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) (u₂ : Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))), Eq.{succ u1} α (HSub.hSub.{u1, u1, u1} α α α (instHSub.{u1} α (SubNegMonoid.toHasSub.{u1} α (AddGroup.toSubNegMonoid.{u1} α (AddGroupWithOne.toAddGroup.{u1} α (AddCommGroupWithOne.toAddGroupWithOne.{u1} α (Ring.toAddCommGroupWithOne.{u1} α (CommRing.toRing.{u1} α _inst_1))))))) (divp.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1)) a u₁) (divp.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1)) b u₂)) (divp.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1)) (HSub.hSub.{u1, u1, u1} α α α (instHSub.{u1} α (SubNegMonoid.toHasSub.{u1} α (AddGroup.toSubNegMonoid.{u1} α (AddGroupWithOne.toAddGroup.{u1} α (AddCommGroupWithOne.toAddGroupWithOne.{u1} α (Ring.toAddCommGroupWithOne.{u1} α (CommRing.toRing.{u1} α _inst_1))))))) (HMul.hMul.{u1, u1, u1} α α α (instHMul.{u1} α (Distrib.toHasMul.{u1} α (Ring.toDistrib.{u1} α (CommRing.toRing.{u1} α _inst_1)))) a ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) α (HasLiftT.mk.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) α (CoeTCₓ.coe.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) α (coeBase.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) α (Units.hasCoe.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1)))))) u₂)) (HMul.hMul.{u1, u1, u1} α α α (instHMul.{u1} α (Distrib.toHasMul.{u1} α (Ring.toDistrib.{u1} α (CommRing.toRing.{u1} α _inst_1)))) ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) α (HasLiftT.mk.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) α (CoeTCₓ.coe.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) α (coeBase.{succ u1, succ u1} (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) α (Units.hasCoe.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1)))))) u₁) b)) (HMul.hMul.{u1, u1, u1} (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) (instHMul.{u1} (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) (MulOneClass.toHasMul.{u1} (Units.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))) (Units.mulOneClass.{u1} α (Ring.toMonoid.{u1} α (CommRing.toRing.{u1} α _inst_1))))) u₁ u₂))
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : CommRing.{u1} α] (a : α) (b : α) (u₁ : Units.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1))))) (u₂ : Units.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1))))), Eq.{succ u1} α (HSub.hSub.{u1, u1, u1} α α α (instHSub.{u1} α (Ring.toSub.{u1} α (CommRing.toRing.{u1} α _inst_1))) (divp.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1)))) a u₁) (divp.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1)))) b u₂)) (divp.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1)))) (HSub.hSub.{u1, u1, u1} α α α (instHSub.{u1} α (Ring.toSub.{u1} α (CommRing.toRing.{u1} α _inst_1))) (HMul.hMul.{u1, u1, u1} α α α (instHMul.{u1} α (NonUnitalNonAssocRing.toMul.{u1} α (NonAssocRing.toNonUnitalNonAssocRing.{u1} α (Ring.toNonAssocRing.{u1} α (CommRing.toRing.{u1} α _inst_1))))) a (Units.val.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1)))) u₂)) (HMul.hMul.{u1, u1, u1} α α α (instHMul.{u1} α (NonUnitalNonAssocRing.toMul.{u1} α (NonAssocRing.toNonUnitalNonAssocRing.{u1} α (Ring.toNonAssocRing.{u1} α (CommRing.toRing.{u1} α _inst_1))))) (Units.val.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1)))) u₁) b)) (HMul.hMul.{u1, u1, u1} (Units.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1))))) (Units.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1))))) (Units.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1))))) (instHMul.{u1} (Units.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1))))) (MulOneClass.toMul.{u1} (Units.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1))))) (Units.instMulOneClassUnits.{u1} α (MonoidWithZero.toMonoid.{u1} α (Semiring.toMonoidWithZero.{u1} α (Ring.toSemiring.{u1} α (CommRing.toRing.{u1} α _inst_1))))))) u₁ u₂))
Case conversion may be inaccurate. Consider using '#align units.divp_sub_divp Units.divp_sub_divpₓ'. -/
@[field_simps]
theorem divp_sub_divp [CommRing α] (a b : α) (u₁ u₂ : αˣ) :
    a /ₚ u₁ - b /ₚ u₂ = (a * u₂ - u₁ * b) /ₚ (u₁ * u₂) := by
  simp_rw [sub_eq_add_neg, neg_divp, divp_add_divp, mul_neg]
#align units.divp_sub_divp Units.divp_sub_divp

/- warning: units.add_eq_mul_one_add_div -> Units.add_eq_mul_one_add_div is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : Semiring.{u1} R] {a : Units.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1))} {b : R}, 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 (Semiring.toNonAssocSemiring.{u1} R _inst_1))))) ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (Units.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1))) R (HasLiftT.mk.{succ u1, succ u1} (Units.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1))) R (CoeTCₓ.coe.{succ u1, succ u1} (Units.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1))) R (coeBase.{succ u1, succ u1} (Units.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1))) R (Units.hasCoe.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1)))))) a) b) (HMul.hMul.{u1, u1, u1} R R R (instHMul.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R _inst_1))))) ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (Units.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1))) R (HasLiftT.mk.{succ u1, succ u1} (Units.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1))) R (CoeTCₓ.coe.{succ u1, succ u1} (Units.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1))) R (coeBase.{succ u1, succ u1} (Units.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1))) R (Units.hasCoe.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1)))))) a) (HAdd.hAdd.{u1, u1, u1} R R R (instHAdd.{u1} R (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R _inst_1))))) (OfNat.ofNat.{u1} R 1 (OfNat.mk.{u1} R 1 (One.one.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} R (NonAssocSemiring.toAddCommMonoidWithOne.{u1} R (Semiring.toNonAssocSemiring.{u1} R _inst_1))))))) (HMul.hMul.{u1, u1, u1} R R R (instHMul.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R _inst_1))))) ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (Units.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1))) R (HasLiftT.mk.{succ u1, succ u1} (Units.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1))) R (CoeTCₓ.coe.{succ u1, succ u1} (Units.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1))) R (coeBase.{succ u1, succ u1} (Units.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1))) R (Units.hasCoe.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1)))))) (Inv.inv.{u1} (Units.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1))) (Units.hasInv.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1))) a)) b)))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : Semiring.{u1} R] {a : Units.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1))} {b : R}, 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 (Semiring.toNonAssocSemiring.{u1} R _inst_1))))) (Units.val.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1)) a) b) (HMul.hMul.{u1, u1, u1} R R R (instHMul.{u1} R (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R _inst_1)))) (Units.val.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1)) a) (HAdd.hAdd.{u1, u1, u1} R R R (instHAdd.{u1} R (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R _inst_1))))) (OfNat.ofNat.{u1} R 1 (One.toOfNat1.{u1} R (Semiring.toOne.{u1} R _inst_1))) (HMul.hMul.{u1, u1, u1} R R R (instHMul.{u1} R (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R _inst_1)))) (Units.val.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1)) (Inv.inv.{u1} (Units.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1))) (Units.instInvUnits.{u1} R (MonoidWithZero.toMonoid.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1))) a)) b)))
Case conversion may be inaccurate. Consider using '#align units.add_eq_mul_one_add_div Units.add_eq_mul_one_add_divₓ'. -/
theorem add_eq_mul_one_add_div [Semiring R] {a : Rˣ} {b : R} : ↑a + b = a * (1 + ↑a⁻¹ * b) := by
  rwa [mul_add, mul_one, ← mul_assoc, Units.mul_inv, one_mul]
#align units.add_eq_mul_one_add_div Units.add_eq_mul_one_add_div

end Units


/-
Copyright (c) 2020 Devon Tuma. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kenny Lau, Devon Tuma

! This file was ported from Lean 3 source module ring_theory.jacobson_ideal
! leanprover-community/mathlib commit da420a8c6dd5bdfb85c4ced85c34388f633bc6ff
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.RingTheory.Ideal.Quotient
import Mathbin.RingTheory.Polynomial.Quotient

/-!
# Jacobson radical

The Jacobson radical of a ring `R` is defined to be the intersection of all maximal ideals of `R`.
This is similar to how the nilradical is equal to the intersection of all prime ideals of `R`.

We can extend the idea of the nilradical to ideals of `R`,
by letting the radical of an ideal `I` be the intersection of prime ideals containing `I`.
Under this extension, the original nilradical is the radical of the zero ideal `⊥`.
Here we define the Jacobson radical of an ideal `I` in a similar way,
as the intersection of maximal ideals containing `I`.

## Main definitions

Let `R` be a commutative ring, and `I` be an ideal of `R`

* `jacobson I` is the jacobson radical, i.e. the infimum of all maximal ideals containing I.

* `is_local I` is the proposition that the jacobson radical of `I` is itself a maximal ideal

## Main statements

* `mem_jacobson_iff` gives a characterization of members of the jacobson of I

* `is_local_of_is_maximal_radical`: if the radical of I is maximal then so is the jacobson radical

## Tags

Jacobson, Jacobson radical, Local Ideal

-/

universe u v

namespace Ideal

variable {R : Type u} {S : Type v}

open Polynomial

section Jacobson

section Ring

variable [Ring R] [Ring S] {I : Ideal R}

/-- The Jacobson radical of `I` is the infimum of all maximal (left) ideals containing `I`. -/
def jacobson (I : Ideal R) : Ideal R :=
  infₛ { J : Ideal R | I ≤ J ∧ IsMaximal J }
#align ideal.jacobson Ideal.jacobson

theorem le_jacobson : I ≤ jacobson I := fun x hx => mem_infₛ.mpr fun J hJ => hJ.left hx
#align ideal.le_jacobson Ideal.le_jacobson

@[simp]
theorem jacobson_idem : jacobson (jacobson I) = jacobson I :=
  le_antisymm (infₛ_le_infₛ fun J hJ => ⟨infₛ_le hJ, hJ.2⟩) le_jacobson
#align ideal.jacobson_idem Ideal.jacobson_idem

@[simp]
theorem jacobson_top : jacobson (⊤ : Ideal R) = ⊤ :=
  eq_top_iff.2 le_jacobson
#align ideal.jacobson_top Ideal.jacobson_top

@[simp]
theorem jacobson_eq_top_iff : jacobson I = ⊤ ↔ I = ⊤ :=
  ⟨fun H =>
    by_contradiction fun hi =>
      let ⟨M, hm, him⟩ := exists_le_maximal I hi
      lt_top_iff_ne_top.1
        (lt_of_le_of_lt (show jacobson I ≤ M from infₛ_le ⟨him, hm⟩) <|
          lt_top_iff_ne_top.2 hm.ne_top)
        H,
    fun H => eq_top_iff.2 <| le_infₛ fun J ⟨hij, hj⟩ => H ▸ hij⟩
#align ideal.jacobson_eq_top_iff Ideal.jacobson_eq_top_iff

theorem jacobson_eq_bot : jacobson I = ⊥ → I = ⊥ := fun h => eq_bot_iff.mpr (h ▸ le_jacobson)
#align ideal.jacobson_eq_bot Ideal.jacobson_eq_bot

theorem jacobson_eq_self_of_isMaximal [H : IsMaximal I] : I.jacobson = I :=
  le_antisymm (infₛ_le ⟨le_of_eq rfl, H⟩) le_jacobson
#align ideal.jacobson_eq_self_of_is_maximal Ideal.jacobson_eq_self_of_isMaximal

instance (priority := 100) jacobson.isMaximal [H : IsMaximal I] : IsMaximal (jacobson I) :=
  ⟨⟨fun htop => H.1.1 (jacobson_eq_top_iff.1 htop), fun J hJ =>
      H.1.2 _ (lt_of_le_of_lt le_jacobson hJ)⟩⟩
#align ideal.jacobson.is_maximal Ideal.jacobson.isMaximal

theorem mem_jacobson_iff {x : R} : x ∈ jacobson I ↔ ∀ y, ∃ z, z * y * x + z - 1 ∈ I :=
  ⟨fun hx y =>
    by_cases
      (fun hxy : I ⊔ span {y * x + 1} = ⊤ =>
        let ⟨p, hpi, q, hq, hpq⟩ := Submodule.mem_sup.1 ((eq_top_iff_one _).1 hxy)
        let ⟨r, hr⟩ := mem_span_singleton'.1 hq
        ⟨r, by
          rw [mul_assoc, ← mul_add_one, hr, ← hpq, ← neg_sub, add_sub_cancel] <;>
            exact I.neg_mem hpi⟩)
      fun hxy : I ⊔ span {y * x + 1} ≠ ⊤ =>
      let ⟨M, hm1, hm2⟩ := exists_le_maximal _ hxy
      suffices x ∉ M from (this <| mem_infₛ.1 hx ⟨le_trans le_sup_left hm2, hm1⟩).elim
      fun hxm =>
      hm1.1.1 <|
        (eq_top_iff_one _).2 <|
          add_sub_cancel' (y * x) 1 ▸
            M.sub_mem (le_sup_right.trans hm2 <| subset_span rfl) (M.mul_mem_left _ hxm),
    fun hx =>
    mem_infₛ.2 fun M ⟨him, hm⟩ =>
      by_contradiction fun hxm =>
        let ⟨y, i, hi, df⟩ := hm.exists_inv hxm
        let ⟨z, hz⟩ := hx (-y)
        hm.1.1 <|
          (eq_top_iff_one _).2 <|
            sub_sub_cancel (z * -y * x + z) 1 ▸
              M.sub_mem
                (by
                  rw [mul_assoc, ← mul_add_one, neg_mul, ← sub_eq_iff_eq_add.mpr df.symm, neg_sub,
                    sub_add_cancel]
                  exact M.mul_mem_left _ hi)
                (him hz)⟩
#align ideal.mem_jacobson_iff Ideal.mem_jacobson_iff

theorem exists_mul_sub_mem_of_sub_one_mem_jacobson {I : Ideal R} (r : R) (h : r - 1 ∈ jacobson I) :
    ∃ s, s * r - 1 ∈ I := by
  cases' mem_jacobson_iff.1 h 1 with s hs
  use s
  simpa [mul_sub] using hs
#align ideal.exists_mul_sub_mem_of_sub_one_mem_jacobson Ideal.exists_mul_sub_mem_of_sub_one_mem_jacobson

/-- An ideal equals its Jacobson radical iff it is the intersection of a set of maximal ideals.
Allowing the set to include ⊤ is equivalent, and is included only to simplify some proofs. -/
theorem eq_jacobson_iff_infₛ_maximal :
    I.jacobson = I ↔ ∃ M : Set (Ideal R), (∀ J ∈ M, IsMaximal J ∨ J = ⊤) ∧ I = infₛ M :=
  by
  use fun hI => ⟨{ J : Ideal R | I ≤ J ∧ J.IsMaximal }, ⟨fun _ hJ => Or.inl hJ.right, hI.symm⟩⟩
  rintro ⟨M, hM, hInf⟩
  refine' le_antisymm (fun x hx => _) le_jacobson
  rw [hInf, mem_Inf]
  intro I hI
  cases' hM I hI with is_max is_top
  · exact (mem_Inf.1 hx) ⟨le_infₛ_iff.1 (le_of_eq hInf) I hI, IsMax⟩
  · exact is_top.symm ▸ Submodule.mem_top
#align ideal.eq_jacobson_iff_Inf_maximal Ideal.eq_jacobson_iff_infₛ_maximal

theorem eq_jacobson_iff_infₛ_maximal' :
    I.jacobson = I ↔ ∃ M : Set (Ideal R), (∀ J ∈ M, ∀ (K : Ideal R), J < K → K = ⊤) ∧ I = infₛ M :=
  eq_jacobson_iff_infₛ_maximal.trans
    ⟨fun h =>
      let ⟨M, hM⟩ := h
      ⟨M,
        ⟨fun J hJ K hK =>
          Or.rec_on (hM.1 J hJ) (fun h => h.1.2 K hK) fun h => eq_top_iff.2 (le_of_lt (h ▸ hK)),
          hM.2⟩⟩,
      fun h =>
      let ⟨M, hM⟩ := h
      ⟨M,
        ⟨fun J hJ =>
          Or.rec_on (Classical.em (J = ⊤)) (fun h => Or.inr h) fun h => Or.inl ⟨⟨h, hM.1 J hJ⟩⟩,
          hM.2⟩⟩⟩
#align ideal.eq_jacobson_iff_Inf_maximal' Ideal.eq_jacobson_iff_infₛ_maximal'

/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (x «expr ∉ » I) -/
/-- An ideal `I` equals its Jacobson radical if and only if every element outside `I`
also lies outside of a maximal ideal containing `I`. -/
theorem eq_jacobson_iff_not_mem :
    I.jacobson = I ↔ ∀ (x) (_ : x ∉ I), ∃ M : Ideal R, (I ≤ M ∧ M.IsMaximal) ∧ x ∉ M :=
  by
  constructor
  · intro h x hx
    erw [← h, mem_Inf] at hx
    push_neg  at hx
    exact hx
  · refine' fun h => le_antisymm (fun x hx => _) le_jacobson
    contrapose hx
    erw [mem_Inf]
    push_neg
    exact h x hx
#align ideal.eq_jacobson_iff_not_mem Ideal.eq_jacobson_iff_not_mem

theorem map_jacobson_of_surjective {f : R →+* S} (hf : Function.Surjective f) :
    RingHom.ker f ≤ I → map f I.jacobson = (map f I).jacobson :=
  by
  intro h
  unfold Ideal.jacobson
  have : ∀ J ∈ { J : Ideal R | I ≤ J ∧ J.IsMaximal }, f.ker ≤ J := fun J hJ => le_trans h hJ.left
  refine' trans (map_Inf hf this) (le_antisymm _ _)
  · refine'
      infₛ_le_infₛ fun J hJ =>
        ⟨comap f J, ⟨⟨le_comap_of_map_le hJ.1, _⟩, map_comap_of_surjective f hf J⟩⟩
    haveI : J.is_maximal := hJ.right
    exact comap_is_maximal_of_surjective f hf
  · refine' infₛ_le_infₛ_of_subset_insert_top fun j hj => hj.recOn fun J hJ => _
    rw [← hJ.2]
    cases' map_eq_top_or_is_maximal_of_surjective f hf hJ.left.right with htop hmax
    · exact htop.symm ▸ Set.mem_insert ⊤ _
    · exact Set.mem_insert_of_mem ⊤ ⟨map_mono hJ.1.1, hmax⟩
#align ideal.map_jacobson_of_surjective Ideal.map_jacobson_of_surjective

theorem map_jacobson_of_bijective {f : R →+* S} (hf : Function.Bijective f) :
    map f I.jacobson = (map f I).jacobson :=
  map_jacobson_of_surjective hf.right
    (le_trans (le_of_eq (f.injective_iff_ker_eq_bot.1 hf.left)) bot_le)
#align ideal.map_jacobson_of_bijective Ideal.map_jacobson_of_bijective

theorem comap_jacobson {f : R →+* S} {K : Ideal S} :
    comap f K.jacobson = infₛ (comap f '' { J : Ideal S | K ≤ J ∧ J.IsMaximal }) :=
  trans (comap_Inf' f _) infₛ_eq_infᵢ.symm
#align ideal.comap_jacobson Ideal.comap_jacobson

theorem comap_jacobson_of_surjective {f : R →+* S} (hf : Function.Surjective f) {K : Ideal S} :
    comap f K.jacobson = (comap f K).jacobson :=
  by
  unfold Ideal.jacobson
  refine' le_antisymm _ _
  · refine' le_trans (comap_mono (le_of_eq (trans top_inf_eq.symm Inf_insert.symm))) _
    rw [comap_Inf', infₛ_eq_infᵢ]
    refine' infᵢ_le_infᵢ_of_subset fun J hJ => _
    have : comap f (map f J) = J :=
      trans (comap_map_of_surjective f hf J)
        (le_antisymm (sup_le_iff.2 ⟨le_of_eq rfl, le_trans (comap_mono bot_le) hJ.left⟩)
          le_sup_left)
    cases' map_eq_top_or_is_maximal_of_surjective _ hf hJ.right with htop hmax
    · refine' ⟨⊤, ⟨Set.mem_insert ⊤ _, htop ▸ this⟩⟩
    ·
      refine'
        ⟨map f J,
          ⟨Set.mem_insert_of_mem _ ⟨le_map_of_comap_le_of_surjective f hf hJ.1, hmax⟩, this⟩⟩
  · rw [comap_Inf]
    refine' le_infᵢ_iff.2 fun J => le_infᵢ_iff.2 fun hJ => _
    haveI : J.is_maximal := hJ.right
    refine' infₛ_le ⟨comap_mono hJ.left, comap_is_maximal_of_surjective _ hf⟩
#align ideal.comap_jacobson_of_surjective Ideal.comap_jacobson_of_surjective

@[mono]
theorem jacobson_mono {I J : Ideal R} : I ≤ J → I.jacobson ≤ J.jacobson :=
  by
  intro h x hx
  erw [mem_Inf] at hx⊢
  exact fun K ⟨hK, hK_max⟩ => hx ⟨trans h hK, hK_max⟩
#align ideal.jacobson_mono Ideal.jacobson_mono

end Ring

section CommRing

variable [CommRing R] [CommRing S] {I : Ideal R}

theorem radical_le_jacobson : radical I ≤ jacobson I :=
  le_infₛ fun J hJ => (radical_eq_infₛ I).symm ▸ infₛ_le ⟨hJ.left, IsMaximal.isPrime hJ.right⟩
#align ideal.radical_le_jacobson Ideal.radical_le_jacobson

theorem isRadical_of_eq_jacobson (h : jacobson I = I) : I.IsRadical :=
  radical_le_jacobson.trans h.le
#align ideal.is_radical_of_eq_jacobson Ideal.isRadical_of_eq_jacobson

theorem isUnit_of_sub_one_mem_jacobson_bot (r : R) (h : r - 1 ∈ jacobson (⊥ : Ideal R)) :
    IsUnit r := by
  cases' exists_mul_sub_mem_of_sub_one_mem_jacobson r h with s hs
  rw [mem_bot, sub_eq_zero, mul_comm] at hs
  exact isUnit_of_mul_eq_one _ _ hs
#align ideal.is_unit_of_sub_one_mem_jacobson_bot Ideal.isUnit_of_sub_one_mem_jacobson_bot

theorem mem_jacobson_bot {x : R} : x ∈ jacobson (⊥ : Ideal R) ↔ ∀ y, IsUnit (x * y + 1) :=
  ⟨fun hx y =>
    let ⟨z, hz⟩ := (mem_jacobson_iff.1 hx) y
    isUnit_iff_exists_inv.2
      ⟨z, by rwa [add_mul, one_mul, ← sub_eq_zero, mul_right_comm, mul_comm _ z, mul_right_comm]⟩,
    fun h =>
    mem_jacobson_iff.mpr fun y =>
      let ⟨b, hb⟩ := isUnit_iff_exists_inv.1 (h y)
      ⟨b, (Submodule.mem_bot R).2 (hb ▸ by ring)⟩⟩
#align ideal.mem_jacobson_bot Ideal.mem_jacobson_bot

/-- An ideal `I` of `R` is equal to its Jacobson radical if and only if
the Jacobson radical of the quotient ring `R/I` is the zero ideal -/
theorem jacobson_eq_iff_jacobson_quotient_eq_bot :
    I.jacobson = I ↔ jacobson (⊥ : Ideal (R ⧸ I)) = ⊥ :=
  by
  have hf : Function.Surjective (Quotient.mk' I) := Submodule.Quotient.mk_surjective I
  constructor
  · intro h
    replace h := congr_arg (map (Quotient.mk' I)) h
    rw [map_jacobson_of_surjective hf (le_of_eq mk_ker)] at h
    simpa using h
  · intro h
    replace h := congr_arg (comap (Quotient.mk' I)) h
    rw [comap_jacobson_of_surjective hf, ← (Quotient.mk' I).ker_eq_comap_bot] at h
    simpa using h
#align ideal.jacobson_eq_iff_jacobson_quotient_eq_bot Ideal.jacobson_eq_iff_jacobson_quotient_eq_bot

/-- The standard radical and Jacobson radical of an ideal `I` of `R` are equal if and only if
the nilradical and Jacobson radical of the quotient ring `R/I` coincide -/
theorem radical_eq_jacobson_iff_radical_quotient_eq_jacobson_bot :
    I.radical = I.jacobson ↔ radical (⊥ : Ideal (R ⧸ I)) = jacobson ⊥ :=
  by
  have hf : Function.Surjective (Quotient.mk' I) := Submodule.Quotient.mk_surjective I
  constructor
  · intro h
    have := congr_arg (map (Quotient.mk' I)) h
    rw [map_radical_of_surjective hf (le_of_eq mk_ker),
      map_jacobson_of_surjective hf (le_of_eq mk_ker)] at this
    simpa using this
  · intro h
    have := congr_arg (comap (Quotient.mk' I)) h
    rw [comap_radical, comap_jacobson_of_surjective hf, ← (Quotient.mk' I).ker_eq_comap_bot] at this
    simpa using this
#align ideal.radical_eq_jacobson_iff_radical_quotient_eq_jacobson_bot Ideal.radical_eq_jacobson_iff_radical_quotient_eq_jacobson_bot

theorem jacobson_radical_eq_jacobson : I.radical.jacobson = I.jacobson :=
  le_antisymm
    (le_trans (le_of_eq (congr_arg jacobson (radical_eq_infₛ I)))
      (infₛ_le_infₛ fun J hJ => ⟨infₛ_le ⟨hJ.1, hJ.2.IsPrime⟩, hJ.2⟩))
    (jacobson_mono le_radical)
#align ideal.jacobson_radical_eq_jacobson Ideal.jacobson_radical_eq_jacobson

end CommRing

end Jacobson

section Polynomial

open Polynomial

variable [CommRing R]

theorem jacobson_bot_polynomial_le_infₛ_map_maximal :
    jacobson (⊥ : Ideal R[X]) ≤ infₛ (map (C : R →+* R[X]) '' { J : Ideal R | J.IsMaximal }) :=
  by
  refine' le_infₛ fun J => exists_imp.2 fun j hj => _
  haveI : j.is_maximal := hj.1
  refine' trans (jacobson_mono bot_le) (le_of_eq _ : J.jacobson ≤ J)
  suffices (⊥ : Ideal (Polynomial (R ⧸ j))).jacobson = ⊥
    by
    rw [← hj.2, jacobson_eq_iff_jacobson_quotient_eq_bot]
    replace this := congr_arg (map (polynomial_quotient_equiv_quotient_polynomial j).toRingHom) this
    rwa [map_jacobson_of_bijective _, map_bot] at this
    exact RingEquiv.bijective (polynomial_quotient_equiv_quotient_polynomial j)
  refine' eq_bot_iff.2 fun f hf => _
  simpa [(fun hX => by simpa using congr_arg (fun f => coeff f 1) hX : (X : (R ⧸ j)[X]) ≠ 0)] using
    eq_C_of_degree_eq_zero (degree_eq_zero_of_is_unit ((mem_jacobson_bot.1 hf) X))
#align ideal.jacobson_bot_polynomial_le_Inf_map_maximal Ideal.jacobson_bot_polynomial_le_infₛ_map_maximal

theorem jacobson_bot_polynomial_of_jacobson_bot (h : jacobson (⊥ : Ideal R) = ⊥) :
    jacobson (⊥ : Ideal R[X]) = ⊥ :=
  by
  refine' eq_bot_iff.2 (le_trans jacobson_bot_polynomial_le_Inf_map_maximal _)
  refine' fun f hf => (Submodule.mem_bot _).2 (Polynomial.ext fun n => trans _ (coeff_zero n).symm)
  suffices f.coeff n ∈ Ideal.jacobson ⊥ by rwa [h, Submodule.mem_bot] at this
  exact mem_Inf.2 fun j hj => (mem_map_C_iff.1 ((mem_Inf.1 hf) ⟨j, ⟨hj.2, rfl⟩⟩)) n
#align ideal.jacobson_bot_polynomial_of_jacobson_bot Ideal.jacobson_bot_polynomial_of_jacobson_bot

end Polynomial

section IsLocal

variable [CommRing R]

/-- An ideal `I` is local iff its Jacobson radical is maximal. -/
class IsLocal (I : Ideal R) : Prop where
  out : IsMaximal (jacobson I)
#align ideal.is_local Ideal.IsLocal

theorem isLocal_iff {I : Ideal R} : IsLocal I ↔ IsMaximal (jacobson I) :=
  ⟨fun h => h.1, fun h => ⟨h⟩⟩
#align ideal.is_local_iff Ideal.isLocal_iff

theorem isLocal_of_isMaximal_radical {I : Ideal R} (hi : IsMaximal (radical I)) : IsLocal I :=
  ⟨have : radical I = jacobson I :=
      le_antisymm (le_infₛ fun M ⟨him, hm⟩ => hm.IsPrime.radical_le_iff.2 him)
        (infₛ_le ⟨le_radical, hi⟩)
    show IsMaximal (jacobson I) from this ▸ hi⟩
#align ideal.is_local_of_is_maximal_radical Ideal.isLocal_of_isMaximal_radical

theorem IsLocal.le_jacobson {I J : Ideal R} (hi : IsLocal I) (hij : I ≤ J) (hj : J ≠ ⊤) :
    J ≤ jacobson I :=
  let ⟨M, hm, hjm⟩ := exists_le_maximal J hj
  le_trans hjm <| le_of_eq <| Eq.symm <| hi.1.eq_of_le hm.1.1 <| infₛ_le ⟨le_trans hij hjm, hm⟩
#align ideal.is_local.le_jacobson Ideal.IsLocal.le_jacobson

theorem IsLocal.mem_jacobson_or_exists_inv {I : Ideal R} (hi : IsLocal I) (x : R) :
    x ∈ jacobson I ∨ ∃ y, y * x - 1 ∈ I :=
  by_cases
    (fun h : I ⊔ span {x} = ⊤ =>
      let ⟨p, hpi, q, hq, hpq⟩ := Submodule.mem_sup.1 ((eq_top_iff_one _).1 h)
      let ⟨r, hr⟩ := mem_span_singleton.1 hq
      Or.inr ⟨r, by rw [← hpq, mul_comm, ← hr, ← neg_sub, add_sub_cancel] <;> exact I.neg_mem hpi⟩)
    fun h : I ⊔ span {x} ≠ ⊤ =>
    Or.inl <|
      le_trans le_sup_right (hi.le_jacobson le_sup_left h) <| mem_span_singleton.2 <| dvd_refl x
#align ideal.is_local.mem_jacobson_or_exists_inv Ideal.IsLocal.mem_jacobson_or_exists_inv

end IsLocal

theorem isPrimary_of_isMaximal_radical [CommRing R] {I : Ideal R} (hi : IsMaximal (radical I)) :
    IsPrimary I :=
  have : radical I = jacobson I :=
    le_antisymm (le_infₛ fun M ⟨him, hm⟩ => hm.IsPrime.radical_le_iff.2 him)
      (infₛ_le ⟨le_radical, hi⟩)
  ⟨ne_top_of_lt <| lt_of_le_of_lt le_radical (lt_top_iff_ne_top.2 hi.1.1), fun x y hxy =>
    ((isLocal_of_isMaximal_radical hi).mem_jacobson_or_exists_inv y).symm.imp
      (fun ⟨z, hz⟩ => by
        rw [← mul_one x, ← sub_sub_cancel (z * y) 1, mul_sub, mul_left_comm] <;>
          exact I.sub_mem (I.mul_mem_left _ hxy) (I.mul_mem_left _ hz))
      (this ▸ id)⟩
#align ideal.is_primary_of_is_maximal_radical Ideal.isPrimary_of_isMaximal_radical

end Ideal


/-
Copyright (c) 2022 Eric Wieser. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Eric Wieser
-/
import linear_algebra.clifford_algebra.conjugation
import linear_algebra.clifford_algebra.even
import linear_algebra.quadratic_form.prod
/-!
# Isomorphisms with the even subalgebra of a Clifford algebra

This file provides some notable isomorphisms regarding the even subalgebra, `clifford_algebra.even`.

## Main definitions

* `clifford_algebra.equiv_even`: Every Clifford algebra is isomorphic as an algebra to the even
  subalgebra of a Clifford algebra with one more dimension.
  * `clifford_algebra.even_equiv.Q'`: The quadratic form used by this "one-up" algebra.
  * `clifford_algebra.to_even`: The simp-normal form of the forward direction of this isomorphism.
  * `clifford_algebra.of_even`: The simp-normal form of the reverse direction of this isomorphism.

* `clifford_algebra.even_equiv_even_neg`: Every even subalgebra is isomorphic to the even subalgebra
  of the Clifford algebra with negated quadratic form.
  * `clifford_algebra.even_to_neg`: The simp-normal form of each direction of this isomorphism.

## Main results

* `clifford_algebra.coe_to_even_reverse_involute`: the behavior of `clifford_algebra.to_even` on the
  "Clifford conjugate", that is `clifford_algebra.reverse` composed with
  `clifford_algebra.involute`.
-/

namespace clifford_algebra

variables {R M : Type*} [comm_ring R] [add_comm_group M] [module R M]
variables (Q : quadratic_form R M)

/-! ### Constructions needed for `clifford_algebra.equiv_even` -/

namespace equiv_even

/-- The quadratic form on the augmented vector space `M × R` sending `v + r•e0` to `Q v - r^2`. -/
@[reducible]
def Q' : quadratic_form R (M × R) := (Q.prod $ -@quadratic_form.sq R _)

lemma Q'_apply (m : M × R) : Q' Q m = Q m.1 - m.2 * m.2 := (sub_eq_add_neg _ _).symm

/-- The unit vector in the new dimension -/
def e0 : clifford_algebra (Q' Q) := ι (Q' Q) (0, 1)

/-- The embedding from the existing vector space -/
def v : M →ₗ[R] clifford_algebra (Q' Q) := (ι (Q' Q)) ∘ₗ linear_map.inl _ _ _

lemma ι_eq_v_add_smul_e0 (m : M) (r : R) : ι (Q' Q) (m, r) = v Q m + r • e0 Q :=
by rw [e0, v, linear_map.comp_apply, linear_map.inl_apply, ←linear_map.map_smul, prod.smul_mk,
  smul_zero, smul_eq_mul, mul_one, ←linear_map.map_add, prod.mk_add_mk, zero_add, add_zero]

lemma e0_mul_e0 : e0 Q * e0 Q = -1 :=
(ι_sq_scalar _ _).trans $ by simp

lemma v_sq_scalar (m : M) : v Q m * v Q m = algebra_map _ _ (Q m) :=
(ι_sq_scalar _ _).trans $ by simp

lemma neg_e0_mul_v (m : M) : -(e0 Q * v Q m) = v Q m * e0 Q :=
begin
  refine neg_eq_of_add_eq_zero_right ((ι_mul_ι_add_swap _ _).trans _),
  dsimp [quadratic_form.polar],
  simp only [add_zero, mul_zero, mul_one, zero_add, neg_zero, quadratic_form.map_zero,
    add_sub_cancel, sub_self, map_zero, zero_sub],
end

lemma neg_v_mul_e0 (m : M) : -(v Q m * e0 Q) = e0 Q * v Q m :=
begin
  rw neg_eq_iff_eq_neg,
  exact (neg_e0_mul_v _ m).symm
end

@[simp] lemma e0_mul_v_mul_e0 (m : M) : e0 Q * v Q m * e0 Q = v Q m :=
by rw [←neg_v_mul_e0, ←neg_mul, mul_assoc, e0_mul_e0, mul_neg_one, neg_neg]

@[simp] lemma reverse_v (m : M) : reverse (v Q m) = v Q m := reverse_ι _
@[simp] lemma involute_v (m : M) : involute (v Q m) = -v Q m := involute_ι _

@[simp] lemma reverse_e0 : reverse (e0 Q) = e0 Q := reverse_ι _
@[simp] lemma involute_e0 : involute (e0 Q) = -e0 Q := involute_ι _

end equiv_even

open equiv_even

/-- The embedding from the smaller algebra into the new larger one. -/
def to_even : clifford_algebra Q →ₐ[R] clifford_algebra.even (Q' Q) :=
begin
  refine clifford_algebra.lift Q ⟨_, λ m, _⟩,
  { refine linear_map.cod_restrict _ _ (λ m, submodule.mem_supr_of_mem ⟨2, rfl⟩ _),
    exact (linear_map.mul_left R $ e0 Q).comp (v Q),
    rw [subtype.coe_mk, pow_two],
    exact submodule.mul_mem_mul (linear_map.mem_range_self _ _) (linear_map.mem_range_self _ _), },
  { ext1,
    dsimp only [subalgebra.coe_mul, linear_map.cod_restrict_apply, linear_map.comp_apply,
      linear_map.mul_left_apply, linear_map.inl_apply, subalgebra.coe_algebra_map],
    rw [←mul_assoc, e0_mul_v_mul_e0, v_sq_scalar] }
end

@[simp]
lemma to_even_ι (m : M) : (to_even Q (ι Q m) : clifford_algebra (Q' Q)) = e0 Q * v Q m :=
begin
  rw [to_even, clifford_algebra.lift_ι_apply, linear_map.cod_restrict_apply],
  refl,
end

/-- The embedding from the even subalgebra with an extra dimension into the original algebra. -/
def of_even : clifford_algebra.even (Q' Q) →ₐ[R] clifford_algebra Q :=
begin
  /-
  Recall that we need:
   * `f ⟨0,1⟩ ⟨x,0⟩ = ι x`
   * `f ⟨x,0⟩ ⟨0,1⟩ = -ι x`
   * `f ⟨x,0⟩ ⟨y,0⟩ = ι x * ι y`
   * `f ⟨0,1⟩ ⟨0,1⟩ = -1`
  -/
  let f : (M × R) →ₗ[R] (M × R) →ₗ[R] clifford_algebra Q :=
  ((algebra.lmul R (clifford_algebra Q)).to_linear_map.comp
    $ ((ι Q).comp (linear_map.fst _ _ _)) +
      (algebra.linear_map R _).comp (linear_map.snd _ _ _)).compl₂
    (((ι Q).comp (linear_map.fst _ _ _)) - (algebra.linear_map R _).comp (linear_map.snd _ _ _)),
  have f_apply :
    ∀ x y, f x y = (ι Q x.1 + algebra_map R _ x.2) * (ι Q y.1 - algebra_map R _ y.2) :=
    λ x y, rfl,
  have hc : ∀ (r : R) (x : clifford_algebra Q), commute (algebra_map _ _ r) x := algebra.commutes,
  have hm : ∀ m : M × R,
    ι Q m.1 * ι Q m.1 - algebra_map R _ m.2 * algebra_map R _ m.2 = algebra_map R _ (Q' Q m),
  { intro m,
    rw [ι_sq_scalar, ←ring_hom.map_mul, ←ring_hom.map_sub,
      sub_eq_add_neg, Q'_apply, sub_eq_add_neg] },
  refine even.lift (Q' Q) ⟨f, _, _⟩; simp_rw [f_apply],
  { intro m,
    rw [←(hc _ _).symm.mul_self_sub_mul_self_eq, hm] },
  { intros m₁ m₂ m₃,
    rw [←mul_smul_comm, ←mul_assoc, mul_assoc(_ + _), ←(hc _ _).symm.mul_self_sub_mul_self_eq',
      algebra.smul_def, ←mul_assoc, hm] },
end

lemma to_even_comp_of_even : (to_even Q).comp (of_even Q) = alg_hom.id R _ :=
even.alg_hom_ext (Q' Q) $ even_hom.ext _ _ $ linear_map.ext $ λ m₁, linear_map.ext $ λ m₂,
  subtype.ext $
  let ⟨m₁, r₁⟩ := m₁, ⟨m₂, r₂⟩ := m₂ in
  calc  ↑(to_even Q (of_even Q ((even.ι (Q' Q)).bilin (m₁, r₁) (m₂, r₂))))
      = (e0 Q * v Q m₁ + algebra_map R _ r₁) * (e0 Q * v Q m₂ - algebra_map R _ r₂) :
        by rw [of_even_ι, alg_hom.map_mul, alg_hom.map_add, alg_hom.map_sub, alg_hom.commutes,
             alg_hom.commutes, subalgebra.coe_mul, subalgebra.coe_add, subalgebra.coe_sub,
             to_even_ι, to_even_ι, subalgebra.coe_algebra_map, subalgebra.coe_algebra_map]
  ... = e0 Q * v Q m₁ * (e0 Q * v Q m₂) + r₁ • e0 Q * v Q m₂ - r₂ • e0 Q * v Q m₁
          - algebra_map R _ (r₁ * r₂) :
        by rw [mul_sub, add_mul, add_mul, ←algebra.commutes, ←algebra.smul_def, ←map_mul,
               ←algebra.smul_def, sub_add_eq_sub_sub, smul_mul_assoc, smul_mul_assoc]
  ... = v Q m₁ * v Q m₂ + r₁ • e0 Q * v Q m₂ + v Q m₁ * r₂ • e0 Q + (r₁ • e0 Q) * r₂ • e0 Q :
        have h1 : e0 Q * v Q m₁ * (e0 Q * v Q m₂) = v Q m₁ * v Q m₂,
          by rw [←mul_assoc, e0_mul_v_mul_e0],
        have h2 : -(r₂ • e0 Q * v Q m₁) = v Q m₁ * r₂ • e0 Q,
          by rw [mul_smul_comm, smul_mul_assoc, ←smul_neg, neg_e0_mul_v],
        have h3 : - algebra_map R _ (r₁ * r₂) = (r₁ • e0 Q) * r₂ • e0 Q,
          by rw [algebra.algebra_map_eq_smul_one, smul_mul_smul, e0_mul_e0, smul_neg],
        by rw [sub_eq_add_neg, sub_eq_add_neg, h1, h2, h3]
  ... = ι _ (m₁, r₁) * ι _ (m₂, r₂) :
        by rw [ι_eq_v_add_smul_e0, ι_eq_v_add_smul_e0, mul_add, add_mul, add_mul, add_assoc]

lemma of_even_comp_to_even :
  (of_even Q).comp (to_even Q) = alg_hom.id R _ :=
clifford_algebra.hom_ext $ linear_map.ext $ λ m,
  calc  of_even Q (to_even Q (ι Q m))
      = of_even Q ⟨_, (to_even Q (ι Q m)).prop⟩ : by rw subtype.coe_eta
  ... = (ι Q 0 + algebra_map R _ 1) * (ι Q m - algebra_map R _ 0) : begin
          simp_rw to_even_ι,
          exact of_even_ι Q _ _,
        end
  ... = ι Q m : by rw [map_one, map_zero, map_zero, sub_zero, zero_add, one_mul]

/-- Any clifford algebra is isomorphic to the even subalgebra of a clifford algebra with an extra
dimension (that is, with vector space `M × R`), with a quadratic form evaluating to `-1` on that new
basis vector. -/
@[simps]
def equiv_even : clifford_algebra Q ≃ₐ[R] clifford_algebra.even (Q' Q) :=
alg_equiv.of_alg_hom
  (to_even Q)
  (of_even Q)
  (to_even_comp_of_even Q)
  (of_even_comp_to_even Q)

/-- The representation of the clifford conjugate (i.e. the reverse of the involute) in the even
subalgebra is just the reverse of the representation. -/
lemma coe_to_even_reverse_involute (x : clifford_algebra Q) :
  ↑(to_even Q (reverse (involute x))) = reverse (to_even Q x : clifford_algebra (Q' Q)) :=
begin
  induction x using clifford_algebra.induction,
  case h_grade0 : r { simp only [alg_hom.commutes, subalgebra.coe_algebra_map, reverse.commutes] },
  case h_grade1 : m
  { simp only [involute_ι, subalgebra.coe_neg, to_even_ι, reverse.map_mul,
      reverse_v, reverse_e0, reverse_ι, neg_e0_mul_v, map_neg] },
  case h_mul : x y hx hy { simp only [map_mul, subalgebra.coe_mul, reverse.map_mul, hx, hy] },
  case h_add : x y hx hy { simp only [map_add, subalgebra.coe_add, hx, hy] },
end

/-! ### Constructions needed for `clifford_algebra.even_equiv_even_neg` -/

/-- One direction of `clifford_algebra.even_equiv_even_neg` -/
def even_to_neg (Q' : quadratic_form R M) (h : Q' = -Q) :
  clifford_algebra.even Q →ₐ[R] clifford_algebra.even Q' :=
even.lift Q
  { bilin := -(even.ι Q' : _).bilin,
    contract := λ m, by simp_rw [linear_map.neg_apply, even_hom.contract, h,
                                 quadratic_form.neg_apply, map_neg, neg_neg],
    contract_mid := λ m₁ m₂ m₃,
      by simp_rw [linear_map.neg_apply, neg_mul_neg, even_hom.contract_mid, h,
                  quadratic_form.neg_apply, smul_neg, neg_smul] }

@[simp] lemma even_to_neg_ι (Q' : quadratic_form R M) (h : Q' = -Q) (m₁ m₂ : M) :
  even_to_neg Q Q' h ((even.ι Q).bilin m₁ m₂) = -(even.ι Q').bilin m₁ m₂ :=
even.lift_ι _ _ m₁ m₂

lemma even_to_neg_comp_even_to_neg (Q' : quadratic_form R M)
  (h : Q' = -Q) (h' : Q = -Q') :
  (even_to_neg Q' Q h').comp (even_to_neg Q Q' h) = alg_hom.id R _ :=
begin
  ext m₁ m₂ : 4,
  dsimp only [even_hom.compr₂_bilin, linear_map.compr₂_apply, alg_hom.to_linear_map_apply,
              alg_hom.comp_apply, alg_hom.id_apply],
  rw [even_to_neg_ι, map_neg, even_to_neg_ι, neg_neg]
end

/-- The even subalgebras of the algebras with quadratic form `Q` and `-Q` are isomorphic.

Stated another way, `𝒞ℓ⁺(p,q,r)` and `𝒞ℓ⁺(q,p,r)` are isomorphic. -/
@[simps]
def even_equiv_even_neg : clifford_algebra.even Q ≃ₐ[R] clifford_algebra.even (-Q) :=
alg_equiv.of_alg_hom
  (even_to_neg Q _ rfl)
  (even_to_neg (-Q) _ (neg_neg _).symm)
  (even_to_neg_comp_even_to_neg _ _ _ _)
  (even_to_neg_comp_even_to_neg _ _ _ _)

end clifford_algebra


import data.real.basic
import analysis.special_functions.exp_log
import analysis.special_functions.pow
import analysis.calculus.deriv
import algebra.group.pi

noncomputable theory

/-
Problem:
Let a,b,t∈ℝ be positive such that a≠b, a=tb^3, and a^a=b^b.
(1) If t=4, prove that 1/e+4/e^3 < a+b < 1.
(2) Let a,b,t be such that a+b>2/sqrt(t). View a,b as functions of t and denote g(t)=a+b.
  Compute the range of t and prove that g(t) increases as t increases.

Human readable proof:
Let y=f(x)=x log x for x>0, then f(x)<0 when x<1, f(x)=0 when x=1,
f(x)>0 when x>1.
We have f'(x)=1+log x, and
f'(x)<0 when x<1/e, f'(x)>0 when x>1/e.
Therefore f(x) decreases as x increases if x∈(0,1/e),
f(x) increases as x increases if x∈(1/e, +∞),
and f(x) takes minimun at x=1/e with value -1/e.
Therefore if a≠b such that a^a=b^b, then f(a)=f(b)=:y, we must have
y∈(-1/e,0), a,b∈(0,1/e)∪(1/e,1), and
- b decreases and t increases as a increases,
- either a∈(0,1/e),b∈(1/e,1),t∈(0,e^2), or a∈(1/e,1),b∈(0,1/e),t∈(e^2,+∞).
- If a > b, then 1/sqrt(t)=sqrt(b^3/a) < sqrt(b^3/b)=b and hence a+b > 2b > 2/sqrt(t).
- If a < b, then 1/sqrt(t)=sqrt(b^3/a) > sqrt(b^3/b)=b and hence a+b < 2b < 2/sqrt(t).
Therefore the (1) comes from that since t=4 < e^2, we have a < 1/e < b,
hence a+b < 2/sqrt(t)=1 and a+b=tb^3+b>t/e^3+1/e=1/e+4/e^3.
In (2), the range of t is (e^2,+∞). Since t increases as a increases, we only need to show that
g increases as a increases, namely d(a+b)/da>0. We have
d(a+b)/da=1+db/da=1+(dy/da)/(dy/db)=1+(1+log a)/(1+log b). Since 1+log b<0, we only need to show
log b+log a+2<0, namely ab<1/e^2, namely b<1/ae^2. Since b<1/e and 1/ae^2<1/e, this is equivalent to
f(b)>f(1/ae^2), namely a log a > 1/ae^2 * (-2-log a), note that f(a)=f(b).
This is equivalent to g(x)>0 for x∈(1/e,1),
where g(x)=(x+1/xe^2)log x + 2/xe^2. Since g(1/e)=0, we only need to show that
g'(x)>0 for x∈(1/e,1). This is true since
g'(x)= ... = (1-1/x^2e^2)(1+log x).

Please translate it into a machine readable proof.
-/

def condition {a b t : ℝ} (ha : a > 0) (hb : b > 0) (ht : t > 0) := a ≠ b ∧ a = t * b ^ 3 ∧ a ^ a = b ^ b

def e : ℝ := real.exp 1

lemma e_gt_one : e > 1 :=
begin
  change 1 < e,
  unfold e,
  rw real.one_lt_exp_iff,
  linarith,
end

lemma e_gt_two : e > 2 :=
begin
  unfold e,
  have key := real.exp_approx_end 2 3 1 (by norm_num) (by norm_num),
  norm_num at key,
  rw abs_le at key,
  linarith,
end

lemma einv_lt_one : 1/e < 1 := by { rw one_div e, exact inv_lt_one e_gt_one, }

def xlogx (x : ℝ) : ℝ := x * real.log x

lemma eq1_iff_eq2 {a b : ℝ} (ha : a > 0) (hb : b > 0) : a ^ a = b ^ b ↔ xlogx a = xlogx b :=
begin
  unfold xlogx,
  split, {
    intro h,
    rw [← real.log_rpow ha a, ← real.log_rpow hb b, h],
  }, {
    intro h,
    rw [← real.log_rpow ha a, ← real.log_rpow hb b] at h,
    have h2 : real.exp (real.log (a ^ a)) = real.exp (real.log (b ^ b)) := by rw h,
    rw [real.exp_log (real.rpow_pos_of_pos ha a), real.exp_log (real.rpow_pos_of_pos hb b)] at h2,
    exact h2,
  },
end

lemma xlogx_pos_iff {x : ℝ} (hx : x > 0)
: xlogx x > 0 ↔ x > 1 :=
begin
  unfold xlogx,
  split, {
    intro h,
    exact (real.log_pos_iff hx).mp ((zero_lt_mul_left hx).mp h),
  }, {
    intro h,
    exact mul_pos hx (real.log_pos h),
  },
end

lemma xlogx_neg_iff {x : ℝ} (hx : x > 0)
: xlogx x < 0 ↔ x < 1 :=
begin
  unfold xlogx,
  split, {
    intro h,
    have h1 : x * (-real.log x) > 0 := by linarith,
    have h2 : (-real.log x) > 0 := (zero_lt_mul_left hx).mp h1,
    have h3 : real.log x < 0 := by linarith,
    exact (real.log_neg_iff hx).mp h3,
  }, {
    intro h,
    have h1 := real.log_neg hx h,
    have h2 : (-real.log x) > 0 := by linarith,
    have h3 : x * (-real.log x) > 0 := mul_pos hx h2,
    linarith,
  },
end

lemma xlogx_zero_iff {x : ℝ} (hx : x > 0)
: xlogx x = 0 ↔ x = 1 :=
begin
  unfold xlogx,
  split, {
    intro h,
    have h1 : x ≠ 0 := by linarith,
    have h2 : real.log x = 0 := by { rw mul_eq_zero at h, tauto },
    symmetry,
    calc 1 = real.exp 0 : real.exp_zero.symm
      ... = real.exp (real.log x) : by rw ← h2
      ... = x : real.exp_log (by linarith),
  }, {
    intro h,
    rw [h, real.log_one],
    ring,
  },
end

lemma xlogx_cont : continuous_on (λ u : ℝ, xlogx u) (set.Ioi 0) :=
begin
  refine continuous_on.mul continuous_on_id _,
  intros u hu,
  exact continuous_at.continuous_within_at (real.continuous_at_log hu),
end

lemma xlogx_diff_on : differentiable_on ℝ (λ u : ℝ, xlogx u) (set.Ioi 0) :=
begin
  refine differentiable_on.mul differentiable_on_id (differentiable_on_id.log _),
  intros u hu,
  have : u > 0 := hu, rw id, linarith,
end

lemma xlogx_has_deriv_at {u : ℝ} (hu : u > 0)
: has_deriv_at (λ u : ℝ, xlogx u) (1 + real.log u) u :=
begin
  have d0 := has_deriv_at_id' u,
  have d2 : u ≠ 0 := by linarith,
  have d1 := real.has_deriv_at_log d2,
  have d3 := has_deriv_at.mul d0 d1,
  have d4 : u * u⁻¹ = 1 := div_self d2,
  rw [d4, add_comm] at d3,
  simp at d3,
  exact d3,
end

lemma xlogx_mvt {a b : ℝ} (ha : a > 0) (hab: a < b)
: ∃ (c : ℝ), a < c ∧ c < b ∧ 1 + real.log c = (xlogx b - xlogx a) / (b - a) :=
begin
  have hb : b > 0 := by linarith,
  have c0 : (set.Icc a b) ⊆ (set.Ioi 0) := (set.Ioi 0).Icc_subset ha hb,
  have c1 : continuous_on (λ u : ℝ, xlogx u) (set.Icc a b) := continuous_on.mono xlogx_cont c0,
  have c2 : (set.Ioo a b) ⊆ (set.Ioo 0 b) := set.Ioo_subset_Ioo (by linarith) (by linarith),
  have c3 : (set.Ioo a b) ⊆ (set.Ioi 0) := set.subset.trans c2 set.Ioo_subset_Ioi_self,
  have c4 : differentiable_on ℝ (λ u : ℝ, xlogx u) (set.Ioo a b) := differentiable_on.mono xlogx_diff_on c3,

  have mvt1 := exists_deriv_eq_slope xlogx hab c1 c4,
  cases mvt1 with c mvt2,
  cases mvt2 with H mvt3,
  use c,
  rw ← set.Ioo_def at H,
  have z1 : a < c := H.1,
  have z2 : c < b := H.2,
  have z4 := xlogx_has_deriv_at (calc c > 0 : by linarith),
  have z3 : deriv xlogx c = 1 + real.log c := has_deriv_at.deriv z4,
  rw z3 at mvt3,
  exact ⟨ z1, z2, mvt3 ⟩,
end

lemma log_einv_eq_minus_one : real.log (1/e) = -1 := calc
  real.log (1/e) = real.log (e⁻¹) : by { rw one_div e }
  ... = -real.log e : e.log_inv
  ... = -1 : by { congr, exact real.log_exp 1 }

lemma xlogx_monotone {x y : ℝ} (hx : x > 0) (hy : y > 0)
: (1/e ≤ x → x < y → xlogx x < xlogx y) ∧ (1/e ≥ x → x > y → xlogx x < xlogx y) :=
begin
  split, {
    intros h1 h2,
    cases xlogx_mvt hx h2 with c mvt1,
    have d1 : c > 1/e := by linarith,
    have d2 : real.log c > -1 := by { rw ← log_einv_eq_minus_one, exact real.log_lt_log (one_div_pos.mpr (1 : ℝ).exp_pos) d1 },
    have d3 : xlogx y - xlogx x > 0 := calc
      xlogx y - xlogx x = (1 + real.log c) * (y - x) : by { have : y - x ≠ 0 := by linarith, rw ← div_eq_iff this, rw mvt1.2.2 }
      ... > 0 : by { have d4 : 0 < 1 + real.log c := by linarith, have d5 : 0 < y - x := by linarith, exact mul_pos d4 d5 },
    linarith,
  }, {
    intros h1 h2,
    cases xlogx_mvt hy h2 with c mvt1,
    have d1 : c < 1/e := by linarith,
    have d2 : real.log c < -1 := by { rw ← log_einv_eq_minus_one, exact real.log_lt_log (by linarith) d1 },
    have d3 : xlogx x - xlogx y < 0 := calc
      xlogx x - xlogx y = (1 + real.log c) * (x - y) : by { have : x - y ≠ 0 := by linarith, rw ← div_eq_iff this, rw mvt1.2.2 }
      ... < 0 : by { have d4 : 0 < -(1 + real.log c) := by linarith, have d5 : 0 < x - y := by linarith, have d6 := mul_pos d4 d5, linarith },
    linarith,
  },
end

lemma xlogx_inj {x y : ℝ} (hx : x > 0) (hy : y > 0)
: (1/e ≤ x → 1/e ≤ y → (x = y ↔ xlogx x = xlogx y)) ∧ (1/e ≥ x → 1/e ≥ y → (x = y ↔ xlogx x = xlogx y)) :=
begin
  split, {
    intros hxx hyy,
    split, { intro hxy, rw hxy, },
    intro hxy,
    by_contradiction,
    have d0 : x ≠ y := h,
    by_cases hxy2 : x < y, {
      linarith [(xlogx_monotone hx hy).1 hxx hxy2],
    }, {
      have d1 : y < x := (ne.le_iff_lt d0.symm).mp (by linarith),
      linarith [(xlogx_monotone hy hx).1 hyy d1],
    },
  }, {
    intros hxx hyy,
    split, { intro hxy, rw hxy, },
    intro hxy,
    by_contradiction,
    have d0 : x ≠ y := h,
    by_cases hxy2 : x < y, {
      linarith [(xlogx_monotone hy hx).2 hyy hxy2],
    }, {
      have d1 : y < x := (ne.le_iff_lt d0.symm).mp (by linarith),
      linarith [(xlogx_monotone hx hy).2 hxx d1],
    },
  },
end

lemma xlogx_monotone_iff {x y : ℝ} (hx : x > 0) (hy : y > 0)
: (1/e ≤ x → 1/e ≤ y → (x < y ↔ xlogx x < xlogx y)) ∧ (1/e ≥ x → 1/e ≥ y → (x > y ↔ xlogx x < xlogx y)) :=
begin
  split, {
    intros hxx hyy,
    split, { exact (xlogx_monotone hx hy).1 hxx, },
    contrapose, push_neg, intro hxy,
    by_cases hxy2 : y = x, { rw hxy2, },
    have := (xlogx_monotone hy hx).1 hyy ((ne.le_iff_lt hxy2).mp hxy),
    linarith,
  }, {
    intros hxx hyy,
    split, { exact (xlogx_monotone hx hy).2 hxx, },
    contrapose, push_neg, intro hxy,
    by_cases hxy2 : x = y, { rw hxy2, },
    have := (xlogx_monotone hy hx).2 hyy ((ne.le_iff_lt hxy2).mp hxy),
    linarith,
  },
end

lemma range_of_a {a b : ℝ} (ha : a > 0) (hb : b > 0) (h1 : a ≠ b) (h2 : a ^ a = b ^ b)
: a < 1 ∧ a ≠ 1/e :=
begin
  rw eq1_iff_eq2 ha hb at h2,
  split, {
    have e1 := einv_lt_one,
    by_cases b1 : b ≥ 1, {
      by_contradiction,
      have a1 : a ≥ 1 := by linarith,
      rw ← (xlogx_inj ha hb).1 (by linarith) (by linarith) at h2,
      contradiction,
    }, {
      have b2 : xlogx b < 0 := (xlogx_neg_iff hb).2 (by linarith),
      rw ← h2 at b2,
      exact (xlogx_neg_iff ha).1 b2,
    },
  }, {
    by_contradiction,
    have hh : a = 1/e := by finish,
    by_cases h1a : a > b, {
      linarith [(xlogx_monotone ha hb).2 (by linarith) h1a],
    }, {
      have d0 : a < b := (ne.le_iff_lt h1).mp (by linarith),
      linarith [(xlogx_monotone ha hb).1 (by linarith) d0],
    },
  },
end

lemma range_of_a_b {a b : ℝ} (ha : a > 0) (hb : b > 0) (h1 : a ≠ b) (h2 : a ^ a = b ^ b)
: (a < 1/e ∧ b > 1/e ∧ b < 1)
∨ (a > 1/e ∧ a < 1 ∧ b < 1/e) :=
begin
  have haa := range_of_a ha hb h1 h2,
  have hbb := range_of_a hb ha h1.symm h2.symm,
  rw eq1_iff_eq2 ha hb at h2,
  by_cases ha2 : a < 1/e, {
    left,
    have r2 : b > 1/e := by {
      by_contradiction,
      rw ← (xlogx_inj ha hb).2 (by linarith) (by linarith) at h2,
      contradiction,
    },
    exact ⟨ ha2, r2, hbb.1 ⟩,
  }, {
    right,
    have ha2b : a > 1/e := (ne.le_iff_lt haa.2.symm).mp (by linarith),
    have r2 : b < 1/e := by {
      by_contradiction,
      rw ← (xlogx_inj ha hb).1 (by linarith) (by linarith) at h2,
      contradiction,
    },
    exact ⟨ ha2b, haa.1, r2 ⟩,
  },
end

lemma range_of_a_b_t {a b t : ℝ} (ha : a > 0) (hb : b > 0) (ht : t > 0) (h1 : condition ha hb ht)
: (a < 1/e ∧ b > 1/e ∧ b < 1 ∧ t < e^2 ∧ b < 1 / (real.sqrt t))
∨ (a > 1/e ∧ a < 1 ∧ b < 1/e ∧ t > e^2 ∧ b > 1 / (real.sqrt t)) :=
begin
  unfold condition at h1,
  have h121b : t = a / b^3 := by {
    symmetry,
    have : b^3 ≠ 0 := pow_ne_zero 3 (by linarith),
    rw div_eq_iff this, exact h1.2.1,
  },
  have stupid : (1/e) / (1/e)^3 = e^2 := by {
    rw one_div_pow 3,
    have t2 : e ≠ 0 := by linarith [e_gt_one],
    have t3 : e^3 ≠ 0 := pow_ne_zero 3 t2,
    have t1 : 1/e^3 ≠ 0 := one_div_ne_zero t3,
    rw [div_eq_iff t1, div_eq_iff t2], ring,
    symmetry, rw mul_comm, exact div_self t3,
  },
  cases range_of_a_b ha hb h1.1 h1.2.2 with ha2 ha2, {
    left,
    have r4 : t < e^2 := calc
      t = a / b^3 : h121b
      ... < (1/e) / (1/e)^3 : by {
        have t2 : (1/e)^3 < b^3 := pow_lt_pow_of_lt_left ha2.2.1 (by linarith) (by linarith),
        have t3 : (1/e)^3 ≤ b^3 := by linarith,
        exact div_lt_div ha2.1 t3 (by linarith) (pow_pos (by linarith) 3),
      }
      ... = e^2 : stupid,
    have r5 : 1 / real.sqrt t > b := by {
      ring,
      rw ← real.sqrt_inv,
      refine lt_of_pow_lt_pow 2 (by linarith [real.sqrt_pos.2 (inv_pos.2 ht)]) _,
      rw real.sqr_sqrt (calc 0 ≤ t⁻¹ : by linarith [inv_pos.2 ht]),
      rw [h121b, inv_div, lt_div_iff ha],
      have := mul_lt_mul_of_pos_left (calc a < b : by linarith) (pow_pos hb 2),
      have : b^2 * b = b^3 := by ring,
      linarith,
    },
    exact ⟨ ha2.1, ha2.2.1, ha2.2.2, r4, r5 ⟩,
  }, {
    right,
    have r4 : t > e^2 := calc
      t = a / b^3 : h121b
      ... > (1/e) / (1/e)^3 : by {
        have t2 : b^3 < (1/e)^3 := pow_lt_pow_of_lt_left ha2.2.2 (by linarith) (by linarith),
        have t3 : b^3 ≤ (1/e)^3 := by linarith,
        exact div_lt_div ha2.1 t3 (by linarith) (pow_pos hb 3),
      }
      ... = e^2 : stupid,
    have r5 : 1 / real.sqrt t < b := by {
      ring,
      rw ← real.sqrt_inv,
      refine lt_of_pow_lt_pow 2 (by linarith [real.sqrt_pos.2 (inv_pos.2 ht)]) _,
      rw real.sqr_sqrt (calc 0 ≤ t⁻¹ : by linarith [inv_pos.2 ht]),
      rw [h121b, inv_div, div_lt_iff ha],
      have := mul_lt_mul_of_pos_left (calc b < a : by linarith) (pow_pos hb 2),
      have : b^2 * b = b^3 := by ring,
      linarith,
    },
    exact ⟨ ha2.1, ha2.2.1, ha2.2.2, r4, r5 ⟩,
  },
end

lemma stupid_log_pow {x : ℝ} (hx : x ≠ 0) (n : ℕ) : real.log (x^n) = n * real.log x :=
begin
  induction n with n hn,
  simp,
  rw pow_succ,
  rw [real.log_mul hx (pow_ne_zero n hx), hn, nat.succ_eq_add_one],
  ring,
  rw mul_comm,
  refl,
end

lemma range_of_a_times_b_0 {a b : ℝ} (ha : a > 0) (hb : b > 0) (h1 : a ≠ b) (h2 : a ^ a = b ^ b)
(haa : a > 1/e) : a * b < 1/e^2 :=
begin
  cases range_of_a_b ha hb h1 h2 with hh hh, {
    exfalso, linarith,
  }, {
    have rab : a > 1/e ∧ a < 1 ∧ b < 1/e
      := by { cases range_of_a_b ha hb h1 h2 with hh hh, { exfalso, linarith }, exact hh, },
    rw eq1_iff_eq2 ha hb at h2,
    suffices : 1/(a*e^2) > b, {
      have := mul_lt_mul_of_pos_right this (calc a > 0 : by linarith),
      rw [div_helper (e^2) (calc a ≠ 0 : by linarith), mul_comm] at this,
      exact this,
    },
    have t1 : 0 < 1/(a*e^2) := by {
      rw [one_div, inv_pos],
      exact mul_pos (by linarith) (pow_pos (by linarith only [e_gt_one]) 2),
    },
    have e_ne_zero : e ≠ 0 := by linarith only [e_gt_one],
    rw (xlogx_monotone_iff (calc 1/(a*e^2) > 0 : by linarith only [t1]) hb).2 (calc 1/e ≥ 1/(a*e^2) : by {
      change 1/(a*e^2) ≤ 1/e,
      repeat {rw one_div},
      refine (inv_le_inv _ _).2 _,
      { exact mul_pos (by linarith) (pow_pos (by linarith only [e_gt_one]) 2), },
      { linarith only [e_gt_one], },
      calc e = (1/e) * e^2 : by { rw [← mul_div_right_comm, eq_div_iff e_ne_zero], ring, }
      ... ≤ a * e^2 : mul_le_mul_of_nonneg_right (calc 1/e ≤ a : by linarith only [haa]) (pow_nonneg (calc e ≥ 0 : by linarith only [e_gt_one]) 2),
    }) (by linarith),
    rw ← h2,
    unfold xlogx,
    rw [one_div, real.log_inv],
    rw real.log_mul (calc a ≠ 0 : by linarith only [ha]) (pow_ne_zero 2 e_ne_zero),
    rw (calc real.log (e^2) = 2 : by {
      rw stupid_log_pow e_ne_zero 2,
      unfold e,
      rw real.log_exp (1 : ℝ),
      simp,
    }),
    suffices : 0 < (a + (a * e ^ 2)⁻¹) * real.log a + 2 * (a * e ^ 2)⁻¹, {
      rw add_mul at this,
      rw [← neg_mul_comm, mul_add],
      linarith,
    },
    let g := λ (x : ℝ), (x + (x * e ^ 2)⁻¹) * real.log x + 2 * (x * e ^ 2)⁻¹,
    have g_has_deriv_at : ∀ (u : ℝ), u > 0 → (has_deriv_at g ((1 - (u^2 * e^2)⁻¹) * (1 + real.log u)) u) := by {
      intros u hu,
      have d0 : u ≠ 0 := by linarith only [hu],
      have d1 := real.has_deriv_at_log d0,
      have d2 := has_deriv_at_inv d0,
      have d3 := has_deriv_at.const_mul (e^2) d2,
      sorry,
    },
    sorry,
  },
end

lemma range_of_a_times_b {a b : ℝ} (ha : a > 0) (hb : b > 0) (h1 : a ≠ b) (h2 : a ^ a = b ^ b)
: a * b < 1/e^2 :=
begin
  cases range_of_a_b ha hb h1 h2 with hh hh, {
    rw mul_comm,
    exact range_of_a_times_b_0 hb ha h1.symm h2.symm hh.2.1,
  }, {
    exact range_of_a_times_b_0 ha hb h1 h2 hh.1,
  },
end

theorem prob1 {a b t : ℝ} (ha : a > 0) (hb : b > 0) (ht : t > 0) (h1 : condition ha hb ht) (h2 : t = 4)
: 1/e + 4/e^3 < a + b ∧ a + b < 1 :=
begin
  have esq_gt_four : e^2 > 4 := calc
    e^2 > 2^2 : pow_lt_pow_of_lt_left e_gt_two (by linarith) (by linarith)
    ... = 4 : by ring,
  cases range_of_a_b_t ha hb ht h1 with hh hh, {
    unfold condition at h1,
    split, {
      calc a + b = 4*b^3 + b : by rw [h1.2.1, h2]
      ... > 1/e + 4/e^3 : by {
        have t1 : b^3 > (1/e)^3 := pow_lt_pow_of_lt_left hh.2.1 (by linarith) (by linarith),
        rw one_div_pow 3 at t1,
        have : 4*b^3 > 4*(1/e^3) := by linarith,
        have : 4*(1/e^3) = 4/e^3 := by ring,
        linarith,
      },
    }, {
      have : 1 / real.sqrt t = 1 / 2 := by {
        have : real.sqrt (2*2) = 2 := real.sqrt_mul_self (by linarith),
        ring at this,
        rw [h2, this],
      },
      linarith,
    },
  }, {
    exfalso,
    linarith,
  },
end

theorem prob2a {a b t : ℝ} (ha : a > 0) (hb : b > 0) (ht : t > 0) (h1 : condition ha hb ht)
(h2 : a + b > 2 / real.sqrt t)
: t > e^2 :=
begin
  cases range_of_a_b_t ha hb ht h1 with hh hh, {
    exfalso,
    have := calc
      a + b < 2 * b : by linarith
      ... < 2 * (1 / real.sqrt t) : by linarith
      ... = 2 / real.sqrt t : by ring,
    linarith,
  }, {
    exact hh.2.2.2.1,
  },
end

theorem prob2b {t : ℝ} (hte2 : t > e^2) : ∃ a b : ℝ,
∃ (ha : a > 0), ∃ (hb : b > 0), ∃ (ht : t > 0), (condition ha hb ht) ∧ (a + b > 2 / real.sqrt t) :=
begin
  have xlogx_surj_1 : ∀ y : ℝ, y < 0 → y > -1/e
  → ∃ x : ℝ, x > 0 ∧ x < 1/e ∧ y = xlogx x := by {
    intros y hy0 hy,
    sorry,
  },
  have xlogx_surj_2 : ∀ y : ℝ, y ≥ -1/e
  → ∃ x : ℝ, x > 1/e ∧ y = xlogx x := by {
    intros y hy,
    sorry,
  },
  sorry,
  -- intermediate_value_Icc
end

theorem prob2c {a b t a' b' t' : ℝ} (ha : a > 0) (hb : b > 0) (ht : t > 0) (h1 : condition ha hb ht)
(h2 : a + b > 2 / real.sqrt t) (ha' : a' > 0) (hb' : b' > 0) (ht' : t' > 0) (h1' : condition ha' hb' ht')
(h2' : a' + b' > 2 / real.sqrt t') (htt : t < t') : a + b < a' + b' :=
begin
  have hte2 := prob2a ha hb ht h1 h2,
  have hte2' := prob2a ha' hb' ht' h1' h2',
  have rabt : a > 1/e ∧ a < 1 ∧ b < 1/e ∧ t > e^2 ∧ b > 1 / (real.sqrt t)
    := by { cases range_of_a_b_t ha hb ht h1 with hh hh, { exfalso, linarith }, exact hh, },
  have rabt' : a' > 1/e ∧ a' < 1 ∧ b' < 1/e ∧ t' > e^2 ∧ b' > 1 / (real.sqrt t')
    := by { cases range_of_a_b_t ha' hb' ht' h1' with hh hh, { exfalso, linarith }, exact hh, },
  unfold condition at h1 h1',
  rw eq1_iff_eq2 ha hb at h1,
  rw eq1_iff_eq2 ha' hb' at h1',
  have haa : a < a' := by {
    by_contradiction,
    push_neg at h,
    by_cases aeq : a' = a, {
      have beq := by calc
        xlogx b' = xlogx a' : h1'.2.2.symm
        ... = xlogx a : by rw aeq
        ... = xlogx b : h1.2.2,
      rw ← (xlogx_inj hb' hb).2 (by linarith) (by linarith) at beq,
      rw [h1.2.1, h1'.2.1, beq] at aeq,
      have : t' = t := (mul_left_inj' (calc b^3 ≠ 0 : pow_ne_zero 3 (by linarith))).mp aeq,
      linarith,
    }, {
      rw ne.le_iff_lt aeq at h,
      have hbb := (xlogx_monotone ha' ha).1 (by linarith) h,
      rw [h1.2.2, h1'.2.2] at hbb,
      rw ← (xlogx_monotone_iff hb' hb).2 (by linarith) (by linarith) at hbb,
      have : b ^ 3 < b' ^ 3 := pow_lt_pow_of_lt_left hbb (by linarith) (by linarith),
      have := mul_lt_mul htt (calc b ^ 3 ≤ b' ^ 3 : by linarith) (pow_pos hb 3) (by linarith),
      rw [h1.2.1, h1'.2.1] at h,
      linarith,
    },
  },
  have hbb : b > b' := by {
    rw (xlogx_monotone_iff hb hb').2 (by linarith) (by linarith),
    rw [← h1.2.2, ← h1'.2.2],
    exact (xlogx_monotone ha ha').1 (by linarith) haa,
  },
  rcases xlogx_mvt ha haa with ⟨ c, ⟨ hc1, hc2, mvt ⟩ ⟩,
  rcases xlogx_mvt hb' hbb with ⟨ c', ⟨ hc1', hc2', mvt' ⟩ ⟩,
  rw [← h1.2.2, ← h1'.2.2] at mvt',
  let A := xlogx a' - xlogx a,
  have AA1 : xlogx a' - xlogx a = A := by refl,
  have AA2 : xlogx a - xlogx a' = -A := by linarith only [AA1],
  have Apos : A > 0 := by linarith[(xlogx_monotone ha ha').1 (by linarith) haa],
  have logc : real.log c > -1 := by {
    rw ← log_einv_eq_minus_one,
    exact real.log_lt_log (one_div_pos.mpr (1 : ℝ).exp_pos) (calc c > 1/e : by linarith),
  },
  have logc' : real.log c' < -1 := by {
    rw ← log_einv_eq_minus_one,
    exact real.log_lt_log (by linarith) (calc c' < 1/e : by linarith),
  },
  have logcB : 1 + real.log c ≠ 0 := by linarith only [logc],
  have logcB' : 1 + real.log c' ≠ 0 := by linarith only [logc'],
  rw [
    AA1, eq_div_iff (calc a' - a ≠ 0 : by linarith only [haa]),
    mul_comm, ← eq_div_iff logcB] at mvt,
  rw [
    AA2, eq_div_iff (calc b - b' ≠ 0 : by linarith only [hbb]),
    mul_comm, ← eq_div_iff logcB'] at mvt',
  have key := calc
    (a' + b') - (a + b) = (a' - a) - (b - b') : by ring
    ... = A / (1 + real.log c) + A / (1 + real.log c') : by { rw [mvt, mvt'], ring }
    ... = (A * (1 + real.log c') + (1 + real.log c) * A) / ((1 + real.log c) * (1 + real.log c')) : div_add_div A A logcB logcB'
    ... = (A * (2 + real.log c + real.log c')) / ((1 + real.log c) * (1 + real.log c')) : by { congr, ring, }
    ... > 0 : by {
      have d1 : (1 + real.log c) * (1 + real.log c') < 0 := mul_neg_of_pos_of_neg (by linarith only [logc]) (by linarith only [logc']),
      have d2 : 2 + real.log c + real.log c' < 0 := by sorry, -- incorrect !!!
      have d3 : A * (2 + real.log c + real.log c') < 0 := mul_neg_of_pos_of_neg Apos d2,
      change 0 < (A * (2 + real.log c + real.log c')) / ((1 + real.log c) * (1 + real.log c')),
      rw div_pos_iff, right, exact ⟨ d3, d1 ⟩,
    },
  linarith only [key],
end