/-
Copyright (c) 2020 Floris van Doorn. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Floris van Doorn

! This file was ported from Lean 3 source module data.set.semiring
! leanprover-community/mathlib commit 62e8311c791f02c47451bf14aa2501048e7c2f33
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Algebra.Order.Kleene
import Mathbin.Data.Set.Pointwise.Smul

/-!
# Sets as a semiring under union

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

This file defines `set_semiring α`, an alias of `set α`, which we endow with `∪` as addition and
pointwise `*` as multiplication. If `α` is a (commutative) monoid, `set_semiring α` is a
(commutative) semiring.
-/

open Function Set

open Pointwise

variable {α β : Type _}

#print SetSemiring /-
/-- An alias for `set α`, which has a semiring structure given by `∪` as "addition" and pointwise
  multiplication `*` as "multiplication". -/
def SetSemiring (α : Type _) : Type _ :=
  Set α deriving Inhabited, PartialOrder, OrderBot
#align set_semiring SetSemiring
-/

#print Set.up /-
/-- The identity function `set α → set_semiring α`. -/
protected def Set.up : Set α ≃ SetSemiring α :=
  Equiv.refl _
#align set.up Set.up
-/

namespace SetSemiring

#print SetSemiring.down /-
/-- The identity function `set_semiring α → set α`. -/
protected def down : SetSemiring α ≃ Set α :=
  Equiv.refl _
#align set_semiring.down SetSemiring.down
-/

#print SetSemiring.down_up /-
@[simp]
protected theorem down_up (s : Set α) : s.up.down = s :=
  rfl
#align set_semiring.down_up SetSemiring.down_up
-/

#print SetSemiring.up_down /-
@[simp]
protected theorem up_down (s : SetSemiring α) : s.down.up = s :=
  rfl
#align set_semiring.up_down SetSemiring.up_down
-/

/- warning: set_semiring.up_le_up -> SetSemiring.up_le_up is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {s : Set.{u1} α} {t : Set.{u1} α}, Iff (LE.le.{u1} (SetSemiring.{u1} α) (Preorder.toLE.{u1} (SetSemiring.{u1} α) (PartialOrder.toPreorder.{u1} (SetSemiring.{u1} α) (SetSemiring.partialOrder.{u1} α))) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (fun (_x : Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) => (Set.{u1} α) -> (SetSemiring.{u1} α)) (Equiv.hasCoeToFun.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.up.{u1} α) s) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (fun (_x : Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) => (Set.{u1} α) -> (SetSemiring.{u1} α)) (Equiv.hasCoeToFun.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.up.{u1} α) t)) (HasSubset.Subset.{u1} (Set.{u1} α) (Set.hasSubset.{u1} α) s t)
but is expected to have type
  forall {α : Type.{u1}} {s : Set.{u1} α} {t : Set.{u1} α}, Iff (LE.le.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Set.{u1} α) => SetSemiring.{u1} α) s) (Preorder.toLE.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Set.{u1} α) => SetSemiring.{u1} α) s) (PartialOrder.toPreorder.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Set.{u1} α) => SetSemiring.{u1} α) s) (instPartialOrderSetSemiring.{u1} α))) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.{u1} α) (fun (_x : Set.{u1} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Set.{u1} α) => SetSemiring.{u1} α) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.up.{u1} α) s) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.{u1} α) (fun (_x : Set.{u1} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Set.{u1} α) => SetSemiring.{u1} α) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.up.{u1} α) t)) (HasSubset.Subset.{u1} (Set.{u1} α) (Set.instHasSubsetSet.{u1} α) s t)
Case conversion may be inaccurate. Consider using '#align set_semiring.up_le_up SetSemiring.up_le_upₓ'. -/
-- TODO: These lemmas are not tagged `simp` because `set.le_eq_subset` simplifies the LHS
theorem up_le_up {s t : Set α} : s.up ≤ t.up ↔ s ⊆ t :=
  Iff.rfl
#align set_semiring.up_le_up SetSemiring.up_le_up

/- warning: set_semiring.up_lt_up -> SetSemiring.up_lt_up is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {s : Set.{u1} α} {t : Set.{u1} α}, Iff (LT.lt.{u1} (SetSemiring.{u1} α) (Preorder.toLT.{u1} (SetSemiring.{u1} α) (PartialOrder.toPreorder.{u1} (SetSemiring.{u1} α) (SetSemiring.partialOrder.{u1} α))) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (fun (_x : Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) => (Set.{u1} α) -> (SetSemiring.{u1} α)) (Equiv.hasCoeToFun.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.up.{u1} α) s) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (fun (_x : Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) => (Set.{u1} α) -> (SetSemiring.{u1} α)) (Equiv.hasCoeToFun.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.up.{u1} α) t)) (HasSSubset.SSubset.{u1} (Set.{u1} α) (Set.hasSsubset.{u1} α) s t)
but is expected to have type
  forall {α : Type.{u1}} {s : Set.{u1} α} {t : Set.{u1} α}, Iff (LT.lt.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Set.{u1} α) => SetSemiring.{u1} α) s) (Preorder.toLT.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Set.{u1} α) => SetSemiring.{u1} α) s) (PartialOrder.toPreorder.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Set.{u1} α) => SetSemiring.{u1} α) s) (instPartialOrderSetSemiring.{u1} α))) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.{u1} α) (fun (_x : Set.{u1} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Set.{u1} α) => SetSemiring.{u1} α) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.up.{u1} α) s) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.{u1} α) (fun (_x : Set.{u1} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Set.{u1} α) => SetSemiring.{u1} α) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.up.{u1} α) t)) (HasSSubset.SSubset.{u1} (Set.{u1} α) (Set.instHasSSubsetSet.{u1} α) s t)
Case conversion may be inaccurate. Consider using '#align set_semiring.up_lt_up SetSemiring.up_lt_upₓ'. -/
theorem up_lt_up {s t : Set α} : s.up < t.up ↔ s ⊂ t :=
  Iff.rfl
#align set_semiring.up_lt_up SetSemiring.up_lt_up

#print SetSemiring.down_subset_down /-
@[simp]
theorem down_subset_down {s t : SetSemiring α} : s.down ⊆ t.down ↔ s ≤ t :=
  Iff.rfl
#align set_semiring.down_subset_down SetSemiring.down_subset_down
-/

/- warning: set_semiring.down_ssubset_down -> SetSemiring.down_ssubset_down is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {s : SetSemiring.{u1} α} {t : SetSemiring.{u1} α}, Iff (HasSSubset.SSubset.{u1} (Set.{u1} α) (Set.hasSsubset.{u1} α) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (fun (_x : Equiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) => (SetSemiring.{u1} α) -> (Set.{u1} α)) (Equiv.hasCoeToFun.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (SetSemiring.down.{u1} α) s) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (fun (_x : Equiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) => (SetSemiring.{u1} α) -> (Set.{u1} α)) (Equiv.hasCoeToFun.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (SetSemiring.down.{u1} α) t)) (LT.lt.{u1} (SetSemiring.{u1} α) (Preorder.toLT.{u1} (SetSemiring.{u1} α) (PartialOrder.toPreorder.{u1} (SetSemiring.{u1} α) (SetSemiring.partialOrder.{u1} α))) s t)
but is expected to have type
  forall {α : Type.{u1}} {s : SetSemiring.{u1} α} {t : SetSemiring.{u1} α}, Iff (HasSSubset.SSubset.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : SetSemiring.{u1} α) => Set.{u1} α) s) (Set.instHasSSubsetSet.{u1} α) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (SetSemiring.{u1} α) (fun (_x : SetSemiring.{u1} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : SetSemiring.{u1} α) => Set.{u1} α) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (SetSemiring.down.{u1} α) s) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (SetSemiring.{u1} α) (fun (_x : SetSemiring.{u1} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : SetSemiring.{u1} α) => Set.{u1} α) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (SetSemiring.down.{u1} α) t)) (LT.lt.{u1} (SetSemiring.{u1} α) (Preorder.toLT.{u1} (SetSemiring.{u1} α) (PartialOrder.toPreorder.{u1} (SetSemiring.{u1} α) (instPartialOrderSetSemiring.{u1} α))) s t)
Case conversion may be inaccurate. Consider using '#align set_semiring.down_ssubset_down SetSemiring.down_ssubset_downₓ'. -/
@[simp]
theorem down_ssubset_down {s t : SetSemiring α} : s.down ⊂ t.down ↔ s < t :=
  Iff.rfl
#align set_semiring.down_ssubset_down SetSemiring.down_ssubset_down

instance : AddCommMonoid (SetSemiring α)
    where
  add s t := (s.down ∪ t.down).up
  zero := (∅ : Set α).up
  add_assoc := union_assoc
  zero_add := empty_union
  add_zero := union_empty
  add_comm := union_comm

/- warning: set_semiring.zero_def -> SetSemiring.zero_def is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}}, Eq.{succ u1} (SetSemiring.{u1} α) (OfNat.ofNat.{u1} (SetSemiring.{u1} α) 0 (OfNat.mk.{u1} (SetSemiring.{u1} α) 0 (Zero.zero.{u1} (SetSemiring.{u1} α) (AddZeroClass.toHasZero.{u1} (SetSemiring.{u1} α) (AddMonoid.toAddZeroClass.{u1} (SetSemiring.{u1} α) (AddCommMonoid.toAddMonoid.{u1} (SetSemiring.{u1} α) (SetSemiring.addCommMonoid.{u1} α))))))) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (fun (_x : Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) => (Set.{u1} α) -> (SetSemiring.{u1} α)) (Equiv.hasCoeToFun.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.up.{u1} α) (EmptyCollection.emptyCollection.{u1} (Set.{u1} α) (Set.hasEmptyc.{u1} α)))
but is expected to have type
  forall {α : Type.{u1}}, Eq.{succ u1} (SetSemiring.{u1} α) (OfNat.ofNat.{u1} (SetSemiring.{u1} α) 0 (Zero.toOfNat0.{u1} (SetSemiring.{u1} α) (AddMonoid.toZero.{u1} (SetSemiring.{u1} α) (AddCommMonoid.toAddMonoid.{u1} (SetSemiring.{u1} α) (SetSemiring.instAddCommMonoidSetSemiring.{u1} α))))) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.{u1} α) (fun (_x : Set.{u1} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Set.{u1} α) => SetSemiring.{u1} α) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.up.{u1} α) (EmptyCollection.emptyCollection.{u1} (Set.{u1} α) (Set.instEmptyCollectionSet.{u1} α)))
Case conversion may be inaccurate. Consider using '#align set_semiring.zero_def SetSemiring.zero_defₓ'. -/
theorem zero_def : (0 : SetSemiring α) = Set.up ∅ :=
  rfl
#align set_semiring.zero_def SetSemiring.zero_def

#print SetSemiring.down_zero /-
@[simp]
theorem down_zero : (0 : SetSemiring α).down = ∅ :=
  rfl
#align set_semiring.down_zero SetSemiring.down_zero
-/

#print Set.up_empty /-
@[simp]
theorem Set.up_empty : (∅ : Set α).up = 0 :=
  rfl
#align set.up_empty Set.up_empty
-/

/- warning: set_semiring.add_def -> SetSemiring.add_def is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} (s : SetSemiring.{u1} α) (t : SetSemiring.{u1} α), Eq.{succ u1} (SetSemiring.{u1} α) (HAdd.hAdd.{u1, u1, u1} (SetSemiring.{u1} α) (SetSemiring.{u1} α) (SetSemiring.{u1} α) (instHAdd.{u1} (SetSemiring.{u1} α) (AddZeroClass.toHasAdd.{u1} (SetSemiring.{u1} α) (AddMonoid.toAddZeroClass.{u1} (SetSemiring.{u1} α) (AddCommMonoid.toAddMonoid.{u1} (SetSemiring.{u1} α) (SetSemiring.addCommMonoid.{u1} α))))) s t) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (fun (_x : Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) => (Set.{u1} α) -> (SetSemiring.{u1} α)) (Equiv.hasCoeToFun.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.up.{u1} α) (Union.union.{u1} (Set.{u1} α) (Set.hasUnion.{u1} α) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (fun (_x : Equiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) => (SetSemiring.{u1} α) -> (Set.{u1} α)) (Equiv.hasCoeToFun.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (SetSemiring.down.{u1} α) s) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (fun (_x : Equiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) => (SetSemiring.{u1} α) -> (Set.{u1} α)) (Equiv.hasCoeToFun.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (SetSemiring.down.{u1} α) t)))
but is expected to have type
  forall {α : Type.{u1}} (s : SetSemiring.{u1} α) (t : SetSemiring.{u1} α), Eq.{succ u1} (SetSemiring.{u1} α) (HAdd.hAdd.{u1, u1, u1} (SetSemiring.{u1} α) (SetSemiring.{u1} α) (SetSemiring.{u1} α) (instHAdd.{u1} (SetSemiring.{u1} α) (AddZeroClass.toAdd.{u1} (SetSemiring.{u1} α) (AddMonoid.toAddZeroClass.{u1} (SetSemiring.{u1} α) (AddCommMonoid.toAddMonoid.{u1} (SetSemiring.{u1} α) (SetSemiring.instAddCommMonoidSetSemiring.{u1} α))))) s t) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.{u1} α) (fun (_x : Set.{u1} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Set.{u1} α) => SetSemiring.{u1} α) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.up.{u1} α) (Union.union.{u1} (Set.{u1} α) (Set.instUnionSet.{u1} α) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (SetSemiring.{u1} α) (fun (_x : SetSemiring.{u1} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : SetSemiring.{u1} α) => Set.{u1} α) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (SetSemiring.down.{u1} α) s) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (SetSemiring.{u1} α) (fun (_x : SetSemiring.{u1} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : SetSemiring.{u1} α) => Set.{u1} α) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (SetSemiring.down.{u1} α) t)))
Case conversion may be inaccurate. Consider using '#align set_semiring.add_def SetSemiring.add_defₓ'. -/
theorem add_def (s t : SetSemiring α) : s + t = (s.down ∪ t.down).up :=
  rfl
#align set_semiring.add_def SetSemiring.add_def

#print SetSemiring.down_add /-
@[simp]
theorem down_add (s t : SetSemiring α) : (s + t).down = s.down ∪ t.down :=
  rfl
#align set_semiring.down_add SetSemiring.down_add
-/

#print Set.up_union /-
@[simp]
theorem Set.up_union (s t : Set α) : (s ∪ t).up = s.up + t.up :=
  rfl
#align set.up_union Set.up_union
-/

/- warning: set_semiring.covariant_class_add -> SetSemiring.covariantClass_add is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}}, CovariantClass.{u1, u1} (SetSemiring.{u1} α) (SetSemiring.{u1} α) (HAdd.hAdd.{u1, u1, u1} (SetSemiring.{u1} α) (SetSemiring.{u1} α) (SetSemiring.{u1} α) (instHAdd.{u1} (SetSemiring.{u1} α) (AddZeroClass.toHasAdd.{u1} (SetSemiring.{u1} α) (AddMonoid.toAddZeroClass.{u1} (SetSemiring.{u1} α) (AddCommMonoid.toAddMonoid.{u1} (SetSemiring.{u1} α) (SetSemiring.addCommMonoid.{u1} α)))))) (LE.le.{u1} (SetSemiring.{u1} α) (Preorder.toLE.{u1} (SetSemiring.{u1} α) (PartialOrder.toPreorder.{u1} (SetSemiring.{u1} α) (SetSemiring.partialOrder.{u1} α))))
but is expected to have type
  forall {α : Type.{u1}}, CovariantClass.{u1, u1} (SetSemiring.{u1} α) (SetSemiring.{u1} α) (fun (x._@.Mathlib.Data.Set.Semiring._hyg.498 : SetSemiring.{u1} α) (x._@.Mathlib.Data.Set.Semiring._hyg.500 : SetSemiring.{u1} α) => HAdd.hAdd.{u1, u1, u1} (SetSemiring.{u1} α) (SetSemiring.{u1} α) (SetSemiring.{u1} α) (instHAdd.{u1} (SetSemiring.{u1} α) (AddZeroClass.toAdd.{u1} (SetSemiring.{u1} α) (AddMonoid.toAddZeroClass.{u1} (SetSemiring.{u1} α) (AddCommMonoid.toAddMonoid.{u1} (SetSemiring.{u1} α) (SetSemiring.instAddCommMonoidSetSemiring.{u1} α))))) x._@.Mathlib.Data.Set.Semiring._hyg.498 x._@.Mathlib.Data.Set.Semiring._hyg.500) (fun (x._@.Mathlib.Data.Set.Semiring._hyg.513 : SetSemiring.{u1} α) (x._@.Mathlib.Data.Set.Semiring._hyg.515 : SetSemiring.{u1} α) => LE.le.{u1} (SetSemiring.{u1} α) (Preorder.toLE.{u1} (SetSemiring.{u1} α) (PartialOrder.toPreorder.{u1} (SetSemiring.{u1} α) (instPartialOrderSetSemiring.{u1} α))) x._@.Mathlib.Data.Set.Semiring._hyg.513 x._@.Mathlib.Data.Set.Semiring._hyg.515)
Case conversion may be inaccurate. Consider using '#align set_semiring.covariant_class_add SetSemiring.covariantClass_addₓ'. -/
/- Since addition on `set_semiring` is commutative (it is set union), there is no need
to also have the instance `covariant_class (set_semiring α) (set_semiring α) (swap (+)) (≤)`. -/
instance covariantClass_add : CovariantClass (SetSemiring α) (SetSemiring α) (· + ·) (· ≤ ·) :=
  ⟨fun a b c => union_subset_union_right _⟩
#align set_semiring.covariant_class_add SetSemiring.covariantClass_add

section Mul

variable [Mul α]

instance : NonUnitalNonAssocSemiring (SetSemiring α) :=
  {-- reducibility linter complains if we use `(s.down * t.down).up`
    SetSemiring.addCommMonoid with
    mul := fun s t => (image2 (· * ·) s.down t.down).up
    zero_mul := fun s => empty_mul
    mul_zero := fun s => mul_empty
    left_distrib := fun _ _ _ => mul_union
    right_distrib := fun _ _ _ => union_mul }

/- warning: set_semiring.mul_def -> SetSemiring.mul_def is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Mul.{u1} α] (s : SetSemiring.{u1} α) (t : SetSemiring.{u1} α), Eq.{succ u1} (SetSemiring.{u1} α) (HMul.hMul.{u1, u1, u1} (SetSemiring.{u1} α) (SetSemiring.{u1} α) (SetSemiring.{u1} α) (instHMul.{u1} (SetSemiring.{u1} α) (Distrib.toHasMul.{u1} (SetSemiring.{u1} α) (NonUnitalNonAssocSemiring.toDistrib.{u1} (SetSemiring.{u1} α) (SetSemiring.nonUnitalNonAssocSemiring.{u1} α _inst_1)))) s t) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (fun (_x : Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) => (Set.{u1} α) -> (SetSemiring.{u1} α)) (Equiv.hasCoeToFun.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.up.{u1} α) (HMul.hMul.{u1, u1, u1} (Set.{u1} α) (Set.{u1} α) (Set.{u1} α) (instHMul.{u1} (Set.{u1} α) (Set.mul.{u1} α _inst_1)) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (fun (_x : Equiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) => (SetSemiring.{u1} α) -> (Set.{u1} α)) (Equiv.hasCoeToFun.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (SetSemiring.down.{u1} α) s) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (fun (_x : Equiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) => (SetSemiring.{u1} α) -> (Set.{u1} α)) (Equiv.hasCoeToFun.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (SetSemiring.down.{u1} α) t)))
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Mul.{u1} α] (s : SetSemiring.{u1} α) (t : SetSemiring.{u1} α), Eq.{succ u1} (SetSemiring.{u1} α) (HMul.hMul.{u1, u1, u1} (SetSemiring.{u1} α) (SetSemiring.{u1} α) (SetSemiring.{u1} α) (instHMul.{u1} (SetSemiring.{u1} α) (NonUnitalNonAssocSemiring.toMul.{u1} (SetSemiring.{u1} α) (SetSemiring.instNonUnitalNonAssocSemiringSetSemiring.{u1} α _inst_1))) s t) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.{u1} α) (fun (_x : Set.{u1} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Set.{u1} α) => SetSemiring.{u1} α) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.up.{u1} α) (HMul.hMul.{u1, u1, u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : SetSemiring.{u1} α) => Set.{u1} α) s) ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : SetSemiring.{u1} α) => Set.{u1} α) t) ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : SetSemiring.{u1} α) => Set.{u1} α) s) (instHMul.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : SetSemiring.{u1} α) => Set.{u1} α) s) (Set.mul.{u1} α _inst_1)) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (SetSemiring.{u1} α) (fun (_x : SetSemiring.{u1} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : SetSemiring.{u1} α) => Set.{u1} α) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (SetSemiring.down.{u1} α) s) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (SetSemiring.{u1} α) (fun (_x : SetSemiring.{u1} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : SetSemiring.{u1} α) => Set.{u1} α) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (SetSemiring.down.{u1} α) t)))
Case conversion may be inaccurate. Consider using '#align set_semiring.mul_def SetSemiring.mul_defₓ'. -/
theorem mul_def (s t : SetSemiring α) : s * t = (s.down * t.down).up :=
  rfl
#align set_semiring.mul_def SetSemiring.mul_def

#print SetSemiring.down_mul /-
@[simp]
theorem down_mul (s t : SetSemiring α) : (s * t).down = s.down * t.down :=
  rfl
#align set_semiring.down_mul SetSemiring.down_mul
-/

#print Set.up_mul /-
@[simp]
theorem Set.up_mul (s t : Set α) : (s * t).up = s.up * t.up :=
  rfl
#align set.up_mul Set.up_mul
-/

instance : NoZeroDivisors (SetSemiring α) :=
  ⟨fun a b ab =>
    a.eq_empty_or_nonempty.imp_right fun ha =>
      b.eq_empty_or_nonempty.resolve_right fun hb =>
        Nonempty.ne_empty ⟨_, mul_mem_mul ha.some_mem hb.some_mem⟩ ab⟩

/- warning: set_semiring.covariant_class_mul_left -> SetSemiring.covariantClass_mul_left is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Mul.{u1} α], CovariantClass.{u1, u1} (SetSemiring.{u1} α) (SetSemiring.{u1} α) (HMul.hMul.{u1, u1, u1} (SetSemiring.{u1} α) (SetSemiring.{u1} α) (SetSemiring.{u1} α) (instHMul.{u1} (SetSemiring.{u1} α) (Distrib.toHasMul.{u1} (SetSemiring.{u1} α) (NonUnitalNonAssocSemiring.toDistrib.{u1} (SetSemiring.{u1} α) (SetSemiring.nonUnitalNonAssocSemiring.{u1} α _inst_1))))) (LE.le.{u1} (SetSemiring.{u1} α) (Preorder.toLE.{u1} (SetSemiring.{u1} α) (PartialOrder.toPreorder.{u1} (SetSemiring.{u1} α) (SetSemiring.partialOrder.{u1} α))))
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Mul.{u1} α], CovariantClass.{u1, u1} (SetSemiring.{u1} α) (SetSemiring.{u1} α) (fun (x._@.Mathlib.Data.Set.Semiring._hyg.786 : SetSemiring.{u1} α) (x._@.Mathlib.Data.Set.Semiring._hyg.788 : SetSemiring.{u1} α) => HMul.hMul.{u1, u1, u1} (SetSemiring.{u1} α) (SetSemiring.{u1} α) (SetSemiring.{u1} α) (instHMul.{u1} (SetSemiring.{u1} α) (NonUnitalNonAssocSemiring.toMul.{u1} (SetSemiring.{u1} α) (SetSemiring.instNonUnitalNonAssocSemiringSetSemiring.{u1} α _inst_1))) x._@.Mathlib.Data.Set.Semiring._hyg.786 x._@.Mathlib.Data.Set.Semiring._hyg.788) (fun (x._@.Mathlib.Data.Set.Semiring._hyg.801 : SetSemiring.{u1} α) (x._@.Mathlib.Data.Set.Semiring._hyg.803 : SetSemiring.{u1} α) => LE.le.{u1} (SetSemiring.{u1} α) (Preorder.toLE.{u1} (SetSemiring.{u1} α) (PartialOrder.toPreorder.{u1} (SetSemiring.{u1} α) (instPartialOrderSetSemiring.{u1} α))) x._@.Mathlib.Data.Set.Semiring._hyg.801 x._@.Mathlib.Data.Set.Semiring._hyg.803)
Case conversion may be inaccurate. Consider using '#align set_semiring.covariant_class_mul_left SetSemiring.covariantClass_mul_leftₓ'. -/
instance covariantClass_mul_left : CovariantClass (SetSemiring α) (SetSemiring α) (· * ·) (· ≤ ·) :=
  ⟨fun a b c => mul_subset_mul_left⟩
#align set_semiring.covariant_class_mul_left SetSemiring.covariantClass_mul_left

/- warning: set_semiring.covariant_class_mul_right -> SetSemiring.covariantClass_mul_right is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Mul.{u1} α], CovariantClass.{u1, u1} (SetSemiring.{u1} α) (SetSemiring.{u1} α) (Function.swap.{succ u1, succ u1, succ u1} (SetSemiring.{u1} α) (SetSemiring.{u1} α) (fun (ᾰ : SetSemiring.{u1} α) (ᾰ : SetSemiring.{u1} α) => SetSemiring.{u1} α) (HMul.hMul.{u1, u1, u1} (SetSemiring.{u1} α) (SetSemiring.{u1} α) (SetSemiring.{u1} α) (instHMul.{u1} (SetSemiring.{u1} α) (Distrib.toHasMul.{u1} (SetSemiring.{u1} α) (NonUnitalNonAssocSemiring.toDistrib.{u1} (SetSemiring.{u1} α) (SetSemiring.nonUnitalNonAssocSemiring.{u1} α _inst_1)))))) (LE.le.{u1} (SetSemiring.{u1} α) (Preorder.toLE.{u1} (SetSemiring.{u1} α) (PartialOrder.toPreorder.{u1} (SetSemiring.{u1} α) (SetSemiring.partialOrder.{u1} α))))
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Mul.{u1} α], CovariantClass.{u1, u1} (SetSemiring.{u1} α) (SetSemiring.{u1} α) (Function.swap.{succ u1, succ u1, succ u1} (SetSemiring.{u1} α) (SetSemiring.{u1} α) (fun (ᾰ : SetSemiring.{u1} α) (ᾰ : SetSemiring.{u1} α) => SetSemiring.{u1} α) (fun (x._@.Mathlib.Data.Set.Semiring._hyg.846 : SetSemiring.{u1} α) (x._@.Mathlib.Data.Set.Semiring._hyg.848 : SetSemiring.{u1} α) => HMul.hMul.{u1, u1, u1} (SetSemiring.{u1} α) (SetSemiring.{u1} α) (SetSemiring.{u1} α) (instHMul.{u1} (SetSemiring.{u1} α) (NonUnitalNonAssocSemiring.toMul.{u1} (SetSemiring.{u1} α) (SetSemiring.instNonUnitalNonAssocSemiringSetSemiring.{u1} α _inst_1))) x._@.Mathlib.Data.Set.Semiring._hyg.846 x._@.Mathlib.Data.Set.Semiring._hyg.848)) (fun (x._@.Mathlib.Data.Set.Semiring._hyg.861 : SetSemiring.{u1} α) (x._@.Mathlib.Data.Set.Semiring._hyg.863 : SetSemiring.{u1} α) => LE.le.{u1} (SetSemiring.{u1} α) (Preorder.toLE.{u1} (SetSemiring.{u1} α) (PartialOrder.toPreorder.{u1} (SetSemiring.{u1} α) (instPartialOrderSetSemiring.{u1} α))) x._@.Mathlib.Data.Set.Semiring._hyg.861 x._@.Mathlib.Data.Set.Semiring._hyg.863)
Case conversion may be inaccurate. Consider using '#align set_semiring.covariant_class_mul_right SetSemiring.covariantClass_mul_rightₓ'. -/
instance covariantClass_mul_right :
    CovariantClass (SetSemiring α) (SetSemiring α) (swap (· * ·)) (· ≤ ·) :=
  ⟨fun a b c => mul_subset_mul_right⟩
#align set_semiring.covariant_class_mul_right SetSemiring.covariantClass_mul_right

end Mul

section One

variable [One α]

instance : One (SetSemiring α) where one := Set.up 1

/- warning: set_semiring.one_def -> SetSemiring.one_def is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : One.{u1} α], Eq.{succ u1} (SetSemiring.{u1} α) (OfNat.ofNat.{u1} (SetSemiring.{u1} α) 1 (OfNat.mk.{u1} (SetSemiring.{u1} α) 1 (One.one.{u1} (SetSemiring.{u1} α) (SetSemiring.hasOne.{u1} α _inst_1)))) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (fun (_x : Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) => (Set.{u1} α) -> (SetSemiring.{u1} α)) (Equiv.hasCoeToFun.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.up.{u1} α) (OfNat.ofNat.{u1} (Set.{u1} α) 1 (OfNat.mk.{u1} (Set.{u1} α) 1 (One.one.{u1} (Set.{u1} α) (Set.one.{u1} α _inst_1)))))
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : One.{u1} α], Eq.{succ u1} (SetSemiring.{u1} α) (OfNat.ofNat.{u1} (SetSemiring.{u1} α) 1 (One.toOfNat1.{u1} (SetSemiring.{u1} α) (SetSemiring.instOneSetSemiring.{u1} α _inst_1))) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.{u1} α) (fun (_x : Set.{u1} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Set.{u1} α) => SetSemiring.{u1} α) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.up.{u1} α) (OfNat.ofNat.{u1} (Set.{u1} α) 1 (One.toOfNat1.{u1} (Set.{u1} α) (Set.one.{u1} α _inst_1))))
Case conversion may be inaccurate. Consider using '#align set_semiring.one_def SetSemiring.one_defₓ'. -/
theorem one_def : (1 : SetSemiring α) = Set.up 1 :=
  rfl
#align set_semiring.one_def SetSemiring.one_def

#print SetSemiring.down_one /-
@[simp]
theorem down_one : (1 : SetSemiring α).down = 1 :=
  rfl
#align set_semiring.down_one SetSemiring.down_one
-/

#print Set.up_one /-
@[simp]
theorem Set.up_one : (1 : Set α).up = 1 :=
  rfl
#align set.up_one Set.up_one
-/

end One

instance [MulOneClass α] : NonAssocSemiring (SetSemiring α) :=
  { SetSemiring.nonUnitalNonAssocSemiring,
    Set.mulOneClass with
    one := 1
    mul := (· * ·) }

instance [Semigroup α] : NonUnitalSemiring (SetSemiring α) :=
  { SetSemiring.nonUnitalNonAssocSemiring, Set.semigroup with }

instance [Monoid α] : IdemSemiring (SetSemiring α) :=
  { SetSemiring.nonAssocSemiring, SetSemiring.nonUnitalSemiring, Set.completeBooleanAlgebra with }

instance [CommSemigroup α] : NonUnitalCommSemiring (SetSemiring α) :=
  { SetSemiring.nonUnitalSemiring, Set.commSemigroup with }

instance [CommMonoid α] : IdemCommSemiring (SetSemiring α) :=
  { SetSemiring.idemSemiring, Set.commMonoid with }

instance [CommMonoid α] : CanonicallyOrderedCommSemiring (SetSemiring α) :=
  { SetSemiring.idemSemiring, Set.commMonoid,
    SetSemiring.noZeroDivisors with
    add_le_add_left := fun a b => add_le_add_left
    exists_add_of_le := fun a b ab => ⟨b, (union_eq_right_iff_subset.2 ab).symm⟩
    le_self_add := subset_union_left }

/- warning: set_semiring.image_hom -> SetSemiring.imageHom is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} [_inst_1 : MulOneClass.{u1} α] [_inst_2 : MulOneClass.{u2} β], (MonoidHom.{u1, u2} α β _inst_1 _inst_2) -> (RingHom.{u1, u2} (SetSemiring.{u1} α) (SetSemiring.{u2} β) (SetSemiring.nonAssocSemiring.{u1} α _inst_1) (SetSemiring.nonAssocSemiring.{u2} β _inst_2))
but is expected to have type
  forall {α : Type.{u1}} {β : Type.{u2}} [_inst_1 : MulOneClass.{u1} α] [_inst_2 : MulOneClass.{u2} β], (MonoidHom.{u1, u2} α β _inst_1 _inst_2) -> (RingHom.{u1, u2} (SetSemiring.{u1} α) (SetSemiring.{u2} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} β _inst_2))
Case conversion may be inaccurate. Consider using '#align set_semiring.image_hom SetSemiring.imageHomₓ'. -/
/-- The image of a set under a multiplicative homomorphism is a ring homomorphism
with respect to the pointwise operations on sets. -/
def imageHom [MulOneClass α] [MulOneClass β] (f : α →* β) : SetSemiring α →+* SetSemiring β
    where
  toFun s := (image f s.down).up
  map_zero' := image_empty _
  map_one' := by rw [down_one, image_one, map_one, singleton_one, Set.up_one]
  map_add' := image_union _
  map_mul' _ _ := image_mul f
#align set_semiring.image_hom SetSemiring.imageHom

/- warning: set_semiring.image_hom_def -> SetSemiring.imageHom_def is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} [_inst_1 : MulOneClass.{u1} α] [_inst_2 : MulOneClass.{u2} β] (f : MonoidHom.{u1, u2} α β _inst_1 _inst_2) (s : SetSemiring.{u1} α), Eq.{succ u2} (SetSemiring.{u2} β) (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RingHom.{u1, u2} (SetSemiring.{u1} α) (SetSemiring.{u2} β) (SetSemiring.nonAssocSemiring.{u1} α _inst_1) (SetSemiring.nonAssocSemiring.{u2} β _inst_2)) (fun (_x : RingHom.{u1, u2} (SetSemiring.{u1} α) (SetSemiring.{u2} β) (SetSemiring.nonAssocSemiring.{u1} α _inst_1) (SetSemiring.nonAssocSemiring.{u2} β _inst_2)) => (SetSemiring.{u1} α) -> (SetSemiring.{u2} β)) (RingHom.hasCoeToFun.{u1, u2} (SetSemiring.{u1} α) (SetSemiring.{u2} β) (SetSemiring.nonAssocSemiring.{u1} α _inst_1) (SetSemiring.nonAssocSemiring.{u2} β _inst_2)) (SetSemiring.imageHom.{u1, u2} α β _inst_1 _inst_2 f) s) (coeFn.{succ u2, succ u2} (Equiv.{succ u2, succ u2} (Set.{u2} β) (SetSemiring.{u2} β)) (fun (_x : Equiv.{succ u2, succ u2} (Set.{u2} β) (SetSemiring.{u2} β)) => (Set.{u2} β) -> (SetSemiring.{u2} β)) (Equiv.hasCoeToFun.{succ u2, succ u2} (Set.{u2} β) (SetSemiring.{u2} β)) (Set.up.{u2} β) (Set.image.{u1, u2} α β (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MonoidHom.{u1, u2} α β _inst_1 _inst_2) (fun (_x : MonoidHom.{u1, u2} α β _inst_1 _inst_2) => α -> β) (MonoidHom.hasCoeToFun.{u1, u2} α β _inst_1 _inst_2) f) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (fun (_x : Equiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) => (SetSemiring.{u1} α) -> (Set.{u1} α)) (Equiv.hasCoeToFun.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (SetSemiring.down.{u1} α) s)))
but is expected to have type
  forall {α : Type.{u2}} {β : Type.{u1}} [_inst_1 : MulOneClass.{u2} α] [_inst_2 : MulOneClass.{u1} β] (f : MonoidHom.{u2, u1} α β _inst_1 _inst_2) (s : SetSemiring.{u2} α), Eq.{succ u1} ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : SetSemiring.{u2} α) => SetSemiring.{u1} β) s) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (RingHom.{u2, u1} (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2)) (SetSemiring.{u2} α) (fun (_x : SetSemiring.{u2} α) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : SetSemiring.{u2} α) => SetSemiring.{u1} β) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (RingHom.{u2, u1} (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2)) (SetSemiring.{u2} α) (SetSemiring.{u1} β) (NonUnitalNonAssocSemiring.toMul.{u2} (SetSemiring.{u2} α) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} (SetSemiring.{u2} α) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1))) (NonUnitalNonAssocSemiring.toMul.{u1} (SetSemiring.{u1} β) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2))) (NonUnitalRingHomClass.toMulHomClass.{max u2 u1, u2, u1} (RingHom.{u2, u1} (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2)) (SetSemiring.{u2} α) (SetSemiring.{u1} β) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} (SetSemiring.{u2} α) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1)) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2)) (RingHomClass.toNonUnitalRingHomClass.{max u2 u1, u2, u1} (RingHom.{u2, u1} (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2)) (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2) (RingHom.instRingHomClassRingHom.{u2, u1} (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2))))) (SetSemiring.imageHom.{u2, u1} α β _inst_1 _inst_2 f) s) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (Set.{u1} β) (SetSemiring.{u1} β)) (Set.{u1} β) (fun (_x : Set.{u1} β) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Set.{u1} β) => SetSemiring.{u1} β) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (Set.{u1} β) (SetSemiring.{u1} β)) (Set.up.{u1} β) (Set.image.{u2, u1} α β (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MonoidHom.{u2, u1} α β _inst_1 _inst_2) α (fun (_x : α) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : α) => β) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MonoidHom.{u2, u1} α β _inst_1 _inst_2) α β (MulOneClass.toMul.{u2} α _inst_1) (MulOneClass.toMul.{u1} β _inst_2) (MonoidHomClass.toMulHomClass.{max u2 u1, u2, u1} (MonoidHom.{u2, u1} α β _inst_1 _inst_2) α β _inst_1 _inst_2 (MonoidHom.monoidHomClass.{u2, u1} α β _inst_1 _inst_2))) f) (FunLike.coe.{succ u2, succ u2, succ u2} (Equiv.{succ u2, succ u2} (SetSemiring.{u2} α) (Set.{u2} α)) (SetSemiring.{u2} α) (fun (_x : SetSemiring.{u2} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : SetSemiring.{u2} α) => Set.{u2} α) _x) (Equiv.instFunLikeEquiv.{succ u2, succ u2} (SetSemiring.{u2} α) (Set.{u2} α)) (SetSemiring.down.{u2} α) s)))
Case conversion may be inaccurate. Consider using '#align set_semiring.image_hom_def SetSemiring.imageHom_defₓ'. -/
theorem imageHom_def [MulOneClass α] [MulOneClass β] (f : α →* β) (s : SetSemiring α) :
    imageHom f s = (image f s.down).up :=
  rfl
#align set_semiring.image_hom_def SetSemiring.imageHom_def

/- warning: set_semiring.down_image_hom -> SetSemiring.down_imageHom is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} [_inst_1 : MulOneClass.{u1} α] [_inst_2 : MulOneClass.{u2} β] (f : MonoidHom.{u1, u2} α β _inst_1 _inst_2) (s : SetSemiring.{u1} α), Eq.{succ u2} (Set.{u2} β) (coeFn.{succ u2, succ u2} (Equiv.{succ u2, succ u2} (SetSemiring.{u2} β) (Set.{u2} β)) (fun (_x : Equiv.{succ u2, succ u2} (SetSemiring.{u2} β) (Set.{u2} β)) => (SetSemiring.{u2} β) -> (Set.{u2} β)) (Equiv.hasCoeToFun.{succ u2, succ u2} (SetSemiring.{u2} β) (Set.{u2} β)) (SetSemiring.down.{u2} β) (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RingHom.{u1, u2} (SetSemiring.{u1} α) (SetSemiring.{u2} β) (SetSemiring.nonAssocSemiring.{u1} α _inst_1) (SetSemiring.nonAssocSemiring.{u2} β _inst_2)) (fun (_x : RingHom.{u1, u2} (SetSemiring.{u1} α) (SetSemiring.{u2} β) (SetSemiring.nonAssocSemiring.{u1} α _inst_1) (SetSemiring.nonAssocSemiring.{u2} β _inst_2)) => (SetSemiring.{u1} α) -> (SetSemiring.{u2} β)) (RingHom.hasCoeToFun.{u1, u2} (SetSemiring.{u1} α) (SetSemiring.{u2} β) (SetSemiring.nonAssocSemiring.{u1} α _inst_1) (SetSemiring.nonAssocSemiring.{u2} β _inst_2)) (SetSemiring.imageHom.{u1, u2} α β _inst_1 _inst_2 f) s)) (Set.image.{u1, u2} α β (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MonoidHom.{u1, u2} α β _inst_1 _inst_2) (fun (_x : MonoidHom.{u1, u2} α β _inst_1 _inst_2) => α -> β) (MonoidHom.hasCoeToFun.{u1, u2} α β _inst_1 _inst_2) f) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (fun (_x : Equiv.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) => (SetSemiring.{u1} α) -> (Set.{u1} α)) (Equiv.hasCoeToFun.{succ u1, succ u1} (SetSemiring.{u1} α) (Set.{u1} α)) (SetSemiring.down.{u1} α) s))
but is expected to have type
  forall {α : Type.{u2}} {β : Type.{u1}} [_inst_1 : MulOneClass.{u2} α] [_inst_2 : MulOneClass.{u1} β] (f : MonoidHom.{u2, u1} α β _inst_1 _inst_2) (s : SetSemiring.{u2} α), Eq.{succ u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : SetSemiring.{u1} β) => Set.{u1} β) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (RingHom.{u2, u1} (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2)) (SetSemiring.{u2} α) (fun (a : SetSemiring.{u2} α) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : SetSemiring.{u2} α) => SetSemiring.{u1} β) a) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (RingHom.{u2, u1} (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2)) (SetSemiring.{u2} α) (SetSemiring.{u1} β) (NonUnitalNonAssocSemiring.toMul.{u2} (SetSemiring.{u2} α) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} (SetSemiring.{u2} α) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1))) (NonUnitalNonAssocSemiring.toMul.{u1} (SetSemiring.{u1} β) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2))) (NonUnitalRingHomClass.toMulHomClass.{max u2 u1, u2, u1} (RingHom.{u2, u1} (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2)) (SetSemiring.{u2} α) (SetSemiring.{u1} β) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} (SetSemiring.{u2} α) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1)) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2)) (RingHomClass.toNonUnitalRingHomClass.{max u2 u1, u2, u1} (RingHom.{u2, u1} (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2)) (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2) (RingHom.instRingHomClassRingHom.{u2, u1} (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2))))) (SetSemiring.imageHom.{u2, u1} α β _inst_1 _inst_2 f) s)) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (SetSemiring.{u1} β) (Set.{u1} β)) (SetSemiring.{u1} β) (fun (_x : SetSemiring.{u1} β) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : SetSemiring.{u1} β) => Set.{u1} β) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (SetSemiring.{u1} β) (Set.{u1} β)) (SetSemiring.down.{u1} β) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (RingHom.{u2, u1} (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2)) (SetSemiring.{u2} α) (fun (_x : SetSemiring.{u2} α) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : SetSemiring.{u2} α) => SetSemiring.{u1} β) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (RingHom.{u2, u1} (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2)) (SetSemiring.{u2} α) (SetSemiring.{u1} β) (NonUnitalNonAssocSemiring.toMul.{u2} (SetSemiring.{u2} α) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} (SetSemiring.{u2} α) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1))) (NonUnitalNonAssocSemiring.toMul.{u1} (SetSemiring.{u1} β) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2))) (NonUnitalRingHomClass.toMulHomClass.{max u2 u1, u2, u1} (RingHom.{u2, u1} (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2)) (SetSemiring.{u2} α) (SetSemiring.{u1} β) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} (SetSemiring.{u2} α) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1)) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2)) (RingHomClass.toNonUnitalRingHomClass.{max u2 u1, u2, u1} (RingHom.{u2, u1} (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2)) (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2) (RingHom.instRingHomClassRingHom.{u2, u1} (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2))))) (SetSemiring.imageHom.{u2, u1} α β _inst_1 _inst_2 f) s)) (Set.image.{u2, u1} α β (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MonoidHom.{u2, u1} α β _inst_1 _inst_2) α (fun (_x : α) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : α) => β) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MonoidHom.{u2, u1} α β _inst_1 _inst_2) α β (MulOneClass.toMul.{u2} α _inst_1) (MulOneClass.toMul.{u1} β _inst_2) (MonoidHomClass.toMulHomClass.{max u2 u1, u2, u1} (MonoidHom.{u2, u1} α β _inst_1 _inst_2) α β _inst_1 _inst_2 (MonoidHom.monoidHomClass.{u2, u1} α β _inst_1 _inst_2))) f) (FunLike.coe.{succ u2, succ u2, succ u2} (Equiv.{succ u2, succ u2} (SetSemiring.{u2} α) (Set.{u2} α)) (SetSemiring.{u2} α) (fun (_x : SetSemiring.{u2} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : SetSemiring.{u2} α) => Set.{u2} α) _x) (Equiv.instFunLikeEquiv.{succ u2, succ u2} (SetSemiring.{u2} α) (Set.{u2} α)) (SetSemiring.down.{u2} α) s))
Case conversion may be inaccurate. Consider using '#align set_semiring.down_image_hom SetSemiring.down_imageHomₓ'. -/
@[simp]
theorem down_imageHom [MulOneClass α] [MulOneClass β] (f : α →* β) (s : SetSemiring α) :
    (imageHom f s).down = f '' s.down :=
  rfl
#align set_semiring.down_image_hom SetSemiring.down_imageHom

/- warning: set.up_image -> Set.up_image is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} [_inst_1 : MulOneClass.{u1} α] [_inst_2 : MulOneClass.{u2} β] (f : MonoidHom.{u1, u2} α β _inst_1 _inst_2) (s : Set.{u1} α), Eq.{succ u2} (SetSemiring.{u2} β) (coeFn.{succ u2, succ u2} (Equiv.{succ u2, succ u2} (Set.{u2} β) (SetSemiring.{u2} β)) (fun (_x : Equiv.{succ u2, succ u2} (Set.{u2} β) (SetSemiring.{u2} β)) => (Set.{u2} β) -> (SetSemiring.{u2} β)) (Equiv.hasCoeToFun.{succ u2, succ u2} (Set.{u2} β) (SetSemiring.{u2} β)) (Set.up.{u2} β) (Set.image.{u1, u2} α β (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MonoidHom.{u1, u2} α β _inst_1 _inst_2) (fun (_x : MonoidHom.{u1, u2} α β _inst_1 _inst_2) => α -> β) (MonoidHom.hasCoeToFun.{u1, u2} α β _inst_1 _inst_2) f) s)) (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RingHom.{u1, u2} (SetSemiring.{u1} α) (SetSemiring.{u2} β) (SetSemiring.nonAssocSemiring.{u1} α _inst_1) (SetSemiring.nonAssocSemiring.{u2} β _inst_2)) (fun (_x : RingHom.{u1, u2} (SetSemiring.{u1} α) (SetSemiring.{u2} β) (SetSemiring.nonAssocSemiring.{u1} α _inst_1) (SetSemiring.nonAssocSemiring.{u2} β _inst_2)) => (SetSemiring.{u1} α) -> (SetSemiring.{u2} β)) (RingHom.hasCoeToFun.{u1, u2} (SetSemiring.{u1} α) (SetSemiring.{u2} β) (SetSemiring.nonAssocSemiring.{u1} α _inst_1) (SetSemiring.nonAssocSemiring.{u2} β _inst_2)) (SetSemiring.imageHom.{u1, u2} α β _inst_1 _inst_2 f) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (fun (_x : Equiv.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) => (Set.{u1} α) -> (SetSemiring.{u1} α)) (Equiv.hasCoeToFun.{succ u1, succ u1} (Set.{u1} α) (SetSemiring.{u1} α)) (Set.up.{u1} α) s))
but is expected to have type
  forall {α : Type.{u2}} {β : Type.{u1}} [_inst_1 : MulOneClass.{u2} α] [_inst_2 : MulOneClass.{u1} β] (f : MonoidHom.{u2, u1} α β _inst_1 _inst_2) (s : Set.{u2} α), Eq.{succ u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Set.{u1} β) => SetSemiring.{u1} β) (Set.image.{u2, u1} α β (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MonoidHom.{u2, u1} α β _inst_1 _inst_2) α (fun (a : α) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : α) => β) a) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MonoidHom.{u2, u1} α β _inst_1 _inst_2) α β (MulOneClass.toMul.{u2} α _inst_1) (MulOneClass.toMul.{u1} β _inst_2) (MonoidHomClass.toMulHomClass.{max u2 u1, u2, u1} (MonoidHom.{u2, u1} α β _inst_1 _inst_2) α β _inst_1 _inst_2 (MonoidHom.monoidHomClass.{u2, u1} α β _inst_1 _inst_2))) f) s)) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} (Set.{u1} β) (SetSemiring.{u1} β)) (Set.{u1} β) (fun (_x : Set.{u1} β) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Set.{u1} β) => SetSemiring.{u1} β) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} (Set.{u1} β) (SetSemiring.{u1} β)) (Set.up.{u1} β) (Set.image.{u2, u1} α β (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MonoidHom.{u2, u1} α β _inst_1 _inst_2) α (fun (_x : α) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : α) => β) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MonoidHom.{u2, u1} α β _inst_1 _inst_2) α β (MulOneClass.toMul.{u2} α _inst_1) (MulOneClass.toMul.{u1} β _inst_2) (MonoidHomClass.toMulHomClass.{max u2 u1, u2, u1} (MonoidHom.{u2, u1} α β _inst_1 _inst_2) α β _inst_1 _inst_2 (MonoidHom.monoidHomClass.{u2, u1} α β _inst_1 _inst_2))) f) s)) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (RingHom.{u2, u1} (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2)) (SetSemiring.{u2} α) (fun (_x : SetSemiring.{u2} α) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : SetSemiring.{u2} α) => SetSemiring.{u1} β) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (RingHom.{u2, u1} (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2)) (SetSemiring.{u2} α) (SetSemiring.{u1} β) (NonUnitalNonAssocSemiring.toMul.{u2} (SetSemiring.{u2} α) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} (SetSemiring.{u2} α) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1))) (NonUnitalNonAssocSemiring.toMul.{u1} (SetSemiring.{u1} β) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2))) (NonUnitalRingHomClass.toMulHomClass.{max u2 u1, u2, u1} (RingHom.{u2, u1} (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2)) (SetSemiring.{u2} α) (SetSemiring.{u1} β) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} (SetSemiring.{u2} α) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1)) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2)) (RingHomClass.toNonUnitalRingHomClass.{max u2 u1, u2, u1} (RingHom.{u2, u1} (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2)) (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2) (RingHom.instRingHomClassRingHom.{u2, u1} (SetSemiring.{u2} α) (SetSemiring.{u1} β) (SetSemiring.instNonAssocSemiringSetSemiring.{u2} α _inst_1) (SetSemiring.instNonAssocSemiringSetSemiring.{u1} β _inst_2))))) (SetSemiring.imageHom.{u2, u1} α β _inst_1 _inst_2 f) (FunLike.coe.{succ u2, succ u2, succ u2} (Equiv.{succ u2, succ u2} (Set.{u2} α) (SetSemiring.{u2} α)) (Set.{u2} α) (fun (_x : Set.{u2} α) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Set.{u2} α) => SetSemiring.{u2} α) _x) (Equiv.instFunLikeEquiv.{succ u2, succ u2} (Set.{u2} α) (SetSemiring.{u2} α)) (Set.up.{u2} α) s))
Case conversion may be inaccurate. Consider using '#align set.up_image Set.up_imageₓ'. -/
@[simp]
theorem Set.up_image [MulOneClass α] [MulOneClass β] (f : α →* β) (s : Set α) :
    (f '' s).up = imageHom f s.up :=
  rfl
#align set.up_image Set.up_image

end SetSemiring


/-
Copyright (c) 2018 Johannes Hölzl. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johannes Hölzl, Jens Wagemaker

Theory of unique factorization domains.

@TODO: setup the complete lattice structure on `factor_set`.
-/
import algebra.gcd_domain

variables {α : Type*}
local infix ` ~ᵤ ` : 50 := associated

/-- Unique factorization domains.

In a unique factorization domain each element (except zero) is uniquely
represented as a multiset of irreducible factors.
Uniqueness is only up to associated elements.

This is equivalent to defining a unique factorization domain as a domain in
which each element (except zero) is non-uniquely represented as a multiset
of prime factors. This definition is used.

To define a UFD using the traditional definition in terms of multisets
of irreducible factors, use the definition `of_unique_irreducible_factorization`

-/
class unique_factorization_domain (α : Type*) [integral_domain α] :=
(factors : α → multiset α)
(factors_prod : ∀{a : α}, a ≠ 0 → (factors a).prod ~ᵤ a)
(prime_factors : ∀{a : α}, a ≠ 0 → ∀x∈factors a, prime x)

namespace unique_factorization_domain

variables [integral_domain α] [unique_factorization_domain α]

@[elab_as_eliminator] lemma induction_on_prime {P : α → Prop}
  (a : α) (h₁ : P 0) (h₂ : ∀ x : α, is_unit x → P x)
  (h₃ : ∀ a p : α, a ≠ 0 → prime p → P a → P (p * a)) : P a :=
by haveI := classical.dec_eq α; exact
if ha0 : a = 0 then ha0.symm ▸ h₁
else @multiset.induction_on _
  (λ s : multiset α, ∀ (a : α), a ≠ 0 → s.prod ~ᵤ a → (∀ p ∈ s, prime p) →  P a)
  (factors a)
  (λ _ _ h _, h₂ _ ((is_unit_iff_of_associated h.symm).2 is_unit_one))
  (λ p s ih a ha0 ⟨u, hu⟩ hsp,
    have ha : a = (p * u) * s.prod, by simp [hu.symm, mul_comm, mul_assoc],
    have hs0 : s.prod ≠ 0, from λ _ : s.prod = 0, by simp * at *,
    ha.symm ▸ h₃ _ _ hs0
      (prime_of_associated ⟨u, rfl⟩ (hsp p (multiset.mem_cons_self _ _)))
      (ih _ hs0 (by refl) (λ p hp, hsp p (multiset.mem_cons.2 (or.inr hp)))))
  _
  ha0
  (factors_prod ha0)
  (prime_factors ha0)

lemma factors_irreducible {a : α} (ha : irreducible a) :
  ∃ p, a ~ᵤ p ∧ factors a = p :: 0 :=
by haveI := classical.dec_eq α; exact
multiset.induction_on (factors a)
  (λ h, (ha.1 (associated_one_iff_is_unit.1 h.symm)).elim)
  (λ p s _ hp hs, let ⟨u, hu⟩ := hp in ⟨p,
    have hs0 : s = 0, from classical.by_contradiction
      (λ hs0, let ⟨q, hq⟩ := multiset.exists_mem_of_ne_zero hs0 in
       (hs q (by simp [hq])).2.1 $
        (ha.2 ((p * u) * (s.erase q).prod) _
          (by rw [mul_right_comm _ _ q, mul_assoc, ← multiset.prod_cons,
            multiset.cons_erase hq]; simp [hu.symm, mul_comm, mul_assoc])).resolve_left $
              mt is_unit_of_mul_is_unit_left $ mt is_unit_of_mul_is_unit_left
                (hs p (multiset.mem_cons_self _ _)).2.1),
    ⟨associated.symm (by clear _let_match; simp * at *), hs0 ▸ rfl⟩⟩)
  (factors_prod (nonzero_of_irreducible ha))
  (prime_factors (nonzero_of_irreducible ha))

lemma irreducible_iff_prime {p : α} : irreducible p ↔ prime p :=
by letI := classical.dec_eq α; exact
if hp0 : p = 0 then by simp [hp0]
else
  ⟨λ h, let ⟨q, hq⟩ := factors_irreducible h in
      have prime q, from hq.2 ▸ prime_factors hp0 _ (by simp [hq.2]),
      suffices prime (factors p).prod,
        from prime_of_associated (factors_prod hp0) this,
      hq.2.symm ▸ by simp [this],
    irreducible_of_prime⟩

lemma irreducible_factors : ∀{a : α}, a ≠ 0 → ∀x∈factors a, irreducible x :=
by simp only [irreducible_iff_prime]; exact @prime_factors _ _ _

lemma unique : ∀{f g : multiset α},
  (∀x∈f, irreducible x) → (∀x∈g, irreducible x) → f.prod ~ᵤ g.prod →
  multiset.rel associated f g :=
by haveI := classical.dec_eq α; exact
λ f, multiset.induction_on f
  (λ g _ hg h,
    multiset.rel_zero_left.2 $
      multiset.eq_zero_of_forall_not_mem (λ x hx,
        have is_unit g.prod, by simpa [associated_one_iff_is_unit] using h.symm,
        (hg x hx).1 (is_unit_iff_dvd_one.2 (dvd.trans (multiset.dvd_prod hx)
          (is_unit_iff_dvd_one.1 this)))))
  (λ p f ih g hf hg hfg,
    let ⟨b, hbg, hb⟩ := exists_associated_mem_of_dvd_prod
      (irreducible_iff_prime.1 (hf p (by simp)))
      (λ q hq, irreducible_iff_prime.1 (hg _ hq)) $
        (dvd_iff_dvd_of_rel_right hfg).1
          (show p ∣ (p :: f).prod, by simp) in
    begin
      rw ← multiset.cons_erase hbg,
      exact multiset.rel.cons hb (ih (λ q hq, hf _ (by simp [hq]))
        (λ q (hq : q ∈ g.erase b), hg q (multiset.mem_of_mem_erase hq))
        (associated_mul_left_cancel
          (by rwa [← multiset.prod_cons, ← multiset.prod_cons, multiset.cons_erase hbg]) hb
        (nonzero_of_irreducible (hf p (by simp)))))
    end)

end unique_factorization_domain

structure unique_irreducible_factorization (α : Type*) [integral_domain α] :=
(factors : α → multiset α)
(factors_prod : ∀{a : α}, a ≠ 0 → (factors a).prod ~ᵤ a)
(irreducible_factors : ∀{a : α}, a ≠ 0 →  ∀x∈factors a, irreducible x)
(unique : ∀{f g : multiset α},
  (∀x∈f, irreducible x) → (∀x∈g, irreducible x) → f.prod ~ᵤ g.prod → multiset.rel associated f g)

namespace unique_factorization_domain
open unique_factorization_domain associated lattice
variables [integral_domain α] [unique_factorization_domain α] [decidable_eq (associates α)]

lemma exists_mem_factors_of_dvd {a p : α} (ha0 : a ≠ 0) (hp : irreducible p) : p ∣ a →
  ∃ q ∈ factors a, p ~ᵤ q :=
λ ⟨b, hb⟩,
have hb0 : b ≠ 0, from λ hb0, by simp * at *,
have multiset.rel associated (p :: factors b) (factors a),
  from unique
    (λ x hx, (multiset.mem_cons.1 hx).elim (λ h, h.symm ▸ hp)
      (irreducible_factors hb0 _))
    (irreducible_factors ha0)
    (associated.symm $ calc multiset.prod (factors a) ~ᵤ a : factors_prod ha0
      ... = p * b : hb
      ... ~ᵤ multiset.prod (p :: factors b) :
        by rw multiset.prod_cons; exact associated_mul_mul
          (associated.refl _)
          (associated.symm (factors_prod hb0))),
multiset.exists_mem_of_rel_of_mem this (by simp)

def of_unique_irreducible_factorization {α : Type*} [integral_domain α]
  (o : unique_irreducible_factorization α) : unique_factorization_domain α :=
by letI := classical.dec_eq α; exact
{ prime_factors := λ a h p (hpa : p ∈ o.factors a),
    have hpi : irreducible p, from o.irreducible_factors h _ hpa,
    ⟨nonzero_of_irreducible hpi, hpi.1,
      λ a b ⟨x, hx⟩,
      if hab0 : a * b = 0
      then (eq_zero_or_eq_zero_of_mul_eq_zero hab0).elim
        (λ ha0, by simp [ha0])
        (λ hb0, by simp [hb0])
      else
        have hx0 : x ≠ 0, from λ hx0, by simp * at *,
        have ha0 : a ≠ 0, from ne_zero_of_mul_ne_zero_right hab0,
        have hb0 : b ≠ 0, from ne_zero_of_mul_ne_zero_left hab0,
        have multiset.rel associated  (p :: o.factors x) (o.factors a + o.factors b),
          from o.unique
            (λ i hi, (multiset.mem_cons.1 hi).elim
              (λ hip, hip.symm ▸ hpi)
              (o.irreducible_factors hx0 _))
            (show ∀ x ∈ o.factors a + o.factors b, irreducible x,
              from λ x hx, (multiset.mem_add.1 hx).elim
                (o.irreducible_factors (ne_zero_of_mul_ne_zero_right hab0) _)
                (o.irreducible_factors (ne_zero_of_mul_ne_zero_left hab0) _)) $
              calc multiset.prod (p :: o.factors x)
                  ~ᵤ a * b : by rw [hx, multiset.prod_cons];
                    exact associated_mul_mul (by refl)
                      (o.factors_prod hx0)
              ... ~ᵤ (o.factors a).prod * (o.factors b).prod :
                associated_mul_mul
                  (o.factors_prod ha0).symm
                  (o.factors_prod hb0).symm
              ... = _ : by rw multiset.prod_add,
        let ⟨q, hqf, hq⟩ := multiset.exists_mem_of_rel_of_mem this
          (multiset.mem_cons_self p _) in
        (multiset.mem_add.1 hqf).elim
          (λ hqa, or.inl $ (dvd_iff_dvd_of_rel_left hq).2 $
            (dvd_iff_dvd_of_rel_right (o.factors_prod ha0)).1
              (multiset.dvd_prod hqa))
          (λ hqb, or.inr $ (dvd_iff_dvd_of_rel_left hq).2 $
            (dvd_iff_dvd_of_rel_right (o.factors_prod hb0)).1
              (multiset.dvd_prod hqb))⟩,
  ..o }

end unique_factorization_domain

namespace associates
open unique_factorization_domain associated lattice
variables [integral_domain α] [unique_factorization_domain α] [decidable_eq (associates α)]

/-- `factor_set α` representation elements of unique factorization domain as multisets.

`multiset α` produced by `factors` are only unique up to associated elements, while the multisets in
`factor_set α` are unqiue by equality and restricted to irreducible elements. This gives us a
representation of each element as a unique multisets (or the added ⊤ for 0), which has a complete
lattice struture. Infimum is the greatest common divisor and supremum is the least common multiple.
-/
@[reducible] def {u} factor_set (α : Type u) [integral_domain α] [unique_factorization_domain α] :
  Type u :=
with_top (multiset { a : associates α // irreducible a })

local attribute [instance] associated.setoid

theorem unique' {p q : multiset (associates α)} :
  (∀a∈p, irreducible a) → (∀a∈q, irreducible a) → p.prod = q.prod → p = q :=
begin
  apply multiset.induction_on_multiset_quot p,
  apply multiset.induction_on_multiset_quot q,
  assume s t hs ht eq,
  refine multiset.map_mk_eq_map_mk_of_rel (unique_factorization_domain.unique _ _ _),
  { exact assume a ha, ((irreducible_mk_iff _).1 $ hs _ $ multiset.mem_map_of_mem _ ha) },
  { exact assume a ha, ((irreducible_mk_iff _).1 $ ht _ $ multiset.mem_map_of_mem _ ha) },
  simpa [quot_mk_eq_mk, prod_mk, mk_eq_mk_iff_associated] using eq
end

private theorem forall_map_mk_factors_irreducible (x : α) (hx : x ≠ 0) :
  ∀(a : associates α), a ∈ multiset.map associates.mk (factors x) → irreducible a :=
begin
  assume a ha,
  rcases multiset.mem_map.1 ha with ⟨c, hc, rfl⟩,
  exact (irreducible_mk_iff c).2 (irreducible_factors hx _ hc)
end

theorem prod_le_prod_iff_le {p q : multiset (associates α)}
  (hp : ∀a∈p, irreducible a) (hq : ∀a∈q, irreducible a) :
  p.prod ≤ q.prod ↔ p ≤ q :=
iff.intro
  begin
    rintros ⟨⟨c⟩, eq⟩,
    have : c ≠ 0, from (mt mk_eq_zero_iff_eq_zero.2 $
      assume (hc : quot.mk setoid.r c = 0),
      have (0 : associates α) ∈ q, from prod_eq_zero_iff.1 $ eq ▸ hc.symm ▸ mul_zero _,
      not_irreducible_zero ((irreducible_mk_iff 0).1 $ hq _ this)),
    have : associates.mk (factors c).prod = quot.mk setoid.r c,
      from mk_eq_mk_iff_associated.2 (factors_prod this),

    refine le_iff_exists_add.2 ⟨(factors c).map associates.mk, unique' hq _ _⟩,
    { assume x hx,
      rcases multiset.mem_add.1 hx with h | h,
      exact hp x h,
      exact forall_map_mk_factors_irreducible c ‹c ≠ 0› _ h },
    { simp [multiset.prod_add, prod_mk, *] at * }
  end
  prod_le_prod

@[simp] theorem factor_set.coe_add {a b : multiset { a : associates α // irreducible a }} :
  (↑a + ↑b : factor_set α) = ↑(a + b) :=
with_top.coe_add

lemma factor_set.sup_add_inf_eq_add : ∀(a b : factor_set α), a ⊔ b + a ⊓ b = a + b
| none     b        := show ⊤ ⊔ b + ⊤ ⊓ b = ⊤ + b, by simp
| a        none     := show a ⊔ ⊤ + a ⊓ ⊤ = a + ⊤, by simp
| (some a) (some b) := show (a : factor_set α) ⊔ b + a ⊓ b = a + b, from
  begin
    rw [← with_top.coe_sup, ← with_top.coe_inf, ← with_top.coe_add, ← with_top.coe_add,
      with_top.coe_eq_coe],
    exact multiset.union_add_inter _ _
  end

def factors' (a : α) (ha : a ≠ 0) : multiset { a : associates α // irreducible a } :=
(factors a).pmap (λa ha, ⟨associates.mk a, (irreducible_mk_iff _).2 ha⟩)
  (irreducible_factors $ ha)

@[simp] theorem map_subtype_val_factors' {a : α} (ha : a ≠ 0) :
  (factors' a ha).map subtype.val = (factors a).map associates.mk :=
by simp [factors', multiset.map_pmap, multiset.pmap_eq_map]

theorem factors'_cong {a b : α} (ha : a ≠ 0) (hb : b ≠ 0) (h : a ~ᵤ b) :
  factors' a ha = factors' b hb :=
have multiset.rel associated (factors a) (factors b), from
  unique (irreducible_factors ha) (irreducible_factors hb)
    ((factors_prod ha).trans $ h.trans $ (factors_prod hb).symm),
by simpa [(multiset.map_eq_map subtype.val_injective).symm, rel_associated_iff_map_eq_map.symm]

def factors (a : associates α) : factor_set α :=
begin
  refine (if h : a = 0 then ⊤ else
    quotient.hrec_on a (λx h, some $ factors' x (mt mk_eq_zero_iff_eq_zero.2 h)) _ h),

  assume a b hab,
  apply function.hfunext,
  { have : a ~ᵤ 0 ↔ b ~ᵤ 0, from
      iff.intro (assume ha0, hab.symm.trans ha0) (assume hb0, hab.trans hb0),
    simp [quotient_mk_eq_mk, mk_eq_zero_iff_eq_zero, (associated_zero_iff_eq_zero _).symm, this] },
  exact (assume ha hb eq, heq_of_eq $ congr_arg some $ factors'_cong _ _ hab)
end

@[simp] theorem factors_0 : (0 : associates α).factors = ⊤ :=
dif_pos rfl

@[simp] theorem factors_mk (a : α) (h : a ≠ 0) : (associates.mk a).factors = factors' a h :=
dif_neg (mt mk_eq_zero_iff_eq_zero.1 h)

def factor_set.prod : factor_set α → associates α
| none     := 0
| (some s) := (s.map subtype.val).prod

@[simp] theorem prod_top : (⊤ : factor_set α).prod = 0 := rfl

@[simp] theorem prod_coe {s : multiset { a : associates α // irreducible a }} :
  (s : factor_set α).prod = (s.map subtype.val).prod :=
rfl

theorem prod_factors : ∀(s : factor_set α), s.prod.factors = s
| none     := by simp [factor_set.prod]; refl
| (some s) :=
  begin
    unfold factor_set.prod,
    generalize eq_a : (s.map subtype.val).prod = a,
    rcases a with ⟨a⟩,
    rw quot_mk_eq_mk at *,

    have : (s.map subtype.val).prod ≠ 0, from assume ha,
      let ⟨⟨a, ha⟩, h, eq⟩ := multiset.mem_map.1 (prod_eq_zero_iff.1 ha) in
      have irreducible (0 : associates α), from eq ▸ ha,
      not_irreducible_zero ((irreducible_mk_iff _).1 this),
    have ha : a ≠ 0, by simp [*] at *,
    suffices : (unique_factorization_domain.factors a).map associates.mk = s.map subtype.val,
    { rw [factors_mk a ha],
      apply congr_arg some _,
      simpa [(multiset.map_eq_map subtype.val_injective).symm] },

    refine unique'
      (forall_map_mk_factors_irreducible _ ha)
      (assume a ha, let ⟨⟨x, hx⟩, ha, eq⟩ := multiset.mem_map.1 ha in eq ▸ hx)
      _,
    rw [prod_mk, eq_a, mk_eq_mk_iff_associated],
    exact factors_prod ha
  end

theorem factors_prod (a : associates α) : a.factors.prod = a :=
quotient.induction_on a $ assume a, decidable.by_cases
  (assume : associates.mk a = 0, by simp [quotient_mk_eq_mk, this])
  (assume : associates.mk a ≠ 0,
    have a ≠ 0, by simp * at *,
    by simp [this, quotient_mk_eq_mk, prod_mk, mk_eq_mk_iff_associated.2 (factors_prod this)])

theorem eq_of_factors_eq_factors {a b : associates α} (h : a.factors = b.factors) : a = b :=
have a.factors.prod = b.factors.prod, by rw h,
by rwa [factors_prod, factors_prod] at this

theorem eq_of_prod_eq_prod {a b : factor_set α} (h : a.prod = b.prod) : a = b :=
have a.prod.factors = b.prod.factors, by rw h,
by rwa [prod_factors, prod_factors] at this

@[simp] theorem prod_add : ∀(a b : factor_set α), (a + b).prod = a.prod * b.prod
| none b    := show (⊤ + b).prod = (⊤:factor_set α).prod * b.prod, by simp
| a    none := show (a + ⊤).prod = a.prod * (⊤:factor_set α).prod, by simp
| (some a) (some b) :=
  show (↑a + ↑b:factor_set α).prod = (↑a:factor_set α).prod * (↑b:factor_set α).prod,
    by rw [factor_set.coe_add, prod_coe, prod_coe, prod_coe, multiset.map_add, multiset.prod_add]

theorem prod_mono : ∀{a b : factor_set α}, a ≤ b → a.prod ≤ b.prod
| none b h := have b = ⊤, from top_unique h, by rw [this, prod_top]; exact le_refl _
| a none h := show a.prod ≤ (⊤ : factor_set α).prod, by simp; exact le_top
| (some a) (some b) h := prod_le_prod $ multiset.map_le_map $ with_top.coe_le_coe.1 $ h

@[simp] theorem factors_mul (a b : associates α) : (a * b).factors = a.factors + b.factors :=
eq_of_prod_eq_prod $ eq_of_factors_eq_factors $
  by rw [prod_add, factors_prod, factors_prod, factors_prod]

theorem factors_mono : ∀{a b : associates α}, a ≤ b → a.factors ≤ b.factors
| s t ⟨d, rfl⟩ := by rw [factors_mul] ; exact le_add_of_nonneg_right' bot_le

theorem factors_le {a b : associates α} : a.factors ≤ b.factors ↔ a ≤ b :=
iff.intro
  (assume h, have a.factors.prod ≤ b.factors.prod, from prod_mono h,
    by rwa [factors_prod, factors_prod] at this)
  factors_mono

theorem prod_le {a b : factor_set α} : a.prod ≤ b.prod ↔ a ≤ b :=
iff.intro
  (assume h, have a.prod.factors ≤ b.prod.factors, from factors_mono h,
    by rwa [prod_factors, prod_factors] at this)
  prod_mono

instance : has_sup (associates α) := ⟨λa b, (a.factors ⊔ b.factors).prod⟩
instance : has_inf (associates α) := ⟨λa b, (a.factors ⊓ b.factors).prod⟩

instance : bounded_lattice (associates α) :=
{ sup          := (⊔),
  inf          := (⊓),
  sup_le       :=
    assume a b c hac hbc, factors_prod c ▸ prod_mono (sup_le (factors_mono hac) (factors_mono hbc)),
  le_sup_left  := assume a b,
    le_trans (le_of_eq (factors_prod a).symm) $ prod_mono $ le_sup_left,
  le_sup_right := assume a b,
    le_trans (le_of_eq (factors_prod b).symm) $ prod_mono $ le_sup_right,
  le_inf :=
    assume a b c hac hbc, factors_prod a ▸ prod_mono (le_inf (factors_mono hac) (factors_mono hbc)),
  inf_le_left  := assume a b,
    le_trans (prod_mono inf_le_left) (le_of_eq (factors_prod a)),
  inf_le_right := assume a b,
    le_trans (prod_mono inf_le_right) (le_of_eq (factors_prod b)),
  .. associates.partial_order,
  .. associates.lattice.order_top,
  .. associates.lattice.order_bot }

lemma sup_mul_inf (a b : associates α) : (a ⊔ b) * (a ⊓ b) = a * b :=
show (a.factors ⊔ b.factors).prod * (a.factors ⊓ b.factors).prod = a * b,
begin
  refine eq_of_factors_eq_factors _,
  rw [← prod_add, prod_factors, factors_mul, factor_set.sup_add_inf_eq_add]
end

end associates

section
open associates unique_factorization_domain lattice

/-- `to_gcd_domain` constructs a GCD domain out of a unique factorization domain over a normalization
domain. -/
def unique_factorization_domain.to_gcd_domain
  (α : Type*) [normalization_domain α] [unique_factorization_domain α] [decidable_eq (associates α)] :
  gcd_domain α :=
{ gcd := λa b, (associates.mk a ⊓ associates.mk b).out,
  lcm := λa b, (associates.mk a ⊔ associates.mk b).out,
  gcd_dvd_left := assume a b, (out_dvd_iff a (associates.mk a ⊓ associates.mk b)).2 $ inf_le_left,
  gcd_dvd_right := assume a b, (out_dvd_iff b (associates.mk a ⊓ associates.mk b)).2 $ inf_le_right,
  dvd_gcd := assume a b c hac hab, show a ∣ (associates.mk c ⊓ associates.mk b).out,
    by rw [dvd_out_iff, le_inf_iff, mk_le_mk_iff_dvd_iff, mk_le_mk_iff_dvd_iff]; exact ⟨hac, hab⟩,
  lcm_zero_left := assume a, show (⊤ ⊔ associates.mk a).out = 0, by simp,
  lcm_zero_right := assume a, show (associates.mk a ⊔ ⊤).out = 0, by simp,
  gcd_mul_lcm := assume a b,
    show (associates.mk a ⊓ associates.mk b).out * (associates.mk a ⊔ associates.mk b).out =
      normalize (a * b),
    by rw [← out_mk, ← out_mul, mul_comm, sup_mul_inf]; refl,
  normalize_gcd := assume a b, by convert normalize_out _,
  .. ‹normalization_domain α› }

end


import topology.bounded_continuous_function

noncomputable theory
open set classical
local attribute [instance] prop_decidable

variables {X : Type*} [metric_space X] [compact_space X]

-- We adopt the notation of bounded countinuous function from mathlib
local infixr ` →ᵇ ` : 25 := bounded_continuous_function

/- In this file we establish the main result - `subalgebra_of_R2` alongside some
other lemmas regarding algebra and subalgebras.

We shall assume some trivial propositions with arguments in text form.
-/

-- We now need it to consider both ℝ² and X →ᵇ ℝ (BCF) as algebras.
instance R_R2_scalar_mul : has_scalar ℝ (ℝ × ℝ) := ⟨λ β x, (β * x.1, β * x.2)⟩

-- We define the natural ring homomorphism from ℝ to ℝ² : β ↦ (β, β)
def R_to_R2_hom : ℝ →+* ℝ × ℝ :=
⟨λ β, (β, β), rfl, λ x y, rfl, rfl, λ x y, rfl⟩

instance : algebra ℝ (ℝ × ℝ) :=
{ commutes' := λ r x, by simp [mul_comm],
  smul_def' := λ r x, rfl,
  .. R_R2_scalar_mul, .. R_to_R2_hom }

/- While we find an algebra already constructed for BCF, it requires
normed_algebra ℝ ℝ, so we will prove that here.

As ℝ over ℝ is already an R-algebra, we just have to prove the isometry part
which is true by definition. -/
instance : normed_algebra ℝ ℝ := ⟨λ x, rfl⟩

lemma subalgebra_nonempty (S : subalgebra ℝ (ℝ × ℝ)) :
∃ x, x ∈ S.carrier := ⟨1, S.2.2.1⟩

lemma subalgebra_closed_under_plus {S : subalgebra ℝ (ℝ × ℝ)} :
∀ (x y), x ∈ S.carrier → y ∈ S.carrier → x + y ∈ S.carrier := S.2.1.1.2

lemma subalgebra_closed_under_mul {S : subalgebra ℝ (ℝ × ℝ)} :
∀ (x y), x ∈ S.carrier → y ∈ S.carrier → x * y ∈ S.carrier := S.2.2.2

-- This should be true since a subalgebra is an algebra so it's closed under smul
lemma subalgebra_closed_under_smul {S : subalgebra ℝ (ℝ × ℝ)} :
∀ (α : ℝ) {x}, x ∈ S.carrier → α • x ∈ S.carrier := sorry

lemma non_zero_fst {S : subalgebra ℝ (ℝ × ℝ)} {β}
(h : ((β, 0) : ℝ × ℝ) ∈ S.carrier) (hβ : β ≠ 0) :
∀ γ, ((γ, 0) : ℝ × ℝ) ∈ S.carrier := λ γ,
begin
  convert subalgebra_closed_under_smul (γ / β) h,
  exact ((eq_div_iff hβ).mp rfl).symm, simp only [mul_zero]
end

lemma non_zero_snd {S : subalgebra ℝ (ℝ × ℝ)} {β}
(h : ((0, β) : ℝ × ℝ) ∈ S.carrier) (hβ : β ≠ 0) :
∀ γ, ((0, γ) : ℝ × ℝ) ∈ S.carrier := λ γ,
begin
  convert subalgebra_closed_under_smul (γ / β) h,
  simp only [mul_zero], exact ((eq_div_iff hβ).mp rfl).symm
end

/- The proof of this considers if β.1 ≠ β.2, β and β² are linearly independent
and hence spans the entire space of ℝ² -/
lemma non_zero_fst_snd {S : subalgebra ℝ (ℝ × ℝ)} {β γ}
(h₀ : (β : ℝ × ℝ) ∈ S.carrier) (hβ : β.1 ≠ 0)
(h₁ : (γ : ℝ × ℝ) ∈ S.carrier) (hγ : γ.2 ≠ 0)
(hβγ : β ≠ γ) : ∀ δ, δ ∈ S.carrier := sorry

lemma non_zero_eq {S : subalgebra ℝ (ℝ × ℝ)} {β}
(h : (β : ℝ × ℝ) ∈ S.carrier) (hβ : β.1 = β.2) (hnz : β ≠ 0):
∀ γ, ((γ, γ) : ℝ × ℝ) ∈ S.carrier := λ γ,
begin
  have : β.1 ≠ 0 ∨ β.2 ≠ 0,
    by_contra hn, push_neg at hn,
    refine hnz (prod.ext hn.1 hn.2),
  cases this; convert subalgebra_closed_under_smul (γ / β.1) h;
    try { rw ←hβ at * }; exact (div_eq_iff this).mp rfl
end

/- We prove by considering all cases that a subalgebra of ℝ² must be a set
of one of the indicated forms. -/
theorem subalgebra_of_R2 (S : subalgebra ℝ (ℝ × ℝ)) :
S.carrier = {(0, 0)} ∨
S.carrier = {p | ∃ x : ℝ, p = (x, 0)} ∨
S.carrier = {p | ∃ y : ℝ, p = (0, y)} ∨
S.carrier = {p | ∃ z : ℝ, p = (z, z)} ∨
S.carrier = univ :=
begin
  by_cases (∀ s : ℝ × ℝ, s ∈ S.carrier → s.1 = s.2),
    { cases em (∀ s : ℝ × ℝ, s ∈ S.carrier → s = 0) with hz hnz,
      cases subalgebra_nonempty S with s hs,
      left, ext, split; intro hx,
        { exact hz _ hx },
        { cases subalgebra_nonempty S with s hs, finish [hz _ hs] },
      push_neg at hnz, cases hnz with s hs,
      iterate 3 { right }, left, ext, split; intro hx,
        { refine ⟨x.1, _⟩, apply prod.ext, refl, rw h x hx },
        { cases hx with z hz, rw hz, exact non_zero_eq hs.1 (h s hs.1) hs.2 z} },
    { push_neg at h, rcases h with ⟨s, hs₀, hs₁⟩,
      by_cases (s.1 = 0), rw h at hs₁,
      cases em (∃ (t : ℝ × ℝ) (ht : t ∈ S.carrier) (ht' : t ≠ s), t.1 ≠ 0) with ht ht,
        { rcases ht with ⟨t, ht₀, ht₁, ht₂⟩, iterate 4 { right },
          ext, split; intro hx,
            exact mem_univ x, exact non_zero_fst_snd ht₀ ht₂ hs₀ hs₁.symm ht₁ x },
        { push_neg at ht, iterate 2 { right }, left,
          ext, split; intro hx,
            cases em (x = s) with hxs hnxs,
            refine ⟨s.2, _⟩, rw [hxs, ←h], simp only [prod.mk.eta],
            refine ⟨x.2, _⟩, rw ←(ht x hx hnxs), simp only [prod.mk.eta],
            cases hx with p hp, rw hp,
            refine non_zero_snd _ hs₁.symm p, rw ←h, simp only [prod.mk.eta, hs₀] },
      cases em (∃ (t : ℝ × ℝ) (ht : t ∈ S.carrier) (ht' : t ≠ s), t.2 ≠ 0) with ht ht,
        { rcases ht with ⟨t, ht₀, ht₁, ht₂⟩,
          iterate 4 { right }, ext, split; intro hx,
            exact mem_univ x, exact non_zero_fst_snd hs₀ h ht₀ ht₂ ht₁.symm x },
        { push_neg at ht,
          right, left, ext, split; intro hx,
            cases em (x = s) with hxs hnxs,
            cases em (x.2 = 0) with hz hnz,
            refine ⟨x.1, _⟩, rw ←hz, simp only [prod.mk.eta, hs₀],
            exfalso, have hndouble : s + s ≠ s,
              suffices : s ≠ 0, simpa only [add_right_eq_self, ne.def],
              intro hs, cases hs, apply h, simp only [],
            have := ht (s + s) (subalgebra_closed_under_plus s s hs₀ hs₀) hndouble,
            have : s.2 = 0, simp at this, linarith [this],
            apply hnz, rwa hxs,
            refine ⟨x.1, _⟩, rw ←(ht x hx hnxs), simp only [prod.mk.eta, hs₀],
            cases hx with p hp, rw hp,
            cases em (s.2 = 0) with hsnd hsnd,
            refine non_zero_fst _ h p,
            rw ←hsnd, simp only [prod.mk.eta, hs₀],
            exfalso, have hndouble : s + s ≠ s,
              suffices : s ≠ 0, simpa only [add_right_eq_self, ne.def],
              intro hs, cases hs, apply h, simp only [],
            have := ht (s + s) (subalgebra_closed_under_plus s s hs₀ hs₀) hndouble,
            have : s.2 = 0, simp at this, linarith [this],
            contradiction } }
end