/-
Copyright (c) 2018 Johan Commelin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johan Commelin

! This file was ported from Lean 3 source module deprecated.subring
! leanprover-community/mathlib commit 23aa88e32dcc9d2a24cca7bc23268567ed4cd7d6
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Deprecated.Subgroup
import Mathbin.Deprecated.Group
import Mathbin.RingTheory.Subring.Basic

/-!
# Unbundled subrings (deprecated)

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

This file is deprecated, and is no longer imported by anything in mathlib other than other
deprecated files, and test files. You should not need to import it.

This file defines predicates for unbundled subrings. Instead of using this file, please use
`subring`, defined in `ring_theory.subring.basic`, for subrings of rings.

## Main definitions

`is_subring (S : set R) : Prop` : the predicate that `S` is the underlying set of a subring
of the ring `R`. The bundled variant `subring R` should be used in preference to this.

## Tags

is_subring
-/

universe u v

open Group

variable {R : Type u} [Ring R]

#print IsSubring /-
/-- `S` is a subring: a set containing 1 and closed under multiplication, addition and additive
inverse. -/
structure IsSubring (S : Set R) extends IsAddSubgroup S, IsSubmonoid S : Prop
#align is_subring IsSubring
-/

#print IsSubring.subring /-
/-- Construct a `subring` from a set satisfying `is_subring`. -/
def IsSubring.subring {S : Set R} (hs : IsSubring S) : Subring R
    where
  carrier := S
  one_mem' := hs.one_mem
  mul_mem' _ _ := hs.mul_mem
  zero_mem' := hs.zero_mem
  add_mem' _ _ := hs.add_mem
  neg_mem' _ := hs.neg_mem
#align is_subring.subring IsSubring.subring
-/

namespace RingHom

/- warning: ring_hom.is_subring_preimage -> RingHom.isSubring_preimage is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_2 : Ring.{u1} R] [_inst_3 : Ring.{u2} S] (f : RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) {s : Set.{u2} S}, (IsSubring.{u2} S _inst_3 s) -> (IsSubring.{u1} R _inst_2 (Set.preimage.{u1, u2} R S (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) (fun (_x : RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) => R -> S) (RingHom.hasCoeToFun.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) f) s))
but is expected to have type
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_2 : Ring.{u1} R] [_inst_3 : Ring.{u2} S] (f : RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) {s : Set.{u2} S}, (IsSubring.{u2} S _inst_3 s) -> (IsSubring.{u1} R _inst_2 (Set.preimage.{u1, u2} R S (FunLike.coe.{max (succ u1) (succ u2), succ u1, succ u2} (RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) R (fun (_x : R) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => S) _x) (MulHomClass.toFunLike.{max u1 u2, u1, u2} (RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) R S (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)))) (NonUnitalNonAssocSemiring.toMul.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3)))) (NonUnitalRingHomClass.toMulHomClass.{max u1 u2, u1, u2} (RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) R S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) (RingHomClass.toNonUnitalRingHomClass.{max u1 u2, u1, u2} (RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3)) (RingHom.instRingHomClassRingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3)))))) f) s))
Case conversion may be inaccurate. Consider using '#align ring_hom.is_subring_preimage RingHom.isSubring_preimageₓ'. -/
theorem isSubring_preimage {R : Type u} {S : Type v} [Ring R] [Ring S] (f : R →+* S) {s : Set S}
    (hs : IsSubring s) : IsSubring (f ⁻¹' s) :=
  { IsAddGroupHom.preimage f.to_isAddGroupHom hs.to_isAddSubgroup,
    IsSubmonoid.preimage f.to_isMonoidHom hs.to_isSubmonoid with }
#align ring_hom.is_subring_preimage RingHom.isSubring_preimage

/- warning: ring_hom.is_subring_image -> RingHom.isSubring_image is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_2 : Ring.{u1} R] [_inst_3 : Ring.{u2} S] (f : RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) {s : Set.{u1} R}, (IsSubring.{u1} R _inst_2 s) -> (IsSubring.{u2} S _inst_3 (Set.image.{u1, u2} R S (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) (fun (_x : RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) => R -> S) (RingHom.hasCoeToFun.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) f) s))
but is expected to have type
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_2 : Ring.{u1} R] [_inst_3 : Ring.{u2} S] (f : RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) {s : Set.{u1} R}, (IsSubring.{u1} R _inst_2 s) -> (IsSubring.{u2} S _inst_3 (Set.image.{u1, u2} R S (FunLike.coe.{max (succ u1) (succ u2), succ u1, succ u2} (RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) R (fun (_x : R) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => S) _x) (MulHomClass.toFunLike.{max u1 u2, u1, u2} (RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) R S (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)))) (NonUnitalNonAssocSemiring.toMul.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3)))) (NonUnitalRingHomClass.toMulHomClass.{max u1 u2, u1, u2} (RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) R S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) (RingHomClass.toNonUnitalRingHomClass.{max u1 u2, u1, u2} (RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3)) (RingHom.instRingHomClassRingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3)))))) f) s))
Case conversion may be inaccurate. Consider using '#align ring_hom.is_subring_image RingHom.isSubring_imageₓ'. -/
theorem isSubring_image {R : Type u} {S : Type v} [Ring R] [Ring S] (f : R →+* S) {s : Set R}
    (hs : IsSubring s) : IsSubring (f '' s) :=
  { IsAddGroupHom.image_addSubgroup f.to_isAddGroupHom hs.to_isAddSubgroup,
    IsSubmonoid.image f.to_isMonoidHom hs.to_isSubmonoid with }
#align ring_hom.is_subring_image RingHom.isSubring_image

/- warning: ring_hom.is_subring_set_range -> RingHom.isSubring_set_range is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_2 : Ring.{u1} R] [_inst_3 : Ring.{u2} S] (f : RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))), IsSubring.{u2} S _inst_3 (Set.range.{u2, succ u1} S R (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) (fun (_x : RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) => R -> S) (RingHom.hasCoeToFun.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) f))
but is expected to have type
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_2 : Ring.{u1} R] [_inst_3 : Ring.{u2} S] (f : RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))), IsSubring.{u2} S _inst_3 (Set.range.{u2, succ u1} S R (FunLike.coe.{max (succ u1) (succ u2), succ u1, succ u2} (RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) R (fun (_x : R) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => S) _x) (MulHomClass.toFunLike.{max u1 u2, u1, u2} (RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) R S (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)))) (NonUnitalNonAssocSemiring.toMul.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3)))) (NonUnitalRingHomClass.toMulHomClass.{max u1 u2, u1, u2} (RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) R S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) (RingHomClass.toNonUnitalRingHomClass.{max u1 u2, u1, u2} (RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3)) (RingHom.instRingHomClassRingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_2)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3)))))) f))
Case conversion may be inaccurate. Consider using '#align ring_hom.is_subring_set_range RingHom.isSubring_set_rangeₓ'. -/
theorem isSubring_set_range {R : Type u} {S : Type v} [Ring R] [Ring S] (f : R →+* S) :
    IsSubring (Set.range f) :=
  { IsAddGroupHom.range_addSubgroup f.to_isAddGroupHom, Range.isSubmonoid f.to_isMonoidHom with }
#align ring_hom.is_subring_set_range RingHom.isSubring_set_range

end RingHom

variable {cR : Type u} [CommRing cR]

/- warning: is_subring.inter -> IsSubring.inter is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : Ring.{u1} R] {S₁ : Set.{u1} R} {S₂ : Set.{u1} R}, (IsSubring.{u1} R _inst_1 S₁) -> (IsSubring.{u1} R _inst_1 S₂) -> (IsSubring.{u1} R _inst_1 (Inter.inter.{u1} (Set.{u1} R) (Set.hasInter.{u1} R) S₁ S₂))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : Ring.{u1} R] {S₁ : Set.{u1} R} {S₂ : Set.{u1} R}, (IsSubring.{u1} R _inst_1 S₁) -> (IsSubring.{u1} R _inst_1 S₂) -> (IsSubring.{u1} R _inst_1 (Inter.inter.{u1} (Set.{u1} R) (Set.instInterSet.{u1} R) S₁ S₂))
Case conversion may be inaccurate. Consider using '#align is_subring.inter IsSubring.interₓ'. -/
theorem IsSubring.inter {S₁ S₂ : Set R} (hS₁ : IsSubring S₁) (hS₂ : IsSubring S₂) :
    IsSubring (S₁ ∩ S₂) :=
  { IsAddSubgroup.inter hS₁.to_isAddSubgroup hS₂.to_isAddSubgroup,
    IsSubmonoid.inter hS₁.to_isSubmonoid hS₂.to_isSubmonoid with }
#align is_subring.inter IsSubring.inter

/- warning: is_subring.Inter -> IsSubring.interᵢ is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : Ring.{u1} R] {ι : Sort.{u2}} {S : ι -> (Set.{u1} R)}, (forall (y : ι), IsSubring.{u1} R _inst_1 (S y)) -> (IsSubring.{u1} R _inst_1 (Set.interᵢ.{u1, u2} R ι S))
but is expected to have type
  forall {R : Type.{u2}} [_inst_1 : Ring.{u2} R] {ι : Sort.{u1}} {S : ι -> (Set.{u2} R)}, (forall (y : ι), IsSubring.{u2} R _inst_1 (S y)) -> (IsSubring.{u2} R _inst_1 (Set.interᵢ.{u2, u1} R ι S))
Case conversion may be inaccurate. Consider using '#align is_subring.Inter IsSubring.interᵢₓ'. -/
theorem IsSubring.interᵢ {ι : Sort _} {S : ι → Set R} (h : ∀ y : ι, IsSubring (S y)) :
    IsSubring (Set.interᵢ S) :=
  { IsAddSubgroup.interᵢ fun i => (h i).to_isAddSubgroup,
    IsSubmonoid.interᵢ fun i => (h i).to_isSubmonoid with }
#align is_subring.Inter IsSubring.interᵢ

/- warning: is_subring_Union_of_directed -> isSubring_unionᵢ_of_directed is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : Ring.{u1} R] {ι : Type.{u2}} [hι : Nonempty.{succ u2} ι] {s : ι -> (Set.{u1} R)}, (forall (i : ι), IsSubring.{u1} R _inst_1 (s i)) -> (forall (i : ι) (j : ι), Exists.{succ u2} ι (fun (k : ι) => And (HasSubset.Subset.{u1} (Set.{u1} R) (Set.hasSubset.{u1} R) (s i) (s k)) (HasSubset.Subset.{u1} (Set.{u1} R) (Set.hasSubset.{u1} R) (s j) (s k)))) -> (IsSubring.{u1} R _inst_1 (Set.unionᵢ.{u1, succ u2} R ι (fun (i : ι) => s i)))
but is expected to have type
  forall {R : Type.{u2}} [_inst_1 : Ring.{u2} R] {ι : Type.{u1}} [hι : Nonempty.{succ u1} ι] {s : ι -> (Set.{u2} R)}, (forall (i : ι), IsSubring.{u2} R _inst_1 (s i)) -> (forall (i : ι) (j : ι), Exists.{succ u1} ι (fun (k : ι) => And (HasSubset.Subset.{u2} (Set.{u2} R) (Set.instHasSubsetSet.{u2} R) (s i) (s k)) (HasSubset.Subset.{u2} (Set.{u2} R) (Set.instHasSubsetSet.{u2} R) (s j) (s k)))) -> (IsSubring.{u2} R _inst_1 (Set.unionᵢ.{u2, succ u1} R ι (fun (i : ι) => s i)))
Case conversion may be inaccurate. Consider using '#align is_subring_Union_of_directed isSubring_unionᵢ_of_directedₓ'. -/
theorem isSubring_unionᵢ_of_directed {ι : Type _} [hι : Nonempty ι] {s : ι → Set R}
    (h : ∀ i, IsSubring (s i)) (directed : ∀ i j, ∃ k, s i ⊆ s k ∧ s j ⊆ s k) :
    IsSubring (⋃ i, s i) :=
  { to_isAddSubgroup := isAddSubgroup_unionᵢ_of_directed (fun i => (h i).to_isAddSubgroup) Directed
    to_isSubmonoid := isSubmonoid_unionᵢ_of_directed (fun i => (h i).to_isSubmonoid) Directed }
#align is_subring_Union_of_directed isSubring_unionᵢ_of_directed

namespace Ring

#print Ring.closure /-
/-- The smallest subring containing a given subset of a ring, considered as a set. This function
is deprecated; use `subring.closure`. -/
def closure (s : Set R) :=
  AddGroup.closure (Monoid.Closure s)
#align ring.closure Ring.closure
-/

variable {s : Set R}

attribute [local reducible] closure

/- warning: ring.exists_list_of_mem_closure -> Ring.exists_list_of_mem_closure is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : Ring.{u1} R] {s : Set.{u1} R} {a : R}, (Membership.Mem.{u1, u1} R (Set.{u1} R) (Set.hasMem.{u1} R) a (Ring.closure.{u1} R _inst_1 s)) -> (Exists.{succ u1} (List.{u1} (List.{u1} R)) (fun (L : List.{u1} (List.{u1} R)) => And (forall (l : List.{u1} R), (Membership.Mem.{u1, u1} (List.{u1} R) (List.{u1} (List.{u1} R)) (List.hasMem.{u1} (List.{u1} R)) l L) -> (forall (x : R), (Membership.Mem.{u1, u1} R (List.{u1} R) (List.hasMem.{u1} R) x l) -> (Or (Membership.Mem.{u1, u1} R (Set.{u1} R) (Set.hasMem.{u1} R) x s) (Eq.{succ u1} R x (Neg.neg.{u1} R (SubNegMonoid.toHasNeg.{u1} R (AddGroup.toSubNegMonoid.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))))) (OfNat.ofNat.{u1} R 1 (OfNat.mk.{u1} R 1 (One.one.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1)))))))))))) (Eq.{succ u1} R (List.sum.{u1} R (Distrib.toHasAdd.{u1} R (Ring.toDistrib.{u1} R _inst_1)) (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))) (List.map.{u1, u1} (List.{u1} R) R (List.prod.{u1} R (Distrib.toHasMul.{u1} R (Ring.toDistrib.{u1} R _inst_1)) (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))))) L)) a)))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : Ring.{u1} R] {s : Set.{u1} R} {a : R}, (Membership.mem.{u1, u1} R (Set.{u1} R) (Set.instMembershipSet.{u1} R) a (Ring.closure.{u1} R _inst_1 s)) -> (Exists.{succ u1} (List.{u1} (List.{u1} R)) (fun (L : List.{u1} (List.{u1} R)) => And (forall (l : List.{u1} R), (Membership.mem.{u1, u1} (List.{u1} R) (List.{u1} (List.{u1} R)) (List.instMembershipList.{u1} (List.{u1} R)) l L) -> (forall (x : R), (Membership.mem.{u1, u1} R (List.{u1} R) (List.instMembershipList.{u1} R) x l) -> (Or (Membership.mem.{u1, u1} R (Set.{u1} R) (Set.instMembershipSet.{u1} R) x s) (Eq.{succ u1} R x (Neg.neg.{u1} R (Ring.toNeg.{u1} R _inst_1) (OfNat.ofNat.{u1} R 1 (One.toOfNat1.{u1} R (NonAssocRing.toOne.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))))))) (Eq.{succ u1} R (List.sum.{u1} R (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))) (MonoidWithZero.toZero.{u1} R (Semiring.toMonoidWithZero.{u1} R (Ring.toSemiring.{u1} R _inst_1))) (List.map.{u1, u1} (List.{u1} R) R (List.prod.{u1} R (NonUnitalNonAssocRing.toMul.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))) (NonAssocRing.toOne.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))) L)) a)))
Case conversion may be inaccurate. Consider using '#align ring.exists_list_of_mem_closure Ring.exists_list_of_mem_closureₓ'. -/
theorem exists_list_of_mem_closure {a : R} (h : a ∈ closure s) :
    ∃ L : List (List R), (∀ l ∈ L, ∀ x ∈ l, x ∈ s ∨ x = (-1 : R)) ∧ (L.map List.prod).Sum = a :=
  AddGroup.InClosure.rec_on h
    (fun x hx =>
      match x, Monoid.exists_list_of_mem_closure hx with
      | _, ⟨L, h1, rfl⟩ =>
        ⟨[L], List.forall_mem_singleton.2 fun r hr => Or.inl (h1 r hr), zero_add _⟩)
    ⟨[], List.forall_mem_nil _, rfl⟩
    (fun b _ ih =>
      match b, ih with
      | _, ⟨L1, h1, rfl⟩ =>
        ⟨L1.map (List.cons (-1)), fun L2 h2 =>
          match L2, List.mem_map.1 h2 with
          | _, ⟨L3, h3, rfl⟩ => List.forall_mem_cons.2 ⟨Or.inr rfl, h1 L3 h3⟩,
          by
          simp only [List.map_map, (· ∘ ·), List.prod_cons, neg_one_mul] <;>
            exact
              List.recOn L1 neg_zero.symm fun hd tl ih => by
                rw [List.map_cons, List.sum_cons, ih, List.map_cons, List.sum_cons, neg_add]⟩)
    fun r1 r2 hr1 hr2 ih1 ih2 =>
    match r1, r2, ih1, ih2 with
    | _, _, ⟨L1, h1, rfl⟩, ⟨L2, h2, rfl⟩ =>
      ⟨L1 ++ L2, List.forall_mem_append.2 ⟨h1, h2⟩, by rw [List.map_append, List.sum_append]⟩
#align ring.exists_list_of_mem_closure Ring.exists_list_of_mem_closure

/- warning: ring.in_closure.rec_on -> Ring.InClosure.recOn is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : Ring.{u1} R] {s : Set.{u1} R} {C : R -> Prop} {x : R}, (Membership.Mem.{u1, u1} R (Set.{u1} R) (Set.hasMem.{u1} R) x (Ring.closure.{u1} R _inst_1 s)) -> (C (OfNat.ofNat.{u1} R 1 (OfNat.mk.{u1} R 1 (One.one.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1)))))))) -> (C (Neg.neg.{u1} R (SubNegMonoid.toHasNeg.{u1} R (AddGroup.toSubNegMonoid.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))))) (OfNat.ofNat.{u1} R 1 (OfNat.mk.{u1} R 1 (One.one.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))))))))) -> (forall (z : R), (Membership.Mem.{u1, u1} R (Set.{u1} R) (Set.hasMem.{u1} R) z s) -> (forall (n : R), (C n) -> (C (HMul.hMul.{u1, u1, u1} R R R (instHMul.{u1} R (Distrib.toHasMul.{u1} R (Ring.toDistrib.{u1} R _inst_1))) z n)))) -> (forall {x : R} {y : R}, (C x) -> (C y) -> (C (HAdd.hAdd.{u1, u1, u1} R R R (instHAdd.{u1} R (Distrib.toHasAdd.{u1} R (Ring.toDistrib.{u1} R _inst_1))) x y))) -> (C x)
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : Ring.{u1} R] {s : Set.{u1} R} {C : R -> Prop} {x : R}, (Membership.mem.{u1, u1} R (Set.{u1} R) (Set.instMembershipSet.{u1} R) x (Ring.closure.{u1} R _inst_1 s)) -> (C (OfNat.ofNat.{u1} R 1 (One.toOfNat1.{u1} R (NonAssocRing.toOne.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))) -> (C (Neg.neg.{u1} R (Ring.toNeg.{u1} R _inst_1) (OfNat.ofNat.{u1} R 1 (One.toOfNat1.{u1} R (NonAssocRing.toOne.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)))))) -> (forall (z : R), (Membership.mem.{u1, u1} R (Set.{u1} R) (Set.instMembershipSet.{u1} R) z s) -> (forall (n : R), (C n) -> (C (HMul.hMul.{u1, u1, u1} R R R (instHMul.{u1} R (NonUnitalNonAssocRing.toMul.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)))) z n)))) -> (forall {x : R} {y : R}, (C x) -> (C y) -> (C (HAdd.hAdd.{u1, u1, u1} R R R (instHAdd.{u1} R (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)))))) x y))) -> (C x)
Case conversion may be inaccurate. Consider using '#align ring.in_closure.rec_on Ring.InClosure.recOnₓ'. -/
/- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/
/- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/
@[elab_as_elim]
protected theorem InClosure.recOn {C : R → Prop} {x : R} (hx : x ∈ closure s) (h1 : C 1)
    (hneg1 : C (-1)) (hs : ∀ z ∈ s, ∀ n, C n → C (z * n)) (ha : ∀ {x y}, C x → C y → C (x + y)) :
    C x := by
  have h0 : C 0 := add_neg_self (1 : R) ▸ ha h1 hneg1
  rcases exists_list_of_mem_closure hx with ⟨L, HL, rfl⟩
  clear hx
  induction' L with hd tl ih
  · exact h0
  rw [List.forall_mem_cons] at HL
  suffices C (List.prod hd) by
    rw [List.map_cons, List.sum_cons]
    exact ha this (ih HL.2)
  replace HL := HL.1
  clear ih tl
  rsuffices ⟨L, HL', HP | HP⟩ :
    ∃ L : List R, (∀ x ∈ L, x ∈ s) ∧ (List.prod hd = List.prod L ∨ List.prod hd = -List.prod L)
  · rw [HP]
    clear HP HL hd
    induction' L with hd tl ih
    · exact h1
    rw [List.forall_mem_cons] at HL'
    rw [List.prod_cons]
    exact hs _ HL'.1 _ (ih HL'.2)
  · rw [HP]
    clear HP HL hd
    induction' L with hd tl ih
    · exact hneg1
    rw [List.prod_cons, neg_mul_eq_mul_neg]
    rw [List.forall_mem_cons] at HL'
    exact hs _ HL'.1 _ (ih HL'.2)
  induction' hd with hd tl ih
  · exact ⟨[], List.forall_mem_nil _, Or.inl rfl⟩
  rw [List.forall_mem_cons] at HL
  rcases ih HL.2 with ⟨L, HL', HP | HP⟩ <;> cases' HL.1 with hhd hhd
  ·
    exact
      ⟨hd::L, List.forall_mem_cons.2 ⟨hhd, HL'⟩,
        Or.inl <| by rw [List.prod_cons, List.prod_cons, HP]⟩
  · exact ⟨L, HL', Or.inr <| by rw [List.prod_cons, hhd, neg_one_mul, HP]⟩
  ·
    exact
      ⟨hd::L, List.forall_mem_cons.2 ⟨hhd, HL'⟩,
        Or.inr <| by rw [List.prod_cons, List.prod_cons, HP, neg_mul_eq_mul_neg]⟩
  · exact ⟨L, HL', Or.inl <| by rw [List.prod_cons, hhd, HP, neg_one_mul, neg_neg]⟩
#align ring.in_closure.rec_on Ring.InClosure.recOn

#print Ring.closure.isSubring /-
theorem closure.isSubring : IsSubring (closure s) :=
  {
    AddGroup.closure.isAddSubgroup
      _ with
    one_mem := AddGroup.mem_closure <| IsSubmonoid.one_mem <| Monoid.closure.isSubmonoid _
    mul_mem := fun a b ha hb =>
      AddGroup.InClosure.rec_on hb
        (fun c hc =>
          AddGroup.InClosure.rec_on ha
            (fun d hd => AddGroup.subset_closure ((Monoid.closure.isSubmonoid _).mul_mem hd hc))
            ((MulZeroClass.zero_mul c).symm ▸ (AddGroup.closure.isAddSubgroup _).zero_mem)
            (fun d hd hdc =>
              neg_mul_eq_neg_mul d c ▸ (AddGroup.closure.isAddSubgroup _).neg_mem hdc)
            fun d e hd he hdc hec =>
            (add_mul d e c).symm ▸ (AddGroup.closure.isAddSubgroup _).add_mem hdc hec)
        ((MulZeroClass.mul_zero a).symm ▸ (AddGroup.closure.isAddSubgroup _).zero_mem)
        (fun c hc hac => neg_mul_eq_mul_neg a c ▸ (AddGroup.closure.isAddSubgroup _).neg_mem hac)
        fun c d hc hd hac had =>
        (mul_add a c d).symm ▸ (AddGroup.closure.isAddSubgroup _).add_mem hac had }
#align ring.closure.is_subring Ring.closure.isSubring
-/

#print Ring.mem_closure /-
theorem mem_closure {a : R} : a ∈ s → a ∈ closure s :=
  AddGroup.mem_closure ∘ @Monoid.subset_closure _ _ _ _
#align ring.mem_closure Ring.mem_closure
-/

#print Ring.subset_closure /-
theorem subset_closure : s ⊆ closure s := fun _ => mem_closure
#align ring.subset_closure Ring.subset_closure
-/

#print Ring.closure_subset /-
theorem closure_subset {t : Set R} (ht : IsSubring t) : s ⊆ t → closure s ⊆ t :=
  AddGroup.closure_subset ht.to_isAddSubgroup ∘ Monoid.closure_subset ht.to_isSubmonoid
#align ring.closure_subset Ring.closure_subset
-/

#print Ring.closure_subset_iff /-
theorem closure_subset_iff {s t : Set R} (ht : IsSubring t) : closure s ⊆ t ↔ s ⊆ t :=
  (AddGroup.closure_subset_iff ht.to_isAddSubgroup).trans
    ⟨Set.Subset.trans Monoid.subset_closure, Monoid.closure_subset ht.to_isSubmonoid⟩
#align ring.closure_subset_iff Ring.closure_subset_iff
-/

#print Ring.closure_mono /-
theorem closure_mono {s t : Set R} (H : s ⊆ t) : closure s ⊆ closure t :=
  closure_subset closure.isSubring <| Set.Subset.trans H subset_closure
#align ring.closure_mono Ring.closure_mono
-/

/- warning: ring.image_closure -> Ring.image_closure is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : Ring.{u1} R] {S : Type.{u2}} [_inst_3 : Ring.{u2} S] (f : RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) (s : Set.{u1} R), Eq.{succ u2} (Set.{u2} S) (Set.image.{u1, u2} R S (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) (fun (_x : RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) => R -> S) (RingHom.hasCoeToFun.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) f) (Ring.closure.{u1} R _inst_1 s)) (Ring.closure.{u2} S _inst_3 (Set.image.{u1, u2} R S (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) (fun (_x : RingHom.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) => R -> S) (RingHom.hasCoeToFun.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_3))) f) s))
but is expected to have type
  forall {R : Type.{u2}} [_inst_1 : Ring.{u2} R] {S : Type.{u1}} [_inst_3 : Ring.{u1} S] (f : RingHom.{u2, u1} R S (NonAssocRing.toNonAssocSemiring.{u2} R (Ring.toNonAssocRing.{u2} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u1} S (Ring.toNonAssocRing.{u1} S _inst_3))) (s : Set.{u2} R), Eq.{succ u1} (Set.{u1} S) (Set.image.{u2, u1} R S (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (RingHom.{u2, u1} R S (NonAssocRing.toNonAssocSemiring.{u2} R (Ring.toNonAssocRing.{u2} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u1} S (Ring.toNonAssocRing.{u1} S _inst_3))) R (fun (_x : R) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => S) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (RingHom.{u2, u1} R S (NonAssocRing.toNonAssocSemiring.{u2} R (Ring.toNonAssocRing.{u2} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u1} S (Ring.toNonAssocRing.{u1} S _inst_3))) R S (NonUnitalNonAssocSemiring.toMul.{u2} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} R (NonAssocRing.toNonAssocSemiring.{u2} R (Ring.toNonAssocRing.{u2} R _inst_1)))) (NonUnitalNonAssocSemiring.toMul.{u1} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} S (NonAssocRing.toNonAssocSemiring.{u1} S (Ring.toNonAssocRing.{u1} S _inst_3)))) (NonUnitalRingHomClass.toMulHomClass.{max u2 u1, u2, u1} (RingHom.{u2, u1} R S (NonAssocRing.toNonAssocSemiring.{u2} R (Ring.toNonAssocRing.{u2} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u1} S (Ring.toNonAssocRing.{u1} S _inst_3))) R S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} R (NonAssocRing.toNonAssocSemiring.{u2} R (Ring.toNonAssocRing.{u2} R _inst_1))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} S (NonAssocRing.toNonAssocSemiring.{u1} S (Ring.toNonAssocRing.{u1} S _inst_3))) (RingHomClass.toNonUnitalRingHomClass.{max u2 u1, u2, u1} (RingHom.{u2, u1} R S (NonAssocRing.toNonAssocSemiring.{u2} R (Ring.toNonAssocRing.{u2} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u1} S (Ring.toNonAssocRing.{u1} S _inst_3))) R S (NonAssocRing.toNonAssocSemiring.{u2} R (Ring.toNonAssocRing.{u2} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u1} S (Ring.toNonAssocRing.{u1} S _inst_3)) (RingHom.instRingHomClassRingHom.{u2, u1} R S (NonAssocRing.toNonAssocSemiring.{u2} R (Ring.toNonAssocRing.{u2} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u1} S (Ring.toNonAssocRing.{u1} S _inst_3)))))) f) (Ring.closure.{u2} R _inst_1 s)) (Ring.closure.{u1} S _inst_3 (Set.image.{u2, u1} R S (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (RingHom.{u2, u1} R S (NonAssocRing.toNonAssocSemiring.{u2} R (Ring.toNonAssocRing.{u2} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u1} S (Ring.toNonAssocRing.{u1} S _inst_3))) R (fun (_x : R) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => S) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (RingHom.{u2, u1} R S (NonAssocRing.toNonAssocSemiring.{u2} R (Ring.toNonAssocRing.{u2} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u1} S (Ring.toNonAssocRing.{u1} S _inst_3))) R S (NonUnitalNonAssocSemiring.toMul.{u2} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} R (NonAssocRing.toNonAssocSemiring.{u2} R (Ring.toNonAssocRing.{u2} R _inst_1)))) (NonUnitalNonAssocSemiring.toMul.{u1} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} S (NonAssocRing.toNonAssocSemiring.{u1} S (Ring.toNonAssocRing.{u1} S _inst_3)))) (NonUnitalRingHomClass.toMulHomClass.{max u2 u1, u2, u1} (RingHom.{u2, u1} R S (NonAssocRing.toNonAssocSemiring.{u2} R (Ring.toNonAssocRing.{u2} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u1} S (Ring.toNonAssocRing.{u1} S _inst_3))) R S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} R (NonAssocRing.toNonAssocSemiring.{u2} R (Ring.toNonAssocRing.{u2} R _inst_1))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} S (NonAssocRing.toNonAssocSemiring.{u1} S (Ring.toNonAssocRing.{u1} S _inst_3))) (RingHomClass.toNonUnitalRingHomClass.{max u2 u1, u2, u1} (RingHom.{u2, u1} R S (NonAssocRing.toNonAssocSemiring.{u2} R (Ring.toNonAssocRing.{u2} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u1} S (Ring.toNonAssocRing.{u1} S _inst_3))) R S (NonAssocRing.toNonAssocSemiring.{u2} R (Ring.toNonAssocRing.{u2} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u1} S (Ring.toNonAssocRing.{u1} S _inst_3)) (RingHom.instRingHomClassRingHom.{u2, u1} R S (NonAssocRing.toNonAssocSemiring.{u2} R (Ring.toNonAssocRing.{u2} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u1} S (Ring.toNonAssocRing.{u1} S _inst_3)))))) f) s))
Case conversion may be inaccurate. Consider using '#align ring.image_closure Ring.image_closureₓ'. -/
theorem image_closure {S : Type _} [Ring S] (f : R →+* S) (s : Set R) :
    f '' closure s = closure (f '' s) :=
  le_antisymm
    (by
      rintro _ ⟨x, hx, rfl⟩
      apply in_closure.rec_on hx <;> intros
      · rw [f.map_one]
        apply closure.is_subring.to_is_submonoid.one_mem
      · rw [f.map_neg, f.map_one]
        apply closure.is_subring.to_is_add_subgroup.neg_mem
        apply closure.is_subring.to_is_submonoid.one_mem
      · rw [f.map_mul]
        apply closure.is_subring.to_is_submonoid.mul_mem <;>
          solve_by_elim [subset_closure, Set.mem_image_of_mem]
      · rw [f.map_add]
        apply closure.is_subring.to_is_add_submonoid.add_mem
        assumption')
    (closure_subset (RingHom.isSubring_image _ closure.isSubring) <|
      Set.image_subset _ subset_closure)
#align ring.image_closure Ring.image_closure

end Ring


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

Computational realization of filters (experimental).
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.order.filter.cofinite
import Mathlib.PostPort

universes u_1 u_2 l u_3 u_4 u_5

namespace Mathlib

/-- A `cfilter α σ` is a realization of a filter (base) on `α`,
  represented by a type `σ` together with operations for the top element and
  the binary inf operation. -/
structure cfilter (α : Type u_1) (σ : Type u_2) [partial_order α] where
  f : σ → α
  pt : σ
  inf : σ → σ → σ
  inf_le_left : ∀ (a b : σ), f (inf a b) ≤ f a
  inf_le_right : ∀ (a b : σ), f (inf a b) ≤ f b

namespace cfilter

protected instance has_coe_to_fun {α : Type u_1} {σ : Type u_3} [partial_order α] :
    has_coe_to_fun (cfilter α σ) :=
  has_coe_to_fun.mk (fun (x : cfilter α σ) => σ → α) f

@[simp] theorem coe_mk {α : Type u_1} {σ : Type u_3} [partial_order α] (f : σ → α) (pt : σ)
    (inf : σ → σ → σ) (h₁ : ∀ (a b : σ), f (inf a b) ≤ f a) (h₂ : ∀ (a b : σ), f (inf a b) ≤ f b)
    (a : σ) : coe_fn (mk f pt inf h₁ h₂) a = f a :=
  rfl

/-- Map a cfilter to an equivalent representation type. -/
def of_equiv {α : Type u_1} {σ : Type u_3} {τ : Type u_4} [partial_order α] (E : σ ≃ τ) :
    cfilter α σ → cfilter α τ :=
  sorry

@[simp] theorem of_equiv_val {α : Type u_1} {σ : Type u_3} {τ : Type u_4} [partial_order α]
    (E : σ ≃ τ) (F : cfilter α σ) (a : τ) :
    coe_fn (of_equiv E F) a = coe_fn F (coe_fn (equiv.symm E) a) :=
  sorry

/-- The filter represented by a `cfilter` is the collection of supersets of
  elements of the filter base. -/
def to_filter {α : Type u_1} {σ : Type u_3} (F : cfilter (set α) σ) : filter α :=
  filter.mk (set_of fun (a : set α) => ∃ (b : σ), coe_fn F b ⊆ a) sorry sorry sorry

@[simp] theorem mem_to_filter_sets {α : Type u_1} {σ : Type u_3} (F : cfilter (set α) σ)
    {a : set α} : a ∈ to_filter F ↔ ∃ (b : σ), coe_fn F b ⊆ a :=
  iff.rfl

end cfilter

/-- A realizer for filter `f` is a cfilter which generates `f`. -/
structure filter.realizer {α : Type u_1} (f : filter α) where
  σ : Type u_5
  F : cfilter (set α) σ
  eq : cfilter.to_filter F = f

protected def cfilter.to_realizer {α : Type u_1} {σ : Type u_3} (F : cfilter (set α) σ) :
    filter.realizer (cfilter.to_filter F) :=
  filter.realizer.mk σ F sorry

namespace filter.realizer

theorem mem_sets {α : Type u_1} {f : filter α} (F : realizer f) {a : set α} :
    a ∈ f ↔ ∃ (b : σ F), coe_fn (F F) b ⊆ a :=
  sorry

-- Used because it has better definitional equalities than the eq.rec proof

def of_eq {α : Type u_1} {f : filter α} {g : filter α} (e : f = g) (F : realizer f) : realizer g :=
  mk (σ F) (F F) sorry

/-- A filter realizes itself. -/
def of_filter {α : Type u_1} (f : filter α) : realizer f :=
  mk (↥(sets f))
    (cfilter.mk subtype.val { val := set.univ, property := univ_mem_sets }
      (fun (_x : ↥(sets f)) => sorry) sorry sorry)
    sorry

/-- Transfer a filter realizer to another realizer on a different base type. -/
def of_equiv {α : Type u_1} {τ : Type u_4} {f : filter α} (F : realizer f) (E : σ F ≃ τ) :
    realizer f :=
  mk τ (cfilter.of_equiv E (F F)) sorry

@[simp] theorem of_equiv_σ {α : Type u_1} {τ : Type u_4} {f : filter α} (F : realizer f)
    (E : σ F ≃ τ) : σ (of_equiv F E) = τ :=
  rfl

@[simp] theorem of_equiv_F {α : Type u_1} {τ : Type u_4} {f : filter α} (F : realizer f)
    (E : σ F ≃ τ) (s : τ) : coe_fn (F (of_equiv F E)) s = coe_fn (F F) (coe_fn (equiv.symm E) s) :=
  sorry

/-- `unit` is a realizer for the principal filter -/
protected def principal {α : Type u_1} (s : set α) : realizer (principal s) :=
  mk Unit
    (cfilter.mk (fun (_x : Unit) => s) Unit.unit (fun (_x _x : Unit) => Unit.unit) sorry sorry)
    sorry

@[simp] theorem principal_σ {α : Type u_1} (s : set α) : σ (realizer.principal s) = Unit := rfl

@[simp] theorem principal_F {α : Type u_1} (s : set α) (u : Unit) :
    coe_fn (F (realizer.principal s)) u = s :=
  rfl

/-- `unit` is a realizer for the top filter -/
protected def top {α : Type u_1} : realizer ⊤ := of_eq principal_univ (realizer.principal set.univ)

@[simp] theorem top_σ {α : Type u_1} : σ realizer.top = Unit := rfl

@[simp] theorem top_F {α : Type u_1} (u : Unit) : coe_fn (F realizer.top) u = set.univ := rfl

/-- `unit` is a realizer for the bottom filter -/
protected def bot {α : Type u_1} : realizer ⊥ := of_eq principal_empty (realizer.principal ∅)

@[simp] theorem bot_σ {α : Type u_1} : σ realizer.bot = Unit := rfl

@[simp] theorem bot_F {α : Type u_1} (u : Unit) : coe_fn (F realizer.bot) u = ∅ := rfl

/-- Construct a realizer for `map m f` given a realizer for `f` -/
protected def map {α : Type u_1} {β : Type u_2} (m : α → β) {f : filter α} (F : realizer f) :
    realizer (map m f) :=
  mk (σ F)
    (cfilter.mk (fun (s : σ F) => m '' coe_fn (F F) s) (cfilter.pt (F F)) (cfilter.inf (F F)) sorry
      sorry)
    sorry

@[simp] theorem map_σ {α : Type u_1} {β : Type u_2} (m : α → β) {f : filter α} (F : realizer f) :
    σ (realizer.map m F) = σ F :=
  rfl

@[simp] theorem map_F {α : Type u_1} {β : Type u_2} (m : α → β) {f : filter α} (F : realizer f)
    (s : σ (realizer.map m F)) : coe_fn (F (realizer.map m F)) s = m '' coe_fn (F F) s :=
  rfl

/-- Construct a realizer for `comap m f` given a realizer for `f` -/
protected def comap {α : Type u_1} {β : Type u_2} (m : α → β) {f : filter β} (F : realizer f) :
    realizer (comap m f) :=
  mk (σ F)
    (cfilter.mk (fun (s : σ F) => m ⁻¹' coe_fn (F F) s) (cfilter.pt (F F)) (cfilter.inf (F F)) sorry
      sorry)
    sorry

/-- Construct a realizer for the sup of two filters -/
protected def sup {α : Type u_1} {f : filter α} {g : filter α} (F : realizer f) (G : realizer g) :
    realizer (f ⊔ g) :=
  mk (σ F × σ G)
    (cfilter.mk (fun (_x : σ F × σ G) => sorry) (cfilter.pt (F F), cfilter.pt (F G))
      (fun (_x : σ F × σ G) => sorry) sorry sorry)
    sorry

/-- Construct a realizer for the inf of two filters -/
protected def inf {α : Type u_1} {f : filter α} {g : filter α} (F : realizer f) (G : realizer g) :
    realizer (f ⊓ g) :=
  mk (σ F × σ G)
    (cfilter.mk (fun (_x : σ F × σ G) => sorry) (cfilter.pt (F F), cfilter.pt (F G))
      (fun (_x : σ F × σ G) => sorry) sorry sorry)
    sorry

/-- Construct a realizer for the cofinite filter -/
protected def cofinite {α : Type u_1} [DecidableEq α] : realizer cofinite :=
  mk (finset α)
    (cfilter.mk (fun (s : finset α) => set_of fun (a : α) => ¬a ∈ s) ∅ has_union.union sorry sorry)
    sorry

/-- Construct a realizer for filter bind -/
protected def bind {α : Type u_1} {β : Type u_2} {f : filter α} {m : α → filter β} (F : realizer f)
    (G : (i : α) → realizer (m i)) : realizer (bind f m) :=
  mk (sigma fun (s : σ F) => (i : α) → i ∈ coe_fn (F F) s → σ (G i))
    (cfilter.mk (fun (_x : sigma fun (s : σ F) => (i : α) → i ∈ coe_fn (F F) s → σ (G i)) => sorry)
      (sigma.mk (cfilter.pt (F F))
        fun (i : α) (H : i ∈ coe_fn (F F) (cfilter.pt (F F))) => cfilter.pt (F (G i)))
      (fun (_x : sigma fun (s : σ F) => (i : α) → i ∈ coe_fn (F F) s → σ (G i)) => sorry) sorry
      sorry)
    sorry

/-- Construct a realizer for indexed supremum -/
protected def Sup {α : Type u_1} {β : Type u_2} {f : α → filter β} (F : (i : α) → realizer (f i)) :
    realizer (supr fun (i : α) => f i) :=
  let F' : realizer (supr fun (i : α) => f i) := of_eq sorry (realizer.bind realizer.top F);
  of_equiv F'
    ((fun (this : (sigma fun (u : Unit) => (i : α) → True → σ (F i)) ≃ ((i : α) → σ (F i))) => this)
      (equiv.mk (fun (_x : sigma fun (u : Unit) => (i : α) → True → σ (F i)) => sorry)
        (fun (f_1 : (i : α) → σ (F i)) => sigma.mk Unit.unit fun (i : α) (_x : True) => f_1 i) sorry
        sorry))

/-- Construct a realizer for the product of filters -/
protected def prod {α : Type u_1} {f : filter α} {g : filter α} (F : realizer f) (G : realizer g) :
    realizer (filter.prod f g) :=
  realizer.inf (realizer.comap prod.fst F) (realizer.comap prod.snd G)

theorem le_iff {α : Type u_1} {f : filter α} {g : filter α} (F : realizer f) (G : realizer g) :
    f ≤ g ↔ ∀ (b : σ G), ∃ (a : σ F), coe_fn (F F) a ≤ coe_fn (F G) b :=
  sorry

theorem tendsto_iff {α : Type u_1} {β : Type u_2} (f : α → β) {l₁ : filter α} {l₂ : filter β}
    (L₁ : realizer l₁) (L₂ : realizer l₂) :
    tendsto f l₁ l₂ ↔
        ∀ (b : σ L₂), ∃ (a : σ L₁), ∀ (x : α), x ∈ coe_fn (F L₁) a → f x ∈ coe_fn (F L₂) b :=
  iff.trans (le_iff (realizer.map f L₁) L₂)
    (forall_congr
      fun (b : σ L₂) => exists_congr fun (a : σ (realizer.map f L₁)) => set.image_subset_iff)

theorem ne_bot_iff {α : Type u_1} {f : filter α} (F : realizer f) :
    f ≠ ⊥ ↔ ∀ (a : σ F), set.nonempty (coe_fn (F F) a) :=
  sorry

end Mathlib


import implementation.model.predicate
import implementation.model.sys_state
import implementation.spec.main

variables {pid_t : Type} [linear_order pid_t] [fintype pid_t] {value_t : Type}
          {is_quorum : finset pid_t → Prop} [decidable_pred is_quorum]
          [quorum_assumption is_quorum] {vals : pid_t → value_t}

-- For each process, the current ballot will never decrease when taking a step.
lemma ballot_nondecreasing
  {u v : sys_state pid_t (server pid_t value_t is_quorum vals) (message pid_t value_t)}
  (p : pid_t) : u.possible_next v → (u.procs p).curr ≤ (v.procs p).curr :=
begin
rintros ⟨receiver, sender, e, he, deliverable, proc_change, ntwk_change, procs_same, ntwks_same⟩,
cases decidable.em (p = receiver),
swap,
{ rw procs_same p h },
rw h, clear h p procs_same ntwks_same ntwk_change,
rw proc_change,
have key := state_change receiver (u.procs receiver) e.msg sender,
cases key,
{ rw key },
cases e.msg,
  case p1a : b {
    rw key.right, exact le_of_lt key.left
  },
  case p1b : b p_or {
    cases key,
    { rw key.right, exact le_of_lt key.left },
    cases key,
    { rw key.right.right.right.right },
    rw key.right.right.right.right.right
  },
  case p2a : pr {
    rw key.right, exact key.left
  },
  case p2b : b accepted {
    rw key.right, exact le_of_lt key.left
  },
  case preempt : {
    rw key.right,
    exact le_of_lt (ballot.next_larger receiver (u.procs receiver).curr)
  }
end


import MatroidLinearProgramming.Matroid
import Mathlib.Data.Fintype.Basic
import Mathlib.GroupTheory.Perm.Basic

inductive WithZeroSign : Type
| Pos : WithZeroSign
| Zero : WithZeroSign
| Neg : WithZeroSign
deriving DecidableEq

instance : One WithZeroSign := ⟨WithZeroSign.Pos⟩
instance : Zero WithZeroSign := ⟨WithZeroSign.Zero⟩
instance : Neg WithZeroSign :=
  ⟨fun s => match s with
    | WithZeroSign.Pos => WithZeroSign.Neg
    | WithZeroSign.Zero => WithZeroSign.Zero
    | WithZeroSign.Neg => WithZeroSign.Pos⟩

instance : Mul WithZeroSign :=
  ⟨fun s₁ s₂ => match s₁, s₂ with
    | WithZeroSign.Zero, _ => WithZeroSign.Zero
    | _, WithZeroSign.Zero => WithZeroSign.Zero
    | WithZeroSign.Pos, x => x
    | x, WithZeroSign.Pos => x
    | WithZeroSign.Neg, WithZeroSign.Neg => WithZeroSign.Pos⟩

instance : Fintype WithZeroSign :=
  ⟨⟨[WithZeroSign.Pos, WithZeroSign.Zero, WithZeroSign.Neg], by decide⟩,
    by intro x; cases x <;> simp⟩

instance : Inhabited WithZeroSign := ⟨WithZeroSign.Zero⟩

instance : CommMonoid WithZeroSign :=
  { mul_assoc := by decide
    one_mul := by decide
    mul_one := by decide
    mul_comm := by decide }

def boolLE : WithZeroSign → WithZeroSign → Bool
  | _, WithZeroSign.Pos => true
  | x, WithZeroSign.Zero => x ≠ WithZeroSign.Pos
  | x, WithZeroSign.Neg => x = WithZeroSign.Neg

instance : LE WithZeroSign := ⟨fun s₁ s₂ => boolLE s₁ s₂⟩

instance : DecidableRel (fun s₁ s₂ : WithZeroSign => s₁ ≤ s₂) :=
  fun s₁ s₂ => decidable_of_iff (boolLE s₁ s₂) Iff.rfl

instance : LinearOrder WithZeroSign :=
{ le_refl := by decide
  le_trans := by decide
  le_antisymm := by decide
  le_total := by decide
  decidable_le := by infer_instance }

instance : ZeroLEOneClass WithZeroSign :=
  ⟨by decide⟩

instance : NeZero (1 : WithZeroSign) :=
  ⟨by decide⟩

open Matroid

@[ext] structure SignedSet (E : Type _) :=
  ( toSet : Set E )
  ( sign : toSet → Units ℤ )

namespace SignedSet

instance : EmptyCollection (SignedSet E) := ⟨⟨∅, fun x => False.elim x.2⟩⟩
instance : InvolutiveNeg (SignedSet E) :=
  { neg := fun s => ⟨s.toSet, fun x => -s.sign x⟩
    neg_neg := fun x => by simp [SignedSet.ext_iff] }

instance : Coe (SignedSet E) (Set E) := ⟨fun s => s.toSet⟩
attribute [coe] SignedSet.toSet

instance : Membership E (SignedSet E) := ⟨fun x s => x ∈ s.toSet⟩

@[simp]
theorem coe_empty : (↑∅ : Set E) = ∅ := rfl

@[simp]
theorem coe_neg (s : SignedSet E) : (↑(-s) : Set E) = s := rfl

def pos (c : SignedSet E) : Set E :=
  { x : E | ∃ h : x ∈ c, c.sign ⟨x, h⟩ = 1 }

def neg (c : SignedSet E) : Set E :=
  { x : E | ∃ h : x ∈ c, c.sign ⟨x, h⟩ = -1 }

end SignedSet

class OrientedMatroid (E : Type _) extends Matroid E :=
  ( signedCircuits' : Set (SignedSet E) )
  ( circuits_eq_signedCircuits :
      ((↑) : SignedSet E → Set E) ⁻¹' circuits' = signedCircuits' )
  ( neg_mem : ∀ c, c ∈ signedCircuits' → -c ∈ signedCircuits' )
  ( subset : ∀ c₁ ∈ signedCircuits', ∀ c₂ ∈ signedCircuits', (c₁ : Set E) ⊆ c₂ →
    c₁ = c₂ ∨ c₁ = -c₂ )
  ( eliminate : ∀ c₁ ∈ signedCircuits', ∀ c₂ ∈ signedCircuits', c₁ ≠ -c₂ →
      ∀ e ∈ c₁.pos ∩ c₂.neg, ∃ c₃ ∈ signedCircuits',
        c₃.pos ⊆ (c₁.pos ∪ c₂.pos) \ {e} ∧ c₃.neg ⊆ (c₁.neg ∪ c₂.neg) \ {e} )


/-
Copyright (c) 2021 Christopher Hoskin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Christopher Hoskin
-/
import topology.order.lattice
import analysis.normed.group.basic
import algebra.lattice_ordered_group

/-!
# Normed lattice ordered groups

Motivated by the theory of Banach Lattices, we then define `normed_lattice_add_comm_group` as a
lattice with a covariant normed group addition satisfying the solid axiom.

## Main statements

We show that a normed lattice ordered group is a topological lattice with respect to the norm
topology.

## References

* [Meyer-Nieberg, Banach lattices][MeyerNieberg1991]

## Tags

normed, lattice, ordered, group
-/

/-!
### Normed lattice orderd groups

Motivated by the theory of Banach Lattices, this section introduces normed lattice ordered groups.
-/

local notation `|`a`|` := abs a

/--
Let `α` be a normed commutative group equipped with a partial order covariant with addition, with
respect which `α` forms a lattice. Suppose that `α` is *solid*, that is to say, for `a` and `b` in
`α`, with absolute values `|a|` and `|b|` respectively, `|a| ≤ |b|` implies `∥a∥ ≤ ∥b∥`. Then `α` is
said to be a normed lattice ordered group.
-/
class normed_lattice_add_comm_group (α : Type*)
  extends normed_group α, lattice α :=
(add_le_add_left : ∀ a b : α, a ≤ b → ∀ c : α, c + a ≤ c + b)
(solid : ∀ a b : α, |a| ≤ |b| → ∥a∥ ≤ ∥b∥)

lemma solid {α : Type*} [normed_lattice_add_comm_group α] {a b : α} (h : |a| ≤ |b|) : ∥a∥ ≤ ∥b∥ :=
normed_lattice_add_comm_group.solid a b h

noncomputable instance : normed_lattice_add_comm_group ℝ :=
{ add_le_add_left := λ _ _ h _, add_le_add le_rfl h,
  solid := λ _ _, id, }
/--
A normed lattice ordered group is an ordered additive commutative group
-/
@[priority 100] -- see Note [lower instance priority]
instance normed_lattice_add_comm_group_to_ordered_add_comm_group {α : Type*}
  [h : normed_lattice_add_comm_group α] : ordered_add_comm_group α := { ..h }

/--
Let `α` be a normed group with a partial order. Then the order dual is also a normed group.
-/
@[priority 100] -- see Note [lower instance priority]
instance {α : Type*} : Π [normed_group α], normed_group (order_dual α) := id

variables {α : Type*} [normed_lattice_add_comm_group α]
open lattice_ordered_comm_group

lemma dual_solid (a b : α) (h: b⊓-b ≤ a⊓-a) : ∥a∥ ≤ ∥b∥ :=
begin
  apply solid,
  rw abs_eq_sup_neg,
  nth_rewrite 0 ← neg_neg a,
  rw ← neg_inf_eq_sup_neg,
  rw abs_eq_sup_neg,
  nth_rewrite 0 ← neg_neg b,
  rw ← neg_inf_eq_sup_neg,
  finish,
end

/--
Let `α` be a normed lattice ordered group, then the order dual is also a
normed lattice ordered group.
-/
@[priority 100] -- see Note [lower instance priority]
instance : normed_lattice_add_comm_group (order_dual α) :=
{ add_le_add_left := begin
    intros a b h₁ c,
    rw ← order_dual.dual_le,
    rw ← order_dual.dual_le at h₁,
    exact add_le_add_left h₁ _,
  end,
  solid := begin
    intros a b h₂,
    apply dual_solid,
    rw ← order_dual.dual_le at h₂,
    finish,
  end, }

lemma norm_abs_eq_norm (a : α) : ∥|a|∥ = ∥a∥ :=
(solid (abs_abs a).le).antisymm (solid (abs_abs a).symm.le)

lemma norm_inf_sub_inf_le_add_norm (a b c d : α) : ∥a ⊓ b - c ⊓ d∥ ≤ ∥a - c∥ + ∥b - d∥ :=
begin
  rw [← norm_abs_eq_norm (a - c), ← norm_abs_eq_norm (b - d)],
  refine le_trans (solid _) (norm_add_le (|a - c|) (|b - d|)),
  rw abs_of_nonneg (|a - c| + |b - d|) (add_nonneg (abs_nonneg (a - c)) (abs_nonneg (b - d))),
  calc |a ⊓ b - c ⊓ d| =
    |a ⊓ b - c ⊓ b + (c ⊓ b - c ⊓ d)| : by rw sub_add_sub_cancel
  ... ≤ |a ⊓ b - c ⊓ b| + |c ⊓ b - c ⊓ d| : abs_add_le _ _
  ... ≤ |a -c| + |b - d| : by
    { apply add_le_add,
      { exact abs_inf_sub_inf_le_abs _ _ _, },
      { rw [@inf_comm _ _ c, @inf_comm _ _ c],
        exact abs_inf_sub_inf_le_abs _ _ _, } },
end

lemma norm_sup_sub_sup_le_add_norm (a b c d : α) : ∥a ⊔ b - (c ⊔ d)∥ ≤ ∥a - c∥ + ∥b - d∥ :=
begin
  rw [← norm_abs_eq_norm (a - c), ← norm_abs_eq_norm (b - d)],
  refine le_trans (solid _) (norm_add_le (|a - c|) (|b - d|)),
  rw abs_of_nonneg (|a - c| + |b - d|) (add_nonneg (abs_nonneg (a - c)) (abs_nonneg (b - d))),
  calc |a ⊔ b - (c ⊔ d)| =
    |a ⊔ b - (c ⊔ b) + (c ⊔ b - (c ⊔ d))| : by rw sub_add_sub_cancel
  ... ≤ |a ⊔ b - (c ⊔ b)| + |c ⊔ b - (c ⊔ d)| : abs_add_le _ _
  ... ≤ |a -c| + |b - d| : by
    { apply add_le_add,
      { exact abs_sup_sub_sup_le_abs _ _ _, },
      { rw [@sup_comm _ _ c, @sup_comm _ _ c],
        exact abs_sup_sub_sup_le_abs _ _ _, } },
end

/--
Let `α` be a normed lattice ordered group. Then the infimum is jointly continuous.
-/
@[priority 100] -- see Note [lower instance priority]
instance normed_lattice_add_comm_group_has_continuous_inf : has_continuous_inf α :=
begin
  refine ⟨continuous_iff_continuous_at.2 $ λ q, tendsto_iff_norm_tendsto_zero.2 $ _⟩,
  have : ∀ p : α × α, ∥p.1 ⊓ p.2 - q.1 ⊓ q.2∥ ≤ ∥p.1 - q.1∥ + ∥p.2 - q.2∥,
    from λ _, norm_inf_sub_inf_le_add_norm _ _ _ _,
  refine squeeze_zero (λ e, norm_nonneg _) this _,
  convert (((continuous_fst.tendsto q).sub tendsto_const_nhds).norm).add
        (((continuous_snd.tendsto q).sub tendsto_const_nhds).norm),
  simp,
end

/--
Let `α` be a normed lattice ordered group. Then `α` is a topological lattice in the norm topology.
-/
@[priority 100] -- see Note [lower instance priority]
instance normed_lattice_add_comm_group_topological_lattice : topological_lattice α :=
topological_lattice.mk

lemma norm_abs_sub_abs (a b : α) :
  ∥ |a| - |b| ∥ ≤ ∥a-b∥ :=
solid (lattice_ordered_comm_group.abs_abs_sub_abs_le _ _)